Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Controller override @ModelAttribute request param mapping

Let's say I have a Spring Controller like this:

    @Controller
    public class FooController {

        @RequestMapping(value = "/foo", method = RequestMethod.GET)
        public String update (Model model,
                          @RequestParam (value="id") String id,
                          @RequestParam (value="description") String description) {

                Foo foo = new Foo(id, description);

                fooService.create(update);

        return "foo";
    }

I'd like to re-write it like follows, but define my own request param mapping rather than let Spring's @ModelAttribute define it:

    @Controller
    public class FooController {

        @RequestMapping(value = "/foo", method = RequestMethod.GET)
        public String update(Model model,
                          @ModelAttribute("foo") Foo foo) {

        fooService.update(foo);

        return "foo";
    }

Does anyone know how I would do this? I have looked at converters, PropertyEditors and using @RequestBody but I don't think any of these are quite right. I need to somehow override Spring's databinding it seems.

like image 276
Stuart Avatar asked Jul 03 '26 13:07

Stuart


1 Answers

The solution I settled on was to use implement Spring's HandlerMethodArgumentResolver class to detect the Object and construct it from the HttpServletRequest. Note - this is very similar to @daviooh's answer. The main difference here is that this solution is Spring specific and it can detect the object class "automatically".

Add to spring context.xml

<mvc:annotation-driven>
    <mvc:argument-resolvers>
        <bean class="your.package.name.FooResolver" />   
    </mvc:argument-resolvers>
</mvc:annotation-driven>

Create the FooResolver:

public class FooResolver implements HandlerMethodArgumentResolver {

public static final String ID = "id";
public static final String DESCRIPTION = "description";

@Override
public boolean supportsParameter(MethodParameter parameter) {
    return parameter.getParameterType().equals(Foo.class);
}

@Override
public Object resolveArgument(MethodParameter parameter,
                              ModelAndViewContainer mavContainer, 
                              NativeWebRequest webRequest,
                              WebDataBinderFactory binderFactory) throws Exception {

    Foo foo = null;

    if(parameter.getParameterType().equals(Foo.class)) {

        foo = new Foo();

        if (webRequest.getParameter(ID) != null) tag.setId((String) webRequest.getParameter(ID));
        if (webRequest.getParameter(DESCRIPTION) != null) tag.setDescription((String) webRequest.getParameter(DESCRIPTION));
    }

    return foo;
}

}

Then controller method becomes:

    @RequestMapping(value = "/foo", method = RequestMethod.GET)
    public String update (Model model, Foo foo) {
        fooService.update(foo);
        return "foo";
    }

This solution allows me to de-couple the http request parameter names from the getter and setter method names on my model objects and pull this logic out of my controller so as to keep it uncluttered and so easier to follow. So controller logic is in the controller and http request to object mapping logic is in the resolver class.

like image 143
Stuart Avatar answered Jul 05 '26 03:07

Stuart



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!