自定义注解-动态传入允许的值
希望在校验时动态指定允许的值(例如 0 和 1),而不是硬编码在注解中,可以通过 自定义注解 + 动态参数 的方式实现。
解决方案:自定义注解 @InValues,支持动态传入允许的值
我们可以定义一个注解 @InValues,允许传入一个 int[] 数组,校验参数是否在指定的值范围内。
1. 定义 @InValues 注解
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = InValuesValidator.class) // 指定校验器
public @interface InValues {
String message() default "值不在允许范围内";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
// 允许的值数组
int[] values();
}
2. 实现校验逻辑 InValuesValidator
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class InValuesValidator implements ConstraintValidator<InValues, Integer> {
private int[] allowedValues;
@Override
public void initialize(InValues constraintAnnotation) {
this.allowedValues = constraintAnnotation.values(); // 初始化允许的值
}
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
if (value == null) {
return true; // 如果允许 null,可以返回 true;否则返回 false
}
for (int allowedValue : allowedValues) {
if (value == allowedValue) {
return true;
}
}
return false;
}
}
3. 在实体类中使用 @InValues
public class MyRequest {
@InValues(values = {0, 1}, message = "值必须是 0 或 1")
private Integer status;
// getter & setter
}
4. 在 Controller 中使用 @Validated 校验
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Validated
public class MyController {
@PostMapping("/validate")
public String validate(@RequestBody @Validated MyRequest request) {
return "Valid";
}
}
5. 测试
- ✅ 合法请求(status=0 或 status=1):
{"status": 0} // 通过
{"status": 1} // 通过
- ❌ 非法请求(status=2):
{"status": 2} // 返回 400 Bad Request,错误信息:"值必须是 0 或 1"
6. 进阶:支持动态传值
适用于方法参数校验
如果希望在校验时动态传入允许的值(而不是硬编码在注解中),可以使用 @interface + @Constraint + @Target + @Retention 结合 @Validated 实现。
示例:动态校验方法参数
import org.springframework.validation.annotation.Validated;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = DynamicInValuesValidator.class)
public @interface DynamicInValues {
String message() default "值不在允许范围内";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
// 使用 String 数组存储允许的值(避免编译时硬编码)
String[] values() default {};
}
但由于 @interface 的 values() 是编译时常量,无法动态传值,因此 Spring Validation 不支持直接在方法参数上动态校验。
替代方案:
- 使用 @Validated + 自定义校验逻辑(在 Service 层手动校验)。
- 使用 @Pattern + 字符串转换(适用于简单场景)。
7. 总结
方案 | 适用场景 | 是否支持动态传值 | 备注 |
---|---|---|---|
@InValues(推荐) | 校验 Integer 是否在指定范围内 | ❌ 硬编码在注解中 | 最常用 |
@Pattern + 字符串转换 | 简单校验 | ❌ 不推荐 | 需要额外转换 |
@AssertTrue | 对象校验 | ❌ 不推荐 | 需要额外方法 |
动态校验(Service 层) | 动态传值 | ✅ 支持 | 需手动校验 |
推荐使用 @InValues 注解,代码清晰且可复用。如果需要动态传值,建议在 Service 层手动校验。