前言
Java开发中特别在Web开发中, 经常需要对请求的参数进行验证, 在目前框架中也存在一些常规的参数验证注解, 比如 @NotNull 、@NotBlank等等, 但是在某些特别的情况下需要自定义参数验证才能满足开发中的需要
接下来,介绍一下在Java中自定义注解实现参数验证的功能, 主要实现步骤 :
- 创建一个自定义注解
- 创建验证器
- 验证逻辑实现
- 测试
在开始我们的工作之前, 请确保已经创建了一个SpringBoot项目, 并添加了以下依赖
<!--Springbot提供的web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok依赖,简化代码-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--验证依赖-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.1.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.3.0.Final</version>
</dependency>
<dependency>
<groupId>com.fasterxml</groupId>
<artifactId>classmate</artifactId>
<version>1.3.3</version>
</dependency>
自定义验证注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = AnnotationAnally.class)
public @interface MyAnnotation {
String message() default "参数效验失败!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
其中 :
- @Target 指明这个注解用于在什么地方, 参数是数组类型, 我们一会需要贴字段上,所以只选择了FIELD
- @Retention 声明此注解的生命周期, 可以有SOURCE(源码,编译会丢弃), CLASS(编译,运行时会丢弃), RUNTIME(运行时期也存在)三种类型, 这里选择了生命周期最长的
- @Constraint 这是自定义验证注解最重要的, 它用来表示被贴的这个注解是一个验证注解, 参数中指定了验证器
- message() 指明了验证失败后返回的消息,此方法为@Constraint要求
- groups() 和 payload() 也为@Constraint要求,可默认为空,详细用途可以查看@Constraint文档
创建验证器
public class AnnotationAnally implements ConstraintValidator<MyAnnotation,String> {
@Override
public void initialize(MyAnnotation constraint) {
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return false;
}
}
其中 :
- 自定义验证器需要实现 ConstraintValidator 接口, 其中有两个参数,第一个是验证注解,第二个是需要验证的数据类型
- initialize() 可以在验证开始前调用注解里的方法,从而获取到一些注解里的参数,这里用不到
- isValid() 就是判断是否合法的地方
验证逻辑实现
这里就简单的对手机号码进行验证, 贴上验证器的全部代码
@Slf4j
public class AnnotationAnally implements ConstraintValidator<MyAnnotation, String> {
//验证手机号码
private static final Pattern PATTERN = Pattern.compile("^(13[0-9]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$");
/**
* 初始化方法
*
*/
@Override
public void initialize(MyAnnotation constraint) {
log.info("开始进行参数验证了...");
}
/**
* 具体的验证逻辑
*
* @return true : 验证通过 false : 验证失败
*/
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (StringUtils.hasLength(value)) {
return PATTERN.matcher(value).matches();
}
return false;
}
}
测试
创建一个 User类用来接收参数
@Data
public class User {
@MyAnnotation
private String phone;
}
创建一个控制器类用来接收请求, 要使自定义注解生效,还需要在接收参数的地方贴上 @Valid 注解
@RestController
@Slf4j
public class HelloController {
@PostMapping("/hello")
public String hello(@Valid @RequestBody User user, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
// 获取验证失败的信息,可在验证注解的message()中设置
return bindingResult.getAllErrors().get(0).getDefaultMessage();
}
log.info("接收到参数:{}", user);
return "接收成功了!";
}
}
设置一下SpringBoot内嵌容器的端口号
server:
port: 8090
启动项目通过Postman 测试一下
先来一个假的手机号
可以看到返回的结果是我在message()中设置的信息
再来一个真的
可以看到验证通过了…
本文到此结束