简介

后端常常会需要对参数进行校验,这里提供两种处理校验逻辑的方式。一种是使用Hibernate Validator来处理,另一种是使用全局异常来处理。对于前者,还可以使用自定义注解进行参数校验。

Hibernate Validator

Hibernate Validator是 SpringBoot 内置的校验框架,只要集成了 SpringBoot 就自动集成了它,我们可以通过在对象上面使用它提供的注解来完成参数校验。

常用注解

  • @Null:被注释的属性必须为null;
  • @NotNull:被注释的属性不能为null;
  • @AssertTrue:被注释的属性必须为true;
  • @AssertFalse:被注释的属性必须为false;
  • @Min:被注释的属性必须大于等于其value值;
  • @Max:被注释的属性必须小于等于其value值;
  • @Size:被注释的属性必须在其min和max值之间;
  • @Pattern:被注释的属性必须符合其regexp所定义的正则表达式;
  • @NotBlank:被注释的字符串不能为空字符串;
  • @NotEmpty:被注释的属性不能为空;
  • @Email:被注释的属性必须符合邮箱格式。

使用方式

  • 实体类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class User {
@ApiModelProperty(value = "用户名", required = true)
@NotEmpty(message = "用户名不为空")
private String username;
@ApiModelProperty(value = "密码", required = true)
@NotEmpty(message = "密码不为空")
private String password;
@ApiModelProperty(value = "邮箱", required = true)
@Email(message = "邮箱格式不合法")
private String email;
@ApiModelProperty(value = "是否进行显示")
@FlagValidator(value = {"0","1"}, message = "显示状态不正确")
private Integer showStatus;
}
  • 添加@Validated注解,并注入一个BindingResult参数
1
2
3
4
5
6
7
8
9
@Controller
@RequestMapping("/test")
publicclass TestController {
@RequestMapping(value = "/t0", method = RequestMethod.POST)
@ResponseBody
public T create(@Validated @RequestBody User user, BindingResult result) {
...
}
}
  • 然后在整个Controller层创建一个切面,在其环绕通知中获取到注入的BindingResult对象,通过hasErrors方法判断校验是否通过,如果有错误信息直接返回错误信息,验证通过则放行;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//在controller类的方法中,对参数通过HibernateValidator注解校验,然后利用aop通过此类对校验错误的进行整理输出日志
// 代理
@Aspect
//组件,该类和被代理的类都需要有
@Component
//优先级
@Order(2)
public class BindingResultAspect {
//切入点为controller所有方法
@Pointcut("execution(public * cn.xlh.controller.*.*(..))")
public void BindingResult() {
}

//环绕通知
@Around("BindingResult()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
//获取切入方法的所有参数
Object[] args = joinPoint.getArgs();
for (Object arg : args) {
//参数被HibernateValidator注解校验
if (arg instanceof BindingResult) {
//判断是否出错
...
}
}
return joinPoint.proceed();
}
}

自定义注解

有时候框架提供的校验注解并不能满足我们的需要,此时我们就需要自定义校验注解。如User类的参数showStatus,我们希望它只能是0或者1,不能是其他数字,此时可以使用自定义注解来实现该功能。

  • 首先自定义一个校验注解类FlagValidator
1
2
3
4
5
6
7
8
9
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Constraint(validatedBy = FlagValidatorClass.class)
public @interface FlagValidator {
String[] value() default {};
String message() default "flag is not found";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
  • 然后创建FlagValidatorClass作为校验逻辑的具体实现类,实现ConstraintValidator接口,这里需要指定两个泛型参数,第一个需要指定为你自定义的校验注解类,第二个指定为你要校验属性的类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class FlagValidatorClass implements ConstraintValidator<FlagValidator,Integer> {
private String[] values;
@Override
public void initialize(FlagValidator flagValidator) {
this.values = flagValidator.value();
}

@Override
public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
boolean isValid = false;
if(value==null){
//当状态为空时使用默认值
return true;
}
for(int i=0;i<values.length;i++){
if(values[i].equals(String.valueOf(value))){
isValid = true;
break;
}
}
return isValid;
}
}
  • 使用注解
1
2
3
4
5
public class User {
@ApiModelProperty(value = "是否进行显示")
@FlagValidator(value = {"0","1"}, message = "显示状态不正确")
private Integer showStatus;
}