使用Hibernate-Validator优雅的参数验证

2022-01-04  本文已影响0人  养一只tom猫

在开发中,经常会有各种校验的代码,而这些代码与业务逻辑无关,我们可以通过自定义校验注解来简化这些代码。
以下StringIn注解起到限制入参的作用,如我们数据库存储一个类型值只有"1"或者"2",对前端或者其余系统调用时传了约定以外的值进行校验。

  1. 添加 Hibernate-Validator 依赖
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
        </dependency>
  1. 自定义注解
/**
 * Created by Jie on 2021/12/31 上午9:14
 */
@Documented
@Retention(RUNTIME)
@Repeatable(StringIn.List.class)
@Constraint(validatedBy = {StringInValidator.class})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
public @interface StringIn {

    String[] value() default {};

    Class<?>[] groups() default {};

    String message() default "";

    @SuppressWarnings("unused")
    Class<? extends Payload>[] payload() default {};

    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    @Retention(RUNTIME)
    @Documented
    @interface List {
        StringIn[] value();
    }
}
  1. 编写校验类
/**
 * Created by Jie on 2021/12/31 上午9:19
 */
public class StringInValidator implements ConstraintValidator<StringIn, String> {

    private List<String> valueList;

    @Override
    public void initialize(StringIn constraintAnnotation) {
        valueList = Arrays.asList(constraintAnnotation.value());
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null) {
            return true;
        }

        return valueList.contains(value);
    }

}

由于该框架抛出异常格式令人吐槽,可编写全局异常处理器来解析并返回更合理的格式。

/**
 * Created by Jie on 2021/12/31 上午10:02
 */
@RestControllerAdvice
public class ValidateExceptionHandler {

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Result methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        String message = e.getBindingResult()
                .getAllErrors()
                .stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .collect(Collectors.joining(""));
        return new Result(200, message);
    }

}

测试:

@Data
public class TestEntity {

    private String id;

    @StringIn(value = {"1", "2"}, message = "name值不在给定范围内!", groups = AddGroup.class)
    private String name;
}
/**
 * Created by Jie on 2021/12/30 下午8:18
 */
@RestController
@RequestMapping("/test")
public class TestController {

    @PostMapping("/testAdd")
    public Result testAdd(@RequestBody @Validated(value = AddGroup.class) TestEntity entity) {
        return new Result(200, "添加成功", null);
    }

}

该方式可自由扩展,甚至可用到Spel表达式进行校验,此种方法在service中能完全告别参数校验相关的代码。

上一篇下一篇

猜你喜欢

热点阅读