【问题标题】:Cross field validation with HibernateValidator displays no error messages使用 HibernateValidator 进行跨字段验证不显示错误消息
【发布时间】:2012-08-07 02:05:11
【问题描述】:

我正在使用HibernateValidator 验证表单上的两个字段“密码”和“确认密码”是否相等,如this answer 中指定的那样。以下是约束描述符(验证器接口)。

package constraintdescriptor;

import constraintvalidator.FieldMatchValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;

@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = FieldMatchValidator.class)
@Documented
public @interface FieldMatch
{
    String message() default "{constraintdescriptor.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
    public @interface List{
        FieldMatch[] value();
    }
}

以下是约束验证器(实现类)。


package constraintvalidator;

import constraintdescriptor.FieldMatch;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.apache.commons.beanutils.BeanUtils;

public final class FieldMatchValidator implements ConstraintValidator<FieldMatch, Object>
{
    private String firstFieldName;
    private String secondFieldName;

    public void initialize(final FieldMatch constraintAnnotation) {
        firstFieldName = constraintAnnotation.first();
        secondFieldName = constraintAnnotation.second();
        //System.out.println("firstFieldName = "+firstFieldName+"   secondFieldName = "+secondFieldName);
    }

    public boolean isValid(final Object value, final ConstraintValidatorContext cvc) {
        try {
            final Object firstObj = BeanUtils.getProperty(value, firstFieldName );
            final Object secondObj = BeanUtils.getProperty(value, secondFieldName );
            //System.out.println("firstObj = "+firstObj+"   secondObj = "+secondObj);
            return firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);
        }
        catch (final Exception e) {
            System.out.println(e.toString());
        }
        return true;
    }
}

以下是与 JSP 页面映射的验证器 bean(指定为 commandName="tempBean"&lt;form:form&gt;&lt;/form:form&gt; 标记)。

package validatorbeans;

import constraintdescriptor.FieldMatch;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotEmpty;

@FieldMatch.List({
    @FieldMatch(first = "password", second = "confirmPassword", message = "The password fields must match", groups={TempBean.ValidationGroup.class})
})

public final class TempBean
{        
    @NotEmpty(groups={ValidationGroup.class}, message="Might not be left blank.")
    private String password;
    @NotEmpty(groups={ValidationGroup.class}, message="Might not be left blank.")
    private String confirmPassword;

    public interface ValidationGroup {};

    //Getters and setters                
}

更新

一切正常,并进行了预期的验证。剩下的一件事是在@FieldMatch 内的TempBean 类上方显示指定的错误消息,即只有一个问题: 如何在JSP 页面上显示错误消息时发生验证违规?

TempBean 类中 passwordconfirmPassword 两个字段上的注释 @NotEmpty 有效并在违规时显示指定消息,@FieldMatch 不会发生这种情况。

我正在使用基于this blog 中指定的this question验证组,它运行良好,不会中断显示错误消息(看起来可能如此)。


在JSP页面上这两个字段的指定如下。

<form:form id="mainForm" name="mainForm" method="post" action="Temp.htm" commandName="tempBean">

    <form:password path="password"/>
    <font style="color: red"><form:errors path="password"/></font><br/>

    <form:password path="confirmPassword"/>
    <font style="color: red"><form:errors path="confirmPassword"/></font><br/>

</form:form>

【问题讨论】:

  • 之所以没有执行验证,是因为问题“Everything is in the same package package validatorbeans;”中的这句话。 HibernateValidator 需要 约束描述符(注释)约束验证器(实现类)public 定义,并且我声明了它们在同一个包中,因此,默认修饰符 no modifier 应用于它们两者(因为在同一个包中不可能将多个类或接口声明为 public )。
  • 一个问题仍然存在。它仍然不显示this 注释指定的错误消息。有人知道即使正确执行验证它也不显示错误消息的原因吗?
  • 好的,我认为您应该发布有关包私有验证器的解决方案作为答案。至于错误消息,可能是问题中未指定的 form:errors 声明存在问题。
  • 在我的第一条评论中这是一个错误(在最后一行)“因为在同一个包中不可能将多个类或接口声明为公共”。它应该在同一个 file 中,而不是在同一个包中。我真的为这个错误道歉。
  • 您是否能够显示错误消息以进行简单验证?更重要的是,您使用的是什么 servlet 和 JSP 库?根据您的 JSP sn-p & 标签,我猜是 Spring MVC。

标签: spring jsp spring-mvc bean-validation hibernate-validator


【解决方案1】:

你可以试试你的 isValid 方法是这样的吗? (这在现场项目中肯定对我有用):

 public boolean isValid(final Object value, final ConstraintValidatorContext cvc){
    boolean toReturn = false;

    try{
        final Object firstObj = BeanUtils.getProperty(value, firstFieldName );
        final Object secondObj = BeanUtils.getProperty(value, secondFieldName );

        //System.out.println("firstObj = "+firstObj+"   secondObj = "+secondObj);

        toReturn = firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);
    }
    catch (final Exception e){
        System.out.println(e.toString());
    }
    //If the validation failed
    if(!toReturn) {
        cvc.disableDefaultConstraintViolation();
        //In the initialiaze method you get the errorMessage: constraintAnnotation.message();
        cvc.buildConstraintViolationWithTemplate(errorMessage).addNode(firstFieldName).addConstraintViolation();
    }
    return toReturn;
}

我还看到您正在使用 Object 实现 ConstraintValidator 接口,从字面上看。它应该是您表单中的支持对象:

tempBean // 你在 commandName 中实际指定的那个。

所以你的实现应该是这样的:

 implements ConstraintValidator<FieldMatch, TempBean>

这可能不是这里的问题,但作为将来的参考,应该是这样的。

更新

在您的 FieldMatch 接口/注释中,您有两个方法:第一个和第二个,添加一个称为 errorMessage 例如:

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

/**
 * @return The first field
 */
String first();

/**
 * @return The second field
 */
String second();

/**
  @return the Error Message
 */
String errorMessage

从 Validation 类查看你的方法 - 你在那里得到第一个和第二个字段名称。所以只需添加 errorMessage,例如:

  private String firstFieldName;
  private String secondFieldName;
  //get the error message name
  private String errorMessagename; 
public void initialize(final FieldMatch constraintAnnotation)
{
    firstFieldName = constraintAnnotation.first();
    secondFieldName = constraintAnnotation.second();
    errorMessageNAme = constraintAnnotation.errorMessage(); 

    //System.out.println("firstFieldName = "+firstFieldName+"   secondFieldName = "+secondFieldName);
}

在 isValida 里面得到它,就像你对第一个和第二个字段名做的一样,并使用它。

【讨论】:

  • 试过了,先生!从现在开始提供赏金需要几个小时,我会在系统允许时将其奖励给您的答案。请再说一件事,在这个方法本身 cvc.buildConstraintViolationWithTemplate("Passwords in both of the fields must match.").addNode(password).addConstraintViolation();,我已经指定了错误消息。有没有办法获取@FieldMatch.List({}) 中指定的消息?不管有没有办法这样做。这是小事。对我来说,知道它根据您的回答起作用是一件很棒的事情。非常感谢
  • 现在我的整个应用程序都运行良好。非常感谢,先生!
  • @Tiny 很高兴我能帮上忙!
  • @Eugene 这有可能实现国际化吗? \
  • @HarmeetSinghTaara :这只需要从本地化/国际化属性文件中指定一个消息密钥,替换问题中的@FieldMatch.List({@FieldMatch(first = "password", second = "confirmPassword", message = "{message.key}", groups {TempBean.ValidationGroup.class})}) 等实际消息(message = "{message.key}")。
猜你喜欢
  • 1970-01-01
  • 2021-10-13
  • 1970-01-01
  • 2023-03-23
  • 2019-02-19
  • 2011-02-03
  • 1970-01-01
  • 2022-07-07
  • 1970-01-01
相关资源
最近更新 更多