【问题标题】:Validate only one spring annotation on form field and independently from others field仅验证表单字段上的一个弹簧注释,并且独立于其他字段
【发布时间】:2013-05-24 08:22:23
【问题描述】:

我有一个特定的要求,即使它看起来很简单。

我有一个用户表单(给你一个简化版)。

public class Form{
  @NotEmpty(message = "{empty}")
  @Size(min = 3, max = 32, message = "{size}")
  private String firstName;
  @NotEmpty(message = "{empty}")
  @Size(min = 3, max = 32, message = "{size}")
  private String lastName;
}

我希望两个字段都独立验证,第一次出错时失败(然后只显示一条错误消息)。

例如,如果我发送 firstName="" 和 lastName="aa",我希望得到 firstName 的空消息和 lastName 的 size 消息。

但通过这样做,我会收到 2 条关于 firstName 的错误消息(大小和空)。

我发现的第一个替代方法是使用@groupsequences,但仍然无法独立验证字段。

所以我创建了一个新注释:

@Documented
@Constraint(validatedBy = {})
@Retention(RetentionPolicy.RUNTIME)
@NotEmpty(message = "{empty}", groups = Check.firstTry.class)
@Size(min = 5, max = 32, message = "{size}", groups = Check.secondTry.class)
@GroupSequence({ Check.firstTry.class, Check.secondTry.class, Name.class })
public @interface Name {
    public abstract String message() default "{empty}";

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

    public abstract Class<?>[] payload() default {};
}

但它仍然会验证每条消息。

如果我使用@ReportAsSingleViolation,它将始终返回默认消息。

我是不是遗漏了什么,对于这种情况,表单验证应该很容易,这不是一个奇怪的情况,是吗?

谢谢

【问题讨论】:

    标签: java forms spring annotations validation


    【解决方案1】:

    编写一个自定义的 ConstraintValidator 来逐一检查约束并报告它找到的第一个约束。这样做的(相当大的)缺点是您最终会重新实现每个组件注释的检查机制,但您确实可以完全控制错误消息。

    public class MyConstraintValidator implements ConstraintValidator<Name, String> {
    
        private Name annotation;
    
        @Override
        public void initialize(MyConstraintAnnotation annotation) {
            this.annotation = annotation;
        }
    
        @Override
        public boolean isValid(String name, ConstraintValidatorContext context) {
            if (name == null) {
                context.buildConstraintViolationWithTemplate(emptyMessage).addConstraintViolation();
                return false;
            } else if (name.length() < getMinSize(annotation)) {
                context.buildConstraintViolationWithTemplate(tooShortMessage).addConstraintViolation();    
                return false;
            } else if (name.length > getMaxSize(annotation)) {
                context.buildConstraintViolationWithTemplate(tooLongMessage).addConstraintViolation();
                return false;
            } else {
                return true;
            }
        }
    }
    

    也许您可以获取 ConstraintValidatorFactory 的句柄并获得每个组成注释所需的 ConstraintValidators?尽管这会让您了解实现的内部结构。这根本不是一个完美的答案,但它会得到你所需要的。

    【讨论】:

    • 但它总是会返回相同的错误消息。我希望每个约束都有不同的消息。
    • 这是你正确的方式,谢谢。但这意味着我没有错,他们没有标准的方式吗?只有我一个人认为它应该是基本配置吗?
    • 一方面,我不知道 java 是否保证注释以任何“顺序”存在,它们要么存在,要么不存在。如果是这样,那么“第一个”约束的概念就没有多大意义了。
    • 其实看Class.java的源码,注解是保存在一个HashMap中的,所以没有顺序。当然,这完全取决于实现。
    • 我仍然需要在我的注释声明中添加一条消息,它总是出现。可以将它设置为一个空字符串,但这意味着我总是有两个错误条目,一个是真实的另一个是一个空字符串...有什么解决方案吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-30
    • 2022-12-14
    • 2021-10-09
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    相关资源
    最近更新 更多