直接问的 ds 老师。
在 Spring 框架中, @RequestBody
、 @RequestParam
和「无注解」的用法区别主要体现在 HTTP 请求参数的传递方式上。以下是核心规则及示例解析:
# 关键区别总结
情形 | 典型场景 | 适用注解 | 数据来源 | 参数类型 |
---|---|---|---|---|
接收 JSON/XML | POST/PUT 请求体(非表单) | @RequestBody | 请求体(Body) | 复杂对象(如 User ) |
接收 URL 查询参数或表单数据 | GET 或 POST 表单提交(无 Body) | @RequestParam | URL 或表单 | 基本类型、单字段 |
自动绑定对象属性 | GET 对象参数(如 User user ) | 无注解 | URL 或表单 | 复杂对象 |
# 一、 @RequestBody
的用途
# 典型场景
通过 HTTP Body(如 JSON/XML)传递结构化数据时,必须使用 @RequestBody
。
# 示例代码
@PostMapping("/user_create") | |
public ResponseEntity<User> saveUser(@RequestBody User user) { | |
// 接收 JSON 格式的请求体,反序列化为 User 对象 | |
// 例如: {"username": "john", "password": "123"} | |
userService.save(user); | |
return ResponseEntity.ok(user); | |
} |
# 是否必须使用?
- ✅ 当请求体为 JSON/XML 且需绑定到对象时,必须加
@RequestBody
,否则 Spring 会认为参数来自 URL 或表单,无法正确解析。 - ❌ 如果请求是通过 URL 查询参数或表单提交,则不能使用
@RequestBody
(会报错)。
# 二、 @RequestParam
的用途
# 典型场景
用于获取 URL 查询参数 或 表单参数(非 JSON)。适用单个字段(如 String
, Integer
)。
# 示例代码
@GetMapping("/find_user") | |
public User findUser( | |
@RequestParam("username") String username, // 从 URL 参数获取 username | |
@RequestParam(value = "page", defaultValue = "1") int page | |
) { | |
return userService.findByUsername(username, page); | |
} |
# 是否必须使用?
- ✅ 当方法参数名与请求参数名不一致时,必须通过
@RequestParam("paramName")
明确指定。 - ❗ 若参数名一致且非必填,可通过
required = false
标记非必传:@GetMapping("/items")
public List<Item> getItems(
@RequestParam(required = false) String keyword //keyword 是可选参数
) {
// ...
}
# 三、无注解:自动绑定对象属性
# 典型场景
当参数为复杂对象(如 User
)且未加注解时,Spring 会尝试从 URL 查询参数或表单字段 中匹配属性名,自动填充对象。
# 示例代码
@GetMapping("/login") | |
public Map<String, Object> login(User user) { | |
// 假设请求 URL 为 /login?username=admin&password=123 | |
// Spring 自动创建 User 对象,并赋值 username="admin",password="123" | |
boolean isValid = userService.validate(user); | |
return Map.of("success", isValid); | |
} |
# 为什么不能加 @RequestParam
?
- ❌
@RequestParam
只能绑定单个字段,无法绑定到对象层次:// ❌ 错误示例: User 是对象,无法通过 @RequestParam 接收
public Map<String, Object> login(@RequestParam User user) { ... }
# 四、综合对比
假设有如下请求:
# 请求 1(POST-JSON):
POST /user_create | |
Content-Type: application/json | |
{"username": "alice", "password": "secret"} |
- 对应方法:
saveUser(@RequestBody User user)
- 必须用
@RequestBody
,因为数据在请求体中。
- 必须用
# 请求 2(GET-URL 参数):
GET /login?username=alice&password=secret |
- 对应方法:
login(User user)
(无注解)- Spring 自动将
username
和password
映射到 User 属性。
- Spring 自动将
# 请求 3(表单提交):
<form action="/login" method="post"> | |
<input name="username" value="alice"> | |
<input name="password" value="secret"> | |
</form> |
- 对应方法:
login(User user)
(无注解)- 表单字段与 User 属性名匹配,自动绑定。
# 常见错误及解决
@RequestBody
与 GET 请求混用
GET 请求一般无 Body,使用@RequestBody
会触发HttpMediaTypeNotSupportedException
。@RequestParam
无法绑定对象
处理复杂对象时不要误用@RequestParam
,需通过无注解自动绑定或@ModelAttribute
(表单专用)。POST 表单数据未使用
@RequestBody
表单数据通过application/x-www-form-urlencoded
格式提交时,应用无注解自动绑定或@ModelAttribute
,而非@RequestBody
。
# 扩展: @ModelAttribute
如果前端以表单形式(非 JSON)提交对象,也可以使用 @ModelAttribute
(实际上在方法参数中可省略):
@PostMapping("/login") | |
public String login(@ModelAttribute User user) { ... } |
效果与无注解相同,但更显式,用于处理表单数据。
# 总结
数据来源 | 参数类型 | 可选注解 | 是否必须 |
---|---|---|---|
请求体(JSON/XML) | 复杂对象 | @RequestBody | ✅ 必须 |
URL 或表单参数(单字段) | 基本类型(String 等) | @RequestParam | 按需可选 |
URL 或表单参数(对象属性匹配) | 复杂对象 | 无注解 或 @ModelAttribute | 按需可选 |
理解这些规则后,你可以根据实际请求的数据格式和参数类型,选择正确的注解组合。
讲人话就是:POST 方法里的 @RequestBody
都是必须要加;GET 方法里的 @RequestParam
,基本类型可加可不加,复杂对象不能加。