Thymeleaf单选按钮分组及DtoWrapper数据提交到Controller相关问题
问题1:单选按钮按人员独立分组
你当前所有单选按钮同组是两个原因导致:
name属性没有加th:前缀,Thymeleaf不会解析${}表达式,所有按钮的name都是固定字面量${shiftDto.getFullName()},所以全部属于同一分组- 单选按钮的id全局重复,label的for属性无法对应到正确的输入项
修改方案:循环时引入迭代状态变量,用th:field自动生成分组用的name属性,每个人员的单选按钮name会自动生成为shifts[0].shiftCode、shifts[1].shiftCode格式,天然按人员独立分组。
问题2:选中值写入dtoWrapper对象
- 首先给
ShiftDto、DtoWrapper补全无参构造、所有属性的getter和setter,Spring MVC需要反射调用这些方法完成对象赋值 - 表单提交方式改为
post,避免get请求参数长度限制 - 用
th:field="*{shifts[__${iterStat.index}__].shiftCode}"绑定对应列表元素的shiftCode属性,Thymeleaf会自动处理选中值和对象属性的双向映射 - 增加隐藏域绑定fullName,避免提交后Dto的fullName字段为空
问题3:download接口获取包装对象
Model是单次请求范围内有效的,你在upload接口存到Model的dtoWrapper在返回页面后就已经失效,download接口的Model是新请求的空对象,不能从里面取数据。
直接在download方法上加@ModelAttribute("dtoWrapper") DtoWrapper dtoWrapper入参,Spring MVC会自动把表单提交的参数绑定到这个对象里,直接用入参的dtoWrapper即可。
完整修改代码
1、Java类补全
public class ShiftDto { private String fullName; private int shiftCode; // 补无参构造 public ShiftDto() {} public ShiftDto(String fullName, int shiftCode) { this.fullName = fullName; this.shiftCode = shiftCode; } // 补所有getter setter public String getFullName() {return fullName;} public void setFullName(String fullName) {this.fullName = fullName;} public int getShiftCode() {return shiftCode;} public void setShiftCode(int shiftCode) {this.shiftCode = shiftCode;} } public class DtoWrapper { private List<ShiftDto> shifts; // 补无参构造、getter setter public DtoWrapper() {} public List<ShiftDto> getShifts() {return shifts;} public void setShifts(List<ShiftDto> shifts) {this.shifts = shifts;} }
2、前端模板修改
<form action="#" th:action="@{/download}" th:object="${dtoWrapper}" method="post"> <fieldset> <legend>Select Shift information for each officer</legend> <ul> <li th:each="shiftDto, iterStat : ${dtoWrapper.getShifts()}"> <span th:text="${shiftDto.getFullName()}"></span> <!-- 隐藏域保存fullName,避免提交后丢失 --> <input type="hidden" th:field="*{shifts[__${iterStat.index}__].fullName}" /> <input type="radio" th:id="|ignore-${iterStat.index}|" th:field="*{shifts[__${iterStat.index}__].shiftCode}" value="0" checked> <label th:for="|ignore-${iterStat.index}|">Ignore</label> <input type="radio" th:id="|mgDay-${iterStat.index}|" th:field="*{shifts[__${iterStat.index}__].shiftCode}" value="1"> <label th:for="|mgDay-${iterStat.index}|">MG Day</label> <input type="radio" th:id="|mgNight-${iterStat.index}|" th:field="*{shifts[__${iterStat.index}__].shiftCode}" value="2"> <label th:for="|mgNight-${iterStat.index}|">MG Night</label> <input type="radio" th:id="|epWbDay-${iterStat.index}|" th:field="*{shifts[__${iterStat.index}__].shiftCode}" value="3"> <label th:for="|epWbDay-${iterStat.index}|">EP WB Day</label> <input type="radio" th:id="|epWbNight-${iterStat.index}|" th:field="*{shifts[__${iterStat.index}__].shiftCode}" value="4"> <label th:for="|epWbNight-${iterStat.index}|">EP WB Night</label><br> <input type="radio" th:id="|visRecep-${iterStat.index}|" th:field="*{shifts[__${iterStat.index}__].shiftCode}" value="5"> <label th:for="|visRecep-${iterStat.index}|">Visitors Recep</label> <input type="radio" th:id="|plDay-${iterStat.index}|" th:field="*{shifts[__${iterStat.index}__].shiftCode}" value="6"> <label th:for="|plDay-${iterStat.index}|">Plaistow Day</label> <input type="radio" th:id="|plNight-${iterStat.index}|" th:field="*{shifts[__${iterStat.index}__].shiftCode}" value="7"> <label th:for="|plNight-${iterStat.index}|">Plaistow Night</label> <br><br> </li> <input type="submit" value="Submit" /> <input type="reset" value="Reset" /> </ul> </fieldset> </form>
3、download接口修改
@PostMapping("/download") public ResponseEntity<ByteArrayResource> download(@ModelAttribute("dtoWrapper") DtoWrapper dtoWrapper) { System.out.println("Controller.download"); try { String filename = createFileName(); HttpHeaders header = new HttpHeaders(); header.setContentType(new MediaType("application", "force-download")); header.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename); // 直接使用入参的dtoWrapper即可 List<Shift> shifts = getShifts(dtoWrapper.getShifts()); List<OutputRow> outputData = SwipeProcessor.getOutputDataFrom(allSwipes, shifts); ByteArrayResource resource = new ByteArrayResource(WriteOutputToXlsx.write(outputData)); return new ResponseEntity<>(resource, header, HttpStatus.CREATED); } catch (Exception e) { return new ResponseEntity<>(HttpStatus.EXPECTATION_FAILED); } }
内容的提问来源于stack exchange,提问作者gdogra
相关产品推荐
相关产品推荐

