在Springmvc的控制器中,经常会用到注解修饰参数,这里主要讲解常用的注解。
先来熟悉下content-Type。在HTTP协议消息头中,使用Content-Type来表示请求和响应中的媒体类型信息。它用来告诉服务端如何处理请求的数据,以及告诉客户端(一般是浏览器)如何解析响应的数据,比如显示图片,解析并展示html等等。
application/x-www-form-urlencoded
HTTP会将请求参数用key1=val1&key2=val2的方式进行组织,并放到请求实体里面,注意如果是中文或特殊字符如"/"、","、“:" 等会自动进行URL转码。不支持文件,一般用于表单提交。
下面是一个例子:
-
请求参数
-
http 请求报文
multipart/form-data
与application/x-www-form-urlencoded不同,这是一个多部分多媒体类型。首先生成了一个 boundary 用于分割不同的字段,在请求实体里每个参数以------boundary开始,然后是附加信息和参数名,然后是空行,最后是参数内容。多个参数将会有多个boundary块。如果参数是文件会有特别的文件域。最后以------boundary–为结束标识。multipart/form-data支持文件上传的格式,一般需要上传文件的表单则用该类型。
下面是一个例子:
请求参数
http 请求报文
application/json
JSON 是一种轻量级的数据格式,以“键-值”对的方式组织的数据。这个使用这个类型,需要参数本身就是json格式的数据,参数会被直接放到请求实体里,不进行任何处理。服务端/客户端会按json格式解析数据(约定好的情况下)。
请求参数
http 请求报文
application/xml 和 text/xml
与application/json类似,这里用的是xml格式的数据,text/xml的话,将忽略xml数据里的编码格式,参考。
@RequestParam
用来处理Content-Type: 为 application/x-www-form-urlencoded编码的内容,提交方式为GET或POST。GET和POST请求传的参数会自动转换赋值到@RequestParam 所注解的变量上。RequestParam实质是将Request.getParameter() 中的Key-Value参数Map利用Spring的转化机制ConversionService配置,转化成参数接收对象或字段。get方式中query String的值,和post方式中body data的值都会被Servlet接受到并转化到Request.getParameter()参数集中,所以@RequestParam可以获取的到。例如:
login.jsp
账号:
密码:
控制器
@RequestMapping(value="/requestParamTest", method = RequestMethod.GET)
public String requestParamTest(@RequestParam(value="username") String userName, @RequestParam(value="userpasswd") String userPasswd){
System.out.println("requestParam Test");
System.out.println("username: " + userName);
System.out.println("userpasswd: " + userPasswd);
return "hello";
}
也可以不使用@RequestParam,直接接收,此时要求controller方法中的参数名称要跟form中name名称一致。
控制器
@RequestMapping(value="/requestParamTest", method = RequestMethod.GET)
public String requestParamTest(String username, String userpasswd){
System.out.println("requestParam Test");
System.out.println("username: " + username);
System.out.println("userpasswd: " + userPasswd);
return "hello";
}
@PathVariable
通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过@PathVariable(xxx) 绑定到操作方法的入参中。例如:
控制器
@RequestMapping(value = "/partner/{partner_id}/poi/{poi_id}/contacts", method = RequestMethod.GET)
@ResponseBody
public void getContacts(@PathVariable("partner_id") String partner_id, @PathVariable("poi_id") String poi_id) {
System.out.println("Hello");
}
url中定义了{partner_id}、{poi_id}两个占位符,参数中partner_id 和poi_id直接从url中路径中获取值。
@RequestHeader
顾名思义,这个注解是从HTTP header部分获取数据绑定到参数上面。header属性可以看https://blog.csdn.net/u014175572/article/details/54861813/。
代码块
@Controller
public class HelloController {
@RequestMapping(value = "/hello.htm")
public String hello(@RequestHeader(value="User-Agent") String userAgent) {
//..
}
}
@CookieValue
显然, 用来获取Cookie中的值。
代码块
@RequestMapping("/getCookie")
public String testCookie(@CookieValue(value="name",required=false) String name, @CookieValue(value="age",required=false) Integer age) {
System.out.println(name+","+age);
return "hello";
}
@RequestBody
@RequestBody 注解则是将 HTTP 请求正文插入方法中,使用适合的 HttpMessageConverter 将请求体写入某个对象。该注解用于读取Request请求的body部分数据,使用系统默认配置HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上, 再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上。@requestBody注解常用来处理content-type不是默认的application/x-www-form-urlcoded编码的内容,比如说:application/json或者是application/xml等,一般情况下来说常用其来处理application/json类型。 在一些特殊情况@requestBody也可以用来处理content-type类型为application/x-www-form-urlcoded的内容,只不过这种方式不是很常用。@RequestBody接收的是一个Json对象的字符串,并绑定到参数上。
前端
$.ajax({
url:"/login",
type:"POST",
data:'{"userName":"admin","pwd","admin123"}',
contentType:"application/json charset=utf-8",
success:function(data){
alert("request success ! ");
}
});
控制器
@requestMapping("/login")
public void login(@requestBody String userName,@requestBody String pwd){
System.out.println(userName+" :"+pwd);
}
这种情况是将JSON字符串中的两个变量的值分别赋予了两个字符串。但是呢假如我有一个User类,拥有如下字段:String userName;String pwd;那么上述参数可以改为以下形式:@requestBody User user 这种形式会将JSON字符串中的值赋予user中对应的属性上。
@ModelAttribute
该注解有两个用法,一个是用于方法上,一个是用于参数上;
用于方法上时: 通常用来在处理@RequestMapping之前,为请求绑定需要从后台查询的model;
用于参数上时: 用来通过名称对应,把相应名称的值绑定到注解的参数bean上;
@ModelAttribute的原理是
①. 调用 @ModelAttribute 注解修饰的方法(注解在方法上),实际上把 @ModelAttribute 方法中 Map 中的数据放在了 implicitModel 中.
②. 解析请求处理器的目标参数, 实际上该目标参数来自于 WebDataBinder 对象的 target 属性
下面将举例说明不同的功能。
用于方法上
@Controller
public class HelloWorldController {
@ModelAttribute("user")
public User addAccount() {
return new User("jz","123");
}
@RequestMapping(value = "/helloWorld")
public String helloWorld(@ModelAttribute("user") User user) {
user.setUserName("jizhou");
return "helloWorld";
}
}
如上代码所示,在执行helloWorld方法前执行addAccount方法,构造map["user", User(”jz","123")]加入一个视图对象,这里因为没有明确表示对象名字将指定隐形对象。在执行helloWorld方法时, 参数中使用了@ModelAttribute注解,意思是从视图对象中获取user的属性值绑定到参数bean:user上 。这里多谈一句,如果在视图对象中没有找到user的属性值,则验证当前方法是否使用了 @SessionAttributes 进行修饰, 若使用了, 则尝试从 Session 中 获取 attrName 所对应的属性值 ; 若 session 中依然没有对应的属性值, 则抛出异常。其实很多场合不需要用@ModelAttribute也是能够绑定的。
@RequestParam,@RequestBody, @ModelAttribute三者区别
这三者使用频率较高,这里做个简单的总结:
1. application/x-www-form-urlencoded,这种情况的数据@RequestParam、@ModelAttribute可以处理,@RequestBody也可以处理。@RequestParam绑定简单对象,@ModelAttribute和@RequestBody绑定复合对象。
2. multipart/form-data,@RequestBody不能处理这种格式的数据。(form表单里面有文件上传时,必须要指定enctype属性值为multipart/form-data,意思是以二进制流的形式传输文件。)
3. application/json、application/xml等格式的数据,必须使用@RequestBody来处理。
@ResponseBody
@Responsebody 注解表示该方法的返回的结果直接写入 HTTP 响应正文(ResponseBody)中,一般在异步获取数据时使用,通常是在使用 @RequestMapping 后,返回值通常解析为跳转路径,加上 @Responsebody 后返回结果不会被解析为跳转路径,而是直接写入HTTP 响应正文中。
@SessionAttribute
@ModelAttribute注解作用在方法上或者方法的参数上,表示将被注解的方法的返回值或者是被注解的参数作为Model的属性加入到Model中,然后Spring框架自会将这个Model传递给ViewResolver。Model的生命周期只有一个http请求的处理过程,请求处理完后,Model就销毁了。
如果想让参数在多个请求间共享,那么可以用到要说到的@SessionAttribute注解。
参考:
[1]. https://blog.csdn.net/qq_14869093/article/details/86307084