4

当我在 Spring 中从我的服务层返回实体列表时,我不断收到来自 Tomcat 的错误 500。如果我只是在内存中动态创建实体,我不会收到错误并且它们返回正常,所以这与事务有关。

我的控制器中有以下方法...

@RequestMapping(value = "{examid}", method = RequestMethod.GET)
@ResponseBody
public List<Exam> getExam(@PathVariable String examid, Model model) {
    return examService.getAllExams();
}

调用此方法时,tomcat 显示错误 500 并且根本没有堆栈跟踪。我什至将它包装在一个 try catch 中,并且该堆栈跟踪中没有任何内容。

这个服务只是调用一个 dao...

@Service("examService")
public class ExamServiceImpl implements ExamService{

    @Autowired
    private ExamDao examDao;

        @Override
        @Transactional(readOnly = true)
        public List<Exam> getAllExams() {
            return examDao.getAllExams();
        }

而这个 dao 只是返回一个简单的 HQL 脚本......

@Repository("examDao")
public class ExamDaoImpl implements ExamDao {
@Autowired
    private SessionFactory sessionFactory;

    @Override
    public List<Exam> getAllExams() {
        return sessionFactory.getCurrentSession().createQuery("from Exam")
                .list();
    }

最初,我认为这与延迟加载的实体有关,如您所见,我的实体如下所示,它们非常简单

@Entity
@Table(name = "exams")
public class Exam implements Serializable {

    private static final long serialVersionUID = -5109075534794721930L;

    @Id
    @GeneratedValue(generator="system-uuid")
    @GenericGenerator(name="system-uuid", strategy = "uuid")
    @Column(name = "examid", unique = true)
    private String examId;

    @OneToMany(mappedBy = "exam")
    private Set<Question> questions;

    public String getExamId() {
        return examId;
    }

    public void setExamId(String examId) {
        this.examId = examId;
    }

    /**
     * @return the questions
     */
    @JsonManagedReference
    public Set<Question> getQuestions() {
        return questions;
    }

    /**
     * @param questions the questions to set
     */
    public void setQuestions(Set<Question> questions) {
        this.questions = questions;
    }

}

问题实体

@Entity
@Table(name = "questions")
public class Question  implements Serializable  {

    private static final long serialVersionUID = 8804841647267857850L;
    private String questionId;
    private Exam exam;
    private Set<Answer> answers;

    /**
     * @return the answer
     */
    @JsonManagedReference
    @OneToMany(mappedBy = "question")
    public Set<Answer> getAnswers() {
        return answers;
    }

    /**
     * @param answer
     *            the answer to set
     */
    public void setAnswers(Set<Answer> answers) {
        this.answers = answers;
    }

    /**
     * @return the exam
     */
    @JsonBackReference
    @ManyToOne
    @JoinColumn(name = "examid", nullable = false)
    public Exam getExam() {
        return exam;
    }

    /**
     * @param exam
     *            the exam to set
     */
    public void setExam(Exam exam) {
        this.exam = exam;
    }

    /**
     * @return the questionId
     */
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    @Column(name = "questionid", unique = true)
    public String getQuestionId() {
        return questionId;
    }

    /**
     * @param questionId
     *            the questionId to set
     */
    public void setQuestionId(final String questionId) {
        this.questionId = questionId;
    }
}

回答实体

@Entity
@Table(name = "answers")
public class Answer  implements Serializable {

    private static final long serialVersionUID = -3922870865886851018L;

    @Id
    @GeneratedValue(generator="system-uuid")
    @GenericGenerator(name="system-uuid", strategy = "uuid")
    @Column(name = "answerid", unique = true)
    private String answerId;

    @ManyToOne()
    @JoinColumn(name = "questionid", nullable = false)
    private Question question;

    /**
     * @return the question
     */
    @JsonBackReference
    public Question getQuestion() {
        return question;
    }

    /**
     * @param question the question to set
     */
    public void setQuestion(Question question) {
        this.question = question;
    }

    /**
     * @return the answerId
     */
    public String getAnswerId() {
        return answerId;
    }

    /**
     * @param answerId the answerId to set
     */
    public void setAnswerId(final String answerId) {
        this.answerId = answerId;
    }

}

我正在使用 Jackson 2.2.0 - 现在下面的代码工作正常,所以这肯定是连接的一些问题(最初是延迟加载但为了调试而删除的)。只需从控制器返回以下代码就可以了...

        Exam exam = new Exam();
        Question presidentQuestion = new Question();
        presidentQuestion.setExam(exam);
        Question skyQuestion = new Question();
        skyQuestion.setExam(exam);
        Set<Question> questions = new HashSet<>();
        questions.add(skyQuestion);
        questions.add(presidentQuestion);
        exam.setQuestions(questions);
        Answer answer = new Answer();
        answer.setQuestion(skyQuestion);
        Answer answer1 = new Answer();
        answer1.setQuestion(skyQuestion);
        Answer answer2 = new Answer();
        answer2.setQuestion(presidentQuestion);
        Set<Answer> answers1 = new HashSet<>();
        answers1.add(answer2);
        Set<Answer> answers = new HashSet<>();
        answers.add(answer);
        answers.add(answer1);
        presidentQuestion.setAnswers(answers1);
        skyQuestion.setAnswers(answers);
            return Arrays.asList(exam);

Tomcat 日志中没有任何内容 - 如何强制执行某种堆栈跟踪?Hibernate 版本 = 4.1.10.Final,Spring 版本 3.1.4。

4

1 回答 1

6

得到它的工作与一些变化......

1)main/resources/log4j.xml应该设置debug为查看错误:

<logger name="org.springframework.context">
  <level value="debug" />
</logger>

<logger name="org.springframework.web">
  <level value="debug" />
</logger>

<!-- Root Logger -->
<root>
  <priority value="debug" />
  <appender-ref ref="console" />
</root>

我错误地编辑了test/resources/log4j.xml第一个。也许你也这样做了?否则,您的 IDE 可能会妨碍您,因为一旦我在终端上设置了正确的级别,log4j.xml我就可以看到终端中的日志记录就好了。

最初我认为这个错误是因为 Chrome 在登录后立即要求 a /favicon.ico,而 Spring Security 拒绝访问。

调试:org.springframework.security.web.util.AntPathRequestMatcher - 检查请求的匹配:'/favicon.ico';反对 '/'

调试:org.springframework.security.web.util.AntPathRequestMatcher - 检查请求的匹配:'/favicon.ico';反对'/考试**'

调试:org.springframework.security.web.util.AntPathRequestMatcher - 检查请求的匹配:'/favicon.ico';反对'/考试/**'

调试:org.springframework.security.web.access.intercept.FilterSecurityInterceptor - 安全对象:FilterInvocation:URL:/favicon.ico;属性:[denyAll]

DEBUG:org.springframework.security.web.access.intercept.FilterSecurityInterceptor - 以前经过身份验证:org.springframework.security.authentication.UsernamePasswordAuthenticationToken@fb77dfdd:主体:org.springframework.security.core.userdetails.User@36ebcb:用户名:用户; 密码保护]; 启用:真;AccountNonExpired:真;凭据非过期:真;AccountNonLocked:真;授予权限:ROLE_ADMIN,ROLE_USER;凭证:[受保护];已认证:真实;详细信息:org.springframework.security.web.authentication.WebAuthenticationDetails@0: RemoteIpAddress: 0:0:0:0:0:0:0:1; 会话ID:1qtptnbw65j3g145c9ni63ucw1;授予权限:ROLE_ADMIN,ROLE_USERDEBUG:org.springframework.security.access.vote.AffirmativeBased - 投票者:org.springframework.security.web.access.expression.WebExpressionVoter@96f613,返回:-1

调试:org.springframework.security.web.access.ExceptionTranslationFilter -访问被拒绝(用户不是匿名的);委派给 AccessDeniedHandlerorg.springframework.security.access.AccessDeniedException:访问被拒绝

我添加<http pattern="/favicon.ico" security="none" />security-context.xml以消除此问题,尽管添加后结果是其他问题。

下一个错误是可怕的“未能懒惰地初始化集合”,这在 SO 上已多次提及,例如:

调试:org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver - 从处理程序中解决异常 [public java.util.List com.securetest.app.controller.ExamController.getExam(java.lang.String,org.springframework.ui .Model)]:org.springframework.http.converter.HttpMessageNotWritableException:无法写入JSON:无法懒惰地初始化角色集合:com.securetest.app.entity.Exam.questions,无法初始化代理 - 没有会话(通过引用链:java.util.ArrayList[0]->com.securetest.app.entity.Exam["questions"]);嵌套异常是 com.fasterxml.jackson.databind.JsonMappingException:未能延迟初始化角色集合:com.securetest.app.entity.Exam.questions,无法初始化代理 - 无 Session(通过引用链:java.util. ArrayList[0]->com.securetest.app.entity.Exam["questions"])

调试:org.springframework.web.servlet.DispatcherServlet - Null ModelAndView 返回到名为“appServlet”的 DispatcherServlet:假设 HandlerAdapter 完成了请求处理

调试:org.springframework.web.servlet.DispatcherServlet - 成功完成请求

我通过以下方式解决了这个问题,即在交易中手动获取相关数据的快速方法:

@Override
@Transactional(readOnly = true)
public List<Exam> getAllExams() {
  List<Exam> exams = examDao.getAllExams();
  for (Exam e : exams) {
    for (Question q : e.getQuestions()) {
      q.getAnswers().size();
    }
  }
  return exams;
}

这允许请求成功完成。

希望能帮助到你!

于 2013-06-04T21:49:22.910 回答