【问题标题】:How insert field name when using internationalization with javax validations?使用带有 javax 验证的国际化时如何插入字段名称?
【发布时间】:2017-11-03 14:41:15
【问题描述】:

我在 Spring Boot 和国际化中使用 javax 验证注释。所以我有以下字段:

@Size(min = 3, max = 3, message = "{javax.validation.constraints.Size.message}")
private String currencyCode;

美国资源包有:

javax.validation.constraints.Size.message = size must be between {min} and {max}

因此,当此字段验证失败时,我会看到消息 "size must be between 3 and 3"

但我想要的是这样的消息:

javax.validation.constraints.Size.message = {fieldName}'s size must be between {min} and {max}

这将导致消息"currencyCode's size must be between 3 and 3"

这可能吗?我是否需要覆盖 bean 才能使其工作?字段名称是否有预定义的属性?

【问题讨论】:

    标签: java spring spring-boot internationalization bean-validation


    【解决方案1】:

    您可以为 MethodArgumentNotValidException 创建处理程序

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Object handleMethodArgumentNotValidException(final MethodArgumentNotValidException e) { ...
    

    您可以在其中调用

     e.getBindingResult().getFieldErrors();
    

    这是包含有关无效字段错误的所有信息的集合,例如。字段名称,拒绝值。

    接下来,使用您的示例中的消息,并使用 org.apache.commons.lang3 中的 StrSubstitutor。只需创建参数映射

    key --> fieldName , value --> currencyCode

    当然你必须写一些代码,但这里是解决方案:)

    【讨论】:

    • 使用 StrSubstitutor 是什么意思?
    • 谢谢,这基本上就是答案。我就用fieldError.getDefaultMessage().replace( "{fieldName}", fieldError.getField() );
    • 我的意思是Map valuesMap = HashMap(); valuesMap.put("animal", "quick brown fox"); valuesMap.put("target", "lazy dog"); String templateString = "The ${animal} jumps over the ${target}."; StrSubstitutor sub = new StrSubstitutor(valuesMap); String resolvedString = sub.replace(templateString); 和结果The quick brown fox jumps over the lazy dog. 但你的解决方案也不错
    【解决方案2】:

    默认情况下,@Size 注解不提供在消息中放置标签的选项,相反,您可以创建自己的实现,如下所示,以便在您的应用程序中使用它:

    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
    @Retention(RUNTIME)
    @Documented
    @Constraint(validatedBy = MySizeValidator.class)
    public @interface MySize {
    
        String message() default "{javax.validation.constraints.Size.message}";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    
        int min() default 0;
    
        int max() default Integer.MAX_VALUE;
    
        @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
        @Retention(RUNTIME)
        @Documented
        @interface List {
    
            Size[] value();
        }
    
        public abstract String label();
    }
    

    然后创建您自己的验证器,例如 MySizeValidator 来验证 MySize 注释,如下所示

    public class MySizeValidator implements ConstraintValidator<MySize, String> {
    
        private static final Log log = LoggerFactory.make();
    
        private int min;
        private int max;
    
        @Override
        public void initialize(MySize parameters) {
            min = parameters.min();
            max = parameters.max();
            validateParameters();
        }
    
        @Override
        public boolean isValid(String field, ConstraintValidatorContext constraintValidatorContext) {
            if (field == null) {
                return true;
            }
            int length = field.length();
            return length >= min && length <= max;
        }
    
        private void validateParameters() {
            if (min < 0) {
                throw log.getMinCannotBeNegativeException();
            }
            if (max < 0) {
                throw log.getMaxCannotBeNegativeException();
            }
            if (max < min) {
                throw log.getLengthCannotBeNegativeException();
            }
        }
    }
    

    使用以下键值创建ValidationMessages.properties

    javax.validation.constraints.mySize.message={label} 的大小必须在 {min} 和 {max} 之间

    然后在你的 POJO 中,你可以放这个新的注解,

    @MySize(min = 3, max = 3, message = "{javax.validation.constraints.mySize.message}", label = "Currency Code")
        private String currencyCode;
    

    【讨论】:

    • 在该解决方案中,您还需要正确格式化标签,例如; fieldName 是 POJO 中的 currencyCode,但是您必须在屏幕上显示“货币代码”,然后如果字段 currencyCode 即将到来,则需要在某处放置地图,然后将其替换为货币代码。另一个问题是,如果您有两个具有相同字段名称但描述不同的 POJO,例如一次您想将标签返回为“当前代码”,而另一次您想将标签返回为“货币”,那么黑客解决方案将很混乱,而创建自己的验证器/注释是 spring 也使用的干净解决方案
    • 但这是你的电话,我想提供一个干净的解决方案
    • 标签无论如何都应该是客户端的东西,而不是由服务器驱动。但你的观点是正确的。
    • @AmitKBist 您的解决方案要好得多,但常见的@Size 注释已经过测试等。一般来说,我认为为模型创建自己的验证器比为该模型中的字段添加注释/属性要好得多。注释会破坏 OOP,但需要的时间更少。悲伤但真实。
    猜你喜欢
    • 1970-01-01
    • 2019-12-07
    • 1970-01-01
    • 2012-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-23
    • 1970-01-01
    相关资源
    最近更新 更多