ObjectMapper
?是 Jackson 庫的核心類,專門用于處理 JSON 數據的序列化(Java 對象 → JSON)和反序列化(JSON → Java 對象)。在你提供的代碼中,它解決了字符串響應特殊處理的關鍵問題。
一、為什么需要 ObjectMapper?
問題背景
if (body instanceof String) {return mapper.writeValueAsString(Result.success(body));
}
這段代碼處理的是當控制器返回純字符串時的特殊情況。在 Spring MVC 中,不同類型的返回值有不同的處理方式:
返回值類型 | 處理方式 | 問題 |
---|---|---|
對象/集合 | 自動使用 JSON 轉換器 | 無 |
字符串 | 使用字符串轉換器 | 無法自動包裝為 JSON |
具體問題演示
假設有一個控制器:
@RestController
public class ExampleController {@GetMapping("/string")public String getString() {return "hello"; // 返回純字符串}
}
沒有 ObjectMapper 的情況:
beforeBodyWrite
?返回?Result.success("hello")
- Spring 嘗試使用?
StringHttpMessageConverter
?處理 - 因為?
Result
?不是字符串 →?類型轉換錯誤!
二、ObjectMapper 如何解決這個問題
解決方案
mapper.writeValueAsString(Result.success(body));
分步解析
創建包裝對象:Result result = Result.success("hello");
// 得到:{code:200, msg:"success", data:"hello"}
手動序列化為 JSON 字符串:String json = mapper.writeValueAsString(result);
// 得到:'{"code":200,"msg":"success","data":"hello"}'
?
-
? ?最終返回字符串結果:
- 符合?
StringHttpMessageConverter
?的預期 - 客戶端收到標準 JSON 格式
- 符合?
序列化過程圖解
Java對象: Result├─ code: 200├─ msg: "success"└─ data: "hello"↓ ObjectMapper 序列化
JSON字符串: '{"code":200,"msg":"success","data":"hello"}'
三、ObjectMapper 的核心能力
1. 序列化配置
// 創建時可配置(代碼中通常靜態初始化)
private static ObjectMapper mapper = new ObjectMapper();// 常用配置(可添加到靜態初始化塊)
static {// 美化輸出(開發環境)mapper.enable(SerializationFeature.INDENT_OUTPUT);// 空值不參與序列化mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);// 日期格式標準化mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
}
2.支持復雜類型
// 嵌套對象
Result result = Result.success(new User("Alice", 25));
String json = mapper.writeValueAsString(result);
// 輸出:{"code":200,"msg":"success","data":{"name":"Alice","age":25}}// 集合類型
List<String> list = Arrays.asList("A", "B", "C");
String json = mapper.writeValueAsString(Result.success(list));
// 輸出:{"code":200,"msg":"success","data":["A","B","C"]}
3. 自定義序列化(高級)
// 自定義序列化器
public class MoneySerializer extends StdSerializer<BigDecimal> {public MoneySerializer() {super(BigDecimal.class);}@Overridepublic void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider provider) {gen.writeString(value.setScale(2) + "元");}
}// 注冊自定義序列化器
mapper.registerModule(new SimpleModule().addSerializer(BigDecimal.class, new MoneySerializer()));// 使用效果
Result result = Result.success(new BigDecimal("123.456"));
String json = mapper.writeValueAsString(result);
// 輸出:{"code":200,"msg":"success","data":"123.46元"}
四、實際應用場景
場景 1:統一處理日期格式
static {mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
}// 控制器返回
@GetMapping("/date")
public Date getDate() {return new Date(); // 返回日期對象
}// 處理結果
// 原始輸出:1689987600000(時間戳)
// 處理后輸出:"2023-07-22"
場景 2:處理枚舉類型
public enum Status {ACTIVE, INACTIVE
}// 默認序列化
Status.ACTIVE → "ACTIVE"(枚舉名)// 自定義序列化
mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);// 在枚舉中添加toString
public enum Status {ACTIVE("激活"), INACTIVE("禁用");private String desc;@Overridepublic String toString() {return desc;}
}// 輸出結果:"激活"
場景 3:處理特殊字符
String text = "包含<特殊>字符&符號";
Result result = Result.success(text);// 未處理時:可能破壞JSON結構
// 處理后:自動轉義為"包含\u003C特殊\u003E字符\u0026符號"
完整的最佳實踐
@Slf4j
@ControllerAdvice
public class GlobalResponseAdvice implements ResponseBodyAdvice<Object> {// 靜態初始化(線程安全)private static final ObjectMapper mapper = new ObjectMapper();static {// 基礎配置mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);// 日期格式mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));// 注冊Java 8時間模塊mapper.registerModule(new JavaTimeModule());}@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {// 排除特定注解或類型return !returnType.hasMethodAnnotation(IgnoreWrap.class);}@SneakyThrows@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {// 1. 已經是包裝類型則直接返回if (body instanceof Result) {return body;}// 2. 處理空響應if (body == null) {return Result.success();}// 3. 特殊處理String類型if (body instanceof String) {// 設置正確的Content-Typeresponse.getHeaders().setContentType(MediaType.APPLICATION_JSON);return mapper.writeValueAsString(Result.success(body));}// 4. 添加請求ID到響應頭String requestId = request.getHeaders().getFirst("X-Request-ID");if (requestId != null) {response.getHeaders().add("X-Request-ID", requestId);}// 5. 默認包裝return Result.success(body);}
}
總結
ObjectMapper 在統一響應處理中扮演著JSON 序列化引擎的角色,核心解決了兩個關鍵問題:
- 統一響應格式:將各種類型的數據包裝為標準結構
- 特殊類型處理:解決字符串返回值無法自動包裝的問題
通過合理配置 ObjectMapper,可以實現:
- 日期、枚舉等特殊類型的格式化
- 空值過濾、縮進美化等輸出控制
- 復雜對象和集合的序列化
- 自定義序列化邏輯