You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring+Ajax获取Answer列表仅首个完整其余为ID问题排查

问题诊断与解决方案

看起来你遇到的问题是双向实体关联导致的JSON序列化循环引用处理问题,和控制器逻辑关系不大,核心问题出在实体类的序列化配置与数据获取方式上。

为什么会出现这个现象?

你的Question和Answer是双向关联的:Question包含List<Answer>,Answer又持有Question引用。加上你给每个实体都配置了@JsonIdentityInfo,当Spring默认的Jackson序列化工具处理List<Answer>时:

  1. 第一个Answer对象会被完整序列化,同时会把它关联的Question也序列化出来;
  2. 而这个Question对象里又包含了整个Answer列表,为了避免无限循环序列化,Jackson会把后续重复出现的Answer对象替换成它们的answer_id(也就是你配置的@JsonIdentityInfo的property字段);
  3. 最终就出现了你看到的:第一个Answer完整,其余只有ID的情况。

解决方案(按推荐程度排序)

1. 忽略Answer中的Question关联(最简单有效)

既然你在前端只需要Answer的内容(答案文本、是否正确),不需要关联的Question信息,直接在Answer的question字段上加上@JsonIgnore,让序列化时跳过这个字段:

@Entity
@JsonIdentityInfo(
    generator = ObjectIdGenerators.PropertyGenerator.class,
    property = "answer_id")
public class Answer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int answer_id;
    private String answer;
    private boolean corect;
    
    @ManyToOne
    @JsonIgnore // 新增这个注解
    private Question question;
}

这样序列化出来的每个Answer都是完整的,不会携带Question引用,自然也就不会触发循环引用的ID替换逻辑。

2. 直接查询Answer实体,避免加载Question关联

修改你的findByQuestionId方法,直接从Answer表查询,而不是通过Question的关联获取,这样可以避免加载不必要的Question对象:

@Override
public List<Answer> findByQuestionId(int question_id) {
    Session session = sessionFactory.openSession();
    session.beginTransaction();
    // 直接查询属于该question_id的所有Answer
    List<Answer> answers = session.createQuery(
            "SELECT a FROM Answer a WHERE a.question.id = :questionId", 
            Answer.class)
        .setParameter("questionId", question_id)
        .getResultList();
    session.getTransaction().commit();
    session.close();
    return answers;
}

这种方式获取的Answer列表,不会主动加载关联的Question(因为@ManyToOne默认是懒加载),序列化时也就不会触发循环引用问题。

3. 调整Jackson的循环引用处理策略

如果你确实需要保留双向关联的序列化,可以去掉@JsonIdentityInfo,改用@JsonManagedReference和@JsonBackReference来标记双向关联:

  • 在Question的answers字段上加上@JsonManagedReference(主动序列化的一端)
  • 在Answer的question字段上加上@JsonBackReference(被忽略序列化的一端)

示例:

// Question类
@OneToMany(mappedBy = "question", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@Fetch(value = FetchMode.SUBSELECT)
@JsonManagedReference // 新增
private List<Answer> answers;

// Answer类
@ManyToOne
@JsonBackReference // 新增
private Question question;

这种方式也能解决循环引用问题,同时保留实体间的关联关系序列化(但前端依然不需要Question信息的话,第一种方法更直接)。

额外检查

确认你的Ajax代码中answer.answer是正确的字段名:你的Answer实体里的答案文本字段是private String answer;,所以answer.answer是正确的,可以通过console.log(answers)在浏览器控制台查看序列化后的JSON结构,确认字段名是否匹配。

内容的提问来源于stack exchange,提问作者Ovidiu G

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:49:21