使用自定义资源包的Spring MVC和JSR 303自定义验证

时间:2012-03-31 05:07:03

标签: spring-mvc bean-validation

我知道这已被问过几千次,但这确实是一场噩梦。我一直试图弄清楚如何配置Hibernate Validator来使用我的属性资源包,但我仍然无法获得令人满意的结果......

以下是我的网络环境的一部分:

    <!-- i18n handling -->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
            <property name="basename" value="i18n.eSporx" />
    </bean>

以下是我的应用程序上下文的一部分:

    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
            <property name="validationMessageSource" ref="messageSource"/>
    </bean>

最后,我的(类级别跨字段)自定义约束及其验证器:

@Documented
@Target(TYPE)
@Retention(RUNTIME)
@Constraint(validatedBy = CrossDateConstraintsValidator.class)
public @interface CrossDateConstraints {

    String message() default "crossdate.validation.error";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    String startDateFieldName() default "startDate";

    String endDateFieldName() default "endDate";
}


@Component
@Scope(SCOPE_PROTOTYPE)
public class CrossDateConstraintsValidator implements ConstraintValidator<CrossDateConstraints, Object> {

    private String startDateField;
    private String endDateField;
    private String message;

    @Override
    public void initialize(final CrossDateConstraints constraintAnnotation) {
        startDateField = constraintAnnotation.startDateFieldName();
        endDateField = constraintAnnotation.endDateFieldName();
        message = constraintAnnotation.message();
    }

    @Override
    public boolean isValid(final Object annotatedClassInstance, final ConstraintValidatorContext context) {
        boolean isValid = false;
        try {
            Date startDate = getDateFieldValue(annotatedClassInstance, startDateField);
            Date endDate = getDateFieldValue(annotatedClassInstance, endDateField);
            isValid = endDate.after(startDate);

            if (!isValid) {
                forceErrorsOnBothFields(context);
            }

            return isValid;
        }
        catch (Exception e) {
            return isValid;
        }
    }

    private void forceErrorsOnBothFields(final ConstraintValidatorContext context) {
        context.buildConstraintViolationWithTemplate(message).addNode(startDateField).addConstraintViolation();
        context.buildConstraintViolationWithTemplate(message).addNode(endDateField).addConstraintViolation();
    }

    private Date getDateFieldValue(final Object annotatedClassInstance, final String fieldName) throws IntrospectionException, IllegalAccessException, InvocationTargetException {
        Method dateGetter = new PropertyDescriptor(fieldName, annotatedClassInstance.getClass()).getReadMethod();
        Date date = (Date) dateGetter.invoke(annotatedClassInstance);
        return date;
    }
}

资源包位于src/main/resources/i18n/eSporx.properties下(具有其语言环境变体)。我的JSP中<spring:message code="my.key" />之类的东西运行正常。但是,每当引发CrossDateConstraints错误时,即使密钥存储在属性文件中,我只能读取“crossdate.validation.error”!

如果您有任何想法,请告诉我:) 这太令人沮丧了。

罗尔夫

2 个答案:

答案 0 :(得分:1)

hibernate-validator的旧版本不允许覆盖默认资源包。请确保您使用最新版本,例如4.2.0.Final

也就是说,即使您已经使用了最新版本,也可以通过应用程序服务器中嵌入的版本覆盖此版本。例如,Glassfish 3.0嵌入了不支持资源包覆盖的hibernate-validator版本。

答案 1 :(得分:1)

要启用消息的插值,您必须按大括号括起消息,如下所示:

String message() default "{crossdate.validation.error}";

另请参阅Hibernate Validator指南中的2.2.4. Message interpolation章节。