在Nop平台中对请求数据或者业务对象状态进行验证可以通过validator模型进行。
视频: 如何将Validator DSL嵌入到程序中实现验证逻辑
具体做法:
在validator.xml 模型文件中定义验证逻辑。validator内部可以分为多个check步骤, 每个步骤对应一个判断条件,条件不匹配的时候将抛出对应的异常码和异常消息。
具体判断条件的格式由元模型filter.xdef 规定。 在其中可以写and/or/not等嵌套条件,可以通过eq/gt/ge等实现比较判断。name属性对应于上下文环境中的变量以及变量上的属性。
在调用validator模型的时候需要传入上下文环境对象。
<validator fatalSeverity="100" x:schema="/nop/schema/validator.xdef" xmlns:x="/nop/schema/xdsl.xdef">
<check id="checkTransferCode" errorCode="test.not-transfer-code" errorDescription="扫入的码不是流转码">
<eq name="entity.flowMode" value="1"/>
</check>
</validator>
在Java中可以通过BizValidatorHelper类上的帮助函数runValidator来调用validator模型。vars为传入的上下文环境对象。 validator模型中执行条件判断时,所使用的name属性对应于vars中的变量及其属性。
Map<String,Object> vars = new HashMap<>();
vars.put("entity", myEntity);
BizValidatorHelper.runValidator("/nop/demo/validator/process-card.validator.xml",
vars, context);
Nop平台中的后台服务函数不一定在Java类中实现。在进行无代码开发的时候,后台服务函数可以写在xbiz模型文件中,biz模型支持在线编辑、动态加载, 在不停机的情况下可以增加后台GraphQL服务函数,并立刻起效。
比如Demo.xbiz 模型中定义的 testValidator2和testValidator3函数,它们的作用和DemoBizModel 类中定义的testValidator函数的作用完全等价。
testValidator3函数通过biz:RunValidator
标签函数来装载外部的validator模型文件,并执行验证逻辑。这样做的好处是未来可以通过Delta定制机制来修改验证逻辑,而不用修改Demo.xbiz文件。
<biz:RunValidator xpl:lib="/nop/core/xlib/biz.xlib"
validatorPath="/nop/demo/validator/process-card.validator.xml"
obj="${{entity,firstProductionOrder:entity.productionOrder,firstMaterial}}"/>
Biz模型是XML格式,因此可以通过一个可视化设计器来在线设计Biz模型。对于具体的Action,也可以通过可视化拖拽的方式来实现。 例如,将
<biz:RunValidator>
标签看作是一个组件,validatorPath等是组件的属性,可以从面板中拖拽对应的组件到Action容器中,从而实现可视化的逻辑编排
Demo.xbiz文件中的testValidator2函数演示了另外一种执行Validator验证逻辑的方式。它通过宏标签将Validator模型嵌入到Biz模型中, 在编译宏标签的时候将会把对应节点的内容传入ValidatorParser中进行解析得到ValidatorModel,在运行期直接使用作为全局变量存在的ValidatorModel即可。
<biz:Validator xpl:lib="/nop/core/xlib/biz.xlib" fatalSeverity="100"
obj="${{entity,firstProductionOrder:entity.productionOrder,firstMaterial}}">
<check id="checkTransferCode" errorCode="test.not-transfer-code"
errorDescription="扫入的码不是流转码">
<eq name="entity.flowMode" value="1"/>
</check>
</biz:Validator>
-
一般情况下validator执行的时候会收集所有check的错误,然后一次性抛出异常消息。如果需要发现错误就抛出,则可以配置fatalSeverity属性, 当check的severity>=fatalSeverity的时候就会中断执行,直接抛出异常。
-
errorCode对应的是异常码,可以在i18n国际化文件中配置异常码所对应的异常消息,它会覆盖errorDescription配置
-
在errorDescription中可以通过
{paramName}
这种形式来引用异常参数。通过errorParams="a=expr,b"这种形式来捕获上下文环境中的变量信息作为异常参数。
<check id="checkMaterial" errorCode="test.inconsistent-material"
errorDescription="扫入的流转码物料不一致:物料ID={materialId}" errorParams="materialId=entity.materialId" severity="100">
<eq name="entity.materialId" valueName="firstMaterial.materialId"/>
</check>
在/nop/core/xlib/biz!check.xlib标签库中可以定义扩展标签。然后在check段中就可以使用。
<check id="checkStatus" errorCode="test.invalid-status" errorDescription="错误的状态码">
<biz:InDict name="entity.status" dictName="core/active-status" />
</check>
通过register-model.xml 可以将自定义模型的加载器注册到Nop平台中,这样通过统一的ResourceComponentManager.loadComponentModel函数就可以加载平台中注册的所有种类的模型。
<model x:schema="/nop/schema/register-model.xdef" xmlns:x="/nop/schema/xdsl.xdef"
name="orm">
<loaders>
<xdsl-loader fileType="validator.xml" schemaPath="/nop/schema/validator.xdef"/>
</loaders>
</model>
register-model.xml中注册特定后缀的文件,比如validator.xml后缀,对应于哪个元模型。
- 多种后缀的模型文件可以解析得到同一种模型对象。比如api模型可以采用api.xml文件定义,也可以通过Excel模型文件来定义。
<model x:schema="/nop/schema/register-model.xdef" xmlns:x="/nop/schema/xdsl.xdef"
name="api">
<loaders>
<xlsx-loader fileType="api.xlsx" impPath="/nop/graphql/imp/api.imp.xml"/>
<xdsl-loader fileType="api.xml" schemaPath="/nop/schema/api.xdef"/>
</loaders>
</model>