【问题标题】:Interpolate validation-specific parameters in bean validation message在 bean 验证消息中插入特定于验证的参数
【发布时间】:2011-01-04 17:22:00
【问题描述】:

我有一个自定义 bean 验证器,它检查实体上的给定字段在某些条件下是否是唯一的。如果验证失败,则消息应包含已存在实体的字段(例如 ID)。因此,例如消息应该是:

"Product 42 already has such a value defined, choose a unique value."

这可能使用 bean 验证吗?

AFAICS,消息格式可能包含参数,如:

"Length must be between {min} and {max}."

但这只能引用验证注解的“静态”属性,在这种情况下:

@Size(min=1, max=16)
private String name;

在我的情况下,该值仅在我的自定义验证器的 isValid 内已知。

【问题讨论】:

    标签: java jakarta-ee bean-validation


    【解决方案1】:

    你是对的!,对于你想要的!,你可以在 isValid() 方法中构建约束冲突消息。为此,约束注释应该特定于已应用它的特定类,并且它应该是类级别的验证约束。在 isValid 内部,在验证失败返回 false 之前,您可以创建包含类实例值的消息。例如:

    @check class Test{ int id; @validations...on fields}.
    
    public boolean isValid(Test value, ConstraintValidatorContext context) 
    {
    // your check logic
    context.disableDefaultConstraintViolation();
    context.buildConstraintViolationWithTemplate("It should be different for(custom message) .."+ value.id).addConstraintViolation();
    return false; // based on constraint filure.
    
    }
    

    但我认为您想使用字段级别的注释来做到这一点!我不知道期待你的结果。

    【讨论】:

    • 问题是我不想在验证器中构造最终消息,只有格式(用于翻译)和参数。但我想我应该在验证器中本地化消息。
    • 我发布了我们最终得到的解决方案作为另一个答案。但我认为您的答案允许更具体的错误消息,即使必须在验证器内部完成本地化,我也接受了。
    【解决方案2】:

    这并不是最好的解决方案,但我们最终做的是在我们的顶级异常处理代码中添加如下内容:

    String getConstraintViolationMessages(ConstraintViolationException e) {
        StringBuilder sb = new StringBuilder();
        for (ConstraintViolation<?> violation : e.getConstraintViolations()) {
            sb.append(getMessage(violation));
            sb.append("\n");
        }
        sb.setLength(sb.length() - 1);
        return sb.toString();
    }
    
    String getMessage(ConstraintViolation<?> violation) {
        String key = violation.getMessageTemplate();
        String messageFormat = localize(key);
    
        Object entity = violation.getRootBean();
        String identifier;
        if (entity instanceof PrimaryKeyed) {
            identifier = String.valueOf(((PrimaryKeyed) entity).getId());
        } else {
            identifier = entity.toString();
        }
    
        return MessageFormat.format(messageFormat, identifier);
    }
    

    请注意,PrimaryKeyed 是用于我们实体的自定义接口。我们还有一些上面没有显示的其他接口和自定义处理。

    【讨论】:

    • 这两种方法分别属于哪个类?我的带有context.buildConstraintViolationWithTemplate("{no.mobitroll.rest.resources.entities.beans.validators.QuizType.enum}").addConstraintViolation(); 的自定义约束尚未插入该值。
    • @Stephane 我们将它们放在顶级异常处理程序类中,无论如何,这可能是一件好事。你在哪里添加这个真的取决于你的架构和你使用什么框架,所以很遗憾我不能给出更具体的答案。
    猜你喜欢
    • 2011-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-08
    • 2014-02-24
    • 1970-01-01
    • 2011-05-11
    • 1970-01-01
    相关资源
    最近更新 更多