Spring MVC+Thymeleaf报错:java.lang.IllegalStateException求助排查
问题分析与修复
错误原因
- HTML结构非法:
<form>直接作为<tr>的子元素,违反HTML表格规范(<tr>仅允许<td>/<th>作为直接子元素),浏览器会自动重构DOM,导致Thymeleaf解析逻辑混乱。 - 表单绑定目标缺失:
th:object="${score}"中的score是循环局部变量,Thymeleaf会在request域(Model)中查找名为score的全局对象,但你的控制器仅传入了scores列表,未提供该全局对象,因此触发Neither BindingResult nor plain target object for bean name 'score' available异常。
修复步骤
1. 调整控制器方法
添加一个空的Score对象到Model,供Thymeleaf表单绑定使用:
@GetMapping("/exams/update") public String viewStudentUpdate(@RequestParam("subject") Integer id, Model model) { Subject subject = serviceSubjectDao.getSubjectById(id); List<Score> scores = serviceScoreDao.getScoreForSubject(subject); model.addAttribute("scores", scores); model.addAttribute("subjectName", subject); model.addAttribute("PageName", "StudentMarksUpdate"); // 新增空Score对象,用于表单绑定的目标对象 model.addAttribute("score", new Score()); return "Template"; }
2. 修正Thymeleaf模板
修复HTML结构,将表单合法嵌套进表格,并调整绑定逻辑:
<table class="m-2 table table-bordered"> <thead> <tr class="text-center"> <th scope="col">Student Name</th> <th scope="col">CT-1</th> <th scope="col">CT-2</th> <th scope="col">INTERNAL</th> <th scope="col">END SEMESTER</th> <th scope="col">GRADE</th> <th scope="col">EXAM DATE</th> <th scope="col">UPDATE</th> </tr> </thead> <tbody class="text-center"> <tr th:each="scoreItem : ${scores}"> <!-- 用colspan将表单包裹在单个td中,符合表格结构规范 --> <td colspan="8"> <form th:action="@{/faculty/exams/update/process}" th:object="${score}" method="post" class="d-flex justify-content-around align-items-center"> <!-- 隐藏字段传递当前Score的ID,后端用于定位更新对象 --> <input type="hidden" th:field="*{id}" th:value="${scoreItem.id}"> <span th:text="${scoreItem.student.name}"> <a th:href="@{/Student/profile/view(stId=${scoreItem.student.id})}" class="text-decoration-none">name</a> </span> <input type="number" th:field="*{ct1}" th:value="${scoreItem.ct1}" class="w-10"> <input type="number" th:field="*{ct2}" th:value="${scoreItem.ct2}" class="w-10"> <input type="number" th:field="*{internal}" th:value="${scoreItem.internal}" class="w-10"> <input type="number" th:field="*{endSem}" th:value="${scoreItem.endSem}" class="w-10"> <input type="text" th:field="*{grade}" th:value="${scoreItem.grade}" class="w-10"> <input type="date" th:field="*{examDate}" th:value="${scoreItem.examDate}" class="w-10"> <button type="submit" class="btn btn-warning">Update</button> </form> </td> </tr> </tbody> </table>
可选简化方案(无需添加空Score对象)
如果不想在Model中添加空对象,可以直接使用th:value绑定字段值,放弃th:object和*{}语法:
<table class="m-2 table table-bordered"> <thead> <tr class="text-center"> <th scope="col">Student Name</th> <th scope="col">CT-1</th> <th scope="col">CT-2</th> <th scope="col">INTERNAL</th> <th scope="col">END SEMESTER</th> <th scope="col">GRADE</th> <th scope="col">EXAM DATE</th> <th scope="col">UPDATE</th> </tr> </thead> <tbody class="text-center"> <tr th:each="score : ${scores}"> <td th:text="${score.student.name}"> <a th:href="@{/Student/profile/view(stId=${score.student.id})}" class="text-decoration-none">name</a> </td> <td><input type="number" name="ct1" th:value="${score.ct1}"></td> <td><input type="number" name="ct2" th:value="${score.ct2}"></td> <td><input type="number" name="internal" th:value="${score.internal}"></td> <td><input type="number" name="endSem" th:value="${score.endSem}"></td> <td><input type="text" name="grade" th:value="${score.grade}"></td> <td><input type="date" name="examDate" th:value="${score.examDate}"></td> <td> <form th:action="@{/faculty/exams/update/process}" method="post"> <input type="hidden" name="id" th:value="${score.id}"> <input type="hidden" name="ct1" th:value="${score.ct1}"> <input type="hidden" name="ct2" th:value="${score.ct2}"> <input type="hidden" name="internal" th:value="${score.internal}"> <input type="hidden" name="endSem" th:value="${score.endSem}"> <input type="hidden" name="grade" th:value="${score.grade}"> <input type="hidden" name="examDate" th:value="${score.examDate}"> <button type="submit" class="btn btn-warning">Update</button> </form> </td> </tr> </tbody> </table>
后端POST方法示例
确保后端接收更新请求的方法能正确绑定Score对象:
@PostMapping("/faculty/exams/update/process") public String processScoreUpdate(@ModelAttribute Score score, RedirectAttributes redirectAttributes) { serviceScoreDao.updateScore(score); redirectAttributes.addFlashAttribute("successMsg", "成绩更新成功"); // 重定向回原页面,携带subject参数 return "redirect:/exams/update?subject=" + score.getSubject().getId(); }
内容的提问来源于stack exchange,提问作者Shrikant Bochare
相关产品推荐
相关产品推荐

