spring数据校验

数据校验

概述

在开发中,会存在参数校验的情况,如:注册时,校验用户名不能为空、用户名长度不超过20个字符,手机号格式合法等。如果使用普通方式,会将校验代码和处理逻辑耦合在一起,在需要新增一种校验时,也需要修改很多地方。

spring validation允许通过注解的方式来定义校验规则,把校验和业务分离开。它其实就是对Hibernate Validation进一步的封装。

spring中的校验方式

  • 通过实现org.springframework.validation.Validator接口,然后在代码中调用这个类。
  • 按照Bean Validation方式进行校验(通过注解方式)。
  • 基于方法实现校验。

通过Validator接口实现校验

实现步骤

1、依赖引入
<dependency>
    <groupId>org.hibernate.validatorgroupId>
    <artifactId>hibernate-validatorartifactId>
    <version>8.0.1.Finalversion>
dependency>

<dependency>
    <groupId>org.glassfishgroupId>
    <artifactId>jakarta.elartifactId>
    <version>5.0.0-M1version>
dependency>
2、创建实体类
public class Person {
    private String name;
    private Integer age;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
3、编写校验类
public class PersonValidator implements Validator {
    /**
     * 此方法用来表示此校验用在哪个类型上
     * @param clazz
     * @return
     */
    @Override
    public boolean supports(Class<?> clazz) {
        return Person.class.equals(clazz);
    }

    /**
     * 此方法是设置校验逻辑的地点,其中ValidatorUtils,是Spring封装的工具类。帮助快速实现校验
     * @param target
     * @param errors
     */

    //校验规则
    @Override
    public void validate(Object target, Errors errors) {
        //name不能为空
        ValidationUtils.rejectIfEmpty(errors, "name", "name Empty", "name is null");
        //age不能小于0,不能大于200
        Person p = (Person)target;
        if (p.getAge() <= 0){
            errors.rejectValue("age", "age.value.error", "age<0");
        } else if (p.getAge() >= 200) {
            errors.rejectValue("age", "age.value.error.max", "age>200");
        }
    }
}
4、测试
@Test
public void testValidation(){
    //创建Person对象
    Person person = new Person();
    person.setAge(30);
    person.setName(null);
    //创建person对应对象
    DataBinder binder = new DataBinder(person);
    //设置校验器
    binder.setValidator(new PersonValidator());
    //调用方法、执行校验
    binder.validate();
    //输出校验结果
    BindingResult result = binder.getBindingResult();
    System.out.println("result.getAllErrors() = " + result.getAllErrors());
}
/*
* Empty.name,name Empty.java.lang.String,name Empty]; arguments []; default message [name is null]]
* */

Bean Validation注解实现

使用Bean Validation校验方式,需要使用到javax.validation.ValidatorFactoryjavax.validation.Validator注入到容器中,spring默认有一个实现类LocalValidatorFacoryBean,它实现了上面Bean Validation中的接口,并且也实现了org.springframeworkvalidation.Validator接口。

实现步骤

1、创建配置类,配置LocalValidatorFactoryBean
@Configuration
@ComponentScan("com.louis.testvalidationtwo")
public class ValidationConfig {

    @Bean
    public LocalValidatorFactoryBean validator(){
        return new LocalValidatorFactoryBean();
    }
}
2、创建实体类

定义属性,生成get、set方法,在属性上面使用注解设置校验规则。

public class User {
    @NotNull
    private String name;
    @Min(0)
    @Max(200)
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
3、创建校验器

①使用原生的校验器

@Service
public class MyValidationOne {
    //使用原生的校验器
    @Autowired
    private Validator validator;

    public boolean testValidator(User user){
        Set<ConstraintViolation<User>> validate = validator.validate(user);
        return validate.isEmpty();
    }

②使用spring中的validation

@Service
public class MyValidationTwo {
    //使用spring中的validation
    @Autowired
    private Validator validator;

    public List testValidatorTwo(User user){
        BindException bindException = new BindException(user, user.getName());
        validator.validate(user, bindException);
        List<ObjectError> allErrors = bindException.getAllErrors();
        return allErrors;
    }
}
4、测试

使用方式①

@Test
public void testValidator(){
    ApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);
    MyValidationOne validationOne = context.getBean(MyValidationOne.class);
    User user = new User();
    boolean result = validationOne.testValidator(user);
    System.out.println("result = " + result);
    /*result = false*/
}

使用方式②

@Test
public void testValidatorTwo(){
    ApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);
    MyValidationTwo validationTwo = context.getBean(MyValidationTwo.class);
    User user = new User();
    List result = validationTwo.testValidatorTwo(user);
    System.out.println("result = " + result);
    /*Object name must not be null*/
}

常用注解

注解 说明
@NotNull 限制必须不为空
@NotEmpty 只作用于字符串类型,字符串不为空,且长度不为0
@NotBlank 只作用于字符串类型,字符串不为空且trim()后也并不为空
@DecimalMax(value) 限制必须为一个不大于指定值的数字,小数存在精度
@DecimalMin(value) 限制必须为一个不小于指定值的数字,小数存在精度
@Max(value) 限制必须为一个不大于指定值的数字
@Min(value) 限制必须为一个不小于指定值的数字
@Pattern(value) 限制必须符合指定的正则表达式
@Size(max, min) 限制字符串长度必须在min到max之间
@Email 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式

基于方法实现校验

实现步骤

1、创建配置类
@Configuration
@ComponentScan("com.louis.validationbymethod")
public class ValidationConfig {
    @Bean
    public MethodValidationPostProcessor validationPostProcessor(){
        return new MethodValidationPostProcessor();
    }
}
2、创建实体类

使用注解设置校验规则

public class User {
    @NotNull
    private String name;
    @Max(200)
    @Min(0)
    private int age;
    @NotBlank(message = "手机号不能为空")
    @Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$", message = "手机号格式错误")
    private String phone;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}
3、编写校验器
@Service
@Validated
public class MyService {
    public String testMethod(@NotNull @Valid User user){
        return user.toString();
    }
}
4、测试
@Test
public void testValidationByMethod(){
    ApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);
    MyService service = context.getBean(MyService.class);
    service.testMethod(new User());
    /*testMethod.arg0.phone: 手机号不能为空, testMethod.arg0.name: 不能为null*/
}

实现自定义校验

实现步骤

1、自定义校验注解

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {CannotHaveBlankValidator.class})//表示指定校验器的类,实现真正的校验器规则
public @interface CannotHaveBlank {
    //默认的出现错误的提示信息
    String message() default "不能包含空格";

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

    Class<? extends Payload>[] payload() default {};

    @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface List {
        CannotHaveBlank[] value();
    }
}

2、编写校验规则

public class CannotHaveBlankValidator implements ConstraintValidator<CannotHaveBlank, String> {

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if(value != null &&value.contains(" ")){
            //获取默认提示信息
            String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate();
            System.out.println("default message:"+defaultConstraintMessageTemplate);
            //禁用默认提示信息
            context.disableDefaultConstraintViolation();
            //设置提示语
            context.buildConstraintViolationWithTemplate("can not constrains blank").addConstraintViolation();
            return false;
        }
        return false;
    }
}

3、创建实体类

public class User {
    @NotNull
    private String name;
    @Max(200)
    @Min(0)
    private int age;
    @NotBlank(message = "手机号不能为空")
    @Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$", message = "手机号格式错误")
    private String phone;
    @CannotHaveBlank
    private String message;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

4、测试

//使用基于方法实现校验的校验器
public class TestValidationByMethod {
    @Test
    public void testValidationByMethod(){
        ApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);
        MyService service = context.getBean(MyService.class);
        User user = new User();
        user.setAge(30);
        user.setName("Louie");
        user.setPhone("18111111111");
        user.setMessage("L o u i s");
        service.testMethod(user);
/*default message:不能包含空格
jakarta.validation.ConstraintViolationException: testMethod.arg0.message: can not constrains blank*/
    }
}

你可能感兴趣的:(Spring,spring,java,后端)