Pergunta

This is the code example from Spring 3.1 Spring Source Blog: From XML to @Configuration I'm trying to implement in my application (which was done in Spring 2.0 not by me so it's lot of learning).

@FeatureConfiguration
class MvcFeatures {

    @Feature
    public MvcAnnotationDriven annotationDriven(ConversionService conversionService) {
        return new MvcAnnotationDriven().conversionService(conversionService)
            .argumentResolvers(new CustomArgumentResolver());
    }

    // ...

}

However, I can't understand the point of .argumentResolvers(new CustomArgumentResolver()) and their CustomArgumentResolver looks like bellow. What's the point of it?

public class CustomArgumentResolver implements WebArgumentResolver {

    @Override
    public Object resolveArgument(MethodParameter param, NativeWebRequest request) throws Exception {
        RequestAttribute attr = param.getParameterAnnotation(RequestAttribute.class);
        if (attr != null) {
            return request.getAttribute(attr.value(), WebRequest.SCOPE_REQUEST);
        } else {
            return WebArgumentResolver.UNRESOLVED;
        }
    }
}
Foi útil?

Solução

To add to @GaryF's answer, and to clarify some points, Spring 2.5 introduced annotated controllers, which replaced the old interface-style controllers of Spring 2.0. These new controllers have methods with no fixed parameters - the method declares the parameters that it needs to do its job, and nothing more.

For example, say a controller method needed one thing to do its job - a request parameter that contains the ID of an object from the database. In Spring 2.0, you would need to implement something like AbstractController.handleRequestInternal(), e.g

protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) {
   String id = request.getParameter("id");
   MyThing obj = getObjById(id);
   //... do stuff and return ModelAndView
}

Spring 2.5 made that easier:

@RequestMapping
public ModelAndView handle(String id) {
   MyThing obj = getObjById(id);
   //... do stuff and return ModelAndView
}

Here, we only declare parameters for the stuff we need.

So far so good, but this is where a custom WebArgumentResolver comes in. Say I want to remove the getObjById from my controller altogether, because maybe I think it clutters up the code, and maybe it's used across many other controller methods. Instead, I want to do this:

@RequestMapping
public ModelAndView handle(MyThing id) {
   //... do stuff and return ModelAndView
}

It's even simpler, and has a bare minimum of boilerplate code. A custom WebArgumentResolver can be registered with the app-context which recognises parameters of type MyThing, and knows how to extract the information from the request. Spring invokes that resolver, and passes the result to the controller method.

Custom resolvers aren't commonly used, but can be very handy in the right situation.

The example in your question uses CustomArgumentResolver to resolve the example's custom RequestAttribute class. The resolver pulls out request attributes and binds them to RequestAttribute objects, so that they can be declared as controller method parameters.

Outras dicas

WebArgumentResolvers are a way for you to specify how the parameters of MVC-mapped methods should be resolved. If you'd like to use a custom object as a parameter for an MVC-mapped method, Spring tries to figure out how make sense of it in it's own way. Typically this would happen through binding, where some http parameters you submit match up with the fields of the object and Spring matches them up and creates a new object for you.

If you ever have a situation where the submitted parameters don't match up quite so neatly with your method parameters, WebArgumentResolvers are there to fill in the gap: you provide custom logic so Spring doesn't have to figure it out.

In your example, param is one such parameter to be matched up. This piece of custom code first checks if the parameter has an @RequestAttribute annotation. If it does, then the custom code pulls the value from that object and looks it up as an attribute on the http request, returning it. It it does not have that annotation, then the method returns the UNRESOLVED value, which simply indicates that this WebArgumentResolver doesn't know anything about this particular parameter and Spring should try a different method (such as binding).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top