Spring : Validation, Data Binding, and Type Conversion

279 阅读2分钟

原文地址

Spring : Validation, Data Binding, and Type Conversion

逐节笔记

1. Validation by Using Spring’s Validator Interface

通过实现 org.springframework.validation.Validator接口进行参数校验

@Data
public class Person {

    private String name;
    private Integer age;

}
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

public class PersonValidator implements Validator {

    /**
     * This Validator validates only Person instances
     */
    @Override
    public boolean supports(Class clazz) {
        return Person.class.equals(clazz);
    }

    @Override
    public void validate(Object obj, Errors e) {
        ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
        Person p = (Person) obj;
        if (p.getAge() < 0) {
            e.rejectValue("age", "negative value");
        } else if (p.getAge() > 110) {
            e.rejectValue("age", "too.darn.old");
        }
    }
}
@PostMapping
public void savePerson(@RequestBody Person person) {
    DataBinder dataBinder = new DataBinder(person);
    dataBinder.setValidator(new PersonValidator());

    dataBinder.validate();
    BindingResult bindingResult = dataBinder.getBindingResult();
    log.info("result:{}",bindingResult);
}

  • 嵌套对象校验
@Data
public class Address {

    private String  location;
}
@Data
public class Customer {

    private String firstName;
    private String surname;

    private Address address;
}
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

/**
 * @author Created by niugang on 2020/3/30/18:44
 */
public class AddressValidator implements Validator {

    /**
     * This Validator validates *just* Address instances
     */
    @Override
    public boolean supports(Class<?> clazz) {
        return Address.class.equals(clazz);
    }

    @Override
    public void validate(Object obj, Errors e) {
        ValidationUtils.rejectIfEmpty(e, "location", "location.empty");
        Address p = (Address) obj;
        if (p != null && p.getLocation() != null && p.getLocation().length() > 5) {
            e.rejectValue("location", "value too length", "长度不能超过5");
        }
    }
}
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

/**
 * @author Created by niugang on 2020/3/30/18:47
 */
public class CustomerValidator implements Validator {
    private final Validator addressValidator;

    public CustomerValidator(Validator addressValidator) {

        if (addressValidator == null) {
            throw new IllegalArgumentException("The supplied [Validator] is " +
                    "required and must not be null.");
        }
        if (!addressValidator.supports(Address.class)) {
            throw new IllegalArgumentException("The supplied [Validator] must " +
                    "support the validation of [Address] instances.");
        }
        this.addressValidator = addressValidator;
    }

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

    @Override
    public void validate(Object target, Errors errors) {
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "field.required");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "surname", "field.required");
        Customer customer = (Customer) target;
        try {
            errors.pushNestedPath("address");
            ValidationUtils.invokeValidator(this.addressValidator, customer.getAddress(), errors);
        } finally {
            errors.popNestedPath();
        }
    }
}

以上代码取自这里如果对参数校验感兴趣,可以详细阅读

2. Resolving Codes to Error Messages

Spring 提供了一个接口org.springframework.validation.MessageCodesResolver用于处理上面校验后返回的消息,并且提供了org.springframework.validation.DefaultMessageCodesResolver实现这个接口
可以在application.yml中配置返回消息的格式

spring:
  mvc:
    message-codes-resolver-format: prefix_error_code

详细源码可以参考这个博客
尝试了一下自定义返回消息格式,但我拉闸了,下次想起来在尝试

3. Bean Manipulation and the BeanWrapper

这部分写了一个demo来体验
data-binding-demo
阅读README.md

4. Type Conversion

4.1 Converter

实现Converter,在convert方法中将两种不同类型的数据进行转换
然后将实现的添加到(?)里和其他Spring提供的Converter放在一起
具体demo可以看这个博客的前面部分

4.2 Using ConverterFactory

可以理解为S转为T时 先转为T的子类R(?)
官方的文档中本节已给出demo代码

4.3 Using GenericConverter

可以理解为,比较完善的Converter实现
参考demo
Using ConditionalGenericConverter
在GenericConverter的基础上添加了一个条件判断的方法,当条件判true时转换
参考demo

4.4 ConversionService API

关于Type Conversion本节的余下内容可以参阅这个文档
ConversionService


好了 烂尾了
后面还有一些String、Date格式,数据校验相关的内容下次再看