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

Spring MVC+Thymeleaf报错:java.lang.IllegalStateException求助排查

问题分析与修复

错误原因

  1. HTML结构非法:<form>直接作为<tr>的子元素,违反HTML表格规范(<tr>仅允许<td>/<th>作为直接子元素),浏览器会自动重构DOM,导致Thymeleaf解析逻辑混乱。
  2. 表单绑定目标缺失: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 07:49:49