我有一个 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\main\webapp\WEB-INF\Validation\validation.properties
里面的内容是:
validate.user.yearsexperience = Only numbers can be used here.
validate.user.phone = Phone numbers can only be digits and should exactly be 10 digits.
validate.user.name.blank = Name cannot be left empty or Cannot contain more than 30 chars. It will accept letters only. No numbers or symbols are allowed either.
然后我设置了以下错误代码,以预期 Bean validator 捕获这些消息之一(但它没有)。
typeMismatch.user.yearsexperience = Only numbers can be used here.
typeMismatch.yearsexperience = Only numbers can be used here.
typeMismatch.java.lang.Integer = Only numbers can be used here.
typeMismatch = Only numbers can be used here.
因此,当我在 phone
或 name
字段中输入错误的数据时,JSP 会显示我在 validation.properties
文件中设置的那些消息,但是对于yearsexperience
字段,它显示自己的typeMismatch
或无法将String转换为Integer等异常
。
这里让我向您展示我在模型上使用的注释:
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
异常。
此时,我认为表单绑定(bind)可能存在问题(我不应该这样认为,因为 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)
添加自定义 validator ,如下所示:
@InitBinder("user")
protected void binder(WebDataBinder binder, HttpSession session) throws Exception {
binder.registerCustomEditor(Date.class, new DateConvertor());
binder.addValidators(new myCustormValidator());
}
这就是我的自定义 validator 的外观,
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 为什么某个字段不显示自定义错误消息。但对于其他领域来说,它工作得很好。
最佳答案
Why the custom error doesn't show up for some fields but for others it works perfectly fine
因为涉及两个不同的组件:
- 用于 bean 验证的 hibernate-validator
- 将用户值从 a 绑定(bind)到 POJO 类的 spring-mvc
您已经正确配置了 Bean 验证的消息源并且它可以工作。
但是你正在自定义 typeMismatch
消息,看起来 Spring MVC 没有看到这个。通常,定义名称为 messageSource
的 bean 就足够了。但由于某些奇怪的原因,在你的情况下你需要其他东西。
我的猜测是你有 2 个上下文和 messageSource
是在 Spring MVC 不可见的上下文中定义的。
更新:
我查看了 GitHub 上的示例项目 ( http://github.com/farazdurrani/sscce ),发现问题是无法工作 typeMismatch
消息不是因为配置。发生这种情况是因为您没有使用标准标签并尝试手动显示错误消息(通过对 getDefaultMessage()
中的每个错误调用 Errors.getAllErrors()
方法)。如果您尝试使用<form:errors path="*"/>
,您会看到所有错误消息都已正确本地化。
关于java - 自定义验证消息适用于某些错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43479640/