Spring MVC:属性文件中的验证错误消息无法显示问题排查
我太懂这种挫败感了——明明照着常规步骤配置,验证错误消息就是死活不出来,简直挠头。结合你给出的代码片段,咱们挨个排查最容易踩的坑:
1. 补全messageSource的关键配置
你的Bean定义只写了一半,这几个配置项绝对不能少:
basename的路径要精准:如果你的error-messages.properties放在src/main/resources根目录,basename应该写classpath:error-messages(不用加.properties后缀);如果在子目录比如resources/i18n下,就写classpath:i18n/error-messages- 强制指定编码:避免中文乱码或者文件加载失败,一定要加:
<property name="defaultEncoding" value="UTF-8"/>
- 开发时加缓存时间:方便修改属性文件后不用重启服务,调试更高效:
<property name="cacheSeconds" value="1"/>
完整的messageSource配置大概是这样:
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="classpath:error-messages"/> <property name="defaultEncoding" value="UTF-8"/> <property name="cacheSeconds" value="1"/> </bean>
2. 验证注解的消息键必须和属性文件完全匹配
比如你在StudentRepository的字段上用了这样的注解:
@NotEmpty(message = "{student.name.required}") private String studentName;
那你的error-messages.properties里必须有完全对应的键值对,大小写、点分隔都不能错:
student.name.required=请填写学生姓名
要是键名写错了,Spring就找不到对应的消息,只会显示{student.name.required}这个占位符,或者默认的系统消息。
3. BindingResult的位置绝对不能错
这个是很多人踩的坑:BindingResult必须紧跟在被@Valid注解的参数后面,中间不能插任何其他参数,否则Spring没法把验证结果绑定到BindingResult里,直接就抛出异常了。正确的控制器方法应该是这样:
@RequestMapping("/submitForm") String submitForm( @Valid @ModelAttribute("student") StudentRepository student, BindingResult bindingResult // 必须紧跟在@Valid参数后面 ) { // 第一步先判断有没有错误! if (bindingResult.hasErrors()) { return "student-form"; // 返回表单页面,让错误消息显示 } // 没有错误再处理业务逻辑 studentService.save(student); return "success-page"; }
4. 页面上的错误消息标签要写对
如果你用JSP+Spring表单标签,一定要用form:errors来绑定错误消息:
<form:form modelAttribute="student" action="/submitForm" method="post"> <div> <label>学生姓名:</label> <form:input path="studentName"/> <!-- 这里的path要和实体类字段名完全一致 --> <form:errors path="studentName" cssClass="error-text"/> </div> <button type="submit">提交</button> </form:form>
如果不用Spring表单标签,用JSTL的话要这样取:
<input type="text" name="studentName" value="${student.studentName}"/> <c:if test="${bindingResult.hasFieldErrors('studentName')}"> <span class="error-text">${bindingResult.getFieldError('studentName').defaultMessage}</span> </c:if>
注意path或者字段名必须和实体类里的字段完全匹配,大小写都不能错。
5. 检查属性文件是否被正确打包
有时候属性文件没被放到classpath里,比如Maven项目里,如果你把error-messages.properties放在src/main/java目录下,默认不会被打包到WEB-INF/classes里,必须放到src/main/resources目录,或者在pom.xml里配置资源过滤:
<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> </includes> </resource> </resources> </build>
可以打开打包后的war/jar文件,看看WEB-INF/classes(传统Spring MVC)或者BOOT-INF/classes(Spring Boot)里有没有你的属性文件。
6. 关联验证器和messageSource
如果上面的都没问题,可能是验证器没关联到你的消息源,需要显式配置LocalValidatorFactoryBean:
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <property name="messageSource" ref="messageSource"/> </bean>
然后在MVC注解驱动里指定这个验证器:
<mvc:annotation-driven validator="validator"/>
这样Spring的验证器就会用你的属性文件来加载错误消息了。
最后,要是还没解决,建议开启Spring的DEBUG日志,看看ReloadableResourceBundleMessageSource有没有成功加载属性文件,或者验证时有没有找到对应的消息键——日志里会告诉你到底是加载失败还是键名不匹配。
内容的提问来源于stack exchange,提问作者securecurve

