Java中能否向验证约束消息传递变量?长度校验需求咨询
嘿,针对你提出的两个Java验证相关问题,我来给你捋捋实用的解决方案:
当然有!Java Bean Validation(也就是JSR-380,常用的实现是Hibernate Validator)本身就支持在约束消息中传递变量,主要有几种常用方式:
利用内置注解的参数占位符
大部分内置验证注解都自带可引用的参数,比如@Size的{min}、{max},@Min的{value}等等。直接在message模板里用这些占位符就行,示例代码:@Size(min = 2, max = 10, message = "用户名长度得在{min}到{max}字符之间哦") private String username;自定义约束注解时添加自定义参数
如果是你自己写的自定义验证注解,可以给注解添加属性,然后在message里用{属性名}引用。比如我要做一个密码强度校验的注解:@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = PasswordStrengthValidator.class) public @interface PasswordStrength { String message() default "密码强度不够,至少得达到{requiredStrength}级"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; // 自定义参数:要求的强度等级 int requiredStrength() default 3; } // 使用的时候可以指定参数,消息里会自动替换 @PasswordStrength(requiredStrength = 4, message = "密码必须满足{requiredStrength}级强度要求") private String password;通过EL表达式动态引用值
还能使用EL表达式直接访问被验证的字段值,比如${validatedValue}就代表当前被校验的对象/字段,这能实现更灵活的变量传递,比如后面问题2里用到的就是这种方式。
你说的没错,直接在注解的message属性里写String.length()不行,因为注解属性要求是常量表达式,但完全不用单独写长度校验方法,有个超简便的方式:
利用Bean Validation支持的EL表达式,在消息模板里用${validatedValue.length()}来获取当前字符串的实际长度!示例代码:
@Size(min = 5, max = 20, message = "输入内容长度不对哦,当前长度是${validatedValue.length()},得在{min}-{max}之间") private String content;
这样当验证失败时,消息会自动替换成实际的长度数值——比如如果content是"abc",消息就会变成「输入内容长度不对哦,当前长度是3,得在5-20之间」。
如果你的场景特别复杂(比如还要结合其他字段的逻辑),也可以在自定义验证器里动态设置消息:
public class CustomLengthValidator implements ConstraintValidator<CustomLength, String> { private int min; private int max; @Override public void initialize(CustomLength constraintAnnotation) { this.min = constraintAnnotation.min(); this.max = constraintAnnotation.max(); } @Override public boolean isValid(String value, ConstraintValidatorContext context) { if (value == null) return true; int actualLength = value.length(); if (actualLength < min || actualLength > max) { // 先禁用默认消息,再构建自定义动态消息 context.disableDefaultConstraintViolation(); context.buildConstraintViolationWithTemplate( "长度不符合要求,当前为" + actualLength + ",需在" + min + "-" + max + "之间" ).addConstraintViolation(); return false; } return true; } }
不过这种方式没必要用在简单的长度展示场景,EL表达式完全能搞定你的需求~
内容的提问来源于stack exchange,提问作者Finnegan

