一、针对特定接口null的处理:
方法一:使用 @JsonInclude 注解
1.1 类级别:在接口返回的 DTO 类或字段 上添加 @JsonInclude 注解,强制忽略 null 值:
类级别:所有字段为 null 时不返回
java
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MyResponseDTO {
private String field1;
1.2 字段级别:在具体字段上,仅该字段为 null 时不返回
java
// 字段级别:仅该字段为 null 时不返回
@JsonInclude(JsonInclude.Include.NON_NULL)
private String field2;
1.3 方法级别: 在方法级别使用 @JsonInclude
如果不想在 DTO 类上全局标注 @JsonInclude
,可以直接在 Controller 方法的返回类型上通过 @JsonSerialize
注解临时指定序列化行为。
java
@GetMapping("/user")
@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) // 旧版 Jackson 注解
public MyResponse getUser() {
MyResponse response = new MyResponse();
response.setName("Alice"); // age 为 null,不返回
return response;
}
方法二:动态构建响应对象
在 Controller 方法中手动过滤 null 值,使用 Map 或 JSONObject 动态构建响应体:
java
@GetMapping("/api")
public Map<String, Object> getData() {
MyResponseDTO dto = service.getData();
Map<String, Object> result = new HashMap<>();
if (dto.getField1() != null) {
result.put("field1", dto.getField1());
}
return result;
}
适用于简单场景,但需手动维护字段映射。
方法三:自定义序列化逻辑(针对复杂场景)
通过继承 JsonSerializer 实现特定字段的 null 处理逻辑,并在 DTO 中指定序列化器:
java
public class NullSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) {
// 忽略 null 字段
if (value == null) {
return;
}
gen.writeObject(value);
}
}
// 在 DTO 字段上指定序列化器
public class MyResponseDTO {
@JsonSerialize(using = NullSerializer.class)
private String field1;
}
适用于需要精细化控制序列化逻辑的场景。
方法四:自定义 ObjectMapper
并局部使用
通过注入 ObjectMapper
实例,在特定接口中手动序列化数据,跳过 null
值。
java
@Autowired
private ObjectMapper objectMapper;
@GetMapping("/user")
public String getUser(HttpServletResponse response) throws JsonProcessingException {
MyResponse data = new MyResponse();
data.setName("Alice"); // age 为 null
// 临时配置 ObjectMapper 忽略 null
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
String json = objectMapper.writeValueAsString(data);
// 恢复全局配置(可选)
objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
return json;
}
注意 :此方法需手动处理响应,适用于需要完全控制序列化逻辑的场景,但需谨慎管理 ObjectMapper
的线程安全性。
方法五:使用 ResponseBodyAdvice
全局拦截并处理
通过实现 ResponseBodyAdvice
接口,对特定接口或全局返回值进行统一处理。
-
定义切面类
java@RestControllerAdvice public class NullIgnoreAdvice implements ResponseBodyAdvice<Object> { @Override public boolean supports(MethodParameter returnType, Class converterType) { // 仅处理特定接口(根据注解、包路径等条件判断) return returnType.getExecutable().getName().equals("getUser"); } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType mediaType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { if (body instanceof MyResponse) { // 手动移除 null 值(需根据数据结构处理) ((MyResponse) body).setAge(null); // 示例 } return body; } }
-
结合
ObjectMapper
动态过滤在
beforeBodyWrite
中重新序列化数据:javaObjectMapper mapper = new ObjectMapper(); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); return mapper.convertValue(body, returnType.getParameterType());
二、针对所有接口null 的处理:
2.1 :全局配置(影响所有接口)
若需所有接口忽略null
值,可在application.properties
中配置:
java
spring.jackson.default-property-inclusion=non_null
2.2 Springboot 整合 fastjson:
在springboot 启动类中定义该方法即可
java
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters() {
FastJsonHttpMessageConverter4 fastConverter = new FastJsonHttpMessageConverter4();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat, SerializerFeature.IgnoreNonFieldGetter,
SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty);
fastConverter.setFastJsonConfig(fastJsonConfig);
List supportedMediaTypes = new ArrayList();
supportedMediaTypes.add(new MediaType("text", "json", Charset.forName("utf8")));
supportedMediaTypes.add(new MediaType("application", "json", Charset.forName("utf8")));
fastConverter.setSupportedMediaTypes(supportedMediaTypes);
HttpMessageConverter<?> converter = fastConverter;
return new HttpMessageConverters(converter);
}
2.3 Springboot 整合 jackson:
java
@Configuration
public class JacksonConfig {
@Bean
@Primary
@ConditionalOnMissingBean(ObjectMapper.class)
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString("");
}
});
return objectMapper;
}
}
三、总结:
- 针对新项目,推荐使用全局序列化处理,统一返回值。
- 针对老项目,推荐使用特定接口的处理,避免影响了其他接口的稳定。