版权声明:
本文为博主原创文章,未经博主容许不得转载。关注公众号 技术汇(ID: jishuhui_2015) 可联系到做者。
在上两篇文章中,介绍了BPMN2.0和工做流定义语言(如下简称WDL),以及工单系统的业务流程设计。本文是工单系统系列的最后一篇,着重讲解工单系统的程序设计。segmentfault
由于全部流程的配置和定义都在WDL文件中,因此必然会引入关于WDL的解析层,这是整个工单系统的基础。架构
除了解析层,还少不了执行层的存在,整个工单流程就是靠执行层去推进的。框架
若是对Activiti的源码有所钻研的读者,看完此篇文章后,会以为很是相似,这是不能否认的,站在巨人的肩膀上才能看得更远更全。工具
Activiti:一直被模仿,从未被超越。
这部份内容主要介绍WDL中各元素的设计,它们有个统一的名字:BpmnModel。这个名字来源于Activiti的源码,在此沿用之。ui
根据基于BPMN2.0的工单系统架构设计(上)文章中的介绍,WDL文件中能够提取五个关键的基本要素:spa
一、Definitions,这个是根元素,无可厚非;架构设计
二、Message,关于消息的定义,是Definitions的子元素,能够有多个消息的定义;设计
三、Process,整个流程的定义,也是Definitions的子元素,暂不支持SubProcess;3d
四、EventDefinition,事件定义,与其余元素区别较大,因此单独提取出来,包括了消息事件,定时事件;code
六、FlowNode,能够理解为是Process的各个子元素,好比SequenceFlow,Task,Gateway等等。
BaseElement是最顶层的抽象,id和elementName做为共有属性,同时有一个validate校验方法,对元素的合法性进行校验。
由于是须要将一整个WDL文件解析出来,这其中就会包含不少元素对象,最后还须要一个真正意义上的BpmnModel进行装载,以下:
在上图的BpmnModel中,Process很是关键,由于其下有众多子元素(FlowNode),找到了Process就能找到其余的子元素。因此,Process的另一个做用就是元素容器(Container),容器里面能够维护本身的子元素,以下是接口定义:
Activiti有一个强大之处在于能进行可视化流程配置,只要了解BPMN2.0规范,就能很轻松的配置出想要的流程。
固然,本工单系统是没有必要去实现这个功能的,因此这一部分侧重讲解从WDL文件到BpmnModel的过程。
笔者从Activiti源码中看到了有一个interface,当中定义了全部Activiti支持的元素,固然也涵盖了上述提到的那些基本元素。该类名是BpmnXMLConstants,其内容较大,故不在此展现了。
笔者沿用了这个类,可是作了一点小改进:将元素标签和元素属性分开,作成了两个interface,以下所示:
Activiti中使用的解析工具是JDK自带的XMLStream,大概是不想引入新的依赖,增长开发者的负担吧!笔者使用的是Dom4j,而不是XMLStream。基于这一点考虑,笔者在设计的时候抽象出了顶层接口,以下所示:
BaseBpmnXMLParser接口中的泛型即为元素解析对象,好比XMLStreamReader,Dom4j中的Element对象等等。doParse方法即为解析的入口,WDL中所支持的各种元素标签都将有一个Parser实现。
这一个部分的主要功能是WDL与BpmnModel的互相转换。
与解析器的设计相似,也是要根据XML的解析工具进行实现。
在Converter接口中,定义了三个方法,其中两个是WDL和BpmnModel的互转,目前仅实现了convertToBpmnModel。
还有一个是对BpmnModel的校验方法,校验不经过直接抛出Exception。
对于转换成功的BpmnModel,会存放在一个容器内,称之为BpmnModelContainer。
这个Container接口定义了对BpmnModel基本的添加,移除和查找方法。另外还有三个方法须要解释一下:
一、next。指示工单流程的下一个步骤,返回下一个步骤的元素。由于可能存在ParallelGateway,这就意味着下一个步骤将会有多个节点同步执行,因此返回结果是一个Queue对象,存放着下一个步骤要执行的节点元素。
二、conditionParse。在基于BPMN2.0的工单系统架构设计(上)文章中曾说起到了WDL中表达式的解析。在container中,此方法主要解析的是网关的执行条件,配合next方法使用。
三、fill。这个方法是用于填充Container,该方法的调用时机是构造BpmnModelContainer的时候,固然是要借助WDL转换器实现。以下所示:
@Configuration @EnableConfigurationProperties(WorkflowProperties.class) public class BpmnXmlManager { /** * 构造BpmnModelContainer,解析WDL文件,填充BpmnModel */ @Bean public BpmnModelContainer bpmnContainer(WorkflowProperties workflowProperties, BaseBpmnXMLConverter converter) throws Exception { BpmnModelContainer container = new BpmnModelContainer(workflowProperties, converter); container.fill(); return container; } /** * 构造XML解析工厂,默认是Dom4j的解析方式 */ @Bean @ConditionalOnMissingBean(BpmnXMLParserFactory.class) public Dom4jParserFactory xmlParserFactory() { return new Dom4jParserFactory(); } /** * 构造XML转换工厂,默认是Dom4j的转换方式 */ @Bean @ConditionalOnMissingBean(BaseBpmnXMLConverter.class) public Dom4jConverter xmlConverter() { return new Dom4jConverter(); } }
前三部分工做完成以后,工单就能够正常流转了。
一、start,工单的发起;
二、accept,后台操做人员接单;
三、doTask,执行工单节点(用户任务);
四、getWorkOrderDetail,获取工单详情,包含工单基本信息,工单动态,工单客户信息,工单任务列表等;
五、addWorkOrderProgress,添加一条工单进度信息,方便客户端查看工单进度;
六、nextElement,查找下一个工单节点,查找范围涵盖了Process的全部子元素,是推进工单流程的重要方法。
对于WDL中的Task和Event都有设计其对应的Runner,用于执行其内在的业务逻辑。
在Runner执行期间,会遇到一些定时任务,好比定时边界捕获事件,笔者使用了Quartz开发框架,整合了SpringBoot进行定时任务的管理。
本篇文章对工单系统的程序设计作了较为详细的讲解,对于整个工单系统的设计也就到此为止了。若是笔者能通读工单系统设计系列的三篇文章,对于从此的工单系统设计也将会有所启发。