Java中@Max、@Min、@Valid注解的工作原理及自定义实现问询
Java校验注解(@Valid/@Max)工作机制与自定义实现
一、@Valid/@Max等注解的工作机制
Java参数校验基于**JSR-380(Bean Validation 2.0)**规范,Hibernate Validator是它的主流实现,Spring框架也深度集成了这套机制,核心流程如下:
约束标记与触发
- @Max、@Min这类注解是约束注解,仅标记字段需遵循的规则(比如@Max(value=100)表示字段值不能超过100),本身不包含校验逻辑。
- @Valid是校验触发开关:在Controller方法参数、嵌套对象上标记@Valid时,Spring会启动校验流程。
校验器初始化
- 应用启动时,Bean Validation会扫描所有带@Constraint注解的类,为每个约束注解绑定对应的ConstraintValidator实现类(比如@Max对应MaxValidator)。
- 这些Validator会被加载到ValidatorFactory中,供后续校验调用。
校验执行流程
- 请求到达Controller后,Spring发现参数带@Valid,会从ValidatorFactory获取Validator实例。
- Validator遍历目标对象的字段,识别约束注解,找到对应的ConstraintValidator,调用其
isValid()方法执行校验。 - 若字段值不符合约束,会生成错误信息,最终封装到BindingResult或抛出MethodArgumentNotValidException。
二、自定义类似@Max的校验注解(以@MyMax为例)
自定义约束注解只需两步:定义注解、实现校验逻辑,具体如下:
1. 定义约束注解@MyMax
通过@Constraint指定对应的校验器,同时定义必要属性(最大值、错误提示等):
import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; @Documented @Constraint(validatedBy = MyMaxValidator.class) // 绑定校验器 @Target({ElementType.FIELD, ElementType.PARAMETER}) // 可用于字段和方法参数 @Retention(RetentionPolicy.RUNTIME) // 运行时生效 public @interface MyMax { // 默认错误提示 String message() default "值不能超过指定最大值"; // 分组校验用,默认空数组 Class<?>[] groups() default {}; // 负载信息,用于传递额外数据,默认空数组 Class<? extends Payload>[] payload() default {}; // 核心属性:最大值 long value(); }
2. 实现ConstraintValidator校验逻辑
编写MyMaxValidator类,实现ConstraintValidator接口,重写初始化和校验方法:
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class MyMaxValidator implements ConstraintValidator<MyMax, Number> { private long maxValue; // 初始化:获取注解上的最大值配置 @Override public void initialize(MyMax constraintAnnotation) { this.maxValue = constraintAnnotation.value(); } // 核心校验逻辑:判断值是否符合规则 @Override public boolean isValid(Number value, ConstraintValidatorContext context) { // 允许值为null(如需强制非null,需配合@NotNull注解) if (value == null) { return true; } // 针对不同数值类型做比较 if (value instanceof Integer) { return value.intValue() <= maxValue; } else if (value instanceof Long) { return value.longValue() <= maxValue; } else if (value instanceof Double) { return value.doubleValue() <= maxValue; } // 其他数值类型可自行扩展 return false; } }
3. 使用自定义注解
在实体类或方法参数上使用@MyMax,搭配@Valid触发校验:
// 实体类示例 public class User { @MyMax(value = 100, message = "年龄不能超过100岁") private Integer age; // getter/setter 省略 } // Controller示例 @RestController public class UserController { @PostMapping("/users") public String addUser(@Valid @RequestBody User user) { // 校验通过才会执行到此处 return "用户创建成功"; } }
4. 触发校验
调用/users接口传入age=101时,Spring会触发MyMaxValidator的校验,抛出MethodArgumentNotValidException,返回包含错误信息的响应。
内容的提问来源于stack exchange,提问作者juni
相关产品推荐
相关产品推荐

