美文网首页
Spring Boot 集成 fluent-validator

Spring Boot 集成 fluent-validator

作者: 那个初衷 | 来源:发表于2018-05-30 17:26 被阅读0次

    Spring Boot 集成fluent-validator

    阅读本文之前,请先熟读官网文档


    阅读总结

    1. 验证结果对象
    // 省缺结果对象:
    toSimple() ---> Result
    toComplex() ---> ComplexResult
    
    // 如果你想自己实现一个结果类型,完全可以定制,实现ResultCollector接口即可
    ResultCollector<T>
    
    1. 错误消息抛出
    context.addErrorMsg("Something is wrong about the car seat count!");
    // 简单错误消息
    context.addError(ValidationError.create("Something is wrong about the car seat count!").setErrorCode(100).setField("seatCount").setInvalidValue(t));
    // 完整错误消息
    
    
    1. 验证器
    Validator<T> // 验证器
    ValidatorChain // 调用链
    onEach //验证集合
    failFast() // 校验一个错误打回
    failOver() // 完成所有检验打回
    when() // 满足条件进行校验
    ValidateCallback // doValidate()方法接受一个ValidateCallback接口
    

    ......

    冗余的东西就不多写了,剩下的全都融合到Spring Boot的集成里去,官方文档写的很好,推荐耐心嚼烂。

    开始集成

    pox.xml文件
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.example</groupId>
        <artifactId>demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
    
        <name>demo</name>
        <description>Demo project for Spring Boot</description>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.2.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>com.baidu.unbiz</groupId>
                <artifactId>fluent-validator-spring</artifactId>
                <version>1.0.9</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.slf4j</groupId>
                        <artifactId>slf4j-log4j12</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    
    </project>
    
    
    创建实体类Car

    可以看到我们用了HibernateValidator与fluent-validator验证注解,HibernateValidator负责简单的校验,fluent-validato去校验我们更高级的业务逻辑。

    package com.example.demo.entity;
    
    import com.baidu.unbiz.fluentvalidator.annotation.FluentValidate;
    import com.example.demo.fluent.validator.CarSeatCountValidator;
    import org.hibernate.validator.constraints.NotEmpty;
    
    import javax.validation.constraints.NotNull;
    import javax.validation.constraints.Pattern;
    
    /**
     * @Author Z.xichao
     * @Create 2018-5-30
     * @Comments
     */
    public class Car {
    
        @NotEmpty(message = "厂商信息不能为空")
        @Pattern(regexp = "[0-9a-zA-Z\4e00-\u9fa5]+",message = "厂商信息字符不合法")
        private String manufacturer;
    
        @NotNull(message = "车牌号不能为空")
        private String licensePlate;
    
        @FluentValidate({CarSeatCountValidator.class})
        private int seatCount;
    
        public String getManufacturer() {
            return manufacturer;
        }
    
        public void setManufacturer(String manufacturer) {
            this.manufacturer = manufacturer;
        }
    
        public String getLicensePlate() {
            return licensePlate;
        }
    
        public void setLicensePlate(String licensePlate) {
            this.licensePlate = licensePlate;
        }
    
        public int getSeatCount() {
            return seatCount;
        }
    
        public void setSeatCount(int seatCount) {
            this.seatCount = seatCount;
        }
    }
    
    
    Validator 校验器
    package com.example.demo.fluent.validator;
    
    import com.baidu.unbiz.fluentvalidator.ValidationError;
    import com.baidu.unbiz.fluentvalidator.Validator;
    import com.baidu.unbiz.fluentvalidator.ValidatorContext;
    import com.baidu.unbiz.fluentvalidator.ValidatorHandler;
    import org.springframework.stereotype.Component;
    
    /**
     * @Author Z.xichao
     * @Create 2018-5-30
     * @Comments
     */
    @Component
    public class CarSeatCountValidator extends ValidatorHandler<Integer> implements Validator<Integer> {
    
        @Override
        public boolean validate(ValidatorContext context, Integer t) {
            if (t < 2) {
                context.addError(ValidationError.create("Something is wrong about the car seat count!").setErrorCode(100).setField("seatCount").setInvalidValue(t));
                return false;
            }
            return true;
        }
    }
    
    
    验证回调 ValidateCarCallback
    package com.example.demo.validate_car_callback;
    
    import com.baidu.unbiz.fluentvalidator.ValidateCallback;
    import com.baidu.unbiz.fluentvalidator.ValidationError;
    import com.baidu.unbiz.fluentvalidator.Validator;
    import com.baidu.unbiz.fluentvalidator.validator.element.ValidatorElementList;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @Author Z.xichao
     * @Create 2018-5-30
     * @Comments
     */
    @Component
    public class ValidateCarCallback implements ValidateCallback {
        /**
         * 所有验证完成并且成功后
         *
         * @param validatorElementList 验证器list
         */
        @Override
        public void onSuccess(ValidatorElementList validatorElementList) {
            System.out.println("Everything works fine!");
        }
    
        /**
         * 所有验证步骤结束,发现验证存在失败后
         *
         * @param validatorElementList 验证器list
         * @param errors               验证过程中发生的错误
         */
        @Override
        public void onFail(ValidatorElementList validatorElementList, List<ValidationError> errors) {
            throw new RuntimeException(errors.get(0).getErrorMsg()); //可自定义异常
        }
    
        /**
         * 执行验证过程中发生了异常后
         *
         * @param validator 验证器
         * @param e         异常
         * @param target    正在验证的对象
         * @throws Exception
         */
        @Override
        public void onUncaughtException(Validator validator, Exception e, Object target) throws Exception {
            throw new RuntimeException(e); //可自定义异常
        }
    }
    
    
    配置拦截器
    package com.example.demo.config;
    
    import com.baidu.unbiz.fluentvalidator.interceptor.FluentValidateInterceptor;
    import com.example.demo.validate_car_callback.ValidateCarCallback;
    import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    
    /**
     * @Author Z.xichao
     * @Create 2018-5-30
     * @Comments
     */
    @Configuration
    public class FluentValidatorConfiguration {
    
        @Autowired
        private ValidateCarCallback validateCarCallback; // 注入我们的验证回调
    
        @Bean("fluentValidateInterceptor")
        public FluentValidateInterceptor fluentValidateInterceptor(){
            FluentValidateInterceptor validateInterceptor = new FluentValidateInterceptor();
            validateInterceptor.setCallback(validateCarCallback);
            validateInterceptor.setLocale("zh_CN");
            validateInterceptor.setHibernateDefaultErrorCode(10000);
            return  validateInterceptor;
        }
    
        @Bean
        public BeanNameAutoProxyCreator beanNameAutoProxyCreator(){
            BeanNameAutoProxyCreator proxyCreator = new BeanNameAutoProxyCreator();
            proxyCreator.setBeanNames("*Controller"); // 配置拦截对象 如拦截service(*ServiceImpl)
            proxyCreator.setInterceptorNames("fluentValidateInterceptor");
            return proxyCreator;
        }
    }
    
    
    
    好了万事俱备,只欠东风,让我们跑起来!!
    package com.example.demo.controller;
    
    import com.baidu.unbiz.fluentvalidator.annotation.FluentValid;
    import com.example.demo.entity.Car;
    import com.example.demo.service.CarService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @Author Z.xichao
     * @Create 2018-5-30
     * @Comments
     */
    @RestController
    public class TestController {
    
        @Autowired
        private CarService carService;
    
        @RequestMapping("/")
        public void root(@FluentValid Car car) {
            carService.addCart(car);
        }
    }
    
    

    访问http://localhost:8080/?manufacturer=aa&licensePlate=b

    2018-05-30 17:47:24.128  INFO 5108 --- [  restartedMain] .ConditionEvaluationDeltaLoggingListener : Condition evaluation unchanged
    2018-05-30 17:47:44.171  INFO 5108 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
    2018-05-30 17:47:44.171  INFO 5108 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
    2018-05-30 17:47:44.174  INFO 5108 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 3 ms
    2018-05-30 17:47:44.182  INFO 5108 --- [nio-8080-exec-1] c.b.u.f.AnnotationValidatorCache         : Cached validator CarSeatCountValidator
    2018-05-30 17:47:44.187 ERROR 5108 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: [ValidationError{errorCode=100, errorMsg='Something is wrong about the car seat count!', field='seatCount', invalidValue=0}]] with root cause
    
    java.lang.RuntimeException: [ValidationError{errorCode=100, errorMsg='Something is wrong about the car seat count!', field='seatCount', invalidValue=0}]
        at com.example.demo.validate_car_callback.ValidateCarCallback.onFail(ValidateCarCallback.java:36) ~[classes/:na]
        at com.baidu.unbiz.fluentvalidator.FluentValidator.doValidate(FluentValidator.java:518) ~[fluent-validator-1.0.9.jar:na]
        at com.baidu.unbiz.fluentvalidator.interceptor.FluentValidateInterceptor.invoke(FluentValidateInterceptor.java:189) ~[fluent-validator-spring-1.0.9.jar:na]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.6.RELEASE.jar:5.0.6.RELEASE]
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.0.6.RELEASE.jar:5.0.6.RELEASE]
        at com.example.demo.controller.TestController$$EnhancerBySpringCGLIB$$feb78357.root(<generated>) ~[classes/:na]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_45]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_45]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_45]
        at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_45]
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) ~[spring-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) ~[spring-web-5.0.6.RELEASE.jar:5.0.6.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877) ~[spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783) ~[spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) ~[spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) ~[spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) ~[spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866) ~[spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) ~[tomcat-embed-core-8.5.31.jar:8.5.31]
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851) ~[spring-webmvc-5.0.6.RELEASE.jar:5.0.6.RELEASE]
    

    结语

    本篇博客能算个学习笔记,然后拿大家一起分享。重在抛砖引玉,可能以后会继续完善,先留几个坑。

    比如context上下文共享、闭包、以及验证器的配置、when()、failFast()、failOver()等都要考虑怎么活用。总之先到这吧。各位道友,我们昆仑山见!



    参考资料

    相关文章

      网友评论

          本文标题:Spring Boot 集成 fluent-validator

          本文链接:https://www.haomeiwen.com/subject/aqdxsftx.html