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

相關文章
相關標籤/搜索