java

关注公众号 jb51net

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

Java的validation参数校验代码实例

作者:言烬

这篇文章主要介绍了Java的validation参数校验代码实例,Validation参数校验是指在程序运行中对传进来的参数进行合法性检查,以保证程序的正确性和安全性,需要的朋友可以参考下

bean validation和hibernate validator参数校验

常用注解

@Null(groups={Add.class}) 参数必须为null,group设置分组,默认为default
@NotNull 参数不为null
@NotEmpty 参数不为null ,"",集合不为空
@NotBlank 参数不为null, "", " ",只能作用字符串类型
@AssertFalse 被注释的元素必须是false
@AssertTrue 被注释的元素必须是true
@Min(value) 被注释的元素必须为一个数字  >=
@Max(value) 被注释的元素必须为一个数字 <= 
@DecimalMin("value")  >=
@DecimalMax("value") <= 
@NegativeOrZero <=0
@Range(min,max) 被注释的元素大小必须在指定的范围内 
@Size(min ,max) 被注释的元素大小必须在指定的范围内
@Email 被注释的元素必须是电子邮箱地址
@Past 被注释的元素必须是一个过去的日期
@PastOrPresent  被注释的元素必须是一个过去的时间
@Future 被注释的元素必须是一个将来的日期
@Pattern(regexp = "1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\\d{8}$")  被注释的元素必须是符合指定的正则表达式
@URL 被注释的元素必须是链接地址
备注:参数校验只有!= null的时候才生效

1.导入依赖

        <!--引入hibernate-validator,beanvalidator-->
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.0.18.Final</version>
        </dependency>
        <!--el规范和tomcat的实现,用于解析message里面的表达式-->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-el</artifactId>
            <version>9.0.29</version>
        </dependency>

springboot依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

2.测试

//1.定义实体类
@Data
public class UserInfo{
@NotBlank
private String name;
}
//2.编写工具类
public class UserInfo{
    //声明validator,线程安全的:所有的方法都可以使用这个对象,而不会产生线程安全的问题
    private static Validator validator;
    //初始化默认的validator对象
    static {validator = Validation.buildDefaultValidatorFactory().getValidator();}
    //校验
 public static List<String> valid(UserInfo userInfo,Class<?>... groups){
        //如果被校验对象userInfo没有检验通过,则set里面就有校验信息,返回出去
        Set<ConstraintViolation<UserInfo>> set = validator.validate(userInfo,groups);
        List<String> list = set.stream().map(v -> "属性:" + v.getPropertyPath() + ",属性值是:" + v.getInvalidValue()
                + ",校验不通过的提示信息:" + v.getMessage()+",消息模板:"+v.getMessageTemplate()).collect(Collectors.toList());
        return list;
    }
}
//3.测试
public class ValidationTest {
  public static void main(String[] args) {
        UserInfo info = new UserInfo();
        info.setName("名字");
 }
List<String> valid1 = ValidationUtil.valid(info);
System.out.println(valid1);
//

返回结果:
[属性:name,属性值是:null,校验不通过的提示信息:不能为空,消息模板:{javax.validation.constraints.NotBlank.message}]

3.自定义消息模板

@NotBlank(message = "姓名不能为空!!")
private String name;

返回结果:
[属性:name,属性值是:null,校验不通过的提示信息:姓名不能为空!!,消息模板:姓名不能为空!!]

4.分组校验

//1.定义实体类
public class UserInfo{
	//标记接口 新增,修改,删除
    public interface Add extends Default {}
    public interface Update extends Default{}
    public interface Delete extends Default{}
    //默认组default,指定分组
    @Null(groups = {Add.class}) //只适用于新增
    @NotNull(groups = {Update.class,Delete.class})//只适用于修改/删除
    private Long id;
    @NotBlank(message = "姓名不能为空!!")
	private String name;}
//2.编写工具类
 //校验,要检验的对象,检验分组
    public static List<String> valid(UserInfo userInfo,Class<?>... groups){
        //如果被校验对象userInfo没有检验通过,则2set里面就有校验信息,返回出去
        Set<ConstraintViolation<UserInfo>> set = validator.validate(userInfo,groups);
        List<String> list = set.stream().map(v -> "属性:" + v.getPropertyPath() + ",属性值是:" + v.getInvalidValue()
                + ",校验不通过的提示信息:" + v.getMessage()+",消息模板:"+v.getMessageTemplate()).collect(Collectors.toList());
        return list;
    }
//3.测试
public class ValidationTest {
  public static void main(String[] args) {
        UserInfo info = new UserInfo();
        info.setName("名字");
 }
List<String> valid1 = ValidationUtil.valid(info,UserInfo.Add.class);
List<String> valid2 = ValidationUtil.valid(info,UserInfo.Update.class);
System.out.println(valid1);
System.out.println(valid2);

//结果
valid1[]
valid1[属性:id,属性值是:null,校验不通过的提示信息:不能为null,消息模板:{javax.validation.constraints.NotNull.message}]

5.级联校验

//1.编写实体类
public class UserInfo{
   @NotBlank(message = "姓名不能为空!!")
    private String name;
    @Valid //被引用对象加上@valid注解,才可以完成级联校验
    private Grade grade;
    }
public class Grade {
    @NotBlank
    private String id;
}
//2.工具类同上
//3.测试
public class ValidationTest {
  public static void main(String[] args) {
        UserInfo info = new UserInfo();
        info.setName("名字");
       //添加grade
       Grade grade = new Grade();
       //grade.setId("123");
       info.setGrade(grade);
 }
 

//结果
 valid1[属性:grade.id,属性值是:null,校验不通过的提示信息:不能为空,消息模板:{javax.validation.constraints.NotBlank.message}]

6.自定义注解

status的必须为1000/1001/1002

//1.编写实体类
public class UserInfo{
@NotBlank(message = "姓名不能为空!!")
    private String name;
    @UserStatus
    private Integer status;
}
//2.1编写注解要校验的规则
  -继承ConstraintValidator<UserStatus,Integer>,绑定要校验的约束注解UserStatus,类型
public class UserStatusValidator implements ConstraintValidator<UserStatus,Integer> {
    @Override
    public void initialize(UserStatus constraintAnnotation) {
    }
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
        if (value == null){
            //没有值,不校验
            return true;
        }
        //设置要求之
        Set<Integer> set = new HashSet<>();
        set.add(1000);
        set.add(1001);
        set.add(1002);
        return set.contains(value);
    }
}
//2.2编写注解声明类
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {UserStatusValidator.class})//说明当前注解要被谁来完成校验工作
@Documented
public @interface UserStatus {
    String message() default "{userStatus必须是1000/1001/1002}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
//3.测试
public class ValidationTest {
  public static void main(String[] args) {
        UserInfo info = new UserInfo();
        info.setName("名字");
        info.setStatus(200);
        List<String> valid1 = ValidationUtil.valid(info);
        System.out.println("valid1"+valid1);
 }
 

//结果
 valid1[属性:status,属性值是:200,校验不通过的提示信息:{userStatus必须是1000/1001/1002},消息模板:{userStatus必须是1000/1001/1002}, 属性:grade,属性值是:null,校验不通过的提示信息:不能为空,消息模板:{org.hibernate.validator.constraints.NotEmpty.message}]

7.快速校验

//1.实体类 同上
//2.工具类
public class ValidationUtil {
   //配置快速失败
    private static Validator validFailFast;
    static {
        validFailFast = Validation.byProvider(HibernateValidator.class).configure()
            .failFast(true).buildValidatorFactory().getValidator();//.failFast(true),快速失败
    }
    public static<T> List<String> validNotBean(T object, Method method, Object[] parameterValues, Class<?>... groups){
        Set<ConstraintViolation<T>> set = executables.validateParameters(object, method, parameterValues, groups);
        List<String> list = set.stream().map(v -> "属性:" + v.getPropertyPath() + ",属性值是:" + v.getInvalidValue()
                + ",校验不通过的提示信息:" + v.getMessage()+",消息模板:"+v.getMessageTemplate()).collect(Collectors.toList());
        return list;
    }
 //   3.测试类同上
 //   调用:  
    List<String> valid = ValidationUtil.validFailFast(info,UserInfo.Add.class);
 //   效果:当有错误时,直接返回第一个错误,不再校验其他错误。

8.非bean入参校验

请求参数和返回值并不是一个bean

//1.编写要校验的方法
    /**
     * 方法非bean类型的入参校验
     * 1.方法参数前加注解
     * 2.执行入参校验,真正有用的话可以使用aop编程思想来使用
     */
    public String getByName(@NotBlank String name){
        //执行入参校验
        //当前线程的堆栈,第一个元素就是当前所在方法的名字
        StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[1];
        String methodName = stackTraceElement.getMethodName();
        Method method = null;
        try{
            method = this.getClass().getDeclaredMethod(methodName, String.class);
        }catch (Exception e) {
            e.printStackTrace();
        }
        List<String> strings = ValidationUtil.validNotBean(this, method, new Object[]{name});
        //打印校验结果
        System.out.println("校验结果:" + strings);
        return "ok";
    }
//2.工具类编写
public class ValidationUtil {
  private static ExecutableValidator executables;
 static {
    validator = Validation.buildDefaultValidatorFactory().getValidator();
    //校验入参或返回值的
     executables = validator.forExecutables();
    }
  public static<T> List<String> validNotBean(T object, Method method, Object[] parameterValues, Class<?>... groups){
  		//校验方法参数 validateParameters
        Set<ConstraintViolation<T>> set = executables.validateParameters(object, method, parameterValues, groups);
        List<String> list = set.stream().map(v -> "属性:" + v.getPropertyPath() + ",属性值是:" + v.getInvalidValue()
                + ",校验不通过的提示信息:" + v.getMessage()+",消息模板:"+v.getMessageTemplate()).collect(Collectors.toList());
        return list;
    }
}
//3.测试
method.getByName("");

返回结果
校验结果:[属性:getByName.arg0,属性值是:,校验不通过的提示信息:不能为空,消息模板:{javax.validation.constraints.NotBlank.message}]

9.与SpringBoot整合

1.编程式校验

直接使用工具类校验
 @GetMapping("/addUser")
    public String getByName(UserInfo userInfo){
        List<String> valid = ValidationUtil.valid(userInfo);
        if (valid.size()>0){
            System.out.println(valid);
            return "校验不成功";
        }else {
        return "添加成功!";}
    }

访问:http:8080/addUser
结果:校验不成功  控制台打印报错

2.声明式校验

 @GetMapping("/addUser2")
    public String getByName2(@Valid UserInfo userInfo){
        return "添加成功";}
//结果:页面直接报错
//将校验结果封装到BindingResult,不会页面上报错
    @GetMapping("/addUser2")
    public String getByName2(@Valid UserInfo userInfo, BindingResult result){
        if(result.hasErrors()){//判断是否有不满足约束的
            List<ObjectError> errors = result.getAllErrors();
            for (ObjectError error : errors) {
      			//打印错误信息
                System.out.println(error.getObjectName()+"::"+error.getDefaultMessage());
            }
            //获取没通过校验的字段详情
            List<FieldError> fieldErrorList = result.getFieldErrors();
            for (FieldError fieldError : fieldErrorList) {
                System.out.println(fieldError.getField() + "::" + fieldError.getDefaultMessage() + ",当前没有通过校验规则的值是:" + fieldError.getRejectedValue());
            }
        };
        return "添加成功";
    }

3.@Validated 实现分组校验

 @GetMapping("/addUser3")
    public String getByName3(@Validated(value = {UserInfo.Add.class}) UserInfo userInfo, BindingResult result){
        if(result.hasErrors()){//判断是否有不满足约束的
            List<ObjectError> errors = result.getAllErrors();
            for (ObjectError error : errors) {
                System.out.println(error.getObjectName()+"::"+error.getDefaultMessage());
            }
            //获取没通过校验的字段详情
            List<FieldError> fieldErrorList = result.getFieldErrors();
            for (FieldError fieldError : fieldErrorList) {
                System.out.println(fieldError.getField() + "::" + fieldError.getDefaultMessage() + ",当前没有通过校验规则的值是:" + fieldError.getRejectedValue());
            }
        };
        return "添加成功";
    }

@Validated方法参数校验

@Validated//表示整个类都启用校验,如果碰到入参含有bean validation注解的话就会自动校验
@GetMapping("/getByName")
    public String getByName(@NotBlank String name){
        return name;
    }

10.统一异常处理

不写BindingResult result

方式一:添加一个方法,使用@ExceptionHandler(BindException.class)标记,处理当前controller里抛出的xx异常

@ExceptionHandler(BindException.class)
public String handleEx(BindException e){
        List<FieldError> fieldErrors = e.getFieldErrors();
        StringBuilder builder = new StringBuilder();
        for (FieldError fieldError : fieldErrors) {
            builder.append("属性:").append(fieldError.getField()).append("校验不通过的原因:").append(fieldError.getDefaultMessage()).append(";;");
        }
        return builder.toString();
    }

方式二:编写统一的异常处理方式

@ControllerAdvice
public class RoadControllerAdvice {
    /**
     *@Validated 写在方法上的时候会报这个异常
     */
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public String handleEx(BindException e){
        List<FieldError> fieldErrors = e.getFieldErrors();
        StringBuilder builder = new StringBuilder("RoadControllerAdvice里的:");
        for (FieldError fieldError : fieldErrors) {
            builder.append("属性:").append(fieldError.getField()).append("校验不通过的原因:").append(fieldError.getDefaultMessage()).append(";;");
        }
        return builder.toString();
    }
    /**
     * @Validated 写在类上的时候会报这个异常
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public List<String> handleEx(ConstraintViolationException e){
        Set<ConstraintViolation<?>> fieldErrors = e.getConstraintViolations();
        StringBuilder builder = new StringBuilder("RoadControllerAdvice里的:");
        List<String> list = fieldErrors.stream().map(v -> "属性:" + v.getPropertyPath() + ",属性值是:" + v.getInvalidValue()
                + ",校验不通过的提示信息:" + v.getMessage()+",消息模板:"+v.getMessageTemplate()).collect(Collectors.toList());
        return list;
    }
    /**
     * 处理所有异常信息
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public String handleEx(Exception e){
        return e.getMessage();
    }
}

到此这篇关于Java的validation参数校验代码实例的文章就介绍到这了,更多相关validation参数校验代码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

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