Spring值类型转换问题:自定义错误消息未生效排查
问题场景
我是Spring新手,现在碰到值类型转换的问题。当给需要Integer类型的freePasses字段输入字符串时,想从properties配置文件里获取自定义错误消息“Invalid number”,但实际得到的错误信息是:
Failed to convert property value of type java.lang.String to required type java.lang.Integer for property freePasses; nested exception is java.lang.NumberFormatException: For input string: "sdf"
想问下是不是操作错了,还是缺了什么Java依赖库?
相关代码
Controller代码
import org.springframework.beans.propertyeditors.StringTrimmerEditor; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import javax.validation.Valid; @Controller @RequestMapping("/customer") public class CustomerController { @InitBinder public void initBinder(WebDataBinder dataBinder) { StringTrimmerEditor stringTrimmerEditor = new StringTrimmerEditor(true); dataBinder.registerCustomEditor(String.class, stringTrimmerEditor); } @RequestMapping("/showForm") public String showForm(Model theModel) { theModel.addAttribute("customer", new Customer()); return "customer-form"; } @RequestMapping("/processForm") public String processForm( @Valid @ModelAttribute("customer") Customer theCustomer, BindingResult theBindingResult ) { if (theBindingResult.hasErrors()) { return "customer-form"; } else { return "customer-confirmation"; } } }
实体类代码
import javax.validation.constraints.*; public class Customer { @NotNull(message="is required") @Min(value = 0, message = "cannot be less than 0") @Max(value = 10, message = "cannot be more than 10") private Integer freePasses; public Integer getFreePasses() { return freePasses; } public void setFreePasses(Integer freePasses) { this.freePasses = freePasses; } }
Spring配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!-- 组件扫描支持 --> <context:component-scan base-package="com.autosdet.autosdetmvc" /> <util:properties id="countryOptions" location="classpath:countries.properties" /> <!-- 转换、格式化及验证支持 --> <mvc:annotation-driven/> <!-- Spring MVC视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/view/" /> <property name="suffix" value=".jsp" /> </bean> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames" value="messages" /> </bean> </beans>
JSP表单页面
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Customer Form</title> <style> .error {color: red} </style> </head> <body> Fill out the form. Asterisk (*) required. <form:form action="processForm" modelAttribute="customer"> Free Passes (*): <form:input path="freePasses" /> <form:errors path="freePasses" cssClass="error" /> <br><br> <input type="submit" value="Submit" /> </form:form> <br><br> <a href="/autosdet_mvc_war_exploded">Main Menu</a> </body> </html>
消息配置文件(messages.properties)
type.Mismatch.customer.freePasses=Invalid number
问题原因及解决办法
核心原因
你配置的错误消息键名不符合Spring MVC的规范:类型不匹配的错误消息键应该是驼峰式的typeMismatch(没有中间的点),而非type.Mismatch。Spring MVC会用这个键来匹配类型转换失败的错误场景。
另外,类型转换错误发生在JSR-380(@Valid)验证之前,必须确保Spring能将转换错误捕获并映射到自定义消息。
解决步骤
修正messages.properties中的键名
将原来的配置改为以下任意一种格式:- 针对
customer实体的freePasses字段:typeMismatch.customer.freePasses=Invalid number - 针对所有Integer类型字段:
typeMismatch.java.lang.Integer=Invalid number - 通用类型不匹配消息:
typeMismatch=Invalid number format
- 针对
确认BindingResult参数位置
你的Controller已经正确将BindingResult紧跟在@Valid修饰的参数之后,这是捕获错误的必要条件,无需修改。依赖检查
如果你用的是传统Spring MVC项目,确保已引入spring-webmvc、hibernate-validator(JSR-380实现)和spring-context依赖;如果是Spring Boot项目,确保引入spring-boot-starter-web和spring-boot-starter-validation依赖。从当前代码运行情况看,依赖应该是齐全的。
验证效果
修改配置后,再次向freePasses字段输入字符串提交,页面将显示自定义的“Invalid number”错误消息,而非默认的转换异常信息。
内容的提问来源于stack exchange,提问作者Hasan Humbatov

