自定义注解
依赖导入
在我们的 pom.xml 文件中引入 Spring MVC 的依赖,为了方便我们就使用 Spring Boot 的 Starter 即可。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.0.6.RELEASE</version> </dependency>
注解定义
编写自定义注解,我解释一下下面的几个参数:
1、mssage() 默认错误消息, 和标准的 @NotNull
等一样,主要是提示一个 message.
2、value() 这里是一个枚举范围,就是参数字段限定的枚举范围。但是需要注意的是,咱们的枚举定义的过程中只要有 value
字段的属性和 getValue
方法。
/** * 枚举值限定校验 * 注意:枚举一定要包含 value 字段 * * @author zhengsh * @date 2021-12-08 */ @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER}) @Documented @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = {EnumValueValidator.class}) public @interface EnumValue { // 默认错误消息 String message() default "the integer is not one of the enum values"; // 约束注解在验证时所属的组别 Class<?>[] groups() default {}; // 约束注解的有效负载 Class<? extends Payload>[] payload() default {}; Class<? extends Enum> value(); // 同时指定多个时使用 @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER}) @Documented @Retention(RetentionPolicy.RUNTIME) @interface List { EnumValue[] value(); } }
定义校验器
编写自定义校验器, 在 EnumValueValidator
自定义校验器中,咱们需要实现 ConstraintValidator
其实说白了在参数封装的过程中,Spring MVC 框架会去调用 initialize
方法对当前这个注解的拓展进行初始化,然后在校验过程中会执行 isValid
如果校验通过我们就返回 true , 不通过我们就返回 false 。如果不通过,就会抛出异常,然后异常的错误信息中会包含我们之前定义的 message.
/** * 与约束注解关联的校验器 * * @author zhengsh * @date 2021-12-08 */ public class EnumValueValidator implements ConstraintValidator<EnumValue, Object> { private Class<? extends Enum> enumClass; private static final String METHOD_NAME = "getValue"; /** * 这个方法做一些初始化校验 * * @param constraintAnnotation */ public void initialize(EnumValue constraintAnnotation) { enumClass = constraintAnnotation.value(); try { // 先判断该enum是否实现了getValue方法 enumClass.getDeclaredMethod(METHOD_NAME); } catch (NoSuchMethodException e) { throw new IllegalArgumentException("the enum class has not getValue method", e); } } /** * 这个方法写具体的校验逻辑:校验数字是否属于指定枚举类型的范围 * * @param value * @param constraintValidatorContext * @return */ public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) { // 如果为空返回 true , 判空用 @NotNull 等专用注解 if (Objects.isNull(value)) { return true; } try { Enum[] enumConstants = enumClass.getEnumConstants(); if (enumConstants == null) { // 如果不是枚举类型,返回 enumConstants = null return true; } for (Enum e : enumClass.getEnumConstants()) { Method declaredMethod = e.getClass().getDeclaredMethod(METHOD_NAME); Object obj = declaredMethod.invoke(e); if (Objects.equals(obj, value)) { return true; } } } catch (Exception e) { e.printStackTrace(); } return false; } }
使用示例
下面是我们使用的例子我们需要做三步:
1、定义限定范围的注解.
2、在入参接受的对象上增加 @EnumValue
注解 .
3、在控制器的请求参数方法上增加 Validated
标记需要进行参数验证处理。
下面来看看具体的代码和实现。
定义枚举
首先我们先定义一个 Gender 枚举
public enum Gender { male(0), female(1); private int value; Gender(int value) { this.value = value; } public int getValue() { return this.value; } }
使用和依赖
然后我们在我们的入参上面添加自定义注解即可:
public class Person { @EnumValue(value = Gender.class, message = "gender 字段不在系统支持的枚举范围内") Gender gender; }
最后我们需要在的Controler 的方法上面加上 @Validated
注解,表示对当前参数进行校验。
@RestController public class PersonController { @RequestMapping("/test") public String test(@Validated Person person) { return "OK"; } }
使用总结
在 Java 编程的中,通过注解是一种非常简化代码的方法,就如我们 @EnumValue(Gender.class)
注解的使用,我们减少了对参数的判断,而且可以在 EnumValueValidator
中统一的做处理,方便以后的拓展,而且可以规范化的做一些开发的基础工作,让我们的业务开发者更加的聚焦业务开发。
在 validation-api
中也是提供了非常多的参数校验枚举比如:@NotNull
、@Min
、@Email
等注解在 jakarta.validation.constraints
包下大家都可以去使用的。