如标题中所述,我无法在Fieldmarker模板中显示FieldMatchValidator的错误消息。所有其他“常规”错误消息(例如 @NotNull )都会显示来自message.properties的准确消息。使用FieldMatchValidator进行验证,因为result.hasErrors()返回true,结果对象保存FieldMatch错误。我错过了什么?
的applicationContext.xml:
<!-- Invokes Spring MVC @Controller methods -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<!-- Configures Spring MVC DataBinder instances -->
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="validator" ref="validator"/>
</bean>
</property>
</bean>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="messageInterpolator">
<bean class="com.reco.web.mvc.validator.CustomMessageInterpolator">
<property name="messageSource" ref="messageSource"/>
</bean>
</property>
</bean>
控制器:
@Controller
public class RegisterController extends MyWebController{
private static final String REGISTER_FORM_VIEW = "/action/register/register";
private static final String REGISTER_SUCCESS_VIEW = "/action/register/success";
private org.springframework.validation.Validator validator;
@Autowired
public RegisterController(MessageSource messageSource, Validator validator) {
super(messageSource);
this.validator = validator;
}
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator((org.springframework.validation.Validator)validator);
}
@RequestMapping(value = "/action/register", method = RequestMethod.GET)
public ModelAndView getRegisterForm() {
ModelAndView mav = new ModelAndView(REGISTER_FORM_VIEW);
mav.addObject("registerForm", new RegisterForm());
return mav;
}
@RequestMapping(value = "/action/register", method = RequestMethod.POST)
public final String register(@Valid RegisterForm registerForm, BindingResult result, ModelMap model, HttpServletRequest request) {
if (result.hasErrors()) {
return REGISTER_FORM_VIEW;
}
return "redirect:" + REGISTER_SUCCESS_VIEW;
}
}
注释:
@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = FieldMatchValidator.class)
@Documented
public @interface FieldMatch {
String message() default "{constraints.fieldmatch}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
/**
* @return The first field
*/
String first();
/**
* @return The second field
*/
String second();
/**
* Defines several <code>@FieldMatch</code> annotations on the same element
*
* @see FieldMatch
*/
@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Documented
@interface List {
FieldMatch[] value();
}
}
验证
public class FieldMatchValidator implements ConstraintValidator<FieldMatch, Object>
{
private String firstFieldName;
private String secondFieldName;
@Override
public void initialize(final FieldMatch constraintAnnotation)
{
firstFieldName = constraintAnnotation.first();
secondFieldName = constraintAnnotation.second();
}
@Override
public boolean isValid(final Object value, final ConstraintValidatorContext context)
{
try
{
final Object firstObj = BeanUtils.getProperty(value, firstFieldName);
final Object secondObj = BeanUtils.getProperty(value, secondFieldName);
return firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);
}
catch (final Exception ignore)
{
// ignore
}
return true;
}
}
freemarker模板:
<!doctype html>
<html lang="sv">
<head>
<meta charset="utf-8"/>
<title></title>
</head>
<body id="register">
<div id="content">
<form id="registerForm" action="${rc.contextPath}/action/register" method="POST">
<p>
<label for="firstname">firstname</label>
<@spring.formInput "registerForm.firstName" />
<@spring.showErrors "", "error"/>
</p>
<p>
<label for="lastname">lastname</label>
<@spring.formInput "registerForm.lastName" />
<@spring.showErrors "", "error"/>
</p>
<p>
<label for="email">email</label>
<@spring.formInput "registerForm.email" />
<@spring.showErrors "", "error"/>
</p>
<p>
<label for="email_again">email_again</label>
<@spring.formInput "registerForm.confirmEmail" />
<@spring.showErrors "", "error"/>
</p>
<p>
<label for="password">password</label>
<@spring.formPasswordInput "registerForm.password" />
<@spring.showErrors "", "error"/>
</p>
<p>
<label for="password_again">password_again</label>
<@spring.formPasswordInput "registerForm.confirmPassword" />
<@spring.showErrors "", "error"/>
<@spring.showErrors "", "confirmPassword"/>
</p>
<input type="submit"/>
</form>
</div>
</body>
</html>
FormObject:
@FieldMatch.List({
@FieldMatch(first = "password", second = "confirmPassword", message = "validation.message.confirm.password"),
@FieldMatch(first = "email", second = "confirmEmail", message = "validation.message.confirm.email")
})
public class RegisterForm implements Serializable {
private static final int MAX_TEXT_FIELD_SIZE = 32;
/**
* Password min size.
*/
private static final int PASSWORD_MIN_SIZE = 8;
/**
* Password max size.
*/
private static final int PASSWORD_MAX_SIZE = 36;
@NotNull(message = "validation.message.firstname.empty")
@Size(min = 1, max = MAX_TEXT_FIELD_SIZE, message = "validation.message.firstname.length")
@Pattern(regexp = "^[^<>]*$", message = "validation.message.invalid.characters")
private String firstName;
@NotNull(message = "validation.message.lastname.empty")
@Size(min = 1, max = MAX_TEXT_FIELD_SIZE, message = "validation.message.lastname.length")
@Pattern(regexp = "^[^<>]*$", message = "validation.message.invalid.characters")
private String lastName;
@NotNull(message = "validation.message.email.empty")
@Pattern(regexp = ".+@.+\\.[a-z]+", message = "validation.message.email", flags = { Pattern.Flag.CASE_INSENSITIVE })
private String email;
@NotNull(message = "validation.message.email.empty")
@Pattern(regexp = ".+@.+\\.[a-z]+", message = "validation.message.email", flags = { Pattern.Flag.CASE_INSENSITIVE })
private String confirmEmail;
@NotNull
@Size(min = PASSWORD_MIN_SIZE, max = PASSWORD_MAX_SIZE)
private String password;
@NotNull
@Size(min = PASSWORD_MIN_SIZE, max = PASSWORD_MAX_SIZE)
private String confirmPassword;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getConfirmEmail() {
return confirmEmail;
}
public void setConfirmEmail(String confirmEmail) {
this.confirmEmail = confirmEmail;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getConfirmPassword() {
return confirmPassword;
}
public void setConfirmPassword(String confirmPassword) {
this.confirmPassword = confirmPassword;
}
}
答案 0 :(得分:1)
我通过添加适当的约束验证消息来解决问题:
errorMessage = constraintAnnotation.message();
到自定义FieldMatchValidator中的正确字段。在我的情况下,我将错误添加到第二个字段:
context.buildConstraintViolationWithTemplate(errorMessage).addNode(secondFieldName).addConstraintViolation();
<强> FieldMatchValidator 强>
public class FieldMatchValidator implements ConstraintValidator<FieldMatch, Object>
{
private String firstFieldName;
private String secondFieldName;
private String errorMessage;
@Override
public void initialize(final FieldMatch constraintAnnotation)
{
firstFieldName = constraintAnnotation.first();
secondFieldName = constraintAnnotation.second();
errorMessage = constraintAnnotation.message();
}
@Override
public boolean isValid(final Object value, final ConstraintValidatorContext context)
{
try
{
final Object firstObj = BeanUtils.getProperty(value, firstFieldName);
final Object secondObj = BeanUtils.getProperty(value, secondFieldName);
boolean valid = firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);
if(!valid){
context.buildConstraintViolationWithTemplate(errorMessage).addNode(secondFieldName).addConstraintViolation();
}
return valid;
}
catch (final Exception ignore)
{
// ignore
}
return true;
}
}