控制器返回JSON字段为空?调试正常但浏览器响应异常排查
我来帮你揪出这个问题的根源——其实核心和Jackson的序列化规则以及实体类的字段权限有关:
1. 实体类字段的访问权限是关键问题
你的Municipality和Prediction实体里的所有业务字段(比如name、pm10、municipality等)都是默认的包私有访问权限(没加public修饰符)。而Jackson在把Java对象序列化成JSON时,默认只会处理两种情况的字段:
- 带有
public修饰符的字段 - 拥有
publicgetter方法的字段
调试时IDE能读取包私有字段,所以你能看到数据正常,但Jackson没有这个权限,自然就不会把这些字段输出到响应里,导致浏览器看不到内容。
2. 关联对象的序列化隐性问题
另外,你的Prediction类里关联了Municipality对象,这个municipality字段同样是包私有,就算Prediction的其他字段权限正常,这个关联对象也无法被Jackson序列化,会导致响应里缺失关联数据。
针对性解决方案
方案一:直接给字段添加public修饰符
最简单的办法是把需要序列化的字段改成public,比如:
@Entity public class Municipality { @Id @JsonIgnore @GeneratedValue(strategy = GenerationType.IDENTITY) public Long id; public String name; }
同理给Prediction的所有业务字段加上public修饰:
@Entity public class Prediction { @Id @JsonIgnore @GeneratedValue(strategy = GenerationType.IDENTITY) public Long id; public LocalDateTime tsPredictionMade; public LocalDateTime tsPredictionFor; public float pm10; public float pm25; @ManyToOne @OnDelete(action = OnDeleteAction.CASCADE) public Municipality municipality; }
方案二:添加符合JavaBean规范的public getter方法
这是更推荐的做法,既保留字段的封装性,又能让Jackson正常序列化:
@Entity public class Municipality { @Id @JsonIgnore @GeneratedValue(strategy = GenerationType.IDENTITY) Long id; String name; // 给name添加public getter public String getName() { return name; } // 如果需要接收前端传入的数据,再添加setter public void setName(String name) { this.name = name; } }
给Prediction的每个字段都添加对应的getter方法,比如:
public LocalDateTime getTsPredictionMade() { return tsPredictionMade; } public float getPm10() { return pm10; } public Municipality getMunicipality() { return municipality; }
额外提示:双向关联的循环引用处理
如果后续你给Municipality添加了@OneToMany关联Prediction的字段,要记得添加@JsonIgnore或者@JsonManagedReference/@JsonBackReference注解避免循环序列化,不过从你当前的代码看暂时不需要这个操作。
修改完成后重启应用,再调用接口就能看到浏览器响应里正常显示字段数据了。
内容的提问来源于stack exchange,提问作者zafirzarya

