spring 参数绑定

部分资料来源:

  1. @RequestParam @RequestBody @PathVariable 等参数绑定注解详解
  2. spring学习之@ModelAttribute运用详解
  3. Spring MVC @ModelAttribute 详解

简介

handler method 参数绑定常用的注解,我们根据他们处理的Request的不同内容部分分为四类:(主要讲解常用类型)

  1. 处理requet uri 部分(这里指uri template中variable,不含queryString部分)的注解: @PathVariable;
  2. 处理request header部分的注解: @RequestHeader, @CookieValue;
  3. 处理request body部分的注解:@RequestParam, @RequestBody;
  4. 处理attribute类型是注解: @SessionAttributes, @ModelAttribute;

@RequestBody作用:

  1. 该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上;
  2. 再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上。

使用时机:

  1. GET、POST方式提时, 根据request header Content-Type的值来判断:
    application/x-www-form-urlencoded, 可选(即非必须,因为这种情况的数据 @RequestParam, @ModelAttribute也可以处理,当然 @RequestBody也能处理);
    multipart/form-data, 不能处理(即使用 @RequestBody不能处理这种格式的数据);
    其他格式, 必须(其他格式包括application/json, application/xml等。这些格式的数据,必须使用 @RequestBody来处理);
  2. PUT方式提交时, 根据request header Content-Type的值来判断:
    application/x-www-form-urlencoded, 必须;
    multipart/form-data, 不能处理;
    其他格式, 必须;
    说明:request的body部分的数据编码格式由header部分的Content-Type指定;

@ResponseBody作用:
该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。
使用时机:
返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;

@PathVariable

当使用 @RequestMapping URI template 样式映射时, 即 someUrl/{paramId}, 这时的paramId可通过 @Pathvariable注解绑定它传过来的值到方法的参数上。

  @RequestMapping("/pets/{petId}")  
  public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {      
    // implementation omitted  
  }  

上面代码把URI template 中变量 ownerId的值和petId的值,绑定到方法的参数上。
若方法参数名称和需要绑定的uri template中变量名称不一致,需要在 @PathVariable("name")指定uri template中的名称。

@RequestHeader, @CookieValue

@RequestHeader 注解,可以把Request请求header部分的值绑定到方法的参数上。
Request 的header部分示例:

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)  {  
  
  //...  
  
} 

上面的代码,把request header部分的 Accept-Encoding的值,绑定到参数encoding上了,
Keep-Alive header的值绑定到参数keepAlive上。

@CookieValue 可以把Request header中关于cookie的值绑定到方法的参数上。
cookie值如下:

JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84  

参数绑定的代码:

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

即把JSESSIONID的值绑定到参数cookie上。

@RequestParam, @RequestBody

@RequestParam

  1. 常用来处理简单类型的绑定,通过Request.getParameter()
    获取的String可直接转换为简单类型的情况( String--> 简单类型的转换操作由ConversionService配置的转换器来完成);
    因为使用request.getParameter()方式获取参数,所以可以处理get 方式中queryString的值,也可以处理post方式中 body data的值;

  2. 用来处理Content-Type: 为 application/x-www-form-urlencoded编码的内容,提交方式GET、POST;

  3. 该注解有两个属性: value、required; value用来指定要传入值的id名称,required用来指示参数是否必须绑定;

    @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

该注解常用来处理Content-Type: 不是application/x-www-form-urlencoded编码的内容,例如application/json, application/xml等;
它是通过使用HandlerAdapter 配置的HttpMessageConverters来解析post data body,然后绑定到相应的bean上的。

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

@SessionAttributes, @ModelAttribute

@SessionAttributes:
该注解用来绑定HttpSession中的attribute对象的值,便于在方法中的参数里使用。
该注解有value、types两个属性,可以通过名字和类型指定要使用的attribute 对象。
详细描述:
在默认情况下,ModelMap 中的属性作用域是 request 级别是,也就是说,当本次请求结束后,ModelMap 中的属性将销毁。如果希望在多个请求中共享 ModelMap 中的属性,必须将其属性转存到 session 中,这样 ModelMap 的属性才可以被跨请求访问。
Spring 允许我们有选择地指定 ModelMap 中的哪些属性需要转存到 session 中,以便下一个请求属对应的 ModelMap 的属性列表中还能访问到这些属性。这一功能是通过类定义处标注 @SessionAttributes 注解来实现的。

使模型对象的特定属性具有 Session 范围的作用域

package com.baobaotao.web;  

…  
import org.springframework.ui.ModelMap;  
import org.springframework.web.bind.annotation.SessionAttributes;  
  
@Controller  
@RequestMapping("/bbtForum.do")  
@SessionAttributes("currUser") 
//①.将ModelMap中属性名为currUser的属性  
//放到Session属性列表中,以便这个属性可以跨请求访问  
public class BbtForumController {  
…  
    @RequestMapping(params = "method=listBoardTopic")  
    public String listBoardTopic(@RequestParam("id")int topicId, User user,  
ModelMap model) {  
        bbtForumService.getBoardTopics(topicId);  
        System.out.println("topicId:" + topicId);  
        System.out.println("user:" + user);  
        model.addAttribute("currUser",user); //②.向ModelMap中添加一个属性  
        return "listTopic";  
    }  
}  

我们在 ② 处添加了一个 ModelMap 属性,其属性名为 currUser,而 ① 处通过 @SessionAttributes 注解将 ModelMap 中名为 currUser 的属性放置到 Session 中,所以我们不但可以在 listBoardTopic() 请求所对应的 JSP 视图页面中通过 request.getAttribute(“currUser”) 和 session.getAttribute(“currUser”) 获取 user 对象,还可以在下一个请求所对应的 JSP 视图页面中通过 session.getAttribute(“currUser”) 或 ModelMap#get(“currUser”) 访问到这个属性。
这里我们仅将一个 ModelMap 的属性放入 Session 中,其实 @SessionAttributes 允许指定多个属性。你可以通过字符串数组的方式指定多个属性,如 @SessionAttributes({“attr1”,”attr2”})。此外,@SessionAttributes 还可以通过属性类型指定要 session 化的 ModelMap 属性,如 @SessionAttributes(types = User.class),当然也可以指定多个类,如 @SessionAttributes(types = {User.class,Dept.class}),还可以联合使用属性名和属性类型指定:@SessionAttributes(types = {User.class,Dept.class},value={“attr1”,”attr2”})。

@ModelAttribute具有如下三个作用:

  1. 绑定请求参数到命令对象:放在功能处理方法的入参上时,用于将多个请求参数绑定到一个命令对象,从而简化绑定流程,而且自动暴露为模型数据用于视图页面展示时使用。其实 @ModelAttribute此处对于供视图页面展示来说与model.addAttribute("attributeName", abc);功能类似。
    此处多了一个注解 @ModelAttribute("user"),它的作用是将该绑定的命令对象以“user”为名称添加到模型对象中供视图页面展示使用。我们此时可以在视图页面使用${user.username}来获取绑定的命令对象的属性。

    public String test(@ModelAttribute("user") UserModel user) {
    // do sth.
    }

  2. 暴露 @RequestMapping 方法返回值为模型数据:放在功能处理方法的返回值上时,是暴露功能处理方法的返回值为模型数据,用于视图页面展示时使用。
    大家可以看到返回值类型是命令对象类型,而且通过 @ModelAttribute("user2")注解,此时会暴露返回值到模型数据( 名字为user2 ) 中供视图展示使用
    @ModelAttribute 注解的返回值会覆盖 @RequestMapping 注解方法中的 @ModelAttribute 注解的同名命令对象.

    public @ModelAttribute("user2") UserModel test3(@ModelAttribute("user2") UserModel user) {
    // do sth.
    }

  3. 暴露表单引用对象为模型数据:放在处理器的一般方法(非功能处理方法)上时,是为表单准备要展示的表单引用对象,如注册时需要选择的所在城市等,而且在执行功能处理方法(@RequestMapping 注解的方法)之前,自动添加到模型对象中,用于视图页面展示时使用。

在Spring MVC里,@ModelAttribute通常使用在Controller方法的参数注解中,用于解释model entity,但同时,也可以放在方法注解里。
如果把 @ModelAttribute放在方法的注解上时,代表的是:该Controller的所有方法在调用前,先执行此 @ModelAttribute方法。

@Controller
@RequestMapping(value="test")
public class PassportController {

    @ModelAttribute
    public void preRun() {
        System.out.println("Test Pre-Run");
    }
    
    @RequestMapping(method=RequestMethod.GET)
    public String index() {
        return "login/index";
    }
    
    @RequestMapping(value="login", method=RequestMethod.POST)
    public ModelAndView login(@ModelAttribute @Valid Account account, BindingResult result)
        :
        :
    }
    
    @RequestMapping(value="logout", method=RequestMethod.GET)
    public String logout() {
        :
        :
    }
    
}

在调用所有方法之前,都会先执行preRun()方法。
我们可以把这个 @ModelAttribute特性,应用在BaseController当中,所有的Controller继承BaseController,即可实现在调用Controller时,先执行 @ModelAttribute方法。
比如权限的验证(也可以使用Interceptor)等

posted @ 2017-01-04 11:10  CalronLoveRonnie  阅读(306)  评论(0编辑  收藏  举报
AmazingCounters.com