如何处理视图绑定参数化URL场景下的Thymeleaf验证错误
解决方案
方案1:直接返回视图(推荐)
你原来直接返回视图名不生效的核心原因是表单没有传递customerId字段,导致POST提交后AppointmentViewModel的customerId为空,渲染表单action路径时拿不到id报错。只需两步修复:
- 给表单添加customerId隐藏字段,确保POST提交时该字段被携带:
<form th:object="${appointment}" method="post" th:action="@{/appointments/{id}/book (id=*{customerId})}"> <!-- 新增隐藏字段 --> <input type="hidden" th:field="*{customerId}"> <input type="datetime-local" th:field="*{dateTime}"> <span th:if="${#fields.hasErrors('dateTime')}" th:errors="*{dateTime}"></span> <button type="submit">Book appointment</button> </form>
- 保持POST接口校验失败直接返回视图名的逻辑即可,Spring MVC会自动将校验后的
AppointmentViewModel和Errors对象放入模型,Thymeleaf可以直接读取错误信息和customerId渲染页面:
@PostMapping("/{customerId}/book") String bookAppointment(@PathVariable("customerId") UUID customerId, @Valid AppointmentViewModel appointmentViewModel, Errors errors) { if (errors.hasErrors()) // 直接返回视图即可,无需重定向 return "appointments/creation"; // 后续业务逻辑 }
方案2:重定向传递错误(适用于必须重定向的场景)
如果业务要求校验失败必须重定向到GET请求地址,可以用Spring提供的RedirectAttributes的Flash属性存储临时数据,Flash属性会存到Session中,重定向完成后自动清除:
- 修改POST接口,校验失败时将表单数据和错误信息存入Flash属性:
@PostMapping("/{customerId}/book") String bookAppointment(@PathVariable("customerId") UUID customerId, @Valid AppointmentViewModel appointmentViewModel, Errors errors, RedirectAttributes redirectAttributes) { if (errors.hasErrors()) { // 存入表单对象 redirectAttributes.addFlashAttribute("appointment", appointmentViewModel); // 存入校验错误,键的格式必须为 org.springframework.validation.BindingResult.模型名 redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.appointment", errors); // 重定向到GET地址 return "redirect:/appointments/" + customerId + "/book"; } // 后续业务逻辑 }
- 修改GET接口,优先读取Flash属性中的表单和错误信息,没有的话再新建:
@GetMapping("/{customerId}/book") String viewBookAppointment(@PathVariable("customerId") UUID customerId, Model model, // 读取Flash属性中的表单对象,不存在则为null @ModelAttribute("appointment") AppointmentViewModel appointment) { if (appointment == null) { appointment = new AppointmentViewModel(); appointment.setCustomerId(customerId); model.addAttribute("appointment", appointment); } return "appointments/creation"; }
内容的提问来源于stack exchange,提问作者acejazz
相关产品推荐
相关产品推荐

