@RequestParam @RequestBody @PathVariable parameter binding annotations (GO)

Source: Internet
Author: User


Brief introduction:


The handler method parameter binds common annotations, which we divide into four categories according to the different contents of the request they process: (mainly on common types)



A, the processing Requet URI part (here refers to the URI template in variable, does not contain the QueryString part) the annotation: @PathVariable;



B, the processing of the request header section of the note: @RequestHeader, @CookieValue;



C, the processing of the request body part of the note: @RequestParam, @RequestBody;



D, processing attribute type is annotated: @SessionAttributes, @ModelAttribute;





1. @PathVariable


When using the @requestmapping URI template style mapping, which is Someurl/{paramid}, the Paramid can bind the value passed to the method by @Pathvariable annotations.



Example code:


@Controller
@RequestMapping ("/ owners / {ownerId}")
public class RelativePathUriTemplateController {

  @RequestMapping ("/ pets / {petId}")
  public void findPet (@PathVariable String ownerId, @PathVariable String petId, Model model) {
    // implementation omitted
  }
}
The above code binds the value of the variable ownerId and petId in the URI template to the method parameters. If the method parameter name does not match the variable name in the uri template to be bound, you need to specify the name in the uri template in @PathVariable ("name").


 

@RequestHeader, @CookieValue
@RequestHeader annotation, you can bind the value of the Request header section to the method parameters.

Sample code:

This is the header part of a Request:

Host localhost: 8080
Accept text / html, application / xhtml + xml, application / xml; q = 0.9
Accept-Language fr, en-gb; q = 0.7, en; q = 0.3
Accept-Encoding gzip, deflate
Accept-Charset ISO-8859-1, utf-8; q = 0.7, *; q = 0.7
Keep-Alive 300
@RequestMapping ("/ displayHeaderInfo.do")
public void displayHeaderInfo (@RequestHeader ("Accept-Encoding") String encoding,
                              @RequestHeader ("Keep-Alive") long keepAlive) {

  // ...

}
The above code binds the value of Accept-Encoding in the request header to the parameter encoding, and the value of the Keep-Alive header to the parameter keepAlive.

 

 

@CookieValue can bind the value of the cookie in the Request header to the parameter of the method.

For example, there are the following cookie values:

JSESSIONID = 415A4AC178C59DACE0B2C9CA727CDD84
Parameter binding code:

@RequestMapping ("/ displayHeaderInfo.do")
public void displayHeaderInfo (@CookieValue ("JSESSIONID") String cookie) {

  // ...

}
That is, the value of JSESSIONID is bound to the parameter cookie.

 

 

3. @ RequestParam, @RequestBody
@RequestParam

A) It is often used to handle simple type bindings. Strings obtained through Request.getParameter () can be directly converted to simple types (String-> Simple type conversion operations are completed by converters configured by ConversionService); request.getParameter () method to get parameters, so you can handle the queryString value in the get method, or the body data value in the post method;

B) Used to process Content-Type: application / x-www-form-urlencoded encoded content, submit method GET, POST;

C) The annotation has two attributes: value, required; value is used to specify the id name of the value to be passed in, required is used to indicate whether the parameter must be bound;

Sample code:

@Controller
@RequestMapping ("/ pets")
@SessionAttributes ("pet")
public class EditPetForm {

    // ...

    @RequestMapping (method = RequestMethod.GET)
    public String setupForm (@RequestParam ("petId") int petId, ModelMap model) {
        Pet pet = this.clinic.loadPet (petId);
        model.addAttribute ("pet", pet);
        return "petForm";
    }

    // ...
@RequestBody

This annotation is often used to handle Content-Type: content that is not application / x-www-form-urlencoded, such as application / json, application / xml, etc .;

It uses the HttpMessageConverters configured by the HandlerAdapter to parse the post data body, and then binds it to the corresponding bean.

Because it is configured with FormHttpMessageConverter, it can also be used to process the content of application / x-www-form-urlencoded. The processed result is placed in a MultiValueMap <String, String>. This situation is used in some special needs. View FormHttpMessageConverter api;

Sample code:

@RequestMapping (value = "/ something", method = RequestMethod.PUT)
public void handle (@RequestBody String body, Writer writer) throws IOException {
  writer.write (body);
}
4. @ SessionAttributes, @ModelAttribute
@SessionAttributes:

This annotation is used to bind the value of the attribute object in HttpSession, which is convenient for use in the parameters of the method.

The annotation has two attributes, value and type. You can specify the attribute object to be used by name and type.

Sample code:

@Controller
@RequestMapping ("/ editPet.do")
@SessionAttributes ("pet")
public class EditPetForm {
    // ...
}
@ModelAttribute

This annotation has two uses, one for methods and one for parameters;

When used on methods: It is usually used to bind the model that needs to be queried from the background before processing @RequestMapping;

When used on parameters: It is used to bind the value of the corresponding name to the annotation parameter bean through name correspondence; the value to be bound comes from:

A) @SessionAttributes enabled attribute object;

B) @ModelAttribute is the model object specified when used on the method;

C) When neither of the above situations exists, new a bean object that needs to be bound, and then bind the value to the bean in the request corresponding to the name.

 

Example code using method @ModelAttribute:

// Add one attribute
// The return value of the method is added to the model under the name "account"
// You can customize the name via @ModelAttribute ("myAccount")

@ModelAttribute
public Account addAccount (@RequestParam String number) {
    return accountManager.findAccount (number);
}
The practical effect of this method is to put ("account", Account) in the model of the request object before calling the @RequestMapping method;

 

 

@ModelAttribute sample code used on parameters:

@RequestMapping (value = "/ owners / {ownerId} / pets / {petId} / edit", method = RequestMethod.POST)
public String processSubmit (@ModelAttribute Pet pet) {
   
}
First, check whether the @SessionAttributes is bound to a Pet object. If not, check whether the @ModelAttribute method is bound to a Pet object. If not, bind the value in the URI template to each attribute of the Pet object according to the corresponding name. .


 

Additional explanation: Question: How are parameters bound without a given annotation?
By analyzing the source code of AnnotationMethodHandlerAdapter and RequestMappingHandlerAdapter, it is found that the method's parameters are given without parameters:

To bind an object when simple type: Call @RequestParam to handle it.

To bind an object to a complex type: Call @ModelAttribute to handle it.

The simple type here refers to the types of java primitive types (boolean, int, etc.), primitive type objects (Boolean, Int, etc.), String, Date, and other ConversionServices that can be directly converted from String to target objects;

 

The source code of binding parameters in AnnotationMethodHandlerAdapter is posted below:

private Object [] resolveHandlerArguments (Method handlerMethod, Object handler,
            NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {

        Class [] paramTypes = handlerMethod.getParameterTypes ();
        Object [] args = new Object [paramTypes.length];

        for (int i = 0; i <args.length; i ++) {
            MethodParameter methodParam = new MethodParameter (handlerMethod, i);
            methodParam.initParameterNameDiscovery (this.parameterNameDiscoverer);
            GenericTypeResolver.resolveParameterType (methodParam, handler.getClass ());
            String paramName = null;
            String headerName = null;
boolean requestBodyFound = false;
            String cookieName = null;
            String pathVarName = null;
            String attrName = null;
            boolean required = false;
            String defaultValue = null;
            boolean validate = false;
            Object [] validationHints = null;
            int annotationsFound = 0;
            Annotation [] paramAnns = methodParam.getParameterAnnotations ();

            for (Annotation paramAnn: paramAnns) {
                if (RequestParam.class.isInstance (paramAnn)) {
                    RequestParam requestParam = (RequestParam) paramAnn;
                    paramName = requestParam.value ();
                    required = requestParam.required ();
                    defaultValue = parseDefaultValueAttribute (requestParam.defaultValue ());
                    annotationsFound ++;
                }
                else if (RequestHeader.class.isInstance (paramAnn)) {
                    RequestHeader requestHeader = (RequestHeader) paramAnn;
                    headerName = requestHeader.value ();
                    required = requestHeader.required ();
                    defaultValue = parseDefaultValueAttribute (requestHeader.defaultValue ());
                    annotationsFound ++;
                }
                else if (RequestBody.class.isInstance (paramAnn)) {
                    requestBodyFound = true;
                    annotationsFound ++;
                }
                else if (CookieValue.class.isInstance (paramAnn)) {
                    CookieValue cookieValue = (CookieValue) paramAnn;
                    cookieName = cookieValue.value ();
                    required = cookieValue.required ();
                    defaultValue = parseDefaultValueAttribute (cookieValue.defaultValue ());
                    annotationsFound ++;
                }
                else if (PathVariable.class.isInstance (paramAnn)) {
                    PathVariable pathVar = (PathVariable) paramAnn;
                    pathVarName = pathVar.value ();
                    annotationsFound ++;
                }
                else if (ModelAttribute.class.isInstance (paramAnn)) {
                    ModelAttribute attr = (ModelAttribute) paramAnn;
                    attrName = attr.value ();
                    annotationsFound ++;
                }
                else if (Value.class.isInstance (paramAnn)) {
                    defaultValue = ((Value) paramAnn) .value ();
                }
                else if (paramAnn.annotationType (). getSimpleName (). startsWith ("Valid")) {
                    validate = true;
                    Object value = AnnotationUtils.getValue (paramAnn);
                    validationHints = (value instanceof Object []? (Object []) value: new Object [] {value});
                }
            }

            if (annotationsFound> 1) {
                throw new IllegalStateException ("Handler parameter annotations are exclusive choices-" +
                        "do not specify more than one such annotation on the same parameter:" + handlerMethod);
            }

            if (annotationsFound == 0) {// if no annotations are found
                Object argValue = resolveCommonArgument (methodParam, webRequest); // Determine whether WebRquest can be assigned to a parameter
                if (argValue! = WebArgumentResolver.UNRESOLVED) {
                    args [i] = argValue;
                }
                else if (defaultValue! = null) {
                    args [i] = resolveDefaultValue (defaultValue);
                }
                else {
                    Class <?> ParamType = methodParam.getParameterType ();
                    if (Model.class.isAssignableFrom (paramType) || Map.class.isAssignableFrom (paramType)) {
                        if (! paramType.isAssignableFrom (implicitModel.getClass ())) {
                            throw new IllegalStateException ("Argument [" + paramType.getSimpleName () + "] is of type" +
                                    "Model or Map but is not assignable from the actual model. You may need to switch" +
                                    "newer MVC infrastructure classes to use this argument.");
                        }
                        args [i] = implicitModel;
                    }
                    else if (SessionStatus.class.isAssignableFrom (paramType)) {
                        args [i] = this.sessionStatus;
                    }
                    else if (HttpEntity.class.isAssignableFrom (paramType)) {
                        args [i] = resolveHttpEntityRequest (methodParam, webRequest);
                    }
                    else if (Errors.class.isAssignableFrom (paramType)) {
                        throw new IllegalStateException ("Errors / BindingResult argument declared" +
                                "without preceding model attribute. Check your handler method signature!");
                    }
                    else if (BeanUtils.isSimpleProperty (paramType)) {// determine whether the parameter type is a simple type, if it is being processed using @RequestParam, otherwise use @ModelAttri
bute way deal
                        paramName = "";
                    }
                    else {
                        attrName = "";
                    }
                }
            }

            if (paramName! = null) {
                args [i] = resolveRequestParam (paramName, required, defaultValue, methodParam, webRequest, handler);
            }
            else if (headerName! = null) {
                args [i] = resolveRequestHeader (headerName, required, defaultValue, methodParam, webRequest, handler);
            }
            else if (requestBodyFound) {
                args [i] = resolveRequestBody (methodParam, webRequest, handler);
            }
            else if (cookieName! = null) {
                args [i] = resolveCookieValue (cookieName, required, defaultValue, methodParam, webRequest, handler);
            }
            else if (pathVarName! = null) {
                args [i] = resolvePathVariable (pathVarName, methodParam, webRequest, handler);
            }
            else if (attrName! = null) {
                WebDataBinder binder =
                        resolveModelAttribute (attrName, methodParam, implicitModel, webRequest, handler);
                boolean assignBindingResult = (args.length> i + 1 && Errors.class.isAssignableFrom (paramTypes [i + 1]));
                if (binder.getTarget ()! = null) {
                    doBind (binder, webRequest, validate, validationHints,! assignBindingResult);
                }
                args [i] = binder.getTarget ();
                if (assignBindingResult) {
                    args [i + 1] = binder.getBindingResult ();
                    i ++;
                }
                implicitModel.putAll (binder.getBindingResult (). getModel ());
            }
        }

        return args;
    }
The parameter binding used in RequestMappingHandlerAdapter, the code is slightly different, and interested colleagues can analyze it, and the final processing results are the same.

 

Example:

@RequestMapping ({"/", "/ home"})
    public String showHomePage (String key) {
        
        logger.debug ("key =" + key);
        
        return "home";
    }
In this case, the default @RequestParam is called to handle it.

    @RequestMapping (method = RequestMethod.POST)
    public String doRegister (User user) {
        if (logger.isDebugEnabled ()) {
            logger.debug ("process url [/ user], method [post] in" + getClass ());
            logger.debug (user);
        }

        return "user";
    }
In this case, @ModelAttribute is called to handle it.

 

 

Reference documents:
1. Spring Web Doc:

spring-3.1.0 / docs / spring-framework-reference / html / mvc.html
@RequestParam @RequestBody @PathVariable and other parameter binding annotations

Related Article

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.