Springboot - 9.验证和数据绑定

✍1. 验证:

在Spring框架中,验证是通过Validator接口实现的。

1. Validator接口:

  • 作用:

    • Validator接口用于定义对象的验证逻辑,以确保它们满足特定的业务规则和要求。
  • 使用场景:

    • 在表单提交、API请求等需要验证输入数据的场景中使用。
    • 在数据层面进行验证,确保数据的合法性。
  • 优缺点:

    • 优点:
      • 使验证逻辑与业务逻辑分离,提高代码的可维护性和可重用性。
      • 能够在不同的层次进行验证,例如控制器、服务层等。
      • 提供了灵活的验证规则,可以根据业务需要自定义验证规则。
    • 缺点:
      • 需要手动编写验证逻辑,可能增加一定的开发工作量。
      • 对于复杂的验证规则,需要更多的代码来实现。

示例:

public class PersonValidator implements Validator {

    @Override
    public boolean supports(Class<?> clazz) {
        return Person.class.equals(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        Person person = (Person) target;
        if (person.getAge() < 0) {
            errors.rejectValue("age", "negativevalue");
        } else if (person.getAge() > 110) {
            errors.rejectValue("age", "too.darn.old");
        }
    }

}

2. 使用Validator:

  • 作用:

    • 使用Validator可以对对象进行验证,确保其符合预定的规则和要求。
  • 使用场景:

    • 在服务层或控制层验证数据的合法性。
    • 在接收请求参数后,对数据进行验证,确保数据的有效性。
  • 优缺点:

    • 优点:
      • 提供了一种规范的方式进行验证,减少了重复的验证代码。
      • 可以在不同的层次(例如控制器、服务层)使用,提高了代码的复用性。
    • 缺点:
      • 需要手动绑定和验证对象,可能会增加一些开发工作量。
      • 验证器的逻辑需要开发者自行编写,可能存在错误或遗漏。

示例:

@Service
public class PersonService {

    private final Validator validator;

    @Autowired
    public PersonService(Validator validator) {
        this.validator = validator;
    }

    public void doSomething(Person person) {
        DataBinder dataBinder = new DataBinder(person);
        dataBinder.setValidator(validator);
        dataBinder.validate();
        BindingResult bindingResult = dataBinder.getBindingResult();
        if (bindingResult.hasErrors()) {
            System.out.println(bindingResult.getAllErrors());
        } else {
            System.out.println("Person is valid");
        }
    }

}

✍2. 数据绑定:

在Spring框架中,数据绑定是通过DataBinder类实现的。

1. DataBinder类:

  • 作用:

    • DataBinder类用于将请求参数绑定到目标对象,并可进行数据验证。
  • 使用场景:

    • 在控制器中,将请求参数映射到实体对象或DTO。
    • 需要将HTTP请求的参数绑定到Java对象的情况。
  • 优缺点:

    • 优点:
      • 简化了参数绑定和数据验证的过程。
      • 可以在控制器中直接使用,提高了代码的可读性和简洁性。
    • 缺点:
      • 需要手动设置绑定和验证的规则,可能会增加一些开发工作量。

示例:

@Service
public class PersonService {

    private final Validator validator;

    @Autowired
    public PersonService(Validator validator) {
        this.validator = validator;
    }

    public void doSomething(Map<String, String> parameters) {
        Person person = new Person();
        DataBinder dataBinder = new DataBinder(person);
        dataBinder.setValidator(validator);
        dataBinder.bind(new MutablePropertyValues(parameters));
        dataBinder.validate();
        BindingResult bindingResult = dataBinder.getBindingResult();
        if (bindingResult.hasErrors()) {
            System.out.println(bindingResult.getAllErrors());
        } else {
            System.out.println("Person is valid");
        }
    }

}

高级用法:

1. 自定义验证注解和验证器:

  • 作用:

    • 自定义验证注解和验证器允许您根据应用程序的特定需求创建自定义的验证规则。
  • 使用场景:

    • 在默认验证规则无法满足业务需求时使用自定义验证。
    • 需要根据应用程序的特定逻辑实施验证规则。
  • 示例:

    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @Constraint(validatedBy = AgeValidator.class)
    public @interface ValidAge {
        String message() default "Invalid age";
        Class<?>[] groups() default {};
        Class<? extends Payload>[] payload() default {};
    }
    
    public class AgeValidator implements ConstraintValidator<ValidAge, Integer> {
        public void initialize(ValidAge constraint) {
        }
    
        public boolean isValid(Integer age, ConstraintValidatorContext context) {
            return age >= 0 && age <= 150;
        }
    }
    

    在这个示例中,我们创建了一个自定义的验证注解ValidAge,并使用AgeValidator来验证年龄是否合法。

2. 全局异常处理:

  • 作用:

    • 全局异常处理允许您在验证失败时捕获异常,并返回适当的错误响应。
  • 使用场景:

    • 在多个控制器方法中使用统一的异常处理逻辑。
    • 需要为验证失败的情况提供统一的错误响应。
  • 示例:

    @ControllerAdvice
    public class GlobalExceptionHandler {
    
        @ExceptionHandler(MethodArgumentNotValidException.class)
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        @ResponseBody
        public Map<String, String> handleValidationException(MethodArgumentNotValidException ex) {
            Map<String, String> errors = new HashMap<>();
            ex.getBindingResult().getFieldErrors().forEach(error ->
                    errors.put(error.getField(), error.getDefaultMessage()));
            return errors;
        }
    
    }
    

    在这个示例中,GlobalExceptionHandler捕获MethodArgumentNotValidException异常并返回带有验证错误的响应。

3. 校验分组:

  • 作用:

    • 校验分组允许您根据场景对对象进行不同的验证。
  • 使用场景:

    • 需要在不同的操作中使用不同的验证规则。
    • 对同一对象的不同属性进行不同的验证。
  • 示例:

    public interface CreateValidationGroup {
    }
    
    public interface UpdateValidationGroup {
    }
    
    public class Person {
    
        @NotBlank(groups = {CreateValidationGroup.class, UpdateValidationGroup.class})
        private String name;
    
        @Min(value = 18, groups = CreateValidationGroup.class)
        private int age;
    
        // Other fields and methods
    }
    

    在这个示例中,我们使用校验分组CreateValidationGroupUpdateValidationGroupPerson类的属性进行不同的验证。

4. 国际化消息:

  • 作用:

    • 国际化消息允许您在验证失败时返回本地化的错误消息,提升用户体验。
  • 使用场景:

    • 需要将验证错误消息显示为用户的本地语言。
    • 改善多语言环境下的用户体验。
  • 示例:

    invalid.age=Age must be between 0 and 150.
    

    在资源文件中定义错误消息,然后在验证注解中引用。

    @Min(value = 18, message = "{invalid.age}")
    private int age;
    

    在这个示例中,当年龄验证失败时,会返回本地化的错误消息。

这些高级用法可以根据项目的实际需求进行定制和扩展,从而更好地满足复杂的验证和绑定场景。

你可能感兴趣的:(Springboot-详解,spring,boot,后端,java)