在Springboot中使用自定义注解进行controller层的数据校验

利用Springboot开发后端项目时,常常需要对前端传递的参数进行校验,查看数据的格式是否正确等,多数情况下都会选择重新定义方法进行校验或者自定义注解进行校验,本文讲解利用自定义注解进行校验。

需要引入自定义注解相关的数据包:

<dependency>
     <groupId>javax.validation</groupId>
     <artifactId>validation-api</artifactId>
     <version>2.0.1.Final</version>
 </dependency>

1、首先我们先自定义一个注解进行手机号码的验证

/**
 * 校验手机号注解
 * @author wsl
 * @version 1.0
 * @date 2021/10/15 20:51
 */
@Documented
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IsPhoneValidator.class)
public @interface IsPhone {
    boolean required() default true;
    String message() default "手机号格式不正确";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

首先这里我定义了一个注解命名为IsPhone

首先说明其中各个方法的作用:

  • required()这里为布尔类型,即表示被此注解标记的参数必须含有的,不能为空,默认是true,即含有的。
  • message()的作用是如果被你这个注解标记的参数出现了不满足条件出现了格式错误,则可以由系统定义的全局异常捕获到错误信息,将你的message返回的信息作为错误信息捕获。
  • 下面两个方法均为固定写法。

下面我们来依次说明上面各个注解的作用:

  1. @Documented:为了在生成javadoc的时候就会把@Documented注解给显示出来。
  2. @Target:为了限定你自己在这开发的自定义注解的作用范围,在这里也就是限定我的@Isphone的使用范围。作用范围取决于ELementType。ElementType的用法

取值

注解使用范围

METHOD

可用于方法上

TYPE

可用于类或者接口上

ANNOTATION_TYPE

可用于注解类型上(被@interface修饰的类型)

CONSTRUCTOR

可用于构造方法上

FIELD

可用于域上

LOCAL_VARIABLE

可用于局部变量上

PACKAGE

用于记录java文件的package信息

PARAMETER

可用于参数上

  1. @Retention:定义被它所注解的注解保留多久,一共有三种策略,定义在RetentionPolicy枚举中:
  2. java springboot 注解 验证 正则表达式 springboot自定义校验注解_加载

  3. source:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;被编译器忽略
    class:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期
    runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
    这3个生命周期分别对应于:Java源文件(.java文件) —> .class文件 —> 内存中的字节码。前者能作用的地方后者也一定能作用。
  4. @Constrain:既然我们自定义了注解去进行参数校验,那么参数校验的逻辑在哪呢?就是这个@Constrain在帮我们进行逻辑验证。
    validatedBy指定了我们进行参数逻辑验证的类,下面我们来看看这个类:
/**
 * @author wsl
 * @version 1.0
 * @date 2021/10/15 20:51
 */
public class IsPhoneValidator implements ConstraintValidator<IsPhone,Object> {

    private boolean required;

    @Override
    //类一旦被加载即调用此方法
    public void initialize(IsPhone isphone) {
        System.out.println("进入初始化");
        required = isphone.required();
    }

    @Override
    //这里的o即为传递的参数手机号码mobile
    public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
        //电话号码转换成字符串类型
        String mobile = "" + o;
        System.out.println(mobile);
        if (!"".equals(mobile) && required) {
            String regexp = "^[1][3,4,5,6,7,8,9]\\d{9}$";
            return Pattern.matches(regexp, mobile);
        }
        return true;
    }
}

可以看到这个类实现了ConstraintValidator<IsPhone,Object>这个接口,这样这个类才可以拿到传经来的参数。并且实现了接口中的两个方法。其中类一旦被加载即调用方法initialize,参数进行逻辑校验则在isValid方法中。返回true则表示参数校验成功。

注意:initialize方法只会在注解被第一次调用的时候才会进行

2、使用此注解

首先,最重要的一点,在你将受用此注解的上面加入@Validated注解,必须加入,否则注解无法生效!!!如下:

@RestController
@RequestMapping("/sms")
@Validated //必须加这个配置,自定义注解才能生效!!!
public class SmsController extends BaseController{
    
    @PostMapping("/send")
    public ApiResponse sendSmsCode(@IsPhone @RequestParam long mobile){
        System.out.println(mobile);
        return createResponse();
    }

}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N7X5XupG-1634366220789)(C:\Users\24386\AppData\Roaming\Typora\typora-user-images\image-20211016143444986.png)

java springboot 注解 验证 正则表达式 springboot自定义校验注解_System_02

现在我们来调用这个接口,可以看到以下的输出:

java springboot 注解 验证 正则表达式 springboot自定义校验注解_加载_03

成功进行了自定义注解进行参数校验。