SpringBoot 统一返回数据处理:消息转换器与格式化
在前面我们已经学会了Result 统一返回但这只是第一步。真正企业级项目还需要做到所有接口自动包装 Result不用每个接口手动 return Result.success()日期格式化全局统一yyyy-MM-dd HH:mm:ssLong 类型传给前端不丢失精度JS 精度丢失问题null 自动转空字符串/空数组自定义枚举格式化这一节我们用SpringBoot 消息转换器HttpMessageConverter 全局配置实现真正零入侵、全自动、标准化的返回数据处理。一、本篇文字能解决什么问题Controller 再也不用写 Result直接返回对象自动包装全局日期格式化不用每个字段加注解Long 类型转字符串解决前端 JS 精度丢失null 值统一处理null → / []枚举统一格式化全局统一JSON风格二、消息转换器 HttpMessageConverterSpringBoot 用HttpMessageConverter做请求Body 转 Java 对象Java 对象 转 响应Body JSON我们要做的就是自定义 MappingJackson2HttpMessageConverter接管全局JSON格式化。三、第一步全局 JSON 格式化配置日期、Long、Null1importcom.fasterxml.jackson.databind.ser.std.ToStringSerializer; 2importcom.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 3importcom.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; 4importorg.springframework.context.annotation.Bean; 5importorg.springframework.context.annotation.Configuration; 6importorg.springframework.http.converter.HttpMessageConverter; 7importorg.springframework.http.converter.json.MappingJackson2HttpMessageConverter; 8importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer; 9importcom.fasterxml.jackson.databind.ObjectMapper; 10importcom.fasterxml.jackson.databind.module.SimpleModule; 11 12importjava.time.LocalDateTime; 13importjava.time.format.DateTimeFormatter; 14importjava.util.List; 15 16Configuration 17publicclassWebMvcConfigimplementsWebMvcConfigurer{ 18 19// 全局日期格式 20privatestaticfinalStringDEFAULT_DATE_TIME_FORMATyyyy-MM-dd HH:mm:ss; 21 22/** 23* 替换默认的消息转换器 24*/ 25Override 26publicvoidconfigureMessageConverters(ListHttpMessageConverter? converters){ 27 converters.add(jsonConverter()); 28} 29 30/** 31* 自定义JSON转换器 32*/ 33Bean 34publicMappingJackson2HttpMessageConverterjsonConverter(){ 35MappingJackson2HttpMessageConverter converter newMappingJackson2HttpMessageConverter(); 36ObjectMapper objectMapper newObjectMapper(); 37 38// 1. 全局日期格式化 39JavaTimeModule timeModule newJavaTimeModule(); 40 timeModule.addSerializer(LocalDateTime.class, 41newLocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))); 42 43// 2. Long 转 String解决前端精度丢失 44SimpleModule longModule newSimpleModule(); 45 longModule.addSerializer(Long.class,ToStringSerializer.instance); 46 longModule.addSerializer(Long.TYPE,ToStringSerializer.instance); 47 48// 注册模块 49 objectMapper.registerModule(timeModule); 50 objectMapper.registerModule(longModule); 51 52 converter.setObjectMapper(objectMapper); 53return converter; 54} 55}效果所有LocalDateTime→yyyy-MM-dd HH:mm:ss所有Long→String前端不丢精度四、第二步全局统一包装 Result实现ResponseBodyAdvice全局统一包装返回值。重点以后你的 Controller 可以直接返回对象1importorg.springframework.core.MethodParameter; 2importorg.springframework.http.MediaType; 3importorg.springframework.http.converter.HttpMessageConverter; 4importorg.springframework.http.server.ServerHttpRequest; 5importorg.springframework.http.server.ServerHttpResponse; 6importorg.springframework.web.bind.annotation.RestControllerAdvice; 7importorg.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; 8 9/** 10* 全局统一返回结果包装 11* 所有接口自动封装 Result 12*/ 13RestControllerAdvice 14publicclassGlobalResponseAdviceimplementsResponseBodyAdviceObject{ 15 16// 开启支持 17Override 18publicbooleansupports(MethodParameter returnType,Class?extendsHttpMessageConverter? converterType){ 19returntrue; 20} 21 22// 包装返回结果 23Override 24publicObjectbeforeBodyWrite(Object body, 25MethodParameter returnType, 26MediaType selectedContentType, 27Class?extendsHttpMessageConverter? selectedConverterType, 28ServerHttpRequest request, 29ServerHttpResponse response){ 30 31// 1. 如果已经是 Result直接返回 32if(body instanceofResult){ 33return body; 34} 35 36// 2. 如果是 String 类型特殊处理避免转换异常 37if(body instanceofString){ 38returnResult.success(body).toString(); 39} 40 41// 3. 自动包装成功返回 42returnResult.success(body); 43} 44} 更新变化以前1GetMapping(/user/{id}) 2publicResultUsergetUser(PathVariableInteger id){ 3returnResult.success(userService.getById(id)); 4}现在直接返回对象1GetMapping(/user/{id}) 2publicUsergetUser(PathVariableInteger id){ 3return userService.getById(id); 4}前端收到的依旧是1{ 2code:200, 3msg:操作成功, 4data:{id:1,username:张三} 5}五、第三步Null 值全局统一格式化前端最喜欢的配置null → 空集合 → []空数字 → 0在ObjectMapper中添加配置1// 空值处理 2objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);如需把 null 转空字符串可自定义序列化器。六、第四步异常也统一配合全局异常全局异常 全局返回 完美闭环1RestControllerAdvice 2publicclassGlobalExceptionHandler{ 3ExceptionHandler(Exception.class) 4publicResult?exception(Exception e){ 5returnResult.fail(500,服务器异常); 6} 7}现在正常接口→ 自动包装 Result异常接口→ 自动返回 Result格式全局统一前端一套解析七、企业级全局返回总结HttpMessageConverter统一JSON格式化日期、Long、NullResponseBodyAdvice全局自动包装ResultController 零入侵GlobalExceptionHandler全局异常统一返回一套配置全局生效永久规范