当前位置: 首页 > news >正文

ObjectMapper 在 Spring 统一响应处理中的作用详解

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 的情况

  1. beforeBodyWrite 返回 Result.success("hello")
  2. Spring 尝试使用 StringHttpMessageConverter 处理
  3. 因为 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"}'

 

  1.    最终返回字符串结果

    • 符合 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 序列化引擎的角色,核心解决了两个关键问题:

  1. 统一响应格式:将各种类型的数据包装为标准结构
  2. 特殊类型处理:解决字符串返回值无法自动包装的问题

通过合理配置 ObjectMapper,可以实现:

  • 日期、枚举等特殊类型的格式化
  • 空值过滤、缩进美化等输出控制
  • 复杂对象和集合的序列化
  • 自定义序列化逻辑
http://www.xdnf.cn/news/880579.html

相关文章:

  • 稳定币的深度剖析与展望
  • 探秘实验室铁地板:科技与安全的完美结合
  • Bug问题
  • Axure零基础跟我学:展开与收回
  • 【Axure高保真原型】图片列表添加和删除图片
  • 企业配电系统安全升级,从局放监测开始
  • vue-18(使用 Vuex 插件实现高级功能)
  • Transformer实战——词嵌入技术详解
  • OpenAI技术路线急转:从TypeScript到Rust的Codex CLI重构内幕
  • 深度学习学习率优化方法——pytorch中各类warm up策略
  • 毕业季AI特训营:AI从入门到实践的2天冲刺计划
  • 软件工程:如何做好软件产品
  • Python使用总结之Mac安装docker并配置wechaty
  • DeepSeek 助力 Vue3 开发:打造丝滑的日历(Calendar),日历_天气预报日历示例(CalendarView01_18)
  • 【Redis从入门到精通实战文章汇总】
  • elasticsearch-8.17.4
  • ReLU 激活函数:重大缺陷一去不复返!
  • 智能照明系统:具备认知能力的“光神经网络”
  • 短剧系统开发实践:打造高质量短视频平台的解决方案
  • Flask-Babel 使用示例
  • nodejs里面的http模块介绍和使用
  • EasyRTC音视频实时通话助力新一代WebP2P视频物联网应用解决方案
  • Pandas和Django的示例Demo
  • vlan(虚拟局域网)逻辑图解+实验详解
  • kafka部署
  • SSH/RDP无法远程连接?腾讯云CVM及通用服务器连接失败原因与超全排查指南
  • 前端常见错误
  • 10. vue pinia 和react redux、jotai对比
  • 从零开始的云计算——番外实战,iptables防火墙项目
  • 第六个微信小程序:教师工具集