当我们在写web接口时,常以JSON格式返回,但是对于一些日期、枚举之类的处理通常需要加@JsonFormat
和@JsonValue
、@JsonSerialize
之类的注解进行特定的序列化处理。那么对于公用的序列化处理该如何实现呢?
@JsonFormat
和@JsonValue
、@JsonSerialize
之类的注解,方便进行比较@EnableWebMvc
的作用,点击这里查看Spring Boot默认采用Jackson进行序列化,所以提供的四种全局序列化方式都是针对于Jackson,对于fastJson方式下文中也会顺便提一下。本文以对枚举类的全局序列化来举例。
@JsonComponent
(推荐)首先话不多说先看个例子。
定义枚举类
public enum CurrCode implements BaseEnum {
RMB("156", "rmb"), USD("840", "usd");
private String code;
private String desc;
CurrCode(String code, String desc) {
this.code = code;
this.desc = desc;
}
@JsonCreator
public static CurrCode of(@JsonProperty("code") String c) {
for (CurrCode value : CurrCode.values()) {
if (value.getCode().equals(c)) {
return value;
}
}
return null;
}
public String getCode() {
return code;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return "CurrCode{" +
"code='" + code + '\'' +
", desc='" + desc + '\'' +
'}';
}
@Override
public String getValue() {
return getCode();
}
}
定义配置类
@JsonComponent
public class JacksonComponent {
public static class CurrCodeJsonSerializer extends JsonSerializer<CurrCode> {
@Override
public void serialize(CurrCode currCode, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(currCode.getCode());
}
}
}
分析
查看@JsonComponent
源码
@Component that provides JsonSerializer,JsonDeserializer or KeyDeserializer implementations to be registered with Jackson when JsonComponentModule is in use. Can be used to annotate implementations directly or a class that contains them as inner-classes.
翻译:@Component,提供JsonSerializer,JsonDeserializer或KeyDeserializer实现,以便在使用JsonComponentModule时向Jackson进行注册。可用于直接注解实现或包含它们作为内部类的类。
@JsonComponent
public class CustomerJsonComponent {
public static class Serializer extends JsonSerializer<Customer> {
// ...
}
public static class Deserializer extends JsonDeserializer<Customer> {
// ...
}
}
上面源码里给出的例子在@JsonComponent
注解所修饰的类里面添加继承JsonSerializer
的内部类,spring就会自动帮助我们将定义的序列化类注册到jackson里去。这个过程使用的仍然是Spring Boot自动配置web mvc,这样静态资源不会失效。推荐使用这种方式实现全局JSON序列化。
补充:@JsonComponent
注解value用来指定注册到Spring容器里的Bean Name,type用来指定对哪些类进行了序列化或反序列化处理。scope指定对在作用范围。
使用Jackson2ObjectMapperBuilderCustomizer
实现全局序列化、反序列化,这个过程使用的仍然是Spring Boot自动配置web mvc,这样静态资源不会失效。
@Configuration
public class LocalDateTimeSerializerConfig {
@Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}")
private String pattern;
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return builder -> builder.serializerByType(LocalDateTime.class,
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(pattern)));
}
}
使用ObjectMapper
实现全局序列化、反序列化,这个过程使用的仍然是Spring Boot自动配置web mvc,这样静态资源不会失效。
@Configuration
public class LocalDateTimeSerializerConfig {
@Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}")
private String pattern;
@Bean
public ObjectMapper customObjectMapper() {
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(pattern)));
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(javaTimeModule);
return objectMapper;
}
}
@Configuration
public class JacksonConfig extends WebMvcConfigurationSupport {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(CurrCode.class, new CurrCodeJsonSerializer());
objectMapper.registerModule(simpleModule);
// 配置null值序列化成空字符串
objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString("");
}
});
//这里是fastJSON的配置方式,更多的内容可以查看SerializerFeature
// FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
// converter.setFeatures(SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.WriteNullNumberAsZero,
// SerializerFeature.WriteNullBooleanAsFalse, SerializerFeature.WriteNullListAsEmpty);
converter.setObjectMapper(objectMapper);
converters.add(converter);
}
public static class CurrCodeJsonSerializer extends JsonSerializer<CurrCode> {
@Override
public void serialize(CurrCode currCode, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeObject(currCode.getCode());
}
}
}
分析
继承WebMvcConfigurationSupport类主要是需要往web mvc配置中添加对于我们要特殊处理类的转换器(HttpMessageConverter的子类),由于我们使用的是Jackson序列化对象所以需要往转换里添加Jackson提供的转换器即MappingJackson2HttpMessageConverter。如果使用fastjson可以使用转换器FastJsonHttpMessageConverter。
补充:
1.WebMvcConfigurationSupport会屏蔽Spring Boot的自动配置。这样会导致自动配置的静态资源路径(classpath:/META/resources/,classpath:/resources/,classpath:/static/,classpath:/public/)无法访问。
2.上面的配置类同样可以实现WebMvcConfigurer,实现同名的configureMessageConverters方法具体同上。但是需要这个配置类起作用需要在配置类上加上@EnableWebMvc
注解。
3.@EnableWebMvc
注解同样会导致自动配置的静态资源路径无法访问,也会导致@JsonFormat
之类的注解无法工作。
定义一个测试的接口如下
@RestController
public class JacksonController {
@GetMapping(path = "/test")
public Param getTest() {
Param param = new Param();
param.setCurrCode(CurrCode.RMB);
return param;
}
}
利用postman工具发送请求,查看返回结果,如下可以看出返回的是枚举类的code而不是枚举名称。
以上四种方式都能实现全局JSON序列化,但是为了保证避免静态资源路径无法访问以及@JsonFormat
之类的注解无法工作的问题,推荐使用第一种方法使用@JsonComponent
注解来实现全局JSON序列化或者第二三两种方案都可。
代码地址:
https://github.com/nestorbian/spring-boot-examples/tree/master/jackson-full-config
参考文章:
https://www.cnblogs.com/wang-meng/p/9163875.html
https://blog.csdn.net/zxc123e/article/details/84636521