SpringBoot返回json数据是很常见的需求,我们可以通过配置来控制实体对象的输出形式
目录
版本依赖
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.7</version> <relativePath/> <!-- lookup parent from repository --> </parent>
通过一个简单的SpringBoot项目测试json数据返回格式
对象实体
package com.example.demo.dto; import lombok.Data; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.Date; @Data public class User { private String name; private Integer age; private String password; private Date birthday; private LocalDateTime localDateTime; private LocalDate localDate; private LocalTime localTime; private LocalDateTime localDateTimeFormat; }
控制器
package com.example.demo.controller; import com.example.demo.dto.User; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.Date; @RestController public class UserController { @GetMapping("/user") @ResponseBody public User getUser(){ User user = new User(); user.setAge(20); user.setName("tom"); user.setPassword("123456"); user.setBirthday(new Date()); user.setLocalDateTime(LocalDateTime.now()); user.setLocalDate(LocalDate.now()); user.setLocalTime(LocalTime.now()); user.setLocalDateTimeFormat(LocalDateTime.now()); return user; } }
默认返回
没有任何配置,直接输出对象,可以得到一个如下的json数据(前端看了想打人)
{ "name":"tom", "age":20, "password":"123456", "birthday":1677250587064, "localDateTime":[ 2023, 2, 24, 22, 56, 27, 64000000], "localDate":[ 2023, 2, 24], "localTime":[ 22, 56, 27, 64000000], "localDateTimeFormat":[ 2023, 2, 24, 22, 56, 27, 64000000] }
或者(测试几次发现日期格式输出竟然不固定)
{ "name": "tom", "age": 20, "password": "123456", "birthday": "2023-02-24T23:24:08.956+00:00", "localDateTime": "2023-02-25T07:24:08.956", "localDate": "2023-02-25", "localTime": "07:24:08.956", "localDateTimeFormat": "2023-02-25T07:24:08.956" }
默认返回数据有几个问题:
- 密码字段
password
不需要返回 - 时间格式
Date
返回的是13位时间戳 - 时间格式
LocalDateTime
、LocalDate
、LocalTime
返回的是数组格式 - 字段名是小驼峰个格式,大部分情况需要返回蛇形的下划线小写格式
通过配置格式化
添加配置 application.yml
spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8
返回数据
{ "name": "tom", "age": 20, "password": "123456", "birthday": "2023-02-25 07:25:56", "localDateTime": "2023-02-25T07:25:56.509", "localDate": "2023-02-25", "localTime": "07:25:56.51", "localDateTimeFormat": "2023-02-25T07:25:56.51" }
可以看到,只有Date
类型的birthday
参数生效了
通过注解实现属性设置
通过几个注解,实现实体对象转为json的属性设置
注解 | 作用 |
@JsonIgnoreProperties | 批量设置转 JSON 时忽略的属性 |
@JsonIgnore | 转 JSON 时忽略当前属性 |
@JsonProperty | 修改转换后的 JSON 的属性名 |
@JsonFormat | 转 JSON 时格式化属性的值 |
返回对象实体
package com.example.demo.dto; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.Date; @Data public class User { private String name; private Integer age; // 忽略属性 @JsonIgnore private String password; // 修改属性名 @JsonProperty("birthDay") private Date birthday; private LocalDateTime localDateTime; private LocalDate localDate; private LocalTime localTime; // 格式化 @JsonFormat(pattern = "yyyy年MM月dd日") private LocalDateTime localDateTimeFormat; }
返回结果
{ "name": "tom", "age": 20, "localDateTime": "2023-02-25T07:32:57.637", "localDate": "2023-02-25", "localTime": "07:32:57.637", "localDateTimeFormat": "2023年02月25日", "birthDay": "2023-02-25 07:32:57" }
通过以上配置,我们实现了
- 不返回密码字段
password
- 自定义了字段
localDateTimeFormat
的时间格式 - 自定义了字段
birthday
的命名风格改为了小驼峰形式birthDay
目前为止,localDateTime
和localTime
还没有处理到
全局配置
继承WebMvcConfigurationSupport类,覆写方法
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters){}
WebMvcConfig
package com.example.demo.config; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import java.util.List; @Configuration @Slf4j public class WebMvcConfig extends WebMvcConfigurationSupport { /** * 扩展消息转换器 * * @param converters */ @Override protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) { // 创建消息转换器对象 MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter(); // 设置对象转换器 messageConverter.setObjectMapper(new JacksonObjectMapper()); // 添加到mvc框架消息转换器中,优先使用自定义转换器 converters.add(0, messageConverter); } }
JacksonObjectMapper
package com.example.demo.config; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.deser.std.DateDeserializers; import com.fasterxml.jackson.databind.ser.std.DateSerializer; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.util.Date; import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES; /** * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象 * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象] * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON] */ public class JacksonObjectMapper extends ObjectMapper { private static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd"; private static final String DEFAULT_TIME_FORMAT = "HH:mm:ss"; public JacksonObjectMapper() { super(); // 收到未知属性时不报异常 this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false); // 统一返回数据的输出风格 转为蛇形命名法 this.setPropertyNamingStrategy(new PropertyNamingStrategies.SnakeCaseStrategy()); // 反序列化时,属性不存在的兼容处理 this.getDeserializationConfig() .withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // 格式化时间 JavaTimeModule module = new JavaTimeModule(); module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))) .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))) .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))) .addDeserializer(Date.class, new DateDeserializers.DateDeserializer()) // .addSerializer(BigInteger.class, ToStringSerializer.instance) // .addSerializer(Long.class, ToStringSerializer.instance) .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))) .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))) .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))) .addSerializer(Date.class, new DateSerializer(false, new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT))) ; // 注册功能模块 添加自定义序列化器和反序列化器 this.registerModule(module); } }
最终效果
{ "name": "tom", "age": 20, "local_date_time": "2023-02-25 07:56:22", "local_date": "2023-02-25", "local_time": "07:56:22", "local_date_time_format": "2023年02月25日", "birthDay": "2023-02-25 07:56:22" }
至此,我们解决了一开始的几个格式问题
完整代码: https://mouday.github.io/spring-boot-demo/#/SpringBoot-JSON/README
参考
- Spring Boot——统一设置返回Json数据风格(Java驼峰命名法转下划线命名法)解决方案
- Springboot JSON 转换:Jackson篇
- Jackson解决序列化LocalDateTime到接口中变成数组(Spring boot)