在单据提交过程中,设置了一个必录字段fieldA,并开启了非空校验。同时,通过自定义操作插件为fieldA添加了额外的校验逻辑。当fieldA为空时,如果自定义校验器未先判空则可能报错。需求是当页面配置的校验器不通过时,不执行自定义校验器。通过分析源码得知,校验器按一定顺序(界面校验器在前,插件校验器在后)全部执行。解决方案是调整校验逻辑,确保在自定义校验前进行必要的条件判断,以避免不必要的执行。
问题:
单据中设置一个字段必录比如 fieldA,提交操作中开启了非空必录校验(保存不校验),自定义操作插件也通过
onAddValidators 添加 自定义校验器对fieldA进行特殊逻辑校验 。当提交时,如 fieldA 为空,并且自定义校验器对fieldA 使用前如未判空,则报错。
需求:
如果页面配置的校验器不通过,则不走自定义校验器校验逻辑。
思路与方案
首先需要了解苍穹校验器的执行逻辑,很多同学通过上面描述可以会认为自定义的校验器会首先执行,实际情况是先执行
校验规则列表上面的校验器(包括动态注册的自定义校验器),后再执行操作插件中的自定义校验器,并且所有校验器都会
执行,并不会因为校验规则列表上面的校验器执行不通过就不执行操作插件中的自定义校验器,所以导致的上述问题
源码解读校验器执行流程
首先,先了解校验器添加逻辑,添加校验器由EntityOperateService 实现
可以发现,校验器存放在有序列表中,添加后校验器的校验结果都是success 的,后续执行才修改校验结果,默认顺序为界面的校验器在前,操作插件中的校验器在后
注意:,此时只是单纯获取到所有校验器并添加到列表中,启动每个校验器的校验规则还没有执行,也就是说,
还没有执行
AbstractValidator中 validate() 方法
那具体执行是在什么时候呢
来到 ValidationService ,看代码,可以知道其通过 validate(ValidateContext validateContext) 一步一步执行到 AbstractValidator中 validate() 方法
public ValidateResultCollection validate(ValidateContext validateContext) { if (this.validators.isEmpty()) { return new ValidateResultCollection(); } else { //... this.validators.sort(new ValidatePriorityComparator());//此处做排序,无特殊配置顺序不变 Iterator var6 = this.validators.iterator(); while(var6.hasNext()) { //.... } // ... return this.validate(validateContext, this.validators); } } private ValidateResultCollection validate(ValidateContext validateContext, List<AbstractValidator> validators) { ... //开始按顺序遍历执行 Iterator var6 = validators.iterator(); while(true) { AbstractValidator validator; do { if (!var6.hasNext()) { ... return validateResults; } validator = (AbstractValidator)var6.next(); } while((ignoreInteraction || ignoreWarn) && validator.getErrorLevl() == ErrorLevel.Warning); this.doVaidate(validator, validateResults); } } private void doVaidate(AbstractValidator validator, ValidateResultCollection validateResults) { //... validator.validate(); // 此处调用 validate() 方法,并且可以会修改校验器的校验结果 ValidateResult res = validator.getValidateResult(); if (!res.isSuccess()) { //校验不成功是添加校验错误信息 // ... } //.... }
到此所有校验器全部执行完,同时可以知道每个校验器的执行结果,通过源码可以知道操作插件中的校验器一般为最后执行。
所以,来到最初问题,如何
如果页面配置的校验器不通过,则不走自定义校验器校验逻辑。
很简单,如下所示
推荐阅读