@RequestBody
注解的作用
@RequestBody
將方法上的參數綁定到 HTTP 請求的 Body(請求體)的內容上。
當客戶端發送一個包含數據的請求體(通常在 POST
, PUT
, PATCH
請求中)時,@RequestBody
告訴 Spring MVC 讀取這個請求體,并使用已注冊的 HttpMessageConverter
將其內容**反序列化(Deserialize)**為一個 Java 對象。
簡單來說,它允許我們直接將請求中發送的 JSON、XML 或其他格式的數據映射到一個 Java 對象(通常是一個 POJO - Plain Old Java Object)。
@RequestBody
的工作機制
- 讀取請求體: Spring MVC 獲取 HTTP 請求的輸入流。
- 檢查
Content-Type
Header: 查看請求頭中的Content-Type
,例如application/json
或application/xml
。這個 Header 會告訴服務器客戶端發送的是什么格式的數據。 - 選擇
HttpMessageConverter
: Spring MVC 會查找已注冊的、能夠處理該Content-Type
的請求體內容轉換為方法參數指定類型的HttpMessageConverter
。 - 反序列化:
HttpMessageConverter
讀取請求體內容,并將其轉換為目標 Java 對象。 - 參數綁定: 轉換后的 Java 對象會傳遞給帶有
@RequestBody
注解的方法參數。
常用場景:接收 JSON 或 XML 數據
@RequestBody
最常用于接收客戶端發送的 JSON 或 XML 數據,尤其是在構建 RESTful API 時。
示例:接收 JSON 數據
假設客戶端發送一個 POST
請求到 /api/users
,請求體包含以下 JSON 數據:
{"username": "john.doe","email": "john.doe@example.com","age": 30
}
并且請求頭中設置了 Content-Type: application/json
。
我們可以定義一個對應的 Java POJO:
// User.java (POJO)
public class User {private String username;private String email;private int age;// Getters and Setters (必需,供 Jackson 等庫使用)public String getUsername() { return username; }public void setUsername(String username) { this.username = username; }public String getEmail() { return email; }public void setEmail(String email) { this.email = email; }public int getAge() { return age; }public void setAge(int age) { this.age = age; }@Overridepublic String toString() {return "User{" +"username='" + username + '\'' +", email='" + email + '\'' +", age=" + age +'}';}
}
然后在 Controller 中這樣使用 @RequestBody
:
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;@RestController
@RequestMapping("/api/users")
public class UserController {@PostMappingpublic ResponseEntity<String> createUser(@RequestBody User user) {// 此時,Spring MVC 已經使用 HttpMessageConverter (通常是 Jackson)// 將請求體中的 JSON 數據轉換為了一個 User 對象實例 'user'System.out.println("Received user: " + user);// 在這里可以進行保存用戶等業務邏輯...// userService.save(user);return ResponseEntity.status(HttpStatus.CREATED).body("User created successfully: " + user.getUsername());}
}
所需依賴
Spring MVC 依賴 HttpMessageConverter
來實現 @RequestBody
的功能。
-
處理 JSON (最常用):
- 依賴庫: Jackson Databind (
jackson-databind
) 是 Spring Boot 和 Spring MVC 處理 JSON 的默認庫。 - 如何添加: 如果使用 Spring Boot,
spring-boot-starter-web
starter 會自動包含jackson-databind
。通常不需要手動添加它。 - Maven 示例 (如果未使用 Spring Boot Starter 或需要特定版本):
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><!-- <version>...</version> --> <!-- Spring Boot 管理版本 --> </dependency>
- 替代庫: 雖然不常用,但也可以配置使用其他 JSON 庫,如 Gson (
com.google.code.gson:gson
) 或 JSON-B。
- 依賴庫: Jackson Databind (
-
處理 XML:
- 依賴庫:
- JAXB (Java Architecture for XML Binding): 這是 Java 標準庫的一部分(直到 Java 10,Java 11 及以后需要單獨添加依賴)。Spring 對 JAXB 有內建支持。
- Jackson XML extension (
jackson-dataformat-xml
): 這是 Jackson 提供的用于處理 XML 的模塊,與處理 JSON 的方式非常相似,通常更受歡迎,因為它與 Jackson 的其他功能(如注解)集成得更好。
- 如何添加 (Jackson XML): 如果你想使用 Jackson 處理 XML,需要手動添加
jackson-dataformat-xml
依賴。spring-boot-starter-web
不包含它。 - Maven 示例 (Jackson XML):
<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId><!-- <version>...</version> --> <!-- Spring Boot 管理版本 --> </dependency>
- POJO 注解: 如果使用 JAXB 或 Jackson XML,需要在 POJO 上添加特定的注解(如
@XmlRootElement
,@XmlElement
for JAXB,或者 Jackson 也可以使用 JAXB 注解或其自己的注解)映射 XML 結構。不過,對于簡單的結構,Jackson XML 也能在沒有額外注解的情況下工作。
- 依賴庫:
示例:Controller 處理 XML (假設已添加 jackson-dataformat-xml
)
如果客戶端發送 Content-Type: application/xml
和以下 XML 請求體:
<User><username>jane.doe</username><email>jane.doe@example.com</email><age>28</age>
</User>
上面的 createUser
方法無需修改(只要 User
POJO 的結構匹配),Spring MVC 會自動選擇 MappingJackson2XmlHttpMessageConverter
(如果 jackson-dataformat-xml
在 classpath 中)來處理請求。
關鍵點和注意事項
Content-Type
Header: 客戶端必須發送正確的Content-Type
請求頭,以便 Spring MVC 知道如何解析請求體并選擇合適的HttpMessageConverter
。如果Content-Type
不匹配或缺失,通常會導致 HTTP 415 (Unsupported Media Type) 錯誤。- 必需性:
@RequestBody
標注的參數默認是必需的。如果請求體為空或無法轉換為目標類型,會拋出HttpMessageNotReadableException
,通常導致 HTTP 400 (Bad Request) 錯誤。 - 唯一性: 一個 Controller 方法只能有一個參數使用
@RequestBody
注解,因為一個 HTTP 請求只有一個請求體。 - 不要與
@RequestParam
混淆:@RequestParam
用于獲取 URL 查詢參數或表單數據(application/x-www-form-urlencoded
),而@RequestBody
用于獲取整個請求體的內容(通常是 JSON 或 XML)。 - Validation: 通常會結合 Java Bean Validation API (JSR 380/303) 使用
@RequestBody
。通過在@RequestBody
參數前添加@Valid
注解,可以自動觸請求體反序列化后的對象的校驗。
import javax.validation.Valid;
import javax.validation.constraints.Email;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;// User.java (帶校驗注解)
public class User {@NotBlank(message = "Username cannot be blank")private String username;@NotBlank@Email(message = "Invalid email format")private String email;@Min(value = 0, message = "Age must be positive")private int age;// ... Getters and Setters ...
}// Controller 方法
@PostMapping
public ResponseEntity<String> createUser(@Valid @RequestBody User user) {// 如果校驗失敗,Spring 會自動返回 400 Bad Request// 如果校驗成功,代碼繼續執行System.out.println("Received valid user: " + user);// ...return ResponseEntity.status(HttpStatus.CREATED).body("User created successfully: " + user.getUsername());
}
要使 @Valid
生效,需要添加 spring-boot-starter-validation
依賴(如果使用 Spring Boot)或相應的 hibernate-validator
依賴。
總結
@RequestBody
用于將 HTTP 請求的完整 Body 反序列化為一個 Java 對象。- 主要用于接收
POST
,PUT
,PATCH
請求中的 JSON 或 XML 數據。 - 依賴于
HttpMessageConverter
和相應的庫(如jackson-databind
for JSON,jackson-dataformat-xml
or JAXB for XML)。 spring-boot-starter-web
默認包含 Jackson JSON 支持。處理 XML 需要手動添加依賴。- 客戶端必須發送正確的
Content-Type
Header。 - 一個方法只能有一個
@RequestBody
參數。 - 常與
@Valid
結合進行自動數據校驗。