参考文档 系统执行业务逻辑之前,会对输入数据进行校验,检测数据是否有效合法的。所以我们可能会写大量的if else等判断逻辑,特别是在不同方法出现相同的数据时,校验的逻辑代码会反复出现,导致代码冗余,阅读性和可维护性极差。 hibernate-validator就提供了这套标准的实现,我们在用Springboot开发web应用时,会引入spring-boot-starter-web依赖,它默认会引入spring-boot-starter-validation依赖,而spring-boot-starter-validation中就引用了hibernate-validator依赖。
但是,在比较高版本的spring-boot-starter-web中,默认不再引用spring-boot-starter-validation,自然也就不会默认引入到hibernate-validator依赖,需要我们手动添加依赖。
依赖
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.7.Final</version>
</dependency>
定义一个注解用于字段
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = CheckParam.class)
public @interface Check {
Class<? extends Enum<?>> enumClazz();
String filed();
String message() default "非法参数";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
创建一个校验类
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
@Component
public class CheckParam implements ConstraintValidator<Check, Object> {
private boolean required;
private Class<? extends Enum<?>> enumClass;
private String filed;
@Override
public void initialize(Check constraintAnnotation) {
this.enumClass = constraintAnnotation.enumClazz();
this.filed = constraintAnnotation.filed();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
context.disableDefaultConstraintViolation();
if (StringUtils.isBlank(value.toString())) {
context.buildConstraintViolationWithTemplate("你不对劲").addConstraintViolation();
return false;
}
if (!EnumCheck.valueBelongsToEnum(enumClass, filed, value.toString())) {
context.buildConstraintViolationWithTemplate("参数不在枚举范围").addConstraintViolation();
return false;
}
return true;
}
}
用以校验的bean以及使用
# Pojo
@Data
public class Goods {
private String goodsName;
@Check(enumClazz = GoodsTypeEnum.class,filed = "type")
private Integer goodsType;
}
# Controller
@RestController
@RequestMapping("/enumCheck")
public class EnumCheckController {
@PostMapping("test")
public Object test(@RequestBody @Valid Goods goods){
return goods;
}
}
枚举校验方法
public class EnumCheck {
public static boolean valueBelongsToEnum(Class<? extends Enum<?>> clazz, String fieldName,String val){
final Enum<?>[] enums = clazz.getEnumConstants();
if (null == enums) {
return false;
}
final List<Object> list = new ArrayList<>(enums.length);
for (Enum<?> e : enums) {
list.add(ReflectUtil.getFieldValue(e, fieldName));
}
final List<String> collect = list.stream().map(Object::toString).collect(Collectors.toList());
boolean contains = collect.contains(val);
return contains;
}
}
枚举
public enum GoodsTypeEnum {
PC("pc",1),
MOBILE("mobile",2),
WEB("web",3),
;
private final String info;
private final Integer type;
GoodsTypeEnum(String info, Integer type) {
this.info = info;
this.type = type;
}
public Integer getType() {
return type;
}
}
异常处理
方法默认抛出MethodArgumentNotValidException ,我们在统一异常处理中捕获他进行处理,统一响应
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<Object> methodArgumentNotValidException(MethodArgumentNotValidException e){
log.error("参数校验异常 msg:{}",e.getMessage(),e );
String msg = e.getMessage();
String[] split = msg.split(";");
String temp = split[5].split("\\[")[1];
return Result.fail(50000,"["+split[0].split("'")[1]+"]"+temp.substring(0, temp.length()-3));
}
测试结果
|