After an article on the @requestmapping address mapping, this article mainly explains the request data to the handler method parameter data binding used in the annotations and under what circumstances;
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 in the URI template and the value of the Petid to the parameter of the method. If the variable names in the method parameter names and URI template that need to be bound are inconsistent, you need to specify the name in the URI template in @pathvariable ("name").
2. @RequestHeader, @CookieValue
@RequestHeader annotations, you can bind the value of the header portion of a request to a method parameter.
Example code:
Here is a header part of the request:
Host localhost:8080accept text/html,application/xhtml+xml,application/xml;q=0.9accept-language fr, En-gb;q=0.7,en;q=0.3accept-encoding gzip,deflateaccept-charset iso-8859-1,utf-8;q=0.7,*;q= 0.7keep-alive 300
@RequestMapping ("/displayheaderinfo.do") public void Displayheaderinfo (@RequestHeader ("accept-encoding") String Encoding, @RequestHeader ("keep-alive") long keepAlive) { //...}
The above code binds the accept-encoding value of the request header part to the parameter encoding, and the value of the keep-alive header is bound to the parameter keepalive.
@CookieValue can bind the value of the cookie in the request header to the parameters of the method.
For example, there are the following cookie values:
jsessionid=415a4ac178c59dace0b2c9ca727cdd84
Code for parameter binding:
@RequestMapping ("/displayheaderinfo.do") public void Displayheaderinfo (@CookieValue ("Jsessionid") String cookie) { //...}
That is, bind the value of the Jsessionid to the parameter cookie.
3, @RequestParam, @RequestBody
@RequestParam
A) commonly used to deal with simple types of bindings, a String obtained by Request.getparameter () can be converted directly into a simple type case (string--> The conversion of a simple type is done by a converter configured by Conversionservice), because the parameter is obtained using the Request.getparameter () method, so you can handle the value of querystring in the Get mode, or you can handle the post mode The value of body data;
B) used to process Content-type: For application/x-www-form-urlencoded encoded content, submit way get, POST;
C) The note has two properties: value, required, value specifies the ID name to pass in the value, and required is used to indicate whether the parameter must be bound;
Example 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 deal with Content-type: not application/x-www-form-urlencoded encoded content, such as Application/json, application/xml, etc.;
It is configured by using Handleradapter HttpMessageConverters to parse the post data body and then bind to the corresponding bean.
Because the configuration has formhttpmessageconverter, so can also be used to deal with application/x-www-form-urlencoded the content, processed results in a multivaluemap<string, string>, this situation in some special needs to use, See Formhttpmessageconverter API for details;
Example code:
@RequestMapping (value = "/something", method = requestmethod.put) public void handle (@RequestBody String body, Writer writ ER) throws IOException { writer.write (body);}
4, @SessionAttributes, @ModelAttribute
@SessionAttributes:
This annotation is used to bind the value of the attribute object in the HttpSession, which is convenient for use in parameters in the method.
The annotation has value, types two attributes, and can specify the attribute object to use by name and type;
Example code:
@Controller @requestmapping ("/editpet.do") @SessionAttributes ("Pet") public class Editpetform { //...}
@ModelAttribute
The note has two usages, one for the method and one for the parameter;
When used on a method: the model that needs to be queried from the background to bind the request before processing @requestmapping;
When used on parameters: used to bind the value of the corresponding name to the parameter bean of the annotation by name, and the value to be bound is derived from:
A) on the attribute object that is @SessionAttributes enabled;
B) @ModelAttribute for the model object specified on the method;
C) In either case, the new one needs to bind the Bean object, and then binds the value in the request to the bean in the same way as the name.
Sample code to @modelattribute on the method:
ADD one attribute//The return value of the added to the model under the name ' account '//You can customize T He name via @ModelAttribute ("MyAccount") @ModelAttributepublic account AddAccount (@RequestParam String number) { return Accountmanager.findaccount (number);}
The actual effect of this method is to put ("account" and account) in the model of the request object before invoking the @requestmapping method.
The @modelattribute sample code that is used on the parameter:
@RequestMapping (value= "/owners/{ownerid}/pets/{petid}/edit", method = requestmethod.post) public String Processsubmit (@ModelAttribute Pet Pet) { }
The first query @SessionAttributes there is no bound pet object, if not the query @modelattribute method layer is bound to the Pet object, if not the value in the URI template is bound to the properties of the pet object by the corresponding name.
Supplementary explanation: Question: How is a parameter bound without a given annotation?
By analyzing source code discovery for Annotationmethodhandleradapter and Requestmappinghandleradapter, the parameters of the method are not given in the case of parameters:
To bind an object to a simple type: Call @requestparam to handle it.
To bind an object when complex type: Call @modelattribute to process.
The simple Type here refers to the primitive type of Java (boolean, int, etc.), primitive type Object (boolean, int, etc.), string, date, etc. conversionservice can directly convert the string into the target object type;
The following is a partial source code for binding parameters in Annotationmethodhandleradapter:
Private object[] Resolvehandlerarguments (Method handlermethod, Object handler, Nativewebrequest webRequest, EXT Endedmodelmap 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)) {R Equestparam Requestparam = (requestparam) Paramann; ParamName = Requestparam.value (); Required = requestparam.required (); DefaultValue = Parsedefaultvalueattribute (Requestparam.defaultvalue ()); annotationsfound++; } else if (RequestHeader.class.isInstance (Paramann)) {Requestheader Requestheader = (Re Questheader) 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 = (Cookieva Lue) Paramann; CookieName = Cookievalue.value (); Required = cookievalue.required (); DefaultValue = Parsedefaultvalueattribute (Cookievalue.defaultvalue ()); annotationsfound++; } else if (PathVariable.class.isInstance (Paramann)) {pathvariable Pathvar = (Pathvariab Le) Paramann; Pathvarname = Pathvar.value (); annotationsfound++; } else if (ModelAttribute.class.isInstance (Paramann)) {Modelattribute attr = (modelattr Ibute) Paramann; Attrname = Attr.value (); annotationsfound++; } else if (Value.class.isInstance(Paramann)) {defaultvalue = (value) Paramann). Value (); } else if (Paramann.annotationtype (). Getsimplename (). StartsWith ("Valid")) {validate = T Rue Object value = Annotationutils.getvalue (Paramann); Validationhints = (value instanceof object[]? (object[]) value:new object[] {value}); }} if (Annotationsfound > 1) {throw new IllegalStateException ("Handler parameter Annotations is exclusive choices-"+" does not specify more than one such annotation on the same Parameter: "+ Handlermethod); } if (Annotationsfound = = 0) {//If no annotations are found for Object argvalue = resolvecommonargument (Methodparam, we Brequest); Determine if webrquest can be assigned to a parameter if (argvalue! = webargumentresolver.unresolved) {Args[i] = Argval Ue } 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" is not a assignable from the actual Model. You could need to switch "+" newer MVC infrastructure classes to use this argument. "); } Args[i] = Implicitmodel; } else if (SessionStatus.class.isAssignableFrom (Paramtype)) {Args[i] = this.ses Sionstatus; } elsE if (HttpEntity.class.isAssignableFrom (Paramtype)) {Args[i] = Resolvehttpentityrequest (Methodpara M, webRequest); } else if (Errors.class.isAssignableFrom (Paramtype)) {throw new Illegalstateexc Eption ("Errors/bindingresult argument declared" + "without preceding model attribute. Check your handler method signature! ");} else if (Beanutils.issimpleproperty (Paramtype)) {//Determines whether the parameter type is a simple type, if it is handled using the @requestparam method, Otherwise, the @modelattribute method is used to process 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, DE Faultvalue, Methodparam, WebRequest, Handler); } else if (pathvarname! = null) {Args[i] = resolvepathvariable (Pathvarname, Methodparam, Webreq Uest, Handler); } else if (attrname! = null) {Webdatabinder Binder = Resolvemodelattribu Te (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,!assi GnbiNdingresult); } Args[i] = Binder.gettarget (); if (Assignbindingresult) {args[i + 1] = Binder.getbindingresult (); i++; } implicitmodel.putall (Binder.getbindingresult (). Getmodel ()); }} return args; }
Requestmappinghandleradapter used in the parameter binding, the code is slightly different, interested colleagues can analyze, 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 process.
@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, the call to @modelattribute is processed.
Reference Documentation:
1. Spring Web Doc:
Spring-3.1.0/docs/spring-framework-reference/html/mvc.html
@RequestParam @RequestBody @PathVariable parameter binding annotations (GO)