前言:常用的validation注解可能不太满足实际使用场景,基于它可以拓展自己的注解校验。

示例:自定义正则校验注解

  • @Constraint(validatedBy={IPattern.Validator.class}) 指定当前注解校验器(实现ConstraintValidator校验器的类)
  • @ConstraintComposition(CompositionType.AND) 引入外部注解时的规则(OR、AND、ALL_FALSE)
  • @ReportAsSingleViolation 引入外部注解时,外部注解的错误信息会使用当前注解的错误信息, 否则使用自己的错误信息
  • @Repeatable 是否支持重复注解, 在一个字段上多次使用(分组不同)
  • @OverridesAttribute 覆盖注解属性值(要指定被覆盖注解的某个属性名称)

一、自定义正则校验注解,替代javax.validation.constraints.Pattern注解

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.constraints.CompositionType;
import org.hibernate.validator.constraints.ConstraintComposition;
import org.hibernate.validator.constraints.Length;

import javax.validation.*;
import java.lang.annotation.*;

/**
* 自定义正则注解,支持枚举正则和字符串长度
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = IPattern.Validator.class)
@Repeatable(IPattern.List.class)
@ConstraintComposition(CompositionType.AND)
@ReportAsSingleViolation
@Length
public @interface IPattern {
String message() default "IPattern格式错误"; //必须

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

Class<?>[] payload() default {}; //必须

RegexEnum regexp() default RegexEnum.NONE;

@OverridesAttribute(constraint = Length.class, name = "min")
int min() default 0;

@OverridesAttribute(constraint = Length.class, name = "max")
int max() default Integer.MAX_VALUE;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface List {
IPattern[] value();
}

class Validator implements ConstraintValidator<IPattern, String> {
//正则枚举类
private RegexEnum regex;

@Override
public void initialize(IPattern constraintAnnotation) {
regex = constraintAnnotation.regexp();
}

@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (StringUtils.isBlank(value)) {
return true;
}
return value.matches(regex.getRegex());
}
}
}

二、定义正则枚举类:

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
public enum RegexEnum {
/*
* 任意字符,不校验
*/
NONE(".*"),
/*
* 中英文和空格
*/
NAME("^[\u4e00-\u9fa5a-zA-z ]*$"),
/**
* 密码 8-16位,特殊字符(-和_)
*/
PASSWORD("[0-9a-zA-z-_]{8,16}"),
/*
* 手机号 支持座机号和手机号(简单验证)
* '123-4567890' '1234-5678901' '+8613800138000' '008613800138000'
*/
PHONE("^\\d{3}-\\d{8}$|^\\d{4}-\\d{7}$|^(?:(?:\\+|00)86)?1\\d{10}$"),
/*
* 邮箱 支持中文邮箱(简单验证)
* 'example@example.com', 'user.name@example.co.uk', '张三_李四@domain.com', 'test-123@sub.domain.cn', 'abc.123@domain.info'
*/
EMAIL("^([A-Za-z0-9_\\-.\\u4e00-\\u9fa5])+@([A-Za-z0-9_\\-.])+\\.([A-Za-z]{2,8})$"),
/*
* URL 支持参数(url带参数)
* 'www.qq.com', 'https://baidu.com', '360.com:8080/vue/#/a=1&b=2'
*/
URL("/^(((ht|f)tps?):\\/\\/)?[\\w-]+(\\.[\\w-]+)+([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])?$/"),
/*
* 身份证号码 支持一二代身份证
* '622223199912051311'
*/
ID_CARD("(^\\d{8}(0\\d|10|11|12)([0-2]\\d|30|31)\\d{3}$)|(^\\d{6}(18|19|20)\\d{2}(0[1-9]|10|11|12)([0-2]\\d|30|31)\\d{3}(\\d|X|x)$)"),
/*
* 统一社会信用代码 宽松匹配
* '91110108772551611J', '911101085923662400'
*/
SSC("^[0-9A-Z]{15}$|^[0-9A-Z]{18}$|^[0-9A-Z]{20}$"),
/*
* 纯数字正则
*/
NUMBER("^[0-9]*$"),
/*
*英文 无特殊字符
*/
CHARS_EN("^[a-zA-z0-9]*$"),
/*
*英文 特殊字符(-_)
*/
SPECIAL_CHARS_EN("^[a-zA-z0-9-_]*$"),
/*
*英文 特殊字符带空格
*/
SPECIAL_CHARS_SPACE_EN("^[a-zA-z0-9-_ ]*$"),
/*
*中文 无特殊字符
*/
CHARS_CN("^[\u4e00-\u9fa5a-zA-z0-9]*$"),
/*
*中文 特殊字符(-_) 适合名称输入
*/
SPECIAL_CHARS_CN("^[\u4e00-\u9fa5a-zA-z0-9-_]*$"),
/*
*中文 特殊字符带空格
*/
SPECIAL_CHARS_SPACE_CN("^[\u4e00-\u9fa5a-zA-z0-9-_ ]*$"),

;
private final String regex;

RegexEnum(String regex) {
this.regex = regex;
}

public String getRegex() {
return regex;
}
}

三、使用注解

原来怎么用,这个就怎么用

1
2
3
4
5
public class UserDTO {
//用户名
@IPattern(regexp = RegexEnum.SPECIAL_CHARS_CN, max = 30, message = "用户名称格式不正确")
private String name;
}