成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Spring方法級(jí)別數(shù)據(jù)校驗(yàn):@Validated + MethodValidationPostPr

孫吉亮 / 902人閱讀

摘要:就這樣借助相關(guān)約束注解,就非常簡(jiǎn)單明了,語(yǔ)義清晰的優(yōu)雅的完成了方法級(jí)別入?yún)⑿r?yàn)返回值校驗(yàn)的校驗(yàn)。但倘若是返回值校驗(yàn)執(zhí)行了即使是失敗了,方法體也肯定被執(zhí)行了只能哪些類(lèi)型上提出這個(gè)細(xì)節(jié)的目的是約束注解并不是能用在所有類(lèi)型上的。

每篇一句
在《深度工作》中作者提出這么一個(gè)公式:高質(zhì)量產(chǎn)出=時(shí)間*專(zhuān)注度。所以高質(zhì)量的產(chǎn)出不是靠時(shí)間熬出來(lái)的,而是效率為王
相關(guān)閱讀

【小家Java】深入了解數(shù)據(jù)校驗(yàn):Java Bean Validation 2.0(JSR303、JSR349、JSR380)Hibernate-Validation 6.x使用案例
【小家Java】深入了解數(shù)據(jù)校驗(yàn)(Bean Validation):基礎(chǔ)類(lèi)打點(diǎn)(ValidationProvider、ConstraintDescriptor、ConstraintValidator)
【小家Spring】詳述Spring對(duì)Bean Validation支持的核心API:Validator、SmartValidator、LocalValidatorFactoryBean...

對(duì)Spring感興趣可掃碼加入wx群:Java高工、架構(gòu)師3群(文末有二維碼)

前言

你在書(shū)寫(xiě)業(yè)務(wù)邏輯的時(shí)候,是否會(huì)經(jīng)常書(shū)寫(xiě)大量的判空校驗(yàn)。比如Service層或者Dao層的方法入?yún)?、入?yún)?duì)象、出參中你是否都有自己的一套校驗(yàn)規(guī)則?比如有些字段必傳,有的非必傳;返回值中有些字段必須有值,有的非必須等等~

如上描述的校驗(yàn)邏輯,窺探一下你的代碼,估摸里面有大量的if else吧。此部分邏輯簡(jiǎn)單(因?yàn)楹蜆I(yè)務(wù)關(guān)系不大)卻看起來(lái)眼花繚亂(趕緊偷偷去喵一下你自己的代碼吧,哈哈)。在攻城主鍵變大的時(shí)候,你會(huì)發(fā)現(xiàn)會(huì)有大量的重復(fù)代碼出現(xiàn),這部分就是你入職一個(gè)新公司的吐槽點(diǎn)之一:垃圾代碼。

若你追求干凈的代碼,甚至有代碼潔癖,如上眾多if else的重復(fù)無(wú)意義勞動(dòng)無(wú)疑是你的痛點(diǎn),那么本文應(yīng)該能夠幫到你。
Bean Validation校驗(yàn)其實(shí)是基于DDD思想設(shè)計(jì)的,我們雖然可以不完全的遵從這種思考方式編程,但是其優(yōu)雅的優(yōu)點(diǎn)還是可取的,本文將介紹Spring為此提供的解決方案~

效果示例

在講解之前,首先就來(lái)體驗(yàn)一把吧~

@Validated(Default.class)
public interface HelloService {
    Object hello(@NotNull @Min(10) Integer id, @NotNull String name);
}

// 實(shí)現(xiàn)類(lèi)如下
@Slf4j
@Service
public class HelloServiceImpl implements HelloService {
    @Override
    public Object hello(Integer id, String name) {
        return null;
    }
}

向容器里注冊(cè)一個(gè)處理器:

@Configuration
public class RootConfig {
    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }
}

測(cè)試:

@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {RootConfig.class})
public class TestSpringBean {
    @Autowired
    private HelloService helloService;

    @Test
    public void test1() {
        System.out.println(helloService.getClass());
        helloService.hello(1, null);
    }
}

結(jié)果如圖:

完美的校驗(yàn)住了方法入?yún)ⅰ?/p>

注意此處的一個(gè)小細(xì)節(jié):若你自己運(yùn)行這個(gè)案例你得到的參數(shù)名稱(chēng)可能是hello.args0等,而我此處是形參名。是因?yàn)槲沂褂肑ava8的編譯參數(shù):-parameters(此處說(shuō)一點(diǎn):若你的邏輯中強(qiáng)依賴(lài)于此參數(shù),務(wù)必在你的maven中加入編譯插件并且配置好此編譯參數(shù)

若需要校驗(yàn)方法返回值,改寫(xiě)如下:

    @NotNull
    Object hello(Integer id);

    // 此種寫(xiě)法效果同上
    //@NotNull Object hello(Integer id);

運(yùn)行:

javax.validation.ConstraintViolationException: hello.: 不能為null
...

校驗(yàn)完成。就這樣借助Spring+JSR相關(guān)約束注解,就非常簡(jiǎn)單明了,語(yǔ)義清晰的優(yōu)雅的完成了方法級(jí)別(入?yún)⑿r?yàn)、返回值校驗(yàn))的校驗(yàn)。
校驗(yàn)不通過(guò)的錯(cuò)誤信息,再來(lái)個(gè)全局統(tǒng)一的異常處理,就能讓整個(gè)工程都能盡顯完美之勢(shì)。(錯(cuò)誤消息可以從異常ConstraintViolationExceptiongetConstraintViolations()方法里獲得的~)

MethodValidationPostProcessor

它是Spring提供的來(lái)實(shí)現(xiàn)基于方法MethodJSR校驗(yàn)的核心處理器~它能讓約束作用在方法入?yún)?、返回?/b>上,如:

public @NotNull Object myValidMethod(@NotNull String arg1, @Max(10) int arg2)

官方說(shuō)明:方法里寫(xiě)有JSR校驗(yàn)注解要想其生效的話,要求類(lèi)型級(jí)別上必須使用@Validated標(biāo)注(還能指定驗(yàn)證的Group)

另外提示一點(diǎn):這個(gè)處理器同處理@Async的處理器AsyncAnnotationBeanPostProcessor非常相似,都是繼承自AbstractBeanFactoryAwareAdvisingPostProcessor 的,所以若有興趣再次也推薦@Async的分析博文,可以對(duì)比著觀看和記憶:【小家Spring】Spring異步處理@Async的使用以及原理、源碼分析(@EnableAsync)

// @since 3.1
public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor implements InitializingBean {
    // 備注:此處你標(biāo)注@Valid是無(wú)用的~~~Spring可不提供識(shí)別
    // 當(dāng)然你也可以自定義注解(下面提供了set方法~~~)
    // 但是注意:若自定義注解的話,此注解只決定了是否要代理,并不能指定分組哦  so,沒(méi)啥事別給自己找麻煩吧
    private Class validatedAnnotationType = Validated.class;
    // 這個(gè)是javax.validation.Validator
    @Nullable
    private Validator validator;

    // 可以自定義生效的注解
    public void setValidatedAnnotationType(Class validatedAnnotationType) {
        Assert.notNull(validatedAnnotationType, ""validatedAnnotationType" must not be null");
        this.validatedAnnotationType = validatedAnnotationType;
    }

    // 這個(gè)方法注意了:你可以自己傳入一個(gè)Validator,并且可以是定制化的LocalValidatorFactoryBean哦~(推薦)
    public void setValidator(Validator validator) {
        // 建議傳入LocalValidatorFactoryBean功能強(qiáng)大,從它里面生成一個(gè)驗(yàn)證器出來(lái)靠譜
        if (validator instanceof LocalValidatorFactoryBean) {
            this.validator = ((LocalValidatorFactoryBean) validator).getValidator();
        } else if (validator instanceof SpringValidatorAdapter) {
            this.validator = validator.unwrap(Validator.class);
        } else {
            this.validator = validator;
        }
    }
    // 當(dāng)然,你也可以簡(jiǎn)單粗暴的直接提供一個(gè)ValidatorFactory即可~
    public void setValidatorFactory(ValidatorFactory validatorFactory) {
        this.validator = validatorFactory.getValidator();
    }


    // 毫無(wú)疑問(wèn),Pointcut使用AnnotationMatchingPointcut,并且支持內(nèi)部類(lèi)哦~
    // 說(shuō)明@Aysnc使用的也是AnnotationMatchingPointcut,只不過(guò)因?yàn)樗С謽?biāo)注在類(lèi)上和方法上,所以最終是組合的ComposablePointcut
    
    // 至于Advice通知,此處一樣的是個(gè)`MethodValidationInterceptor`~~~~
    @Override
    public void afterPropertiesSet() {
        Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
        this.advisor = new DefaultPointcutAdvisor(pointcut, createMethodValidationAdvice(this.validator));
    }
    
    // 這個(gè)advice就是給@Validation的類(lèi)進(jìn)行增強(qiáng)的~  說(shuō)明:子類(lèi)可以覆蓋哦~
    // @since 4.2
    protected Advice createMethodValidationAdvice(@Nullable Validator validator) {
        return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor());
    }
}

它是個(gè)普通的BeanPostProcessor,為Bean創(chuàng)建的代理的時(shí)機(jī)是postProcessAfterInitialization(),也就是在Bean完成初始化后有必要的話用一個(gè)代理對(duì)象返回進(jìn)而交給Spring容器管理~(同@Aysnc
容易想到,關(guān)于校驗(yàn)方面的邏輯不在于它,而在于切面的通知:MethodValidationInterceptor

MethodValidationInterceptor

它是AOP聯(lián)盟類(lèi)型的通知,此處專(zhuān)門(mén)用于處理方法級(jí)別的數(shù)據(jù)校驗(yàn)。

注意理解方法級(jí)別:方法級(jí)別的入?yún)⒂锌赡苁歉鞣N平鋪的參數(shù)、也可能是一個(gè)或者多個(gè)對(duì)象
// @since 3.1  因?yàn)樗r?yàn)Method  所以它使用的是javax.validation.executable.ExecutableValidator
public class MethodValidationInterceptor implements MethodInterceptor {

    // javax.validation.Validator
    private final Validator validator;

    // 如果沒(méi)有指定校驗(yàn)器,那使用的就是默認(rèn)的校驗(yàn)器
    public MethodValidationInterceptor() {
        this(Validation.buildDefaultValidatorFactory());
    }
    public MethodValidationInterceptor(ValidatorFactory validatorFactory) {
        this(validatorFactory.getValidator());
    }
    public MethodValidationInterceptor(Validator validator) {
        this.validator = validator;
    }


    @Override
    @SuppressWarnings("unchecked")
    public Object invoke(MethodInvocation invocation) throws Throwable {
        // Avoid Validator invocation on FactoryBean.getObjectType/isSingleton
        // 如果是FactoryBean.getObject() 方法  就不要去校驗(yàn)了~
        if (isFactoryBeanMetadataMethod(invocation.getMethod())) {
            return invocation.proceed();
        }

        Class[] groups = determineValidationGroups(invocation);

        // Standard Bean Validation 1.1 API  ExecutableValidator是1.1提供的
        ExecutableValidator execVal = this.validator.forExecutables();
        Method methodToValidate = invocation.getMethod();
        Set> result; // 錯(cuò)誤消息result  若存在最終都會(huì)ConstraintViolationException異常形式拋出

        try {
            // 先校驗(yàn)方法入?yún)?            result = execVal.validateParameters(invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
        } catch (IllegalArgumentException ex) {
            // 此處回退了異步:找到bridged method方法再來(lái)一次
            methodToValidate = BridgeMethodResolver.findBridgedMethod(ClassUtils.getMostSpecificMethod(invocation.getMethod(), invocation.getThis().getClass()));
            result = execVal.validateParameters(invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
        }
        if (!result.isEmpty()) { // 有錯(cuò)誤就拋異常拋出去
            throw new ConstraintViolationException(result);
        }
        // 執(zhí)行目標(biāo)方法  拿到返回值后  再去校驗(yàn)這個(gè)返回值
        Object returnValue = invocation.proceed();
        result = execVal.validateReturnValue(invocation.getThis(), methodToValidate, returnValue, groups);
        if (!result.isEmpty()) {
            throw new ConstraintViolationException(result);
        }

        return returnValue;
    }


    // 找到這個(gè)方法上面是否有標(biāo)注@Validated注解  從里面拿到分組信息
    // 備注:雖然代理只能標(biāo)注在類(lèi)上,但是分組可以標(biāo)注在類(lèi)上和方法上哦~~~~ 
    protected Class[] determineValidationGroups(MethodInvocation invocation) {
        Validated validatedAnn = AnnotationUtils.findAnnotation(invocation.getMethod(), Validated.class);
        if (validatedAnn == null) {
            validatedAnn = AnnotationUtils.findAnnotation(invocation.getThis().getClass(), Validated.class);
        }
        return (validatedAnn != null ? validatedAnn.value() : new Class[0]);
    }
}

這個(gè)Advice的實(shí)現(xiàn),簡(jiǎn)單到不能再簡(jiǎn)單了,稍微有點(diǎn)基礎(chǔ)的應(yīng)該都能很容易看懂吧(據(jù)我不完全估計(jì)這個(gè)應(yīng)該是最簡(jiǎn)單的)。

==使用細(xì)節(jié)==(重要)

文首雖然已經(jīng)給了一個(gè)使用示例,但是那畢竟只是局部。在實(shí)際生產(chǎn)使用中,比如上面理論更重要的是一些使用細(xì)節(jié)(細(xì)節(jié)往往是區(qū)分你是不是高手的地方),這里從我使用的經(jīng)驗(yàn)中,總結(jié)如下幾點(diǎn)供給大家參考(基本算是分享我躺過(guò)的坑)

使用@Validated去校驗(yàn)方法Method,不管從使用上還是原理上,都是非常簡(jiǎn)單和簡(jiǎn)約的,建議大家在企業(yè)應(yīng)用中多多使用。
1、約束注解(如@NotNull)不能放在實(shí)體類(lèi)上

一般情況下,我們對(duì)于Service層驗(yàn)證(Controller層一般都不給接口),大都是面向接口編程和使用,那么這種@NotNull放置的位置應(yīng)該怎么放置呢?

看這個(gè)例子:

public interface HelloService {
    Object hello(@NotNull @Min(10) Integer id, @NotNull String name);
}

@Validated(Default.class)
@Slf4j
@Service
public class HelloServiceImpl implements HelloService {
    @Override
    public Object hello(Integer id, String name) {
        return null;
    }
}

約束條件都寫(xiě)在實(shí)現(xiàn)類(lèi)上,按照我們所謂的經(jīng)驗(yàn),應(yīng)該是不成問(wèn)題的。但運(yùn)行:

javax.validation.ConstraintDeclarationException: HV000151: A method overriding another method must not redefine the parameter constraint configuration, but method HelloServiceImpl#hello(Integer) redefines the configuration of HelloService#hello(Integer).

    at org.hibernate.validator.internal.metadata.aggregated.rule.OverridingMethodMustNotAlterParameterConstraints.apply(OverridingMethodMustNotAlterParameterConstraints.java:24)
...
重說(shuō)三:請(qǐng)務(wù)必注意請(qǐng)務(wù)必注意請(qǐng)務(wù)必注意這個(gè)異常是javax.validation.ConstraintDeclarationException,而不是錯(cuò)誤校驗(yàn)錯(cuò)誤異常javax.validation.ConstraintViolationException。請(qǐng)?jiān)谧鋈之惓2东@的時(shí)候一定要區(qū)分開(kāi)來(lái)~

異常信息是說(shuō)parameter constraint configuration在校驗(yàn)方法入?yún)?/strong>的約束時(shí),若是@Override父類(lèi)/接口的方法,那么這個(gè)入?yún)⒓s束只能寫(xiě)在父類(lèi)/接口上面~~~

至于為什么只能寫(xiě)在接口處,這個(gè)具體原因其實(shí)是和Bean Validation的實(shí)現(xiàn)產(chǎn)品有關(guān)的,比如使用的Hibernate校驗(yàn),原因可參考它的此類(lèi):OverridingMethodMustNotAlterParameterConstraints

還需注意一點(diǎn):若實(shí)現(xiàn)類(lèi)寫(xiě)的約束和接口一模一樣,那也是沒(méi)問(wèn)題的。比如上面若實(shí)現(xiàn)類(lèi)這么寫(xiě)是沒(méi)有問(wèn)題能夠完成正常校驗(yàn)的:

    @Override
    public Object hello(@NotNull @Min(10) Integer id, @NotNull String name) {
        return null;
    }

雖然能正常work完成校驗(yàn),但需要深刻理解一模一樣這四個(gè)字。簡(jiǎn)單的說(shuō)把10改成9都會(huì)報(bào)ConstraintDeclarationException異常,更別談移除某個(gè)注解了(不管多少字段多少注解,但凡只要寫(xiě)了一個(gè)就必須保證一模一樣)。

關(guān)于@Override方法校驗(yàn)返回值方面:即使寫(xiě)在實(shí)現(xiàn)類(lèi)里也不會(huì)拋ConstraintDeclarationException
另外@Validated注解它寫(xiě)在實(shí)現(xiàn)類(lèi)/接口上均可~

最后你應(yīng)該自己領(lǐng)悟到:若入?yún)⑿r?yàn)失敗了,方法體是不會(huì)執(zhí)行的。但倘若是返回值校驗(yàn)執(zhí)行了(即使是失敗了),方法體也肯定被執(zhí)行了~~
2、@NotEmpty/@NotBlank只能哪些類(lèi)型上?

提出這個(gè)細(xì)節(jié)的目的是:約束注解并不是能用在所有類(lèi)型上的。比如若你把@NotEmpty讓它去驗(yàn)證Object類(lèi)型,它會(huì)報(bào)錯(cuò)如下:

javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint "javax.validation.constraints.NotEmpty" validating type "java.lang.Object". Check configuration for "hello."
需要強(qiáng)調(diào)的是:若標(biāo)注在方法上是驗(yàn)證返回值的,這個(gè)時(shí)候方法體是已經(jīng)執(zhí)行了的,這個(gè)和ConstraintDeclarationException不一樣~

對(duì)這兩個(gè)注解依照官方文檔做如下簡(jiǎn)要說(shuō)明。@NotEmpty只能標(biāo)注在如下類(lèi)型

CharSequence

Collection

Map

Array

注意:""它是空的,但是" "就不是了

@NotBlank只能使用在CharSequence上,它是Bean Validation 2.0新增的注解~

3、接口和實(shí)現(xiàn)類(lèi)上都有注解,以誰(shuí)為準(zhǔn)?

這個(gè)問(wèn)題有個(gè)隱含條件:只有校驗(yàn)方法返回值時(shí)才有這種可能性。

public interface HelloService {
    @NotEmpty String hello(@NotNull @Min(10) Integer id, @NotNull String name);
}

@Slf4j
@Service
@Validated(Default.class)
public class HelloServiceImpl implements HelloService {
    @Override
    public @NotNull String hello(Integer id, String name) {
        return "";
    }
}

運(yùn)行案例,helloService.hello(18, "fsx");打印如下:

javax.validation.ConstraintViolationException: hello.: 不能為空
...

到這里,可能有小伙伴就會(huì)早早下結(jié)論:當(dāng)同時(shí)存在時(shí),以接口的約束為準(zhǔn)。
那么,我只把返回值稍稍修改,你再看一下呢???

    @Override
    public @NotNull String hello(Integer id, String name) {
        return null; // 返回值改為null
    }

再運(yùn)行:

javax.validation.ConstraintViolationException: hello.: 不能為空, hello.: 不能為null
...

透過(guò)打印的信息,結(jié)論就自然不必我多。但是有個(gè)道理此處可說(shuō)明:大膽猜測(cè),小心求證

4、如何校驗(yàn)級(jí)聯(lián)屬性?

在實(shí)際開(kāi)發(fā)中,其實(shí)大多數(shù)情況下我們方法入?yún)⑹莻€(gè)對(duì)象(甚至對(duì)象里面有對(duì)象),而不是單單平鋪的參數(shù),因此就介紹一個(gè)級(jí)聯(lián)屬性校驗(yàn)的例子

@Getter
@Setter
@ToString
public class Person {

    @NotNull
    private String name;
    @NotNull
    @Positive
    private Integer age;

    @Valid // 讓InnerChild的屬性也參與校驗(yàn)
    @NotNull
    private InnerChild child;

    @Getter
    @Setter
    @ToString
    public static class InnerChild {
        @NotNull
        private String name;
        @NotNull
        @Positive
        private Integer age;
    }

}

public interface HelloService {
    String cascade(@NotNull @Valid Person father, @NotNull Person mother);
}

@Slf4j
@Service
@Validated(Default.class)
public class HelloServiceImpl implements HelloService {
    @Override
    public String cascade(Person father, Person mother) {
        return "hello cascade...";
    }
}

運(yùn)行測(cè)試用例:

    @Test
    public void test1() {
        helloService.cascade(null, null);
    }

輸出如下:

cascade.father: 不能為null, cascade.mother: 不能為null

此處說(shuō)明一點(diǎn):若你father前面沒(méi)加@NotNull,那打印的消息只有:cascade.mother: 不能為null

我把測(cè)試用例改造如下,你繼續(xù)感受一把:

    @Test
    public void test1() {
        Person father = new Person();
        father.setName("fsx");
        Person.InnerChild innerChild = new Person.InnerChild();
        innerChild.setAge(-1);
        father.setChild(innerChild);

        helloService.cascade(father, new Person());
    }

錯(cuò)誤消息如下(請(qǐng)小伙伴仔細(xì)觀察和分析緣由):

cascade.father.age: 不能為null, cascade.father.child.name: 不能為null, cascade.father.child.age: 必須是正數(shù)

思考:為何mother的相關(guān)屬性以及子屬性為何全都沒(méi)有校驗(yàn)?zāi)兀?/p> 5、循環(huán)依賴(lài)問(wèn)題

上面說(shuō)了Spring對(duì)@Validated的處理和對(duì)@Aysnc的代理邏輯是差不多的,有了之前的經(jīng)驗(yàn),很容易想到它也存在著如題的問(wèn)題:比如HelloService的A方法想調(diào)用本類(lèi)的B方法,但是很顯然我是希望B方法的方法校驗(yàn)是能生效的,因此其中一個(gè)做法就是注入自己,使用自己的代理對(duì)象來(lái)調(diào)用:

public interface HelloService {
    Object hello(@NotNull @Min(10) Integer id, @NotNull String name);
    String cascade(@NotNull @Valid Person father, @NotNull Person mother);
}

@Slf4j
@Service
@Validated(Default.class)
public class HelloServiceImpl implements HelloService {

    @Autowired
    private HelloService helloService;

    @Override
    public Object hello(@NotNull @Min(10) Integer id, @NotNull String name) {
        helloService.cascade(null, null); // 調(diào)用本類(lèi)方法
        return null;
    }

    @Override
    public String cascade(Person father, Person mother) {
        return "hello cascade...";
    }
}

運(yùn)行測(cè)試用例:

    @Test
    public void test1() {
        helloService.hello(18, "fsx"); // 入口方法校驗(yàn)通過(guò),內(nèi)部調(diào)用cascade方法希望繼續(xù)得到校驗(yàn)
    }

運(yùn)行報(bào)錯(cuò):

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name "helloServiceImpl": Bean with name "helloServiceImpl" has been injected into other beans [helloServiceImpl] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using "getBeanNamesOfType" with the "allowEagerInit" flag turned off, for example.
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean
...

這個(gè)報(bào)錯(cuò)消息不可為不熟悉。關(guān)于此現(xiàn)象,之前做過(guò)非常非常詳細(xì)的說(shuō)明并且提供了多種解決方案,所以此處略過(guò)。

若關(guān)于此問(wèn)的原因和解決方案不明白的,請(qǐng)移步此處:【小家Spring】使用@Async異步注解導(dǎo)致該Bean在循環(huán)依賴(lài)時(shí)啟動(dòng)報(bào)BeanCurrentlyInCreationException異常的根本原因分析,以及提供解決方案

雖然我此處不說(shuō)解決方案,但我提供問(wèn)題解決后運(yùn)行的打印輸出情況,供給小伙伴調(diào)試參考,此舉很暖心有木有:

javax.validation.ConstraintViolationException: cascade.mother: 不能為null, cascade.father: 不能為null
...
總結(jié)

本文介紹了Spring提供給我們方法級(jí)別校驗(yàn)的能力,在企業(yè)應(yīng)用中使用此種方式完成絕大部分的基本校驗(yàn)工作,能夠讓我們的代碼更加簡(jiǎn)潔、可控并且可擴(kuò)展,因此我是推薦使用和擴(kuò)散的~

在文末有必要強(qiáng)調(diào)一點(diǎn):關(guān)于上面級(jí)聯(lián)屬性的校驗(yàn)時(shí)使用的@Valid注解你使用@Validated可替代不了,不會(huì)有效果的。
至于有小伙伴私信我疑問(wèn)的問(wèn)題:為何他Controller方法中使用@Valid@Validated均可,并且網(wǎng)上同意給的答案都是都可用,差不多???還是那句話:這是下篇文章的重點(diǎn),請(qǐng)持續(xù)關(guān)注~

稍稍說(shuō)一下它的弊端:因?yàn)樾r?yàn)失敗它最終采用的是拋異常方式來(lái)中斷,因此效率上有那么一丟丟的損耗。but,你的應(yīng)用真的需要考慮這種極致性能問(wèn)題嗎?這才是你該思考的~
知識(shí)交流
若文章格式混亂,可點(diǎn)擊:原文鏈接-原文鏈接-原文鏈接-原文鏈接-原文鏈接

==The last:如果覺(jué)得本文對(duì)你有幫助,不妨點(diǎn)個(gè)贊唄。當(dāng)然分享到你的朋友圈讓更多小伙伴看到也是被作者本人許可的~==

**若對(duì)技術(shù)內(nèi)容感興趣可以加入wx群交流:Java高工、架構(gòu)師3群。
若群二維碼失效,請(qǐng)加wx號(hào):fsx641385712(或者掃描下方wx二維碼)。并且備注:"java入群" 字樣,會(huì)手動(dòng)邀請(qǐng)入群**

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/75584.html

相關(guān)文章

  • @Validated和@Valid的區(qū)別?校驗(yàn)級(jí)聯(lián)屬性(內(nèi)部類(lèi))

    摘要:畢竟永遠(yuǎn)相信本文能給你帶來(lái)意想不到的收獲使用示例關(guān)于數(shù)據(jù)校驗(yàn)這一塊在中的使用案例,我相信但凡有點(diǎn)經(jīng)驗(yàn)的程序員應(yīng)該沒(méi)有不會(huì)使用的,并且還不乏熟練的選手。 每篇一句 NBA里有兩大笑話:一是科比沒(méi)天賦,二是詹姆斯沒(méi)技術(shù) 相關(guān)閱讀 【小家Java】深入了解數(shù)據(jù)校驗(yàn):Java Bean Validation 2.0(JSR303、JSR349、JSR380)Hibernate-Validati...

    Winer 評(píng)論0 收藏0
  • 讓Controller支持對(duì)平鋪參數(shù)執(zhí)行@Valid數(shù)據(jù)校驗(yàn)

    摘要:方案一借助對(duì)方法級(jí)別數(shù)據(jù)校驗(yàn)的能力首先必須明確一點(diǎn)此能力屬于框架的,而部分框架。 每篇一句 在金字塔塔尖的是實(shí)踐,學(xué)而不思則罔,思而不學(xué)則殆(現(xiàn)在很多編程框架都只是教你碎片化的實(shí)踐) 相關(guān)閱讀 【小家Java】深入了解數(shù)據(jù)校驗(yàn):Java Bean Validation 2.0(JSR303、JSR349、JSR380)Hibernate-Validation 6.x使用案例【小家Spr...

    printempw 評(píng)論0 收藏0
  • 使用spring validation 作為數(shù)據(jù)校驗(yàn)

    摘要:本文主要介紹在中自動(dòng)校驗(yàn)的機(jī)制。引入依賴(lài)我們使用構(gòu)建應(yīng)用來(lái)進(jìn)行演示。在中校驗(yàn)數(shù)據(jù)值得注意的地方參數(shù)前需要加上注解,表明需要對(duì)其進(jìn)行校驗(yàn),而校驗(yàn)的信息會(huì)存放到其后的中。層改寫(xiě)方法限定需要進(jìn)行校驗(yàn),而方法則不做限制。 簡(jiǎn)介 JSR303/JSR-349,hibernate validation,spring validation之間的關(guān)系。JSR303是一項(xiàng)標(biāo)準(zhǔn),JSR-349是其的升級(jí)版...

    huangjinnan 評(píng)論0 收藏0
  • Spring Boot - 表單校驗(yàn)(JSR303&Hibernate Validator)

    摘要:初步使用主要使用注解的方式對(duì)進(jìn)行校驗(yàn),第一個(gè)例子在需要校驗(yàn)的字段上指定約束條件然后在中可以這樣調(diào)用,加上注解即可。如果校驗(yàn)失敗,默認(rèn)會(huì)返回框架的出錯(cuò)信息。指定到的分組名會(huì)全部進(jìn)行校驗(yàn),不指定的不校驗(yàn)。 Spring Boot - 表單校驗(yàn)(JSR303&Hibernate Validator) 回顧 Spring Boot - 初識(shí) Hello World Spring Boot -...

    tinyq 評(píng)論0 收藏0
  • 從深處去掌握數(shù)據(jù)校驗(yàn)@Valid的作用(級(jí)聯(lián)校驗(yàn)

    摘要:如果說(shuō)要使用數(shù)據(jù)校驗(yàn),我十分相信小伙伴們都能夠使用,但估計(jì)大都是有個(gè)前提的環(huán)境。具體使用可參考小家讓支持對(duì)平鋪參數(shù)執(zhí)行數(shù)據(jù)校驗(yàn)?zāi)J(rèn)使用只能對(duì)進(jìn)行校驗(yàn)級(jí)聯(lián)校驗(yàn)什么叫級(jí)聯(lián)校驗(yàn),其實(shí)就是帶校驗(yàn)的成員里存在級(jí)聯(lián)對(duì)象時(shí),也要對(duì)它完成校驗(yàn)。 每篇一句 NBA里有兩大笑話:一是科比沒(méi)天賦,二是詹姆斯沒(méi)技術(shù) 相關(guān)閱讀 【小家Java】深入了解數(shù)據(jù)校驗(yàn):Java Bean Validation 2.0(...

    BlackFlagBin 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<