Thymeleaf中用JQuery动态添加List子对象输入框,控制器无法取值
解决Thymeleaf+JQuery动态添加List子对象输入框后控制器无法取值的问题
我之前也踩过这个坑!核心问题在于Spring MVC绑定集合类型的对象时,对输入框的name属性格式有严格要求,你用JQuery动态生成的输入框大概率是没遵循这个格式,导致后端无法正确映射值。下面一步步给你解决:
1. 先确认后端实体类和控制器的基础配置
首先得保证你的父类TestList和子类ProjectTask有正确的Getter/Setter,不然Spring MVC根本没法给你注入值:
// 父类TestList public class TestList { // 注意这里的集合属性名,后面前端要对应上 private List<ProjectTask> projectTasks; public List<ProjectTask> getProjectTasks() { return projectTasks; } public void setProjectTasks(List<ProjectTask> projectTasks) { this.projectTasks = projectTasks; } } // 子类ProjectTask public class ProjectTask { private String taskName; private Integer taskHours; // 其他属性... // 必须写对应的Getter和Setter public String getTaskName() { return taskName; } public void setTaskName(String taskName) { this.taskName = taskName; } public Integer getTaskHours() { return taskHours; } public void setTaskHours(Integer taskHours) { this.taskHours = taskHours; } }
控制器方法要正确接收TestList对象,用@ModelAttribute注解:
@PostMapping("/submit-form") public String submit(@ModelAttribute TestList testList) { // 现在这里就能拿到projectTasks列表了 System.out.println("收到的任务列表:" + testList.getProjectTasks()); return "success"; }
2. 前端Thymeleaf表单的正确写法
表单要通过th:object绑定TestList对象,初始的子对象输入框用th:each循环生成,注意th:field的格式:
<form th:action="@{/submit-form}" th:object="${testList}" method="post"> <!-- 存放动态生成的任务输入框的容器 --> <div id="task-container"> <!-- 循环渲染已有的ProjectTask --> <div th:each="task, stat : ${testList.projectTasks}" class="task-item"> <input type="text" th:field="*{projectTasks[__${stat.index}__].taskName}" placeholder="任务名称"/> <input type="number" th:field="*{projectTasks[__${stat.index}__].taskHours}" placeholder="耗时"/> <button type="button" class="remove-btn">删除</button> </div> </div> <button type="button" id="add-task-btn">添加新任务</button> <button type="submit">提交</button> </form>
3. JQuery动态生成输入框的关键:正确的name格式
Spring MVC识别List子对象的规则是:集合属性名[索引].子属性名(比如projectTasks[0].taskName)。你的JQuery代码必须严格按照这个格式生成输入框的name属性,同时维护好索引计数器:
// 初始化索引:从已有的任务输入框数量开始 let taskIndex = $('.task-item').length; // 添加新任务的点击事件 $('#add-task-btn').click(function() { // 生成符合格式的输入框HTML,注意name的写法 let newTaskHtml = ` <div class="task-item"> <input type="text" name="projectTasks[${taskIndex}].taskName" placeholder="任务名称"/> <input type="number" name="projectTasks[${taskIndex}].taskHours" placeholder="耗时"/> <button type="button" class="remove-btn">删除</button> </div> `; // 追加到容器里 $('#task-container').append(newTaskHtml); // 索引自增 taskIndex++; }); // 删除任务的事件(用委托绑定,因为是动态生成的元素) $(document).on('click', '.remove-btn', function() { // 删除当前任务项 $(this).closest('.task-item').remove(); // 可选但推荐:重新更新所有输入框的索引,保证索引连续(避免中间有空缺导致绑定失败) $('.task-item').each(function(index) { // 找到当前项里的所有输入框,替换name里的索引值 $(this).find('input[name^="projectTasks["]').each(function() { let oldName = $(this).attr('name'); // 正则替换掉旧的索引 let newName = oldName.replace(/projectTasks\[\d+\]/, `projectTasks[${index}]`); $(this).attr('name', newName); }); }); // 更新全局索引 taskIndex = $('.task-item').length; });
常见坑点提醒
- 忘记加Getter/Setter:这是最容易忽略的,Spring MVC依赖Getter/Setter来注入值,没写的话肯定拿不到。
- name格式错误:一定要严格遵循
集合属性名[索引].子属性名,少了任何一部分都不行。 - 索引重复或空缺:如果删除后不重新整理索引,出现比如
projectTasks[0]、projectTasks[2]这种空缺,Spring MVC可能只会绑定到projectTasks[0],后面的会被忽略,所以删除后重新更新索引更稳妥。
内容的提问来源于stack exchange,提问作者xoxis
相关产品推荐
相关产品推荐

