最近在編寫項目的過程中,老出現前后端傳遞參數格式不一致、不統一的問題,對於一個已經快工作一年的Java程序員來說,實屬不合格,所以我就下來好好研究了一下@RequestParam和@RequestBody的區別,避免大家遭遇同等錯誤;
一 @RequestParam注解
@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RequestParam { /** * 參數名稱(和value同等意思) */ @AliasFor("name") String value() default ""; /** * 參數名稱 (和name同等意思) */ @AliasFor("value") String name() default ""; /** * 是否必選(默認必選) */ boolean required() default true; /** * 參數默認值 */ String defaultValue() default ValueConstants.DEFAULT_NONE; }
(1)@RequestParam總體上來說,該注解類擁有三個參數:
a)value、name 屬性都標識請求參數名(必須配置);
b)required:參數是否必傳,默認為 true,可以設置為非必傳 false;(如果設置了必傳或默認,請求未傳遞參數,將會拋出異常);
c)defaultValue:參數默認值,如果設置了該值,required 將會自動設置為 false;
(2)@RequestParam注解獲取的參數放在請求哪?
a)get請求的 requestHeaders 中 content-type 這個字段,使用 form-data 表單形式攜帶參數請求;
b)Spring中的@RequestParam注解接收的參數大多數場景是來自requestHeaders中,即請求頭,也就是url中,格式為:http://localhost:8080?name=yc&age=23,由於 url 長度有限制,所以參數需要限制數量和值得長度;
(3)如何使用:
使用一:利用Postman工具,使用form-data提交Get請求
執行代碼:
@RequestMapping(value = "/test", method = RequestMethod.GET) public void test(@RequestParam("id") Integer id, @RequestParam("name") String name, @RequestParam("age") Integer age) { log.info("id = {}, name = {}, age = {}", id, name, age); }
結果:
id = 1, name = yc, age = 23
使用二:不使用@RequestParam注解直接進行對象屬性賦值(不推薦使用,容易和@ReuqestBody混淆)
代碼執行:
@Data @AllArgsConstructor @NoArgsConstructor public class User { private Integer id; private String name; private Integer age; } @RequestMapping(value = "/test", method = RequestMethod.GET) public void test(User user) { log.info("id = {}, name = {}, age = {}", user.getId(), user.getName(), user.getAge()); }
結果:
id = 1, name = yc, age = 23
(4)使用場景:
a)請求是為了查找資源,獲取服務器數據;
b)請求結果無持續性的副作用,例如:不會對數據庫進行添加、修改、刪除操作;
c)傳入的參數不會太長,因為Get請求可能會產生很長的URL,或許會超過某些瀏覽器與服務器對URL的長度限制,導致請求失敗;
二、@RequestBody注解
@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RequestBody { /** * 默認參數必傳 */ boolean required() default true; }
(1)@RequestBody注解只擁有一個參數:
required 默認為 true,即對象中的屬性必須有一個要傳,否則會拋出異常:org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing
(2)@RequestBody注解獲取的參數在請求哪?
a)post請求的requestHeaders請求頭中有content-type字段,一般用來處理:applicatin/json格式的參數;
b)Spring中的@RequestBody注解是用來接收請求體中的參數數據,即requestBody請求體中,故不受參數數據長度的限制;
(3)如何使用?
使用Postman工具發送json格式的數據:
執行代碼:
@Data @AllArgsConstructor @NoArgsConstructor public class User { private Integer id; private String name; private Integer age; } @RequestMapping(value = "/test", method = RequestMethod.POST) public void test(@RequestBody User user) { log.info("id = {}, name = {}, age = {}", user.getId(), user.getName(), user.getAge()); }
結果:
id = 1, name = yc, age = 23
(4)使用場景:
a)請求的結果有持續性作用,例如:對數據庫添加、更新、刪除操作;
b)若使用Get請求,表單參數過長;
c)要傳送的數據不是采用7位的ASCII編碼;
測試三:使用Post請求,@RequestParam也可以接收參數;
注意:也可以使用這種方式用,發送Post請求,參數拼接到url之后,這是因為協議之間沒有做嚴格的區分,但這種方式不建議使用,這種方式就使用Get方式即可。例如:localhost:8888/optimus-prime/project/test?id=1&name=yc&age=23 使用瀏覽器請求數據,這種方式Get請求,但后端使用Post方式接收,訪問不成功!
執行代碼:
@PostMapping(value = "/test") public void test(@RequestParam("id") Integer id, @RequestParam("name") String name, @RequestParam("age") Integer age) { log.info("id = {}, name = {}, age = {}", id, name, age); }
結果:
id = 1, name = yc, age = 12
額外知識1:Http協議常用的四種請求方式:Post、Get、Put、Delete等;其中Put、Delete請求方式很少見,都可用Post方式代替!
a)對數據庫而言: get 請求不修改數據庫,只是查詢。Post是增加記錄,put是更新,Delete數據庫刪除;
b)Put,Post,Delete 方式的請求參數會直接放在requestBody里;
c)處理 request uri 部分的注解,路徑參數變量:@PathVariable;
d)處理request header部分的注解: @RequestHeader, @CookieValue,@RequestParam;
e)處理request body部分的注解:@RequestParam, @RequestBody;
綜上所述:@RequestParam注解既可以接收Get方式的請求頭中的參數,也可以接收Post方式的請求體中的參數;
額外知識2:get請求的 headers 中沒有 content-type 這個字段,post 的 content-type 有 :
a)application/x-www-form-urlencoded 這種就是一般的文本表單用 post 傳地數據,只要將得到的 data 用 @RequestParam 或 request.getParamter() 獲取即可;
b)multipart/form-data ,用於文件上傳,此時 form 的 enctype 屬性必須指定為 multipart/form-data;
c)application/json,將數據以json對象的格式傳遞;
d)text/xml;
e)put 和 delete 請求的headers 是有 content-type 這個字段的,只不過這兩個方法類型目前不常用;
每天進步一點點,開心!