- 1. 什么是工作流?
- 2. 工作流用来干什么?
- 3. 什么时候用工作流?
- 4. 什么是工作流引擎?
- 5. Activiti工作流引擎
- 6. 为什么选择Activiti
- 7. 核心7大接口、28张表
- 8. Activiti下载
- 9. 步骤
- 9.1. 设计流程定义文档
- 9.2. 部署流程定义(classpath路径加载文件)
1. 什么是工作流?
问题: 有一天,阿毛到学校,感觉到身体不舒服,然后想跟班主任请假,然后班主任告诉阿毛说,你想请假,那么就必须要请假条,这个上面必须要我同意,然后再拿到教务处去盖章,然后交给我,这样才可以进行请假。阿毛想着,怎么请个假都这么麻烦,这么多层次处理问题,能不能简便一点……好烦好烦!!!
分析: 从上面的小例子,我们可以很明显的得到一个结论,就是:
请假流程:阿毛 —> 提交申请 —> 班主任审批 —> 教务处审批 —> 请假成功
也就是说,这种问题就是一种流式的控制管理,当然,这是最简单的,因为里面没有包含着回馈,相当于只是一个方向。采用工作流技术的公司的请假流程是这样的:
工作流:阿毛使用账户登录系统 —> 点击请假,填写请假条信息,并提交 —> 上级(班主任)登录系统,并点击审批 —> 上级(教务处)登录系统,并点击审批 —> 请假成功
就这样,一个请假流程就结束了。
有人会问,那上级不用向公司提交请假记录?公司不用将记录录入电脑?答案是,用的。但是这一切的工作都会在上级点击允许后自动运行!这就是工作流技术。
工作流(Workflow):
就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在“多个参与者”之间按照某种“预定义的规则”传递文档、信息或任务的过程自动进行,从而实现某个预期的业务目标,或者促使此目标的实现”。通俗的说,流程就是多个人在一起合作完成某件事情的步骤,把步骤变成计算机能理解的形式就是工作流。
2. 工作流用来干什么?
工作流解决的主要问题是:
为实现某个业务目标,在多个参与者之间,利用计算机,按某种预定规则自动传递文档、信息或者任务。简单地说,工作流就是一系列相互衔接、自动进行的业务活动或任务。我们可以将整个业务过程看做是一条河,其中流过的就是工作流。
3. 什么时候用工作流?
是否引入工作流引擎,取决于系统的业务是否复杂以及过程逻辑的变化性。如果过程逻辑相当复杂,或者过程逻辑经常变化,最好是引入工作流,分离业务逻辑和过程逻辑。相反业务逻辑简单且日后的变化甚少,那就没必要引入工作流了、。引入工作流后系统的层次增加了,分层越多,各个层次间的沟通和协调就越复杂,作为一个PM这点是需要考虑的。
4. 什么是工作流引擎?
工作流引擎是工作流应用的一部分。
工作流引擎,常用于审批流程中,现在一线互联网公司也开始使用,并有快速推广的趋势,复杂繁多的业务流程如果采用 if else实现那将是崩溃的,代码不可维护。业务流程在代码中可读性差,所以高人设计了业务流程模型图示BPMN2.0,我们要做到就是把业务场景抽象为标准流程图,把流程图丢到流程引擎中按流程定义约定逐步流转,很显然扩展性和业务可描述性会好很多,所以工作流引擎主要用于解决复杂的业务,目前经常被提起的中台系统抽象业务为服务,也涉及大量智能的业务流程引擎做支撑。
在Java领域,JBPM和Activiti是两个主流的工作流系统,而Activiti的出现无疑将会取代JBPM(Activiti的开发者就是从Jbpm开发者出来的)。
常用业务流框架:
- JBPM
- Activiti
5. Activiti工作流引擎
Activiti是一个开源的自动化业务工作流引擎。
官网:http://www.activiti.org/ 下载地址:http://www.activiti.org/download.html
Activiti是基于Apache许可的开源BPM平台,创始人Tom Baeyens原是JBPM架构师,可以理解为与JBPM出自同一祖师爷。它提供了Eclipse插件,开发可以通过插件直接绘制业务流程图。基于Spring,ibatis等框架,并在此之上构建了非常清晰的开发框架。是由Alfresco软件发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理、工作流、服务协作等领域的一个开源的、灵活的、易扩展的可执行流程语言框架。 本文基于Activiti7的Activiti Core,基于Spring Boot做简单学习总结。(Activiti最新版本向微服务这边靠齐了,并分Activiti Core与Activiti Cloud两块,Activiti Cloud还没研究)。
6. 为什么选择Activiti
7. 核心7大接口、28张表
7大接口
RepositoryService: 提供一系列管理流程部署和流程定义的API。
RuntimeService: 在流程运行时对流程实例进行管理与控制。
TaskService: 对流程任务进行管理,例如任务提醒、任务完成和创建任务等。
IdentityService: 提供对流程角色数据进行管理的API,这些角色数据包括用户组、用户及它们之间的关系。
ManagementService: 提供对流程引擎进行管理和维护的服务。
HistoryService: 对流程的历史数据进行操作,包括查询、删除这些历史数据。
FormService: 表单服务。28张表
act_ge_ 通用数据表,ge是general的缩写
act_hi_ 历史数据表,hi是history的缩写,对应HistoryService接口
act_id_ 身份数据表,id是identity的缩写,对应IdentityService接口
act_re_ 流程存储表,re是repository的缩写,对应RepositoryService接口,存储流程部署和流程定义等静态数据
act_ru_ 运行时数据表,ru是runtime的缩写,对应RuntimeService接口和TaskService接口,存储流程实例和用户任务等动态数据。
3.3.1:资源库流程规则表
1)act_re_deployment 部署信息表
2) act_re_model 流程设计模型部署表
3) act_re_procdef 流程定义数据表
3.3.2:运行时数据库表
1)act_ru_execution 运行时流程执行实例表
2) act_ru_identitylink 运行时流程人员表,主要存储任务节点与参与者的相关信息
3) act_ru_task 运行时任务节点表
4) act_ru_variable 运行时流程变量数据表
3.3.3:历史数据库表
1)act_hi_actinst 历史节点表
2) act_hi_attachment 历史附件表
3) act_ih_comment 历史意见表
4) act_hi_identitylink 历史流程人员表
5) act_hi_detail 历史详情表,提供历史变量的查询
6) act_hi_procinst 历史流程实例表
7) act_hi_taskinst 历史任务实例表
8) act_hi_varinst 历史变量表
3.3.4:组织机构表
1)act_id_group 用户组信息表
2) act_id_info 用户扩展信息表
3) act_id_membership 用户与用户组对应信息表
4) act_id_user 用户信息表
这四张表很常见,基本的组织机构管理,关于用户认证方面建议还是自己开发一套,组件自带的功能太简单,使用中有很多需求难以满足
3.3.5:通用数据表
1)act_ge_bytearray 二进制数据表
2) act_ge_property 属性数据表存储整个流程引擎级别的数据,初始化表结构时,会默认插入三条记录,
1个配置文件
activiti.cfg.xml(activiti的配置文件)
Activiti核心配置文件,配置流程引擎创建工具的基本参数和数据库连接池参数。
8. Activiti下载
Activiti 6下载地址:https://www.activiti.org/get-started
9. 步骤
9.1. 设计流程定义文档
- BPMN文件
流程规则文件。在部署后,每次系统启动时都会被解析,把内容封装成流程定义放入项目缓存中。Activiti框架结合这个XML文件自动管理流程,流程的执行就是按照bpmn文件定义的规则执行的,bpmn文件是给计算机执行用的。 - 展示流程图的图片
在系统里需要展示流程的进展图片,图片是给用户看的。
9.2. 部署流程定义(classpath路径加载文件)
/**
* 部署流程定义
*/
@Test
public void deploymentProcessDefinition_classpath(){
//获得与流程定义和部署对象相关的Service
Deployment deployment = processEngine.getRepostitoryService()
//创建一个部署对象
.createDeployment()
//添加部署的名称
.name("流程定义")
//从classpath的资源中加载一个bpmn文件,一次只能加载一个文件
.addClasspathResource("process/helloworld.bpmn")
.addClasspathResource("process/helloworld.png")
//完成部署
.deploy();
System.out.println("部署ID:" + deployment.getId());
System.out.println("部署名称:" + deployment.getName());
}