java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java参数校验

Java参数校验@Validated、@Valid介绍及使用详解

作者:墨鸦_Cormorant

Javax.validation是 spring 集成自带的一个参数校验接口,可通过添加注解来设置校验条件,这篇文章主要介绍了Java参数校验@Validated、@Valid介绍及使用详解,需要的朋友可以参考下

概述

介绍及使用

描述:Javax.validation是 spring 集成自带的一个参数校验接口。可通过添加注解来设置校验条件。springboot框架创建web项目后,不需要再添加其他的依赖。

使用:在Controller上使用 @Valid 或 @Validated 注解 开启校验

public String test(@RequestBody @Valid MyRequest req){};

@Validated 和 @Valid 的异同

相同点:

不同点:

注:TYPE_USE:在 Java 8 之前的版本中,只能允许在声明式前使用 Annotation。而在 Java 8 版本中,Annotation 可以被用在任何使用 Type 的地方,例如:初始化对象时 (new),对象类型转化时,使用 implements 表达式时,或者使用 throws 表达式时。

//初始化对象时
String myString = new @Valid String();
//对象类型转化时
myString = (@Valid String) str;
//使用 implements 表达式时
class MyList<T> implements List<@Valid T> {...}
//使用 throws 表达式时
public void validateValues() throws @Valid ValidationFailedException{...}

参数校验常用注解

除了前四个 @Null,@ NotNull,@ NotBlank,@NotEmpty外,其他所有的注解,传 null 时都会被当作有效处理

注解常用参数值:message(校验不通过反馈信息)

JSR303定义的基础校验类型:

注解验证的数据类型备注
Null任意类型参数值必须是 Null
NotNull任意类型参数值必须不是 Null
NotBlank只能作用于字符串字符串不能为 null,而且字符串长度必须大于0,至少包含一个非空字符串
NotEmptyCharSequence
Collection
Map
Array
参数值不能为null,且不能为空
(字符串长度必须大于0,空字符串(“ ”)可以通过校验)
Size(min,max )CharSequence
Collection
Map
Array
字符串:字符串长度必须在指定的范围内
Collection:集合大小必须在指定的范围内
Map:map的大小必须在指定的范围内
Array:数组长度必须在指定的范围内
Pattern(regexp)字符串类型验证字符串是否符合正则表达式
Min(value)整型类型参数值必须大于等于 最小值
Max(value)整型类型参数值必须小于等于 最大值
DecimalMin(value)整型类型参数值必须大于等于 最小值
DecimalMax(value)整型类型参数值必须小于等于 最大值
Positive数字类型参数值为正数
PositiveOrZero数字类型参数值为正数或0
Negative数字类型参数值为负数
NegativeOrZero数字类型参数值为负数或0
Digits(integer,fraction)数字类型参数值为数字,且最大长度不超过integer位,整数部分最高位不超过fraction位
AssertTrue布尔类型参数值必须为 true
AssertFalse布尔类型参数值必须为 false
Past时间类型(Date)参数值为时间,且必须小于 当前时间
PastOrPresent时间类型(Date)参数值为时间,且必须小于或等于 当前时间
Future时间类型(Date)参数值为时间,且必须大于 当前时间
FutureOrPresent时间类型(Date)参数值为时间,且必须大于或等于 当前日期
Email字符串类型被注释的元素必须是电子邮箱地址

Hibernate Validator 中附加的 constraint :

注解验证的数据类型备注
Length字符串类型字符串的长度在min 和 max 之间
Range数字类型
字符串类型
数值或者字符串的值必须在 min 和 max 指定的范围内

Pattern注解校验 常用正则表达式

@Pattern(regexp = "^[1-9]]\\d*$", message = "XX参数值必须是正整数")

高阶使用

自定义分组校验

有时多个场景接口公用一个请求对象,不同业务场景对请求对象的参数校验需求不同,可以使用分组校验来解决

注意:

示例:

新建自定义分组校验接口

public interface Student {
}
import javax.validation.groups.Default;
public interface Teacher extends Default {
}

新建请求对象

@Data
public class UserDTO {
    @NotBlank(message = "不能没有名称")
    private String name;
    @NotBlank(message = "老师不能没有手机号", groups = Teacher.class)
    private String phone;
    @NotEmpty(message = "学生不能没有书", groups = Student.clas)
    @Size(min = 2, message = "学生必须有两本书", groups = Student.class)
    private List<String> bookNames;
}

Controller

@RestController
public class ValidatedController {
    /**
     * 测试 校验student分组+默认分组
     */
    @PostMapping("student")
    public UserDTO validatedStudent(@Validated(value = {Student.class, Default.class}) @RequestBody UserDTO userDTO) {
        return userDTO;
    }
    /**
     * 测试 校验student分组+默认分组
     */
    @PostMapping("teacher")
    public UserDTO validatedTeacher(@Validated(value = {Teacher.class}) @RequestBody UserDTO userDTO) {
        return userDTO;
    }
    /**
     * 测试 分组校验  default
     */
    @PostMapping("default")
    public UserDTO validatedDefault(@Validated(value = {Default.class}) @RequestBody UserDTO userDTO) {
        return userDTO;
    }
    /**
     * 测试 分组校验 onlyStudent
     */
    @PostMapping("onlyStudent")
    public UserDTO validatedOnlyStudent(@Validated(value = {Student.class}) @RequestBody UserDTO userDTO) {
        return userDTO;
}

自定义校验注解

定义注解

@Documented
//指定注解的处理类
@Constraint(validatedBy = {VersionValidatorHandler.class })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface ConstantVersion {
   String message() default "{constraint.default.const.message}";
   Class<?>[] groups() default {};
   Class<? extends Payload>[] payload() default {};
   String value();
}

注解处理类

public class VersionValidatorHandler implements ConstraintValidator<Constant, String> {
    private String constant;
    @Override
    public void initialize(Constant constraintAnnotation) {
        //获取设置的字段值
        this.constant = constraintAnnotation.value();
    }
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        //判断参数是否等于设置的字段值,返回结果
        return constant.equals(value);
    }
}

自定义注解使用

@ConstantVersion (message = "verson只能为1.0.0",value="1.0.0")
String version;

Controller

@RestController
public class TestController {
    @RequestMapping("/test")
    public String createUser(@Valid User user, BindingResult bindingResult){
        if (bindingResult.hasErrors()){
            return bindingResult.getFieldError().getDefaultMessage();
        }
        return  "success";
    }
}

嵌套检验

描述:当对象 Man 的字段 houses 包含 House 对象类型时,在检验 houses 字段时可以检验 House 对象的属性字段时,就称为嵌套检验

方案:在被检验的字段上添加 @Valid 注解就可以实现嵌套检验

示例如下:

class Man{
    @Valid
    @Size(min = 1)
    private List<House> houses;
}
class House{
    @Length(min = 1,max = 10)
    private String name;
}

拓展

异常处理

参数校验异常:MethodArgumentNotValidException

方式一:基于异常监听@ControllerAdvice(参考:https://www.cnblogs.com/gezi0815/p/13815397.html)

/**
* 全局异常处理器
*/
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 异常处理
     */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public DataResult exceptionHandler(Exception e) {
        log.error("GlobalExceptionHandler.exceptionHandler , 异常信息",e);
        return DataResult.fail(e.getMessage());
    }
    /**
     * 业务异常
     */
    @ResponseBody
    @ExceptionHandler(value = BplCommonException.class)
    public DataResult bplCommonExceptionHandler(BplCommonException e) {
        log.warn("",e);
        return DataResult.fail(e.getMessage());
    }
    /**
     * 处理所有RequestBody注解参数验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public DataResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e){
        log.warn(e.getMessage());
        return DataResult.fail(e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
    }
    /**
     * 处理所有RequestParam注解数据验证异常
     */
    @ExceptionHandler(BindException.class)
    public DataResult handleBindException(BindException ex) {
        FieldError fieldError = ex.getBindingResult().getFieldError();
        log.warn("必填校验异常:{}({})", fieldError.getDefaultMessage(),fieldError.getField());
        return DataResult.fail(ex.getBindingResult().getAllErrors().get(0).getDefaultMessage());
    }
}

方式二:基于Handle或Filter(参考:https://blog.51cto.com/u_12012821/2511625)

if (e instanceof MethodArgumentNotValidException) {
	String errorMsg = ((MethodArgumentNotValidException) e)
		.getBindingResult()
		.getAllErrors()
        .stream()
		.map(DefaultMessageSourceResolvable::getDefaultMessage)
		.collect(Collectors.joining(","));
	resp = R.builder()
		.code(ResultCodeEnum.BUSINESS_ERROR.getCode())
		.message(errorMsg).success(false)
		.build();
} 

到此这篇关于Java参数校验@Validated、@Valid使用详解的文章就介绍到这了,更多相关java参数校验内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文