Spring MVC注解

在Springmvc的控制器中,经常会用到注解修饰参数,这里主要讲解常用的注解。
先来熟悉下content-Type。在HTTP协议消息头中,使用Content-Type来表示请求和响应中的媒体类型信息。它用来告诉服务端如何处理请求的数据,以及告诉客户端(一般是浏览器)如何解析响应的数据,比如显示图片,解析并展示html等等。
application/x-www-form-urlencoded
HTTP会将请求参数用key1=val1&key2=val2的方式进行组织,并放到请求实体里面,注意如果是中文或特殊字符如"/"、","、“:" 等会自动进行URL转码。不支持文件,一般用于表单提交。
下面是一个例子:

  • 请求参数


    application/x-www-form-urlencoded请求参数
  • http 请求报文


    application/x-www-form-urlencoded报文

multipart/form-data
与application/x-www-form-urlencoded不同,这是一个多部分多媒体类型。首先生成了一个 boundary 用于分割不同的字段,在请求实体里每个参数以------boundary开始,然后是附加信息和参数名,然后是空行,最后是参数内容。多个参数将会有多个boundary块。如果参数是文件会有特别的文件域。最后以------boundary–为结束标识。multipart/form-data支持文件上传的格式,一般需要上传文件的表单则用该类型。
下面是一个例子:
请求参数

image.png

http 请求报文
image.png

application/json
JSON 是一种轻量级的数据格式,以“键-值”对的方式组织的数据。这个使用这个类型,需要参数本身就是json格式的数据,参数会被直接放到请求实体里,不进行任何处理。服务端/客户端会按json格式解析数据(约定好的情况下)。
请求参数
image.png

http 请求报文
image.png

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

<form:form method="GET" action="/loginCheck" align="center">
    <table>
        <tr>
            账号:<input type="text" name="username" />
            </br>
        </tr>
        <tr>
            密码:<input type ="text" name = "userpasswd" />
            </br>
        </tr>
                <input type="submit" value="登录"/><input type="reset" value="清空"/>
        </br>
        </tr>
    </table>
</form:form>

控制器

@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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容