我有这个Web应用程序,我已经设置了bean验证,它的工作非常好。但对于一个字段,它不会读取我在validation.properties文件中设置的消息。对于其他领域,它的工作原理。我很困惑为什么会这样?让我告诉你我的设置:
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setCacheSeconds(0);
messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name());
messageSource.setBasenames("/WEB-INF/Validation/validation"); //I have tried setBaseName as well but same difference.
return messageSource;
}
@Bean
public LocalValidatorFactoryBean localValidatorFactoryBean() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(this.messageSource());
return validator;
}
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
processor.setValidator(this.localValidatorFactoryBean());
return processor;
}
@Autowired
SpringValidatorAdapter validator; //global validator
@Override
public Validator getValidator() {
return this.validator;
}
我的属性文件位于正确的位置。我知道,因为有些错误,会从此validation.properties文件中读取消息。位置是:
SRC \主\ web应用\ WEB-INF \验证\ validation.properties
其中的内容是:
validate.user.yearsexperience =这里只能使用数字。
validate.user.phone =电话号码只能是数字,应该是10位数。
validate.user.name.blank =名称不能为空或不能包含超过30个字符。它只接受信件。也不允许使用数字或符号。
然后我设置了以下错误代码,期待bean验证程序捕获其中一条消息(但它没有)。
typeMismatch.user.yearsexperience =这里只能使用数字。
typeMismatch.yearsexperience =这里只能使用数字。
typeMismatch.java.lang.Integer =这里只能使用数字。
typeMismatch =此处只能使用数字。
因此,当我为phone
或name
字段输入错误数据时,JSP会显示我在validation.properties
文件中设置的那些消息,但对于yearsexperience
字段,则显示显示自己的typeMismatch
或cannot convert String to Integer, etc exceptions
。
这里让我向您展示我在模型中使用的注释:
public class User{
@NotBlankNoFancyLettersOrNumbers(message = "{validate.user.name.blank}") //My own custom annotation. Works like a charm and when user enters wrong data, it shows my custom error.
private String name;
@Pattern(regexp="(^$|[0-9]{10})", message = "{validate.user.phone}") //javax's builtin validation constraint
private String phone;
@So many things I have tried. But first I started with @Pattern
private Integer yearsexperience;
对于此Integer
字段,我无法使用@Pattern
,因为它只能放在String
字段上(我在这里是否正确?)。
然后我尝试@Digits
。当用户输入错误的输入时,它确实有效,但没有显示我的错误消息,它向用户显示typeMismatch
例外。然后我制作了自己的自定义注释,并为其命名@DigitsOnly
。同样的问题,它不会显示我的错误信息。它显示了相同的旧typeMismatch
异常。
此时,我认为表单绑定可能存在问题(我应该不认为因为bean验证适用于其他字段)。无论如何,我注册了我自己的自定义编辑器:
@InitBinder("user")
protected void binder(WebDataBinder binder, HttpSession session) throws Exception {
binder.registerCustomEditor(Date.class, new DateConvertor()); //This is unrelated to my question but it works!
binder.registerCustomEditor(Integer.class, "yearsexperience", new IntegerConvertor(session.getAttribute("user"), this.userdao));
}
这是我的课程PropertyEditorSupport
:
public class IntegerConvertor extends PropertyEditorSupport {
private User user;
private UserDAO userdao;
public IntegerConvertor(){}
public IntegerConvertor(Object object, UserDAO userdao) {
if (object instanceof User){
this.user= new User((User) object);
}
this.userdao = userdao;
}
@Override
public void setAsText(String value) {
if (!value.matches("[0-9]+")) { //if incoming value DOES NOT contains numbers only
setValue(this.userdao.getYearsExperienceBeforeChange(this.user.getId()));
} else {
setValue(value);
}
}
现在,我这样做是为了希望typeMismatch
异常将不显示给用户,但它仍会显示异常。 (我从这个PropertyEditorSupport
知道,或者它不会从validation.properties
文件中读取自定义错误消息。
无论如何,我尝试通过这样的WebDataBinder.addValidator(myCustomValidator)
添加自定义验证器:
@InitBinder("user")
protected void binder(WebDataBinder binder, HttpSession session) throws Exception {
binder.registerCustomEditor(Date.class, new DateConvertor());
binder.addValidators(new myCustormValidator());
}
这是我的自定义验证器的外观,
public class MyCustormValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return User.class.equals(clazz); //return User.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
User user = (User) target;
String a = Integer.toString(user.getYearsExperience());
if(!a.matches("[0-9]+")){
errors.rejectValue("yearsexperience","validate.user.yearsexperience");
}
}
}
我将Integer
转换为String
因为我能够检查传入的值是否只包含数字而不是字母。但在这里它会导致另一个问题:它不显示传入值,它显示旧值。而且由于旧的价值已经是正确的,它不会引起任何问题。所以我添加了else语句,只是为了抛出一个错误,希望现在至少它会显示我的自定义错误。但事实并非如此!
因此,我来到这里寻求帮助。非常感谢任何帮助。
TL; DR 为什么自定义错误消息不会显示在一个字段中。但对于其他领域,它的工作非常好。
答案 0 :(得分:1)
为什么自定义错误不会出现在某些字段中,但对于其他字段则可以正常显示
因为涉及两个不同的组件:
您已正确配置了bean验证的消息源,但它确实有效。
但是你要自定义typeMismatch
消息,看起来像Spring MVC看不到这一点。通常,它足以定义名为messageSource
的bean,但出于某种奇怪的原因,您需要其他东西。
我的猜测是你有两个上下文,messageSource
是在Spring MVC不可见的上下文中定义的。
<强>更新强>
我查看了GitHub上的示例项目(http://github.com/farazdurrani/sscce),我发现非工作typeMismatch
消息的问题不是因为配置问题。之所以会发生这种情况,是因为您未使用标准代码并尝试手动显示错误消息(通过对来自getDefaultMessage()
的每个错误调用Errors.getAllErrors()
方法)。如果您尝试使用<form:errors path="*"/>
,则会发现所有错误消息都已正确本地化。