Java自定义校验注解

出于程序的稳定性以及简洁,会对数据入参时进行校验,常用的两个包 javax.validation.constraints、org.hibernate.validator.constraints,如@NotNull、@Length等。很多时候随着业务的不同,这些注解不一定能满足需求,这时候可以通过自定义注解来校验

核心注解为@Constraint

如下为一个自定义的数字校验注解

@Pattern(regexp = "[0-9]*")
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {})
@ReportAsSingleViolation
public @interface NumberVaildation {

    String message() default "请输入数字";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

}

一些注解的说明:

@Retention:必须是RUNTIME,否则Bean validation不会进行检验

@Documented:标注了这个标记的target,在javadoc中应显示其存在

@Constraint是必须的,表明这是一个Bean Validation限制,否则会被忽略,validatedBy中表明用来验证的constraintValidator的实现

@Pattern:可以理解为正则表达式

@ConstraintComposition:组合校验,下面会测试说明

具体用法测试用例

写一个DTO类

@Data
public class TestDTO implements Serializable {

    @ApiModelProperty(value = "字母")
    @ABCVaildation
    private String abc;

    @ApiModelProperty(value = "数字")
    @NumberVaildation
    private String number;

    @ApiModelProperty(value = "项目id")
    @ItemNumber
    private String itemId;

}

三个自定义注解

@NumberVaildation:校验数字

@ABCVaildation:校验字母

@ItemNumber:组合校验

@Pattern(regexp = "^[A-Za-z]+$")
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {})
@ReportAsSingleViolation
public @interface ABCVaildation {

    String message() default "请输入字母";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

}
@Pattern(regexp = "[0-9]*")
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {})
@ReportAsSingleViolation
public @interface NumberVaildation {

    String message() default "请输入数字";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

}
@ConstraintComposition(CompositionType.OR)
@NumberVaildation
@ABCVaildation
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {})
@ReportAsSingleViolation
public @interface ItemNumber {

    String message() default "请输入数字/字母";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

}

controller:

@RestController
@Api(tags = "测试校验专用api")
public class TestController {


    @PostMapping(value = "vaildation")
    @ApiOperation("测试校验")
    public Result vaildationApi(@Valid @RequestBody TestDTO testDTO) {
        return Result.ok("通过");
    }

}

测试结果:

          

可以看到在@ItemNumber上加了另外两个注解@NumberVaildation、@ABCVaildation, 并且用了@ConstraintComposition(CompositionType.OR),CompositionType.OR是组合类型,有AND、OR、ALL_FALSE。为or说明满足其中一个注解即可,and需要同时满足,all_false则不通过。

还可以通过@Constraint中的validatedBy 自定义类来实现,需要implements ConstraintValidator

@ConstraintComposition(CompositionType.OR)
@NumberVaildation
@ABCVaildation
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {CondictionVaildation.class})
@ReportAsSingleViolation
public @interface ItemNumber {

    String message() default "请输入数字/字母";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

}
public class CondictionVaildation implements ConstraintValidator<ItemNumber, Object> {
    @Override
    public void initialize(ItemNumber constraintAnnotation) {

    }

    @Override
    public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
        ConstraintValidatorContextImpl ctx = (ConstraintValidatorContextImpl)constraintValidatorContext;
        // 逻辑代码这边写,Object为传入的itemId
        return true; // true为通过
    }
}

另外,可以将注解放在类上面,这样拿到的object是整个对象,可以在CondictionVaildation 里面打个断点看看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

l去留无心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值