首頁 > 軟體

淺談@RequestBody和@RequestParam可以同時使用

2022-03-14 13:01:56

@RequestBody和@RequestParam可以同時使用嗎

@RequestParam和@RequestBody這兩個註解是可以同時使用的。

網上有很多部落格說@RequestParam 和@RequestBody不能同時使用,這是錯誤的。

根據HTTP協定,並沒有說post請求不能帶URL引數,經驗證往一個帶有引數的URL傳送post請求也是可以成功的。只不過,我們日常開發使用GET請求搭配@RequestParam,使用POST請求搭配@RequestBody就滿足了需求,基本不怎麼同時使用二者而已。

自己個人實際驗證結果

package com.example.model; 
import java.util.List; 
public class PramInfo {
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public String getStr() {
        return str;
    }
 
    public void setStr(String str) {
        this.str = str;
    }
 
    private int id;
    private String str; 
}
package com.example.demo; 
import com.example.model.PramInfo;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; 
 
@RestController
@RequestMapping(value = "/test")
public class TestContoller { 
    @RequestMapping(value = "/dxc")
    public String print(PramInfo info) {
        return info.getId() + ": :" + info.getStr();
    }
 
    @RequestMapping(value = "/getUserJson")
    public String getUserJson(@RequestParam(value = "id") int id, @RequestParam(value = "name2", required = false) String name2
            , @RequestBody PramInfo pramInfo) {
        return (id + "--" + name2 + ";paramInfo:" + pramInfo.getStr() + ";pramInfo.id:" + pramInfo.getId());
    }
}

在postman傳送如下post請求,返回正常

body中引數如下

從結果來看,post請求URL帶引數是沒有問題的,所以@RequestParam和@RequestBody是可以同時使用的【經測試,分別使用Postman 和 httpClient框架程式設計傳送http請求,後端@RequestParam和@RequestBody都可以正常接收請求引數,所以個人認為可能一些前端框架不支援或者沒必要這麼做,但是不能說@RequestParam和@RequestBody 不能同時使用】。

值得注意的地方

1、postman的GET請求是不支援請求body的;

2、

 @GetMapping(value = "/dxc")
    public String print(PramInfo info) {
        return info.getId() + ": :" + info.getStr();
    }

這種請求方式,不加@RequestParam註解,也能直接取出URL後面的引數,即引數可以與定義的類互相自動轉化。    

3、

@PostMapping(value = "/getUserJson")
    public String getUserJson(@RequestParam(value = "id") int id, @RequestParam(value = "name2", required = false) String name2
            , @RequestBody PramInfo pramInfo) {
        return (id + "--" + name2 + ";paramInfo:" + pramInfo.getStr() + ";pramInfo.id:" + pramInfo.getId());

如果請求中的body沒有ParamInfo物件對應的json串,即當body為空(連json串的{}都沒有)時,會報請求body空異常:

 2018-05-12 23:45:27.494  WARN 6768 --- [nio-8080-exec-6] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public java.lang.String com.example.demo.TestContoller.getUserJson(int,java.lang.String,com.example.model.PramInfo)
-05-12 23:45:27.494  WARN 6768 --- [nio-8080-exec-6] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public java.lang.String com.example.demo.TestContoller.getUserJson(int,java.lang.String,com.example.model.PramInfo)

@RequestBody和@RequestParam註解使用說明

@RequestBody作用

主要用來接收前端傳遞給後端的json字串中的資料的(請求體中的資料);

@RequestParam作用

將請求引數繫結到你控制器的方法引數上

GET方式無請求體,所以使用@RequestBody接收資料時,前端不能使用GET方式提交資料,而是用POST方式進行提交。在後端的同一個接收方法裡,@RequestBody與@RequestParam()可以同時使用,@RequestBody最多隻能有一個,而@RequestParam()可以有多個。

@RequestBody:

  • 注:一個請求,只有一個RequestBody;一個請求,可以有多個RequestParam。
  • 注:當同時使用@RequestParam()和@RequestBody時,@RequestParam()指定的引數可以是普通元素、陣列、集合、物件等等(即:當,@RequestBody 與@RequestParam()可以同時使用時,原SpringMVC接收引數的機制不變,只不過RequestBody 接收的是請求體裡面的資料;而RequestParam接收的是key-value裡面的引數,所以它會被切面進行處理從而可以用普通元素、陣列、集合、物件等接收)。
  • 即:如果引數時放在請求體中,傳入後臺的話,那麼後臺要用@RequestBody才能接收到;如果不是放在請求體中的話,那麼後臺接收前臺傳過來的引數時,要用@RequestParam來接收,或者形參前什麼也不寫也能接收。
  • 注:如果引數前寫了@RequestParam(xxx),那麼前端必須有對應的xxx名字才行(不管其是否有值,當然可以通過設定該註解的required屬性來調節是否必須傳),如果沒有xxx名的話,那麼請求會出錯,報400。
  • 注:如果引數前不寫@RequestParam(xxx)的話,那麼就前端可以有可以沒有對應的xxx名字才行,如果有xxx名的話,那麼就會自動匹配;沒有的話,請求也能正確傳送。
  • 注:這裡與feign消費服務時不同;feign消費服務時,如果引數前什麼也不寫,那麼會被預設是@RequestBody的。

如果後端引數是一個物件

且該引數前是以@RequestBody修飾的,那麼前端傳遞json引數時,必須滿足以下要求:

  • 後端@RequestBody註解對應的類在將HTTP的輸入流(含請求體)裝配到目標類(即:@RequestBody後面的類)時,會根據json字串中的key來匹配對應實體類的屬性,如果匹配一致且json中的該key對應的值符合(或可轉換為),這一條我會在下面詳細分析,其他的都可簡單略過,但是本文末的核心邏輯程式碼以及幾個結論一定要看! 實體類的對應屬性的型別要求時,會呼叫實體類的setter方法將值賦給該屬性。
  • json字串中,如果value為"“的話,後端對應屬性如果是String型別的,那麼接受到的就是”",如果是後端屬性的型別是Integer、Double等型別,那麼接收到的就是null。
  • json字串中,如果value為null的話,後端對應收到的就是null。
  • 如果某個引數沒有value的話,在傳json字串給後端時,要麼乾脆就不把該欄位寫到json字串中;要麼寫value時, 必須有值,null 或""都行

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com