Java Bean Validation自定义注解

前面介绍了Java Bean Validation的使用,本文进一步介绍一下当标准的校验注解不满足要求时,可以自定义校验注解满足特定需求。比如@In,要求参数数据某个固定的集合(类似于枚举值)

自定义注解

  • @In
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Constraint(validatedBy = InValidator.class)
@Target({java.lang.annotation.ElementType.FIELD})
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Documented
public @interface In {
    //提示信息,可以写死,可以填写国际化的key
    String message() default "";

    int[] values() default {};

    //下面这两个属性必须添加
    Class<?>[] groups() default {};

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

注解实现类

  • InValidator
public class InValidator implements ConstraintValidator<In, Integer> {
    private final Set<Integer> values = new HashSet<>();
    private String msg = null;
    @Override
    public void initialize(In constraintAnnotation) {
        for (int value : constraintAnnotation.values()) {
            this.values.add(value);
        }
        String msg = values.stream().map(Object::toString).collect(Collectors.joining(",", "[", "]"));
        this.msg = String.format("只能取值%s", msg);
    }

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        if (value == null) {
            return true;
        }
        boolean contains = values.contains(value);
        if (contains) {
            return true;
        }

        if (context.getDefaultConstraintMessageTemplate().isEmpty()) {
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate(this.msg).addConstraintViolation();
        }
        return false;
    }
}

使用

  • Person.java
@Data
public class Person {
    @Null(message = "id should be empty")
    private Integer id;

    @Length(min = 2, max = 10, message = "name的长度为[2-10]之间")
    @NotBlank(message = "name should not be empty")
    private String name;

    @Min(18)
    @Max(130)
    private Integer age;

    @NotNull(message = "gender should not be empty")
    private Boolean gender;

    @Null(message = "createTime should be empty")
    private LocalDateTime createTime;

    @Null(message = "updateTime should be empty")
    private LocalDateTime updateTime;

    //这里是自定义注解,指定type只能是1或2
    @In(values = {1,2})
    private Integer type;
}

测试

  • 参数
{
    "name": "tenmao",
    "gender": true,
    "type": 3
}
  • 结果
{
    "code": 400,
    "msg": "[只能取值[1,2]]",
    "data": null
}

常见问题

  • 自定义注解需要配置@Constraint(validatedBy = InValidator.class),但是查看内置的注解,比如@NotNull中的却是空的validatedBy = {}。这是因为API中并不包含实现类,这样就需要实现类实现手动配置,比如hibernate-validator是在ConstraintHelper.java完成的

参考

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏FREE SOLO

Java简答面试题(一)

1.问题:介绍一下 finalize 方法 答案: final: 常量声明。 finally: 处理异常。 finalize: 帮助进行垃圾回收。接口里声明的...

12210
来自专栏业余草

手把手教你通过Java代码体验强引用、软引用、弱引用、虚引用的区别

强引用、软引用、弱引用、虚引用这些东西,如果你们平时只写 CRUD 的话,就可能遇不到。今天抽个时间,我给大家讲一讲它们之间的区别与联系。

6620
来自专栏FREE SOLO

2019Java面试代码与编程题

代码与编程题 135、写一个Singleton出来 Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。 一般Si...

21320
来自专栏牛客网

19春招头条 腾讯还有一众中小厂c++后台面经

面经都是19届春招补录,后台相关岗位,大部分都是中小厂,一直也在牛客上找内推,总的一起写个面经算是回馈牛客吧(抱歉都放在一起,实在不想每次面试写一个面经)

21440
来自专栏FREE SOLO

2019Java面试题:用位运算判断一个数是不是奇数?

一个数如果是奇数的话,那么他的二进制最后一位一定为1. 比如 3, 他的二进制表示为 11 而 1 的二进制为 01 ,两个相与,则为1. 而偶数的话则就为0...

17230
来自专栏业余草

一个 System.gc 就能让你在面试中被打击到怀疑人生

人的一生中可能会遭遇到无数次打击。而今天我就给大家介绍一个你可能忽略的知识点:System.gc,给你专门来一次降维打击。降低到某个细微的知识点,让你被打击的体...

90230
来自专栏FREE SOLO

Java面试题整理

Java面向对象 19. super()与this()的区别? This():当前类的对象,super父类对象。 Super():在子类访问父类的成员和行...

92610
来自专栏FREE SOLO

程序员Java面试的陷阱

程序员Java面试的陷阱2010年01月21日 星期四 22:27   找工作要面试,有面试就有对付面试的办法。以下一些题目来自我和我朋友痛苦的面试经历,提这...

17520
来自专栏FREE SOLO

JAVA 1-6章测试题

JAVA 1-6章测试题 简答题: 1、JAVA实现跨平台的原理? 答:Java为我们提供了Java虚拟机(JVM),当程序运行时,Java首先将后缀名为...

18730
来自专栏FREE SOLO

2019面试题:你所用到的几种设计模式,并简单说下?

创建型模式,共五种: 工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七种: 适配器模式、装饰器模式、代理模式、外观模式、桥接...

4.8K20

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励