Spring MVC 参数接收常见注解学习

前端让我传 json,我发现我傻逼了

因为没搞清楚 @RequestBody 和 @ModelAttribute 的区别,我觉得 @ModelAttribute 是 Swagger 的一个注解,结果我明明使用对象接收参数的,结果对象里面都是 null。html

后来把 @ModelAttribute 去掉,发现就能够接收到 json 了。前端

既然遇到了这个问题,那么仍是了解一下这两个注解以及它们的不一样之处吧。java

@RequestBody

@RequestBody 注解经常使用来处理 content-type 不是默认的 application/x-www-form-urlcoded 编码的内容,好比说:application/json 或者是 application/xml 等。通常状况下来讲经常使用其来处理 application/json 类型。ajax

如今有以下的 ajax 请求:json

$.ajax({
    url:"/login",
    type:"POST",
    data:'{"userName":"admin","pwd","admin123"}',
    content-type:"application/json charset=utf-8",
    success:function(data){
        alert("request success ! ");
    }
});

此时做为后台开发,你能够有两种方式接收参数:session

  1. 将 json 字符串中的两个变量分别赋予两个字符串app

    @RequestMapping("/login")
    public void login(@RequestBody String userName, @RequestBody String pwd){
        System.out.println(userName + " :" + pwd);
    }

    这种方法我却是用的比较少,通常都是用第二种方法。函数

  2. 构造一个 User 类,这个 User 类有以下的字段post

    String userName;
    String pwd;

    而后接收方式以下:ui

    @RequestMapping("/login")
    public void login(@RequestBody User user){
        System.out.println(user.getUserName + " :" + user.getPwd);
    }

    这样也能够接收参数,并且是最经常使用的。

在一些特殊状况 @RequestBody 也能够用来处理 content-type 类型为 application/x-www-form-urlcoded 的内容,只不过这种方式不是很经常使用,在处理这类请求的时候,@RequestBody 会将处理结果放到一个 MultiValueMap<String, String> 中。

@RequestBody 用于 post 请求,不能用于 get 请求。(某些时候仍是能够用于 GET 请求的,只不过 HTTP 协议不推荐这么作,由于 GET 通常不在 请求体中带上数据,这个和实现有关。)

@ModelAttribute

在 Spring MVC 中,注解 @ModelAttribute 是一个很是经常使用的注解,其功能主要在两方面:

  1. 运用在参数上,会将客户端传递过来的参数(请求参数或者表单字段)按名称注入到指定对象中,而且会将这个对象自动加入 ModelMap 中,便于 View 层使用;
  2. 运用在方法上,会在每个 @RequestMapping 标注的方法前执行,若是有返回值,则自动将该返回值加入到 ModelMap 中;

通常开发中,第一种用法居多,第二种用法能够节省 controller 层的一些代码。

  1. @ModelAttribute 注释 void 返回值的方法

    @Controller  
    public class HelloWorldController {  
    
        @ModelAttribute  
        public void populateModel(@RequestParam String abc, Model model) {  
            model.addAttribute("attributeName", abc);  
        }  
    
        @RequestMapping(value = "/helloWorld")  
        public String helloWorld() {  
            return "helloWorld";  
        }  
    }

    这个例子,在得到请求 /helloWorld 后,populateModel 方法在 helloWorld 方法以前先被调用,它把请求参数(/helloWorld?abc=text)加入到一个名为 attributeName 的 model 属性中,在它执行后 helloWorld 被调用,返回视图名 helloWorld 和 model 已由 @ModelAttribute 方法生产好了。例子中 model 属性名称和 model 属性对象由 model.addAttribute() 实现,不过前提是要在方法中加入一个 Model 类型的参数。

    当 URL 或者 post 中不包含次参数时,会报错,其实不须要这个方法,彻底能够把请求的方法写成,这样缺乏此参数也不会出错。

    @RequestMapping(value = "/helloWorld")  
    public String helloWorld(String abc) {  
        return "helloWorld";  
    }
  2. @ModelAttribute 注释返回具体类的方法

    @ModelAttribute  
    public Account addAccount(@RequestParam String number) {  
        return accountManager.findAccount(number);  
    }

    这种状况,model 属性的名称没有指定,它由返回类型隐含表示,如这个方法返回 Account 类型,那么这个 model 属性的名称是 account。
    这个例子中 model 属性名称有返回对象类型隐含表示,model 属性对象就是方法的返回值。它无需要特定的参数。

  3. @ModelAttribute(value="") 注释返回具体类的方法

    @Controller  
    public class HelloWorldController {  
    
        @ModelAttribute("attributeName")  
        public String addAccount(@RequestParam String abc) {  
            return abc;  
        }  
    
        @RequestMapping(value = "/helloWorld")  
        public String helloWorld() {  
            return "helloWorld";  
        }  
    }

    这个例子中使用 @ModelAttribute 注释的 value 属性,来指定model属性的名称。model属性对象就是方法的返回值。它无需要特定的参数。

  4. @ModelAttribute 和 @RequestMapping 同时注释一个方法

    @Controller  
    public class HelloWorldController {  
    
        @RequestMapping(value = "/helloWorld.do")  
        @ModelAttribute("attributeName")  
        public String helloWorld() {  
            return "hi";  
        }
    }

    这时这个方法的返回值并非表示一个视图名称,而是 model 属性的值,视图名称由RequestToViewNameTranslator 根据请求 "/helloWorld.do" 转换为逻辑视图 helloWorld。
    Model 属性名称由 @ModelAttribute(value="") 指定,至关于在 request 中封装了 key=attributeName,value=hi。

  5. @ModelAttribute 注释一个方法的参数

    • 从model中获取

      @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";  
          }  
      }

      在这个例子里,@ModelAttribute("user") User user 注释方法参数,参数 user 的值来源于 addAccount() 方法中的 model 属性。此时若是方法体没有标注 @SessionAttributes("user"),那么scope 为 request,若是标注了,那么 scope 为 session

    • 从 Form 表单或 URL 参数中获取(实际上,不用此注解也能拿到 user 对象)

      @Controller  
      public class HelloWorldController {  
      
          @RequestMapping(value = "/helloWorld")  
          public String helloWorld(@ModelAttribute User user) {  
              return "helloWorld";  
          }  
      }

      注意这时候这个User类必定要有没有参数的构造函数。

这他妈的,ModelAttribute 这么麻烦。。。

@RequestParam

GET 和 POST 请求传的参数会自动转换赋值到 @RequestParam 所注解的变量上。

用来处理 Content-Type 为 application/x-www-form-urlencoded 编码的内容。提交方式为 get 或 post。

(HTTP 协议中,若是不指定 Content-Type,则默认传递的参数就是 application/x-www-form-urlencoded 类型)

RequestParam 实质是将 Request.getParameter() 中的 Key-Value 参数 Map 利用 Spring 的转化机制ConversionService 配置,转化成参数接收对象或字段。

能够经过required=false或者true来要求@RequestParam配置的前端参数是否必定要传。

若是用@RequestMapping注解的参数是int基本类型,可是required=false,这时若是不传参数值会报错,由于不传值,会赋值为null给int,这个不能够 。

@PathVariable

@RequestParam 和 @PathVariable 都可以完成相似的功能:由于本质上,它们都是用户的输入,只不过输入的部分不一样,一个在URL路径部分,另外一个在参数部分。

使用这个注解前提是在 @RequestMapping 中必须指定模板。

References

https://www.cnblogs.com/qiankun-site/p/5774300.html

https://blog.csdn.net/zz210891470/article/details/59719251

http://www.javashuo.com/article/p-autfjauv-dp.html

https://www.jianshu.com/p/bf2e67abe8f7

相关文章
相关标签/搜索