Spring自动定义Jackson转换Null得方法
- 背景
- MessageConverter
- 使用Jackson原生方式处理空字段(次重点方案)
- ObjectMapper的配置选项
- 通过使用注解的方式
- MappingJackson2HttpMessageConverter(重点方案)
- 创建MappingJackson2HttpMessageConverter
- XML配置
- Java配置
- MappingJackson2HttpMessageConverter整合ObjectMapper的配置
- XML配置
- JavaConfig配置
- 自定义的null处理类注解
- 方案1:使用注解
- 方案1:序列化器
- 总结一下
背景
在Spring MVC中配置JSON转换器时,当需要全局控制将某些JSON返回值的key转换为一些默认值时,可以通过实现一个自定义的序列化器(Serializer)来实现这个功能。现在,我们来深入了解Spring MVC的整体处理流程,以确定在哪个步骤进行实现和调整。
我们先来总结数量一下整个流程:
- 用户发送请求,由Spring的前端控制Servlet DispatcherServlet捕获。
- DispatcherServlet解析请求URL,并根据URI获取与之相关的Handler和拦截器配置。
- DispatcherServlet选择合适的HandlerAdapter来执行Handler(Controller)。在此过程中,也会执行拦截器的preHandler方法。
- 提取请求中的模型数据(通过MessageConverter对于入参进行转换)并填充Handler的参数,开始执行Handler。
- 执行完成后,返回一个包含Model和View信息的ModelAndView对象。
- 根据ModelAndView选择合适的ViewResolver,将其返回给DispatcherServlet。
- ViewResolver将Model和View结合起来,进行视图渲染。
- 最终将渲染结果返回给客户端(响应的数据转换则通过MessageConverter完成)
MessageConverter
对于JSON转换,涉及到MessageConverter的工作,通过在Spring MVC处理流程中的适当步骤实现自定义序列化器,我们能够全局控制JSON返回值的key,确保它们在需要时转换为指定的默认值。这种方式提供了灵活性和可定制性,使开发者能够更好地适应不同的业务需求。
MappingJackson2HttpMessageConverter是Spring框架中提供的一个HTTP消息转换器,用于在Spring MVC中进行JSON与Java对象之间的转换。它基于Jackson库,利用Jackson提供的功能进行JSON的序列化和反序列化,接下来我们就针对于它进行实现。
使用Jackson原生方式处理空字段(次重点方案)
当返回字段为null时需要进行处理,可以通过配置ObjectMapper来选择合适的处理方式。以下是几种常见的处理方式及其配置方式:
ObjectMapper的配置选项
使得ObjectMapper在将Java对象转换为JSON字符串时,仅包含字段值不为null的属性。对于为null的属性,它们将被忽略并不会显示在生成的JSON中。
// 创建ObjectMapper实例
ObjectMapper objectMapper = new ObjectMapper();
// 配置ObjectMapper处理返回字段为null的方式
objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS); // 字段均包含在结果JSON中,无论是否为null
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 字段的值不为null时,才会包含在结果JSON中
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT); // 字段的值与其默认值不相等时,才会包含在结果JSON中
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); // 字段的值不为null且不为空时,才会包含结果JSON中
// 使用配置好的ObjectMapper进行对象转换
YourObject yourObject = ...; // 要转换的对象
String json = objectMapper.writeValueAsString(yourObject); // 将对象转换为JSON字符串
通过使用注解的方式
使用注解可以更精确地控制每个类或属性的处理方式。
@JsonInclude(JsonInclude.Include.ALWAYS)
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
通过调用setSerializationInclusion方法并传入相应的JsonInclude.Include枚举值,可以配置ObjectMapper处理返回字段为null时的方式。可以根据具体需求选择适合的处理方式。
MappingJackson2HttpMessageConverter(重点方案)
对于SpringMVC,我们会采用MappingJackson2HttpMessageConverter可以将Java对象转换为JSON格式的响应体,并将JSON格式的请求体转换为对应的Java对象。它支持多种媒体类型,如application/json、text/json等。
创建MappingJackson2HttpMessageConverter
在Spring MVC中配置MappingJackson2HttpMessageConverter可以通过以下两种方式:Xml配置和Javaconfig配置
XML配置
下面展示了如何在applicationContext.xml文件中进行XML配置来实现对MappingJackson2HttpMessageConverter 的定义,并通过元素设置了supportedMediaTypes属性:
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json</value>
<!-- 可以添加其他支持的媒体类型 -->
</list>
</property>
<!-- 其他配置属性 -->
</bean>
在上述配置中,我们使用元素定义了MappingJackson2HttpMessageConverter的bean,并指定了其类名org.springframework.http.converter.json.MappingJackson2HttpMessageConverter,通过元素来设置supportedMediaTypes属性。通过元素来指定一个媒体类型列表,其中每个类型由元素表示。在示例中,我们设置了一个值为application/json的媒体类型。这样就可以将Java对象转换为JSON,并以指定的媒体类型返回给客户端。
Java配置
在Java配置中,我们可以使用@Bean注解创建MappingJackson2HttpMessageConverter的bean,并在方法中进行相同的配置。此外,我们还可以使用Charset.forName(“UTF-8”)来替代java.nio.charset.StandardCharsets.UTF_8来创建MediaType。具体示例如下:
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
// 配置媒体类型
converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON));
// 其他配置...
converters.add(converter);
}
}
MappingJackson2HttpMessageConverter整合ObjectMapper的配置
在上面我们定义了一个 MappingJackson2HttpMessageConverter
bean,并设置了 supportedMediaTypes
属性为"application/json",以支持在 Spring MVC 中将 Java 对象转换为 JSON 并返回给客户端。
在这个基础知识,我们加入了最早介绍的 ObjectMapper
bean,并设置其 serializationInclusion
属性为 NON_NULL
,这将使得序列化时排除掉值为null的字段。
XML配置
<bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="serializationInclusion">
<value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value>
</property>
</bean>
</property>
</bean>
JavaConfig配置
通过mappingJacksonHttpMessageConverter方法创建了一个MappingJackson2HttpMessageConverter的实例,并设置了支持的媒体类型为application/json;charset=UTF-8。
@Configuration
public class WebConfig {
@Bean
public MappingJackson2HttpMessageConverter mappingJacksonHttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
// 配置支持的媒体类型为application/json;charset=UTF-8
converter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON_UTF8));
// 配置ObjectMapper,设置serializationInclusion为NON_NULL
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
converter.setObjectMapper(objectMapper);
return converter;
}
}
创建了一个ObjectMapper实例,并配置了其serializationInclusion为NON_NULL,然后将该ObjectMapper设置到MappingJackson2HttpMessageConverter中。
自定义的null处理类注解
自定义的 DetfaultNullJsonSerializer
,它是一个继承自 JsonSerializer<Object>
的序列化器,用于处理值为null的情况。在 serialize
方法中,我们将使用自定义的 JsonNullDef
对象来替代值为null的字段进行序列化。
public class DetfaultNullJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeObject(new JsonNullDef());
}
}
class JsonNullDef {
private List<String> def = new ArrayList<>();
public List<String> getDef() {
return def;
}
public void setDef(List<String> def) {
this.def = def;
}
}
因此,我们可以通过自定义ObjectMapper和注册自定义的序列化器来在转换过程中添加我们需要的控制逻辑。上述的示例代码展示了如何在WebConfig
配置类中实现这一点,通过注册自定义的序列化器实现对特定字段null值的转换为默认值。
在 JsonNullDef
类中,我们定义了一个包含一个名为 def
的列表字段,用于存储默认值。通过这个自定义的null处理类,我们可以在值为null的字段处提供一个默认值,从而避免在序列化时出现null值。
方案1:使用注解
在需要使用自定义序列化器的类或对象上,通过注解或方法来指定使用 DetfaultNullJsonSerializer,例如在 MyData 类中使用注解:
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
public class MyData {
@JsonSerialize(nullsUsing = DetfaultNullJsonSerializer.class)
private String name;
@JsonSerialize(nullsUsing = DetfaultNullJsonSerializer.class)
private String description;
// 其他字段和方法...
// 构造函数、getter和setter方法...
}
除了直接用到了注解上,还可以定义到序列化器上面,方便控制和整合到MappingJackson2HttpMessageConverter中。
方案1:序列化器
创建一个自定义的 ObjectMapper 并注册自定义的序列化器:
@Configuration
public class WebConfig {
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Object.class, new DetfaultNullJsonSerializer());
objectMapper.registerModule(module);
return objectMapper;
}
@Bean
public MappingJackson2HttpMessageConverter mappingJacksonHttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
// 配置支持的媒体类型为application/json;charset=UTF-8
converter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON_UTF8));
converter.setObjectMapper(objectMapper());
return converter;
}
}
总结一下
用自定义的DetfaultNullJsonSerializer,在类或属性上使用@JsonSerialize(nullsUsing = DetfaultNullJsonSerializer.class)注解指定使用该序列化器,以及在配置类中创建并注册自定义的ObjectMapper,将自定义序列化器与ObjectMapper关联。在代码中使用该ObjectMapper实现对象的序列化和反序列化操作。这样,你就可以灵活地控制值为null的字段的处理方式。