@ResponseBody 注解轉換為 JSON 的原理與實現詳解
1. 核心作用
@ResponseBody
是 Spring MVC 的一個注解,用于將方法返回的對象直接序列化為 HTTP 響應體(如 JSON 或 XML),而不是通過視圖解析器渲染為視圖(如 HTML)。
- 關鍵作用:
- 跳過視圖解析階段,直接返回數據。
- 觸發 消息轉換器(HttpMessageConverter) 將對象轉換為指定格式(如 JSON)。
2. 工作流程詳解
步驟 1:方法返回對象
@RestController
public class UserController {@GetMapping("/user")public User getUser() {return new User("John", 25); // 返回 Java 對象}
}
步驟 2:觸發消息轉換
- Spring 檢測到
@ResponseBody
:跳過視圖解析,直接進入消息轉換階段。 - 選擇合適的
HttpMessageConverter
:- 根據 返回對象類型 和 請求的 Accept 頭(如
application/json
)選擇轉換器。 - 默認情況下,Spring Boot 自帶的 Jackson 庫 提供的
MappingJackson2HttpMessageConverter
會被選中。
- 根據 返回對象類型 和 請求的 Accept 頭(如
步驟 3:Jackson 序列化對象
- Jackson 的
ObjectMapper
:負責將 Java 對象轉換為 JSON 字符串。 - 序列化過程:
- 遍歷對象的 getter 方法 或 字段。
- 根據注解(如
@JsonProperty
)和配置(如日期格式)處理屬性。 - 忽略
transient
字段或@JsonIgnore
標記的字段。
// 示例 JSON 輸出
{"name": "John","age": 25
}
3. 完整代碼示例
3.1 實體類(User.java)
public class User {private String name;private int age;// 構造函數、getter 和 setter 方法public User(String name, int age) {this.name = name;this.age = age;}// 省略 getter/setter
}
3.2 控制器(UserController.java)
import org.springframework.web.bind.annotation.*;@RestController // 等效于 @Controller + @ResponseBody
public class UserController {@GetMapping("/user")public User getUser() {return new User("John", 25); // 直接返回對象,由 @ResponseBody 觸發轉換}@PostMapping("/user")public User createUser(@RequestBody User user) {// 處理 POST 請求,將 JSON 反序列化為 User 對象return user;}
}
3.3 測試請求
# GET 請求獲取 JSON
curl http://localhost:8080/user
# 輸出:{"name":"John","age":25}# POST 請求發送 JSON
curl -X POST -H "Content-Type: application/json" -d '{"name":"Jane","age":30}' http://localhost:8080/user
4. 消息轉換器(HttpMessageConverter)詳解
Spring MVC 通過 HttpMessageConverter
完成對象到 HTTP 響應的轉換。
-
核心接口:
HttpMessageConverter<T>
canRead()
:判斷是否支持反序列化(如 JSON → 對象)。canWrite()
:判斷是否支持序列化(如對象 → JSON)。write()
:實際執行序列化操作。
-
常用實現類:
類名 作用 默認支持格式 MappingJackson2HttpMessageConverter
JSON 轉換(依賴 Jackson 庫) application/json
MappingJackson2XmlHttpMessageConverter
XML 轉換(需額外配置) application/xml
StringHttpMessageConverter
字符串轉換 text/plain
5. Jackson 配置與自定義
通過自定義 ObjectMapper
可控制 JSON 序列化行為:
5.1 配置示例
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.text.SimpleDateFormat;@Configuration
public class JacksonConfig {@Beanpublic ObjectMapper objectMapper() {ObjectMapper mapper = new ObjectMapper();// 設置日期格式mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));// 忽略未找到的字段(反序列化時)mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);return mapper;}
}
5.2 常用注解
注解 | 作用 |
---|---|
@JsonProperty | 指定 JSON 鍵名(覆蓋字段名)。 |
@JsonFormat | 定制日期/數字格式。 |
@JsonInclude | 控制字段是否參與序列化(如 @JsonInclude(JsonInclude.Include.NON_NULL) )。 |
@JsonIgnore | 忽略字段。 |
6. 常見問題與解決方案
Q1:為什么 JSON 中沒有某個字段?
- 可能原因:
- 字段沒有
getter
方法。 - 字段被
@JsonIgnore
或transient
修飾。 @JsonInclude
配置排除了該字段(如NON_NULL
且值為null
)。
- 字段沒有
Q2:如何處理循環引用?
- 解決方案:
@JsonManagedReference // 主對象(單向引用) @JsonBackReference // 被引用對象(忽略反向引用)
Q3:如何自定義序列化邏輯?
- 自定義序列化器:
public class CustomSerializer extends JsonSerializer<Date> {@Overridepublic void serialize(Date value, JsonGenerator gen, SerializerProvider serializers)throws IOException {gen.writeString(new SimpleDateFormat("yyyy-MM-dd").format(value));} }
Q4:如何禁用 HTML 轉義?
- 配置:
@Bean public MappingJackson2HttpMessageConverter jackson2HttpMessageConverter() {MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();converter.getObjectMapper().disable(SerializationFeature.ESCAPE_NON_ASCII);return converter; }
7. 總結表格
環節 | 關鍵組件 | 職責 |
---|---|---|
觸發轉換 | @ResponseBody | 告知 Spring 直接返回數據,跳過視圖解析。 |
選擇轉換器 | HttpMessageConverter | 根據返回類型和 Accept 頭選擇合適的轉換器。 |
序列化 | Jackson (ObjectMapper ) | 將 Java 對象轉換為 JSON 字符串。 |
配置擴展 | 自定義 ObjectMapper | 精細控制序列化格式、日期、忽略策略等。 |
總結
@ResponseBody
通過結合 HttpMessageConverter
和 Jackson,將 Java 對象無縫轉換為 JSON 響應。掌握其工作原理和配置方法,可以靈活處理 RESTful API 的數據格式化需求。對于復雜場景(如自定義序列化、處理循環引用),可通過 Jackson 的注解和配置進一步優化。