|
1 | 1 | # 自定义约束注解
|
2 | 2 |
|
3 |
| -如果你使用过 `javax.validation` 的自定义约束注解,那么你会发现 `SpEL Validator` 的自定义约束注解几乎与 `javax.validation` |
4 |
| -一致。 |
| 3 | +::: tip |
| 4 | +如果你使用过 `javax.validation` 的自定义约束注解,那么你会发现 `SpEL Validator` 的自定义约束注解几乎与 `javax.validation` 一致。 |
| 5 | +::: |
5 | 6 |
|
6 |
| -下面以 `@SpelNotNull` 为例,展示如何实现自定义约束注解。 |
7 |
| - |
8 |
| -**以下内容还没写完** |
| 7 | +下面以 `@SpelNotBlank` 为例,展示如何实现自定义约束注解。 |
9 | 8 |
|
10 | 9 | ## 创建约束注解类
|
11 | 10 |
|
| 11 | +每个约束注释必须包含以下属性: |
| 12 | +- `String message() default "";` 用于指定约束校验失败时的错误消息。 |
| 13 | +- `String condition() default "";` 用于指定约束开启条件的SpEL表达式。 |
| 14 | +- `String[] group() default {};` 用于指定分组条件的SpEL表达式。 |
| 15 | + |
12 | 16 | ```java
|
13 |
| -@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) |
14 |
| -@Retention(RetentionPolicy.RUNTIME) |
15 | 17 | @Documented
|
16 |
| -@Constraint(validatedBy = SpelNotNullValidator.class) |
17 |
| -public @interface SpelNotNull { |
| 18 | +@Retention(RetentionPolicy.RUNTIME) |
| 19 | +@Target(ElementType.FIELD) |
| 20 | +@Repeatable(SpelNotBlank.List.class) |
| 21 | +public @interface SpelNotBlank { |
18 | 22 |
|
19 |
| - String message() default "{javax.validation.constraints.NotNull.message}"; |
| 23 | + String message() default "不能为空字符串"; |
20 | 24 |
|
21 |
| - Class<?>[] groups() default {}; |
| 25 | + String condition() default ""; |
22 | 26 |
|
23 |
| - Class<? extends Payload>[] payload() default {}; |
| 27 | + String[] group() default {}; |
24 | 28 |
|
25 |
| - String condition() default ""; |
| 29 | + @Target(FIELD) |
| 30 | + @Retention(RUNTIME) |
| 31 | + @Documented |
| 32 | + @interface List { |
| 33 | + |
| 34 | + SpelNotBlank[] value(); |
| 35 | + |
| 36 | + } |
26 | 37 |
|
27 | 38 | }
|
28 | 39 | ```
|
29 | 40 |
|
30 | 41 | ## 创建约束验证器
|
31 | 42 |
|
| 43 | +创建类 `SpelNotBlankValidator`,实现 `SpelConstraintValidator<T>` 接口,其中泛型 `T` 为要校验的约束注解类,在这里是 `SpelNotBlank`。 |
| 44 | + |
| 45 | +实现 `isValid` 方法,校验逻辑在该方法中实现。 |
| 46 | + |
| 47 | +`isValid` 方法的参数说明如下: |
| 48 | +- `annotation`:当前约束注解的实例。 |
| 49 | +- `obj`:当前校验的根对象。 |
| 50 | +- `field`:当前校验的字段。 |
| 51 | + |
32 | 52 | ```java
|
33 |
| -public class SpelNotNullValidator implements ConstraintValidator<SpelNotNull, Object> { |
| 53 | +public class SpelNotBlankValidator implements SpelConstraintValidator<SpelNotBlank> { |
| 54 | + |
| 55 | + @Override |
| 56 | + public FieldValidResult isValid(SpelNotBlank annotation, Object obj, Field field) throws IllegalAccessException { |
| 57 | + CharSequence fieldValue = (CharSequence) field.get(obj); |
| 58 | + return new FieldValidResult(StringUtils.hasText(fieldValue)); |
| 59 | + } |
| 60 | + |
| 61 | +} |
| 62 | +``` |
| 63 | + |
| 64 | +一般情况下,只需要校验当前字段的值,通过 `field.get(obj)` 即可获取。 |
| 65 | + |
| 66 | +有些约束注解可能仅支持特定类型的字段,可以通过重写 `supportType()` 方法来指定支持的类型。默认情况下,支持所有类型。 |
34 | 67 |
|
35 |
| - private String condition; |
| 68 | +```java |
| 69 | +public class SpelNotBlankValidator implements SpelConstraintValidator<SpelNotBlank> { |
36 | 70 |
|
37 | 71 | @Override
|
38 |
| - public void initialize(SpelNotNull constraintAnnotation) { |
39 |
| - this.condition = constraintAnnotation.condition(); |
| 72 | + public FieldValidResult isValid(SpelNotBlank annotation, Object obj, Field field) throws IllegalAccessException { |
| 73 | + CharSequence fieldValue = (CharSequence) field.get(obj); |
| 74 | + return new FieldValidResult(StringUtils.hasText(fieldValue)); |
40 | 75 | }
|
41 | 76 |
|
| 77 | + private static final Set<Class<?>> SUPPORT_TYPE = Collections.singleton(CharSequence.class); |
| 78 | + |
42 | 79 | @Override
|
43 |
| - public boolean isValid(Object value, ConstraintValidatorContext context) { |
44 |
| - if (value == null) { |
45 |
| - return false; |
46 |
| - } |
47 |
| - if (StringUtils.hasText(condition)) { |
48 |
| - return SpelUtils.evaluate(condition, value, Boolean.class); |
49 |
| - } |
50 |
| - return true; |
| 80 | + public Set<Class<?>> supportType() { |
| 81 | + return SUPPORT_TYPE; |
51 | 82 | }
|
52 | 83 |
|
53 | 84 | }
|
54 | 85 | ```
|
| 86 | + |
| 87 | +## 关联注解和验证器 |
| 88 | + |
| 89 | +在 `SpelNotBlank` 注解上添加 `@SpelConstraint` 注解,指定该注解的验证器为 `SpelNotBlankValidator`。 |
| 90 | + |
| 91 | +```java |
| 92 | +@Documented |
| 93 | +@Retention(RUNTIME) |
| 94 | +@Target(FIELD) |
| 95 | +@Repeatable(SpelNotBlank.List.class) |
| 96 | +@SpelConstraint(validatedBy = SpelNotBlankValidator.class) // 关联验证器 |
| 97 | +public @interface SpelNotBlank { |
| 98 | + // ... |
| 99 | +} |
| 100 | +``` |
| 101 | + |
| 102 | +## 使用自定义约束注解 |
| 103 | + |
| 104 | +完成上面的步骤,就可以在需要校验的字段上使用 `@SpelNotBlank` 注解了,使用方法就和内置的约束注解一样,[使用指南](user-guide.md)。 |
| 105 | + |
| 106 | +已经大功告成了,这里我就不举例了。 |
0 commit comments