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")@ResponseBodypublic 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:sstime-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;// 忽略属性@JsonIgnoreprivate 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*/@Overrideprotected 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)