使用Spring Data JPA时JSP校验错误信息无法正常显示问题
嘿,这个问题我之前也碰到过!核心原因其实是你控制器里的逻辑漏洞——当表单校验失败时,你没有终止流程返回表单页面,反而继续执行了保存操作,导致Spring Data JPA在持久化实体时触发了Bean Validation校验,直接抛出异常返回500错误,根本没机会让<form:errors>标签渲染错误。
为什么原来用Hibernate SessionFactory没问题?
之前用SessionFactory的时候,要么你没开启实体级的自动校验,要么控制器层的校验已经把错误拦下来了,根本没走到持久化那一步,所以能正常显示表单错误。但Spring Data JPA默认会在持久化时触发实体上的校验注解(比如你加的@NotEmpty),这时候如果实体不符合规则,就会直接抛出异常。
具体修复步骤
1. 修正控制器的校验失败分支逻辑
你现在的代码里,就算bindingResult.hasErrors()为true,还是会执行productService.save(product),这才是问题根源!修改成下面这样,校验失败时直接返回表单视图:
@PostMapping("/add-product") String addProduct(@Validated @ModelAttribute("product") Product product, BindingResult bindingResult) { if (bindingResult.hasErrors()) { System.out.println("has errors: " + bindingResult.toString()); // 关键:校验失败就返回表单页面,让<form:errors>显示错误 return "add-product-form"; // 这里替换成你实际的表单视图名称 } System.out.println("adding Product ..."); productService.save(product); return "redirect:/products/success"; }
2. 确认Bean Validation依赖和配置(可选)
如果是Spring Boot项目,只要引入了spring-boot-starter-web,默认已经包含了hibernate-validator,不需要额外配置。如果是传统Spring项目,要确保配置了校验器:
<mvc:annotation-driven validator="validator"/> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
3. 搞懂两层校验的区别(重要)
- Spring MVC控制器层校验:用
@Validated+BindingResult,在用户提交后第一时间拦截错误,这时候还没到数据库操作,能直接返回表单显示错误。 - JPA持久化层校验:是数据入库前的最后一道防线,当你调用
save时会触发实体上的校验注解,这时候如果有错误就会抛出异常。
你的问题就是跳过了第一层拦截,直接触发了第二层校验的异常。
额外小提示
如果实在想禁用JPA的实体校验(不推荐,因为会失去数据合法性保障),可以在Spring Boot的application.properties里加一行:
spring.jpa.properties.javax.persistence.validation.mode=none
但还是建议保持两层校验,同时在控制器层正确处理校验结果,这样既友好又安全。
内容的提问来源于stack exchange,提问作者securecurve

