Spring 校验

Spring 校验使用场景

• Spring 常规校验(Validator)
• Spring 数据绑定(DataBinder)
• Spring Web 参数绑定(WebDataBinder)
• Spring Web MVC / Spring WebFlux 处理方法参数校验

Validator 接口设计

• 接口职责

  • Spring 内部校验器接口,通过编程的方式校验目标对象

• 核心方法

  • supports(Class):校验目标类能否校验
  • validate(Object,Errors):校验目标对象,并将校验失败的内容输出至 Errors 对象

• 配套组件

  • 错误收集器:org.springframework.validation.Errors
  • Validator 工具类:org.springframework.validation.ValidationUtils

Errors 接口设计

• 接口职责

  • 数据绑定和校验错误收集接口,与 Java Bean 和其属性有强关联性

• 核心方法

  • reject 方法(重载):收集错误文案
  • rejectValue 方法(重载):收集对象字段中的错误文案

• 配套组件

  • Java Bean 错误描述:org.springframework.validation.ObjectError
  • Java Bean 属性错误描述:org.springframework.validation.FieldError

Errors 文案来源

• Errors 文案生成步骤

  • 选择 Errors 实现(如:org.springframework.validation.BeanPropertyBindingResult)
  • 调用 reject 或 rejectValue 方法
  • 获取 Errors 对象中 ObjectError 或 FieldError
  • 将 ObjectError 或 FieldError 中的 code 和 args,关联 MessageSource 实现(如:
    ResourceBundleMessageSource)
/**
 * 错误文案示例
 */
public class ErrorsMessageDemo {

    public static void main(String[] args) {

        // 0. 创建 User 对象
        User user = new User();
        user.setName("小马哥");
        // 1. 选择 Errors - BeanPropertyBindingResult
        Errors errors = new BeanPropertyBindingResult(user, "user");
        // 2. 调用 reject 或 rejectValue
        // reject 生成 ObjectError
        // reject 生成 FieldError
        errors.reject("user.properties.not.null");
        // user.name = user.getName()
        errors.rejectValue("name", "name.required");

        // 3. 获取 Errors 中 ObjectError 和 FieldError
        // FieldError is ObjectError
        List<ObjectError> globalErrors = errors.getGlobalErrors();
        List<FieldError> fieldErrors = errors.getFieldErrors();
        List<ObjectError> allErrors = errors.getAllErrors();

        // 4. 通过 ObjectError 和 FieldError 中的 code 和 args 来关联 MessageSource 实现
        MessageSource messageSource = createMessageSource();

        for (ObjectError error : allErrors) {
            String message = messageSource.getMessage(error.getCode(), error.getArguments(), Locale.getDefault());
            System.out.println(message);
        }
    }

    static MessageSource createMessageSource() {
        StaticMessageSource messageSource = new StaticMessageSource();
        messageSource.addMessage("user.properties.not.null", Locale.getDefault(), "User 所有属性不能为空");
        messageSource.addMessage("id.required", Locale.getDefault(), "the id of User must not be null.");
        messageSource.addMessage("name.required", Locale.getDefault(), "the name of User must not be null.");
        return messageSource;
    }
}

自定义 Validator

• 实现 org.springframework.validation.Validator 接口

  • 实现 supports 方法
  • 实现 validate 方法
    • 通过 Errors 对象收集错误
      • ObjectError:对象(Bean)错误:
      • FieldError:对象(Bean)属性(Property)错误
    • 通过 ObjectError 和 FieldError 关联 MessageSource 实现获取最终文案
/**
 * 自定义 Spring {@link Validator} 示例
 */
public class ValidatorDemo {

    public static void main(String[] args) {
        // 1. 创建 Validator
        Validator validator = new UserValidator();
        // 2. 判断是否支持目标对象的类型
        User user = new User();
        System.out.println("user 对象是否被 UserValidator 支持检验:" + validator.supports(user.getClass()));
        // 3. 创建 Errors 对象
        Errors errors = new BeanPropertyBindingResult(user, "user");
        validator.validate(user, errors);

        // 4. 获取 MessageSource 对象
        MessageSource messageSource = createMessageSource();

        // 5. 输出所有的错误文案
        for (ObjectError error : errors.getAllErrors()) {
            String message = messageSource.getMessage(error.getCode(), error.getArguments(), Locale.getDefault());
            System.out.println(message);
        }
    }

    static class UserValidator implements Validator {

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

        @Override
        public void validate(Object target, Errors errors) {
            User user = (User) target;
            ValidationUtils.rejectIfEmptyOrWhitespace(errors, "id", "id.required");
            ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "name.required");
            String userName = user.getName();
            // ...
        }
    }
}

Validator 的救赎

• Bean Validation 与 Validator 适配

  • 核心组件 - org.springframework.validation.beanvalidation.LocalValidatorFactoryBean
  • 依赖 Bean Validation - JSR-303 or JSR-349 provider
  • Bean 方法参数校验 - org.springframework.validation.beanvalidation.MethodValidationPostProcessor
<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <context:component-scan base-package="org.geekbang.thinking.in.spring.validation"/>

    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">

    </bean>

    <bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor">
        <property name="validator" ref="validator"/>
    </bean>

</beans>
/**
 * Spring Bean Validation 整合示例
 */
public class SpringBeanValidationDemo {

    public static void main(String[] args) {
        // 配置 XML 配置文件
        // 启动 Spring 应用上下文
        ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-validation-context.xml");

//        Validator validator = applicationContext.getBean(Validator.class);
//        System.out.println(validator instanceof LocalValidatorFactoryBean);

        UserProcessor userProcessor = applicationContext.getBean(UserProcessor.class);
        userProcessor.process(new User());

        // 关闭应用上下文
        applicationContext.close();
    }

    @Component
    @Validated
    static class UserProcessor {

        public void process(@Valid User user) {
            System.out.println(user);
        }

    }

    static class User {

        @NotNull
        private String name;

        public String getName() {
            return name;
        }

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

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
}

面试题

Spring 校验接口是哪个?
答:org.springframework.validation.Validator

Spring 有哪些校验核心组件?
答:
• 检验器:org.springframework.validation.Validator
• 错误收集器:org.springframework.validation.Errors
• Java Bean 错误描述:org.springframework.validation.ObjectError
• Java Bean 属性错误描述:org.springframework.validation.FieldError
• Bean Validation 适配:org.springframework.validation.beanvalidation.LocalValidatorFactoryBean

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值