在Spring Boot项目开发中,后端同学经常遇到一个奇怪的现象:实体类里明明定义了某个字段,查询结果里该字段确实是null,但接口返回的JSON数据中压根找不到这个字段名。前端同学取值时自然就报了undefined的错误,双方来回扯皮半天才发现问题出在序列化配置上。这篇文章就来彻底讲清楚null值字段不显示的原因,以及几种实用的解决方案。

为什么null值字段会在返回结果中消失
Spring Boot默认使用Jackson作为JSON序列化框架,而Jackson在序列化Java对象时,对于值为null的字段,默认行为是直接忽略、不输出。也就是说,如果你的实体类有name、age、address三个字段,其中address为null,那么返回的JSON里只会出现name和age两个属性。
这个默认行为在某些场景下其实是合理的,比如数据量大、null字段多的接口,省略null可以减少响应体体积。但在前后端强约定的项目中,字段缺失会带来麻烦:前端需要额外判断属性是否存在,TypeScript项目中的类型定义也会对不上,甚至一些表格组件会因为属性缺失而显示异常。
还有一种常见情况是项目里有人自定义了配置,比如在application.yml中开启了non_null策略,或者通过@Configuration类定制了ObjectMapper,后来的开发者不了解背景,排查起来就很费劲。所以第一步是确认项目的序列化配置现状。
方案一:全局配置文件开启null值返回
最简单的办法是修改application.yml,直接告诉Jackson在序列化时包含null字段:
spring:
jackson:
default-property-inclusion: always
如果只是想忽略null,可以设置为non_null;其他可选值还有non_empty(忽略空字符串、空集合等)和non_absent(忽略Optional.empty等)。这里选择always表示任何情况都输出字段,null值会以JSON的null形式出现在响应中。
这种方式的好处是改动小、生效范围全局,一行配置解决所有接口的问题。但也要注意副作用:如果项目接口很多、实体类字段很长,全局开启后响应体会明显变大,对带宽敏感的移动端场景需要权衡。另外,配置的加载依赖于Spring Boot自动装配机制,如果你自己手动创建过ObjectMapper的Bean,这个yml配置可能会失效,这一点后面会讲到。
方案二:通过代码配置ObjectMapper
对于需要更精细控制的场景,可以写一个配置类,显式定制序列化行为:
@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
return builder -> builder.serializationInclusion(JsonInclude.Include.ALWAYS);
}
}
使用Jackson2ObjectMapperBuilderCustomizer的好处是不会替换掉Spring Boot默认创建的ObjectMapper,而是在其基础上做增强,兼容性最好。如果你选择直接定义一个ObjectMapper Bean来覆盖默认行为,代码会像这样:
@Configuration
public class JacksonConfig {
@Primary
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
return mapper;
}
}
需要注意,直接覆盖ObjectMapper会丢掉Spring Boot默认注册的一些模块(如JavaTimeModule对LocalDateTime的支持),除非你清楚自己在做什么,否则推荐用Customizer的方式。这种方式适合团队有统一序列化规范、需要集中管理的场景,配置集中在代码里也方便版本管理和review。
方案三:使用@JsonInclude注解按需控制
如果只有个别实体类需要输出null字段,不想影响全局,可以在类或字段级别使用注解:
@Data
@JsonInclude(JsonInclude.Include.ALWAYS)
public class UserVO {
private String name;
private Integer age;
// 单独控制某个字段:null时不序列化
@JsonInclude(JsonInclude.Include.NON_NULL)
private String internalRemark;
类级别的注解作用于整个对象,字段级别的注解优先级更高,可以覆盖类级别的配置。这种方式的粒度最细,非常适合同一个项目里不同接口有不同返回要求的场景,比如对外接口尽量精简、内部管理后台则要求字段完整。
注解方式的缺点是侵入性强,每个需要的类都要加注解,字段多了容易遗漏。实践中常见的做法是定义一个基础VO类加上注解,其他VO继承它,减少重复代码。
方案对比与选择建议
三种方案没有绝对的好坏,关键看项目的实际需求。简单项目、想快速解决问题,用yml全局配置最省事;多模块项目或者需要统一技术规范的中大型项目,用配置类的代码方式更可控;字段级别差异化需求多,就混合使用注解。
另外还有一个容易踩的坑:如果项目中同时引入了Fastjson并配置为消息转换器,那么上述Jackson的配置全部无效,需要去改Fastjson的SerializerFeature配置,比如加上WriteMapNullValue让Map中的null值也能输出。排查问题时先确认当前生效的到底是哪个JSON框架,否则改了半天配置毫无效果。
最后提醒一点,接口返回null字段还是空字符串,最好在团队内部统一约定并写进接口文档,避免后端返回null、前端期望空串之类的隐性分歧。序列化配置看似是小问题,但处理不好会反复消耗前后端的沟通成本,值得在一开始就定好规矩。
Spring Bootnull值过滤Jackson配置修改时间:2026-09-15 16:24:31