Spring Boot 自定义Validation注解

在项目开发过程中,注解给我们带来方便、快捷的极简编程体验,前面也有记录了一些常用的注解命令,可见注解是比较常用且重要的功能,有时候validation自带的注解可能不能满足我们的个性化需要时,我们能不能根据自己的情况自定义注解命令呢?

源码浅析

我们先来看看常用的@Min注解,学习一下它是如何实现的,先看源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(List.class)
@Documented
@Constraint(validatedBy = { })
public @interface Min {

String message() default "{javax.validation.constraints.Min.message}";

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

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

/**
* @return value the element must be higher or equal to
*/
long value();

/**
* Defines several {@link Min} annotations on the same element.
*
* @see Min
*/
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
@interface List {

Min[] value();
}
}
  • @Target 注解的作用范围,参数是一个枚举类型:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     public enum ElementType {
    /** 类、接口或者是枚举 */
    TYPE,

    /** 字段属性 */
    FIELD,

    /** 方法 */
    METHOD,

    /** 参数 */
    PARAMETER,

    /** 构造方法 */
    CONSTRUCTOR,

    /** 局部变量 */
    LOCAL_VARIABLE,

    /** 注解类型 如:@interface修饰的类型 */
    ANNOTATION_TYPE,

    /** 包 */
    PACKAGE,

    /**
    * Type parameter declaration
    *
    * @since 1.8
    */
    TYPE_PARAMETER,

    /**
    * Use of a type
    *
    * @since 1.8
    */
    TYPE_USE
    }
  • @Retention用于声明注解的声明周期,也是一个枚举类型:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     public enum RetentionPolicy {
    /**
    * Annotations are to be discarded by the compiler. 注解是保留在源代码中,编译时丢弃
    */
    SOURCE,

    /**
    * Annotations are to be recorded in the class file by the compiler
    * but need not be retained by the VM at run time. This is the default
    * behavior.代码保留在class文件中,加载到JVM虚拟机时丢弃
    */
    CLASS,

    /**
    * Annotations are to be recorded in the class file by the compiler and
    * retained by the VM at run time, so they may be read reflectively.
    * 保留在程序运行期间,此时可以通过反射获得定义在某个类上的所有注解
    * @see java.lang.reflect.AnnotatedElement
    */
    RUNTIME
    }
  • @Repeatable注解表明标记的注解可以多次应用于相同的声明或类型

  • @Documented注解会被javadoc之类的工具处理, 所以注解类型信息也会被包括在生成的文档中.默认情况下javadoc是不包括注解的

  • @Constraint注解限定自定义注解的方法,指定自定义的处理类。

自定义注解

刚才简单介绍了一下Spring给我们带来的注解的定义方式,接下来就依样画葫芦来实现自定义Validation注解。首先新建一个Phone注解:

1
2
3
4
5
6
7
8
9
10
11
12
@Target({FIELD })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {PhoneConstraintValidator.class})
public @interface Phone {
String message() default "手机号错误";

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

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

}

再创建一个Validator校验类,用于Phone @Constraint指定的处理校验类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class PhoneConstraintValidator implements ConstraintValidator<Phone,String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return isMobile(value);
}
private boolean isMobile(String source) {
Pattern pattern = null;
Matcher matcher = null;

String reg="^[1](([3|5|8][\\d])|([4][4,5,6,7,8,9])|([6][2,5,6,7])|([7][^9])|([9][1,8,9]))[\\d]{8}$";// 验证手机号
if(!StringUtils.isEmpty(source)){
pattern = Pattern.compile(reg);
matcher = pattern.matcher(source);
return matcher.matches();
}
return false;
}
}

现在就可以在使用我们自定义的注解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@ApiModel("StudentVO")
@Data
public class StudentVO {

@NotEmpty(message ="学生名字不能为空")
@ApiModelProperty("学生名字")
private String name;


@Range(min = 5, max = 30, message = "学生年龄不能大于30岁或者小于5岁")
@ApiModelProperty("学生年龄")
private Integer age;

@NotEmpty(message ="学生住址不能为空")
@ApiModelProperty("学生住址")
private String address;

@NotBlank(message = "手机号必填")
@Phone(message = "号码不正确")
@ApiModelProperty("手机号")
private String PhoneNo;
}



自定义Validation就暂时告一段落,后面,我们再来总结一下其他实用注解的定义方法。

You forgot to set the qrcode for Alipay. Please set it in _config.yml.
You forgot to set the qrcode for Wechat. Please set it in _config.yml.
You forgot to set the business and currency_code for Paypal. Please set it in _config.yml.
You forgot to set the url Patreon. Please set it in _config.yml.
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×