SpringBoot 2.3.0版本之后就没有引入validation对应的包,需要手动引用,依赖如下
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
SpringBoot有四个注解用来注解注解的@Retention
@Target
@Document
@Inherited
注解保留位置的:@Retention
//注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.SOURCE)
// 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
@Retention(RetentionPolicy.CLASS)
// 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Retention(RetentionPolicy.RUNTIME)
注解的作用目标:@Target
//接口、类、枚举、注解
@Target(ElementType.TYPE)
//字段、枚举的常量
@Target(ElementType.FIELD)
//方法
@Target(ElementType.METHOD)
//方法参数
@Target(ElementType.PARAMETER)
//构造函数
@Target(ElementType.CONSTRUCTOR)
//局部变量
@Target(ElementType.LOCAL_VARIABLE)
//注解
@Target(ElementType.ANNOTATION_TYPE)
//包
@Target(ElementType.PACKAGE)
将注解包含在javadoc中@Documented
注解可以被继承@Inherited
自定义注解@Constraint
如果想对接口参数进行校验,必须使用@valid才能使注解生效
@GetMapping("/check")
public String test02(@Valid @RequestBody Parm s){
return s.getNameS();
}
下面就是如何具体完成一个自定义注解,首先是定义一个@interface
@Constraint(validatedBy= {CheckNameValidator.class})
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CheckName {
String message();
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
其中,CheckName为注解名,validatedBy= {CheckNameValidator.class}的CheckNameValidator是真正进行校验方法的类,message可自定义个数和属性,作为注解传参的参数
注意,这三个必须有,否则报错:
String message() default "参数不为指定值";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
真正校验的类:
public class CheckNameValidator implements ConstraintValidator<CheckName, String> {
String message;
@Override
public void initialize(CheckName constraintAnnotation) {
this.message = constraintAnnotation.message();
}
@Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
if (s.equals("a")) {
System.out.println(message);
return true;
}
return false;
}
}
需要继承ConstraintValidator<注解名,校验的Object>
有两个方法initialize()
和isValid()
方法initialize()
不需要一定有,使用可用来对注解定义的参数进行初始化给isValid()
方法进行使用
方法isValid()
必须实现,是校验逻辑所在的位置
最后是注解的位置:
public class Parm {
@CheckName(message = "message")
private String NameS;
public String getNameS() {
return NameS;
}
public void setNameS(String name) {
NameS = name;
}
}
注解括号里的是注解中定义的参数,可自定义
一个完整例子:
Check.java(注解类)
// 校验逻辑和注解作用范围都是数组,可以选择多个
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {ParamConstraintValidated.class})
public @interface Check {
// 使用注解的传参,可用作校验的逻辑
// 可自定义多个
// @Check(paramValues={"","",...})
String[] paramValues();
/**
* 缺少报错:XXX contains Constraint annotation, but does not contain a message parameter
**/
String message() default "参数不为指定值";
/**
* 缺少报错:XXX contains Constraint annotation, but does not contain a groups parameter
**/
Class<?>[] groups() default {};
/**
* 缺少报错:XXX contains Constraint annotation, but does not contain a payload parameter
**/
Class<? extends Payload>[] payload() default { };
}
ParamConstraintValidated.java(校验类)
/**
* Check为注解名 Object为校验的数据类型
*/
public class ParamConstraintValidated implements ConstraintValidator<Check,Object> {
private List<String> paramValues;
@Override
public void initialize(Check constraintAnnotation) {
// 通过属性上的注解,拿到自定义属性的值
paramValues= Arrays.asList(constraintAnnotation.paramValues());
}
@Override
public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
// 校验逻辑
// true 通过 false 失败
return paramValues.contains(o);
}
}