在Spring应用程序中自定义FieldMatchValidator的freemarker模板中不显示错误消息

时间:2012-02-10 14:13:49

标签: spring freemarker customvalidator

如标题中所述,我无法在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;
    }
}

1 个答案:

答案 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;
    }
}