Detailed description of the working principle of parameters in the Controller Method in SpringMVC [with source code analysis]

Source: Internet
Author: User
Tags dateformat

Directory

  • Preface
  • Symptom
  • Source code analysis
    • HandlerMethodArgumentResolver and HandlerMethodReturnValueHandler
    • HandlerMethodArgumentResolver and HandlerMethodReturnValueHandler
    • Introduction to HandlerMethodArgumentResolver
    • Introduction to HandlerMethodReturnValueHandler
    • Symptoms and solutions at the beginning of this article
  • Write custom HandlerMethodArgumentResolver
  • Summary
  • References
Preface

SpringMVC is one of the mainstream Web MVC frameworks.

If you are not familiar with it, please refer to its entry blog: http://www.cnblogs.com/fangjian0423/p/springMVC-introduction.html

The Controller method parameters in SpringMVC can be Integer, Double, custom object, ServletRequest, ServletResponse, ModelAndView, and so on. This article will analyze how SpringMVC processes these parameters so that readers can process custom parameters.

Symptom

The demo used in this article is based on maven. Let's take a look at the corresponding phenomenon.

@Controller@RequestMapping(value = "/test")public class TestController {    @RequestMapping("/testRb")  @ResponseBody  public Employee testRb(@RequestBody Employee e) {    return e;  }    @RequestMapping("/testCustomObj")  @ResponseBody  public Employee testCustomObj(Employee e) {    return e;  }    @RequestMapping("/testCustomObjWithRp")  @ResponseBody  public Employee testCustomObjWithRp(@RequestParam Employee e) {    return e;  }    @RequestMapping("/testDate")  @ResponseBody  public Date testDate(Date date) {    return date;  }  }

First, this is a Controller with four methods. Their corresponding parameters are custom objects with @ RequestBody, custom objects with @ RequestParam, and date objects.

Next, we will perform access one by one to see what the corresponding phenomenon is.

First, the first testRb:

 

The second testCustomObj:

The third testCustomObjWithRp:

Fourth testDate:

 

Why is the returned Employee object automatically parsed as xml? Please refer to another blog of the author: Stamp me

Why is the Employee parameter parsed, and the Employee parameter with @ RequestParam not parsed or even reported an error?

Why cannot the date type be parsed?

How does SpringMVC handle the parameters of these methods?

@ RequestBody and @ RequestParam are two annotations different?

With these questions. Let's start the analysis.

Source code analysis

The source code analyzed in this article is Spring 4.0.2.

Before analyzing the source code, let's take a look at two important interfaces in SpringMVC.

The two interfaces correspond to the processing of request method parameters and the processing of response return values respectively.HandlerMethodArgumentResolverAndHandlerMethodReturnValueHandlerThe two interfaces are added after Spring3.1.

SpringMVC processes requests like this:

DispatcherServlet intercepts HandlerExecutionChain first, and DispatcherServlet obtains HandlerExecutionChain through handlerMapping, and then obtains HandlerAdapter.

The HandlerAdapter instantiates a ServletInvocableHandlerMethod for processing each request internally,The ServletInvocableHandlerMethod processes the request and response in two parts..

Then HandlerAdapter gets ModelAndView and then processes it accordingly.

This article focuses on how ServletInvocableHandlerMethod processes requests and responses.

1. when processing a request, it will be processed according to the attribute argumentResolvers (defined in its parent class InvocableHandlerMethod) of ServletInvocableHandlerMethod, the argumentResolvers attribute is an aggregate class (a type of deformation in the combination mode is used here). This class implements the HandlerMethodArgumentResolver interface class, which contains various List sets that implement HandlerMethodArgumentResolver.

2. When processing the response, it will be processed according to the returnValueHandlers attribute of ServletInvocableHandlerMethod (its own attribute). The returnValueHandlers attribute is a HandlerMethodReturnValueHandlerComposite class(A deformation of the combination mode is used here)This class implements the HandlerMethodReturnValueHandler interface class, which has various List sets that implement HandlerMethodReturnValueHandler.

The returnValueHandlers and argumentResolvers attributes of ServletInvocableHandlerMethod are assigned values when ServletInvocableHandlerMethod is instantiated (the RequestMappingHandlerAdapter attribute is used to assign values ).

The argumentResolvers and returnValueHandlers attributes of RequestMappingHandlerAdapter are injected by the Spring container when RequestMappingHandlerAdapter is instantiated.

The default ArgumentResolvers is as follows:

Default returnValueHandlers:

 

We have already learned in the article on automatic conversion of json and xml. If the @ ResponseBody annotation is used, the final return value will be processed by the HandlerMethodReturnValueHandler class of RequestResponseBodyMethodProcessor.

We found through the source code that the RequestResponseBodyMethodProcessor class actually implements the HandlerMethodReturnValueHandler and HandlerMethodArgumentResolver interfaces at the same time.

The request type supported by RequestResponseBodyMethodProcessor is the @ RequestBody annotation in the Controller method parameter. The supported response type is the Controller method with the @ ResponseBody annotation.

The message converter is used to process the response of RequestResponseBodyMethodProcessor.

Use the internal readWithMessageConverters method to process requests.

Then the readWithMessageConverters method of the parent class (AbstractMessageConverterMethodArgumentResolver) is executed.

 

Next, let's take a look at the commonly used HandlerMethodArgumentResolver implementation class (in this article, readers who are interested can study it on their own ).

1. RequestParamMethodArgumentResolver

Support Parameters with @ RequestParam annotation or parameters with MultipartFile type

2. RequestParamMapMethodArgumentResolver

Support attribute values with @ RequestParam annotation & @ RequestParam annotation exist & the parameter type is the attribute that implements the Map interface

3. PathVariableMethodArgumentResolver

Supports parameters with the @ PathVariable annotation. If the parameter implements the Map interface, the @ PathVariable annotation must have the value attribute.

4. MatrixVariableMethodArgumentResolver

Supports parameters with the @ MatrixVariable annotation. If the parameter implements the Map interface, the @ MatrixVariable annotation must have the value attribute.

5. RequestResponseBodyMethodProcessor

Analyzed in this article

6. ServletRequestMethodArgumentResolver

Parameter types are implemented or inherited or WebRequest, ServletRequest, MultipartRequest, HttpSession, Principal, Locale, TimeZone, InputStream, Reader, and HttpMethod.

(This is why we add an HttpServletRequest parameter to the Controller method, and Spring will automatically obtain the HttpServletRequest object for us)

7. ServletResponseMethodArgumentResolver

Parameter types are implemented or inherited or ServletResponse, OutputStream, and Writer classes.

8. RedirectAttributesMethodArgumentResolver

The parameter is a class that implements the RedirectAttributes interface.

9. HttpEntityMethodProcessor

The parameter type is HttpEntity.

We can also see from the name that the class ending with Resolver implements the HandlerMethodArgumentResolver interface, and the class ending with Processor implements the HandlerMethodArgumentResolver and HandlerMethodReturnValueHandler classes.

 

Next let's take a look at the commonly used HandlerMethodReturnValueHandler implementation class.

1. ModelAndViewMethodReturnValueHandler

The return value type is ModelAndView or its subclass.

2. ModelMethodProcessor

The return value type is Model or its subclass.

3. ViewMethodReturnValueHandler

The return value type is View or its subclass.

4. HttpHeadersReturnValueHandler

The return value type is HttpHeaders or its subclass.

5. ModelAttributeMethodProcessor

The returned values are annotated with @ ModelAttribute.

6. ViewNameMethodReturnValueHandler

The return value is void or String.

You can view the source code by yourself.

 

The following explains why these phenomena occur at the beginning of this article:

1. The first method is testRb and the address is http: // localhost: 8888/SpringMVCDemo/test/testRb? Name = 1 & age = 3

The parameter of this method uses @ RequestBody, which has been analyzed before and is processed by RequestResponseBodyMethodProcessor. Then, based on the contentType in the http Request Header, select the appropriate message converter for reading.

Obviously, our message converter only has the default json and xml converters, and the passed parameter name = 1 & age = 3. The transmitted header does not contain content-type, application/octet-stream is used by default, so an exception occurs in HttpMediaTypeNotSupportedException.

Liberation solution: Change the transmitted data to json, and change the Content-Type of the http request to application/json.

Perfect solution.

2. testCustomObj method and address http: // localhost: 8888/SpringMVCDemo/test/testCustomObj? Name = 1 & age = 3

This request will find the resolver ServletModelAttributeMethodProcessor. The default resolver contains two ServletModelAttributeMethodProcessor, but the annotationNotRequired attribute is true and the default resolver is false. This ServletModelAttributeMethodProcessor processing parameter supports @ ModelAttribute annotation. If the annotationNotRequired attribute is true, the parameter is not a simple type. Therefore, ServletModelAttributeMethodProcessor is selected, and the Employee object is instantiated through DataBinder and the corresponding attribute.

3. The testCustomObjWithRp method and the address http: // localhost: 8888/SpringMVCDemo/test/testCustomObjWithRp? Name = 1 & age = 3

This request will find RequestParamMethodArgumentResolver (the @ RequestParam annotation is used ). RequestParamMethodArgumentResolver uses request when processing parameters. getParameter (parameter name) is request. getParameter ("e") is obtained. It is obvious that our parameter is passed by name = 1 & age = 3. Therefore, if null is obtained, RequestParamMethodArgumentResolver will trigger the MissingServletRequestParameterException when processing the missing value. [For more information, see the source code.]

Solution: remove the @ RequestParam annotation and let ServletModelAttributeMethodProcessor process the annotation.

4. testDate method and address http: // localhost: 8888/SpringMVCDemo/test/testDate? Date = 2014-05-15

This request will find RequestParamMethodArgumentResolver. Because this method is the same as the second method, there are two RequestParamMethodArgumentResolver, and the attribute useDefaultResolution is different. RequestParamMethodArgumentResolver supports simple types. ServletModelAttributeMethodProcessor supports non-simple types. The final step is the same as the third method. Our parameter name is date, so the request is passed. getParameter ("date") finds the date string (if the parameter name is not date, the final page is blank, because there is no @ RequestParam annotation, and the parameter is not required, requestParamMethodArgumentResolver returns null when processing null values ). Finally, use DataBinder to find an appropriate Attribute Editor for type conversion. Finally, the constructor public Date (String s) of the java. util. Date object is found. Because the format we passed is not the standard UTC time format, the IllegalArgumentException exception is triggered.

Solution:

1. Change the format of the passed parameter to the standard UTC time format: http: // localhost: 8888/SpringMVCDemo/test/testDate? Date = Sat, 17 May 2014 16:30:00 GMT

2. Add the custom attribute editor to the Controller.

@InitBinderpublic void initBinder(WebDataBinder binder) {  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");  binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));}

This @ InitBinder annotation is injected into WebDataBinderFactory when ServletInvocableHandlerMethod is instantiated, while WebDataBinderFactory is an attribute of ServletInvocableHandlerMethod. In the first line of the RequestMappingHandlerAdapter source code, getDataBinderFactory is the obtained WebDataBinderFactory.

Then, RequestParamMethodArgumentResolver uses the custom attribute editor in the WebDataBinderFactory created in WebDataBinder to find the appropriate Attribute Editor (our custom attribute editor uses CustomDateEditor to process Date objects, the testDate parameter is exactly Date), and CustomDateEditor converts the String object to the Date object.

Write custom HandlerMethodArgumentResolver

Through the above analysis, we understand the parameter process of SpringMVC's method in Controller processing.

Now, if there are two parameters in the method and all are custom class parameters, what should we do?

@RequestMapping("/save")public ModelAndView saveAll(@FormModel Employee employee, @FormModel Dept dept, ModelAndView view) {
view.setViewName("test/success"); view.addObject("employee", employee);
view.addObject("dept", dept); return view;}

Let's try it.

Obviously, you can implement only one class to implement HandlerMethodArgumentResolver.

The author has referenced the implementation in this blog. The implementation details will be detailed in the subsequent blog.

The result is as follows:

Summary

After writing so much, I want to consolidate my summary of SpringMVC's handling of requests and responses. I don't know whether this process is clear.

To get familiar with this part of content, you should be familiar with HandlerMethodArgumentResolver and HandlerMethodReturnValueHandler interfaces, as well as the Attribute Editor and data binding mechanism.

This article will inevitably cause errors. I hope readers can point it out.

References

Http://www.iteye.com/topic/1127676

Http://jinnianshilongnian.iteye.com/blog/1717180

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.