版权声明:
本文为博主原创文章,未经博主允许不得转载。关注公众号 技术汇(ID: jishuhui_2015) 可联系到作者。

一、前言

『工单系统』从宏观上看,是一些状态流的转换,笔者认为,工单系统的实现即是对工作流(workflow)的实现,典型的应用有企业OA系统,各类CRM,ERP等。

对于工单系统的实现,其实可以结合实际业务去编写相应的业务代码,这样做的最大的好处是定制化程度高,运行业务流程高度自定义化。然而,物极必反,高度定制的业务流程将会失去一定的灵活性。

那么问题来了:如何权衡?

答曰:基于业内标准实现。

标准=权威

当我们发现设计出来的业务流程不符合标准,就不得不怀疑了。

是时候要祭出工作流的“杀手锏”了:BPMN2.0

至于BPMN2.0的基础介绍,我在此不再赘述,用一句话概括:BPMN2.0是IBM制定的一套完善的工作流开发标准,它包含了诸如事件,网关,顺序流,任务等各类基本元素。

BPMN2.0毕竟只是一套标准,还需要付诸实现,业内知名的工作流开发框架当属Activiti了,使用的编程语言是受众较多的Java,如果实际工作中有用到工作流,可以使用此开发框架,如果主流开发框架不是Java,只能自造轮子了。

如果准备进入工作流的开发,无论是使用框架,还是自研,建议阅读一下这份文档,对实际开发工作非常有帮助。

再回到文章开头提到的“工单系统”,说说笔者启动此项目前的一些个人想法。

工单的流程推动本身就是工作流的一种体现,所以理所当然是使用了BPMN2.0的标准。大概花了一个工作日去研读了上述提到的参考文档,愈发觉得BPMN2.0标准的精妙之处,要囊括现有的业务需求,那是绰绰有余。

当然,在做系统架构的时候,必定是要结合实际业务需求的。仔细分析了自身的业务需求,发现都是一些“短流程”,工单任务不会超过2个,工单任务类型也只会有一种(即为userTask),流程分支也不多,总而言之,笔者面临的都是一些较为简单的工单流程。

如果直接使用Acviti这类庞大复杂的框架,一方面是实际的工单流程不算复杂,二来有大材小用之嫌,再者团队成员都不熟悉此标准,理解并对接起来有难度。

因此,笔者走上了基于BPMN2.0标准自研的道路。

倒不是有重造一个Activiti的雄心壮志,而其实质是对Activiti进行功能裁剪,只实现了一些必要的标准。

关于此工单系统的架构设计将会分三篇文章讲解,此篇文章将着重介绍我用到了哪些BPMN2.0标准元素。

二、工作流定义语言(WDL)

Workflow Definition Language(以下简称WDL),意思是工作流定义语言,属于个人自创,并非官方术语,只是想在团队内统一语言而已。

沿袭Activiti的设计实现,WDL也是基于XML的。

在工单系统里面,笔者实现了以下8种基本元素:

下面对WDL的组成部分进行介绍:

1、根节点,由一对definitions标签组成

<definitions id="def" name="工作流程配置"> </definitions>

2、流程定义节点,由一对process标签表示,与其下属子节点组成一个完整的流程
值得一提的是,BPMN2.0标准中是允许subProcess(子流程)存在的,这个feature在此工单系统里并未实现。

<process id="verify_work" name="用户审核流程"> </process>

3、空开始事件节点,通常表示一个流程的开始

<startEvent id="start" name="开始事件"/> 

4、定时事件定义,不可单独存在,其效果是在其他事件的基础上加了一个定时器,典型的应用是下面将提到的定时边界事件

<timerEventDefinition>     <!-- 时间点 或者 cron表达式 --><timeDuration>${duration}</timeDuration>
</timerEventDefinition> 

5、定时边界事件

边界事件都是捕获事件,它会附在一个节点上,当节点运行时,事件会监听对应的触发类型。 当边界事件被捕获,节点就会中断运行,同时执行事件的后续流程。

定时边界事件可以理解为一个暂停等待警告的时钟。当流程执行到绑定了边界事件的环节, 会启动一个定时器。

当定时器触发时,环节就会中断,并沿着定时边界事件的外出连线继续执行。

<boundaryEvent id="escalationTimer" cancelActivity="true" attachedToRef="userTask"><!-- cancelActivity表示是否会中断边界事件所依附的任务 -->   <timerEventDefinition>       <timeDuration>0 15 10 * * ? *</timeDuration>   </timerEventDefinition>
</boundaryEvent>

6、消息(边界)事件,消息的接收和发送要在应用或架构的一层实现的,流程引擎则内嵌其中

这个元素相较于标准,还是有改动的。消息事件在工单系统中被界定为是一种回调通知的手段,通知的类型有REST和MQ两种方式,通知所携带的参数在params中可被定义,name是参数名。

message标签是唯一一个与process标签同级的标签,message就好比全局变量,可以被WDL中多个元素引用。

以下定义了一个消息体,并在消息边界事件中引用该消息体。

<message id="newInvoice" name="newInvoiceMessage" type="REST | MQ"><params><param name="target">${target}</param><param name="a">${a}</param><param name="x">${x}</param></params>
</message>
<boundaryEvent id="boundary" attachedToRef="task" cancelActivity="true"><messageEventDefinition messageRef="newInvoice"/>
</boundaryEvent>

7、顺序流程节点,在表现形式上是一个单向箭头,因此需要定义两端的元素。起始元素用sourceRef属性定义,指向元素用targetRef属性定义,其值都是元素的id属性值。由此也可以看出,顺序流上的基本元素通常都需要有id属性进行标识的,而且最好不要重复,避免混淆。

<sequenceFlow id="flow1" sourceRef="ss" targetRef="tt" />

8、 条件流程节点,意思满足某种条件才通向对应的顺序流

<sequenceFlow id="flow1" sourceRef="exclusiveGw" targetRef="task1"><conditionExpression>${condition}</conditionExpression>
</sequenceFlow>

9、用户任务,表示需要工作人员实际操作推动的任务节点

BPMN2.0标准中有很丰富的任务类型,诸如脚本任务,Java服务任务,邮件任务等等,Activiti也扩展出来了Mule任务,Camel任务等。

而在工单系统中,只需要用到用户任务,搭配其他事件,即可很好的满足业务需求。

<userTask id="task" name="verify_task"/>

10、排他性网关节点,就像程序的if-else的判断,连接排他性网关的众多分支,最终只会走向其中一个分支

<exclusiveGateway id="xgid" name="Request approved" default="sf"/>  <!-- default表示默认流程 -->

11、并行性网关节点,和排他性网关是对立的,连接并行性网关的众多分支将会同时执行

<parallelGateway id="pgid" name="gname"/>

12、空结束事件节点,通常作为一个流程的结束

<endEvent id="end" name="结束事件"/>

补充说明

在上述的定时事件,消息定义,顺序流等元素均用到了同一种取值方式,即我们常见的&dollar;{value}形式,并非用到了spring相关的解析手段,而是受到Activiti的启发,使用的是JUEL工具对表达式进行解析和执行。

在WDL中,不需要太复杂的表达式,支持简单的取值和逻辑运算即可,如:&dollar;{name},&dollar;{approved==true}。

三、实例讲解

为了加深对上述元素的理解,笔者挑了5个具有代表性的实例,展示其WDL的内容,实例配图均来自这份文档。

需要注意的是,definitions下面的子节点不讲究先后顺序,不一定要按流程走向书写WDL。个人习惯是先定义节点元素,然后用顺序流(sequenceFlow)进行连接。

这种情况比较简单,只有一个开始节点和一个任务节点。

<definitions id="def" name="工作流程配置"> <process id="verifyCredit" name="verify credit"> <startEvent id="start" name="开始"/> <userTask id="unkown" name=""/> <sequenceFlow id="flow1" sourceRef="start" targetRef="unkown"> <conditionExpression>${condition}</conditionExpression> </sequenceFlow> </process>
</definitions>

这是一个典型的单支顺序流程。

<definitions id="def" name="工作流程配置"> <process id="pid" name="my process"> <startEvent id="start" name="开始"/> <userTask id="write" name="Write monthly financial report"/> <userTask id="verify" name="Verify monthly financial report"/> <sequenceFlow id="flow1" sourceRef="start" targetRef="write"/> <sequenceFlow id="flow2" sourceRef="write" targetRef="verify"/> <sequenceFlow id="flow2" sourceRef="verify" targetRef="end"/> <endEvent id="end"/> </process>
</definitions>

此处出现了多分支情况,并且定义了一个defaultFlow,类似于:

if (conditionA) {doTask1
} else if (conditionB) {doTask3
} else {doTask2
}

不难看出,排他性网关一般都会伴随一个defaultFlow,以下是WDL内容。

<definitions id="def" name="工作流程配置"> <process id="pid" name="my process"> <startEvent id="start" name="开始"/> <userTask id="t1" name="Task1"/> <userTask id="t2" name="Task2"/> <userTask id="t3" name="Task3"/> <exclusiveGateway id="xgid" name="Exclusive Gateway" default="t2"/> <sequenceFlow id="flow1" sourceRef="xgid" targetRef="t1"> <conditionExpression>${conditionA}</conditionExpression> </sequenceFlow> <sequenceFlow id="flow2" sourceRef="xgid" targetRef="t2"/> <sequenceFlow id="flow1" sourceRef="xgid" targetRef="t3"> <conditionExpression>${conditionB}</conditionExpression> </sequenceFlow> </process>
</definitions>

到此处为止,算是可以看到一个完整的流程定义了,有开始和结束,各个任务节点,以及分支。

<definitions id="def" name="工作流程配置"> <process id="verifyCredit" name="verify credit"> <startEvent id="start" name="开始"/> <userTask id="verifyCreditHistory" name="Verify credit history"/> <sequenceFlow id="verify_flow" sourceRef="start" targetRef="verifyCreditHistory"/> <exclusiveGateway id="approve" name="approve or not"/> <sequenceFlow id="end_flow" sourceRef="verifyCreditHistory" targetRef="approve"><userTask id="contact" name="Contact customer for further information"/> <sequenceFlow id="disapprove_flow" sourceRef="approve" targetRef="contact"> <conditionExpress>${approve==false}</conditionExpress> </sequenceFlow> <sequenceFlow id="end_flow" sourceRef="contact" targetRef="end1"> <endEvent id="end1"/> <sequenceFlow id="approve_flow" sourceRef="contact" targetRef="end2"> <conditionExpress>${approve==true}</conditionExpress> </sequenceFlow> <endEvent id="end2"/> </process>
</definitions>

这种情况是包含了一个定时边界事件,如果cancelActivity="false",那么情况就变得较为复杂了,因为有两处结束节点,cancelActivity="true"的时候,则只在一处结束。

<definitions id="def" name="工作流程配置"> <process id="verifyCredit" name="verify credit"> <startEvent id="start" name="开始"/> <userTask id="firstLineSupport" name="First line support"/> <boundaryEvent id="escalationTimer" cancelActivity="true" attachedToRef="firstLineSupport"> <timerEventDefinition> <timeDuration>2017-02-12 12:00:00</timeDuration> </timerEventDefinition> </boundaryEvent> <sequenceFlow id="flow1" sourceRef="start" targetRef="firstLineSupport"/> <sequenceFlow id="flow2" sourceRef="firstLineSupport" targetRef="end1"/> <endEvent id="end1"/> <userTask id="secondLineSupport" name="Second line support"/> <sequenceFlow id="flow3" sourceRef="firstLineSupport" targetRef="secondLineSupport"/> <sequenceFlow id="flow4" sourceRef="secondLineSupport" targetRef="end2"/> <endEvent id="end2"/></process>
</definitions>

到此,工单系统所需的基础知识就讲解完毕了。整体感觉,BPMN2.0还是简单易懂的,并且能覆盖到绝大多数工单流程,其能成为业内标准,也是自有一番道理的。

基于BPMN2.0的工单系统架构设计(上)相关推荐

  1. 基于BPMN2.0的工单系统架构设计(下)

    版权声明: 本文为博主原创文章,未经博主允许不得转载.关注公众号技术汇(ID: jishuhui_2015) 可联系到作者. 在上两篇文章中,介绍了BPMN2.0和工作流定义语言(以下简称WDL),以 ...

  2. 基于BPMN2.0的工单系统架构设计(上) 1

    版权声明: 本文为博主原创文章,未经博主允许不得转载.关注公众号 技术汇(ID: jishuhui_2015) 可联系到作者. 一.前言 『工单系统』从宏观上看,是一些状态流的转换,笔者认为,工单系统 ...

  3. 系统架构设计上需要注意的

    系统架构设计上需要注意的 快速阅读 如何保证系统的防重放和不可抵赖性. socket 长连接和短连接,tuxedo和webloigc的平台架构以及这两者之间如何进行通讯.nh结尾的文献资料用什么打开. ...

  4. 工单系统的设计与实现(3)

    工程创建成功后,构建本项目的层次结构. 本工单系统采用的是mapper(dao)层+service层+controller层来进行实现. mapper层主要是利用mybatis与数据库进行交互,创建数 ...

  5. 工单系统的设计与实现(4)

    项目的层次结构清楚之后,首先进行mapper层的编写.关于Mybatis的更多知识,可参见之前的博客. 因为要进行ORM映射,首先准备好pojo,也可以用mybatis的逆向工程生成. OrderIn ...

  6. 0. 视频监控系统架构设计

    0.视频监控系统架构设计 0.1.功能指标 (1)搭建共享文件夹 (2)实现Ubuntu的NAT上网和桥接上网 (3)搭建局域网 (4)搭建nfs服务器.tftp服务器 (5)将uboot.kerne ...

  7. ITSM软件与工单系统的区别是什么?

    01. 什么是工单系统? 工单系统,又称为工单管理系统,是用来记录.处理.跟踪一项工作完成情况的.工单系统分为两大类:一是企业内部部门工作任务传达的系统,比如公司内一般都会有办公电脑报障类工单,是由办 ...

  8. 搭建PESCMS-Ticket开源客服工单系统

    运行环境 服务器宝塔面板 PHP 7.0及以上版本 Mysql 5.5及以上版本 IE浏览器不保证兼容 PESMCS Ticket简介 PESMCS Ticket(下称PT)是一款基于GPLv2协议发 ...

  9. java自动下发工单源码_PESCMS Ticket开源客服工单系统 v1.3.5

    PESMCS Ticket(下称PT)是一款基于GPLv2协议发布的开源客服工单系统.除了传统的站内工单提交模式,我们以全新的设计理念,基于Javascript语言开发的跨域工单提交.实现在任何系统. ...

最新文章

  1. Redis的安装配置及简单集群部署
  2. Flutter 中的国际化之多语言环境
  3. jave导出mysql_java导出mysql数据到excel(poi)
  4. ARP挂马***--嗅探欺骗的最恐怖方式
  5. java 二叉树_拼多多Java开发1234面:二叉树+负载均衡+MySQL+Redis+高并发
  6. 信号与槽QVariant传递结构体指针
  7. Memcache集群安装与配置
  8. 帮你找影视剧同款的“影觅”宣布完成百万美元级Pre-A轮融资_36氪
  9. 使用tesserocr二值化识别知网登录验证码
  10. MATLAB提取不规则txt文件中的数值数据(简单且实用)
  11. nacos2.0服务提示注册成功,但是服务管理列表中没有注册到
  12. 计算机组成原理实验一报告——运算器
  13. gpio_typedef_超经典的STM32学习笔记——第一章GPIO口
  14. C#产生随机数之一 生成真随机数
  15. OpenGL二 - 画一个五角星 pentagram
  16. 使用“PC定时执行专家”,提高你的工作效率
  17. Unreal Engine 4 使用HLSL自定义着色器(Custom Shaders)教程(下)
  18. 中国电商物流行业专项规划与发展机遇研究报告2022版
  19. galerkin有限元法matlab实现,有限元法求解二维Poisson方程的MATLAB实现
  20. 最新版本金蝶cloud软件下载地址

热门文章

  1. 传入一个中文字符串,返回一个字符串中的中文拼音
  2. Android控件的继承关系图
  3. v8学习笔记(二) Handle和HandleScope机制
  4. 设计模式---单例模式(多线程下的单例模式)
  5. Java中二维数组的用法(不定长二维数组)
  6. Java调用js方法
  7. 【转】shell之for、while、until循环
  8. vue的 v-for 循环中图片加载路径问题
  9. elasticsearch 自定义routing
  10. 安卓初学者必看实例,(手机GPS简单编程访问)