当我在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中,并且该stacktrace中没有任何内容。
这项服务只是叫道...
@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。
最佳答案
进行了一些更改就可以使用…
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在登录后立即要求输入
/favicon.ico
,而Spring Security拒绝访问。调试:org.springframework.security.web.util.AntPathRequestMatcher-检查请求是否匹配:“/ favicon.ico”;反对 '/'
调试:org.springframework.security.web.util.AntPathRequestMatcher-检查请求是否匹配:“/ favicon.ico”;针对“/ exam **”
调试:org.springframework.security.web.util.AntPathRequestMatcher-检查请求是否匹配:“/ favicon.ico”;针对“/ exam / **”
调试:org.springframework.security.web.access.intercept.FilterSecurityInterceptor-安全对象:FilterInvocation:URL:/favicon.ico;属性:[denyAll]
调试:org.springframework.security.web.access.intercept.FilterSecurityInterceptor-先前已验证:org.springframework.security.authentication.UsernamePasswordAuthenticationToken@fb77dfdd:主体:org.springframework.security.core.userdetails.User@36ebcb:用户名:user ;密码保护];启用:true; AccountNonExpired:true; certificateNonExpired:true; AccountNonLocked:true;授予的权限:ROLE_ADMIN,ROLE_USER;凭证:[受保护];已验证:true;详细信息:org.springframework.security.web.authentication.WebAuthenticationDetails@0:RemoteIpAddress:0:0:0:0:0:0:0:0:1; SessionId: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-从处理程序[公共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,无法初始化代理-没有会话(通过参考链:java.util。 ArrayList [0]-> com.securetest.app.entity.Exam [“questions”])
调试:org.springframework.web.servlet.DispatcherServlet-Null ModelAndView返回到DispatcherServlet,名称为“appServlet”:假设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;
}
允许请求成功完成。
希望能帮助到你!