1、什么是工作流&工作流引擎
1.1、工作流介绍
# 工作流
工作的一个流程,事物发展的一个过程。
比如说:
我们请假的流程就是一个工作流:
1、填写申请单
2、部门经理审批
3、人事存档
那么这种工作流在传统的来说,就是给你一张纸纸,你填写申请信息,然后给经理审核,再给人事存档。
那么我们互联网时代,都说的是无纸化办公、自动化控制,也就是这样:线上填写申请单--线上审批--完成请假
1.2、工作流引擎
# 工作流引擎
为了实现我们的无纸化办公、自动化控制,那么就需要工作流引擎来完成。
工作流引擎提供了一套工作流的解决方案,如果不使用那么我们全程都需要自己来编写,极其的恶心和麻烦,有了工作流引擎以后,就为我们提供了很多解决方案供我们来使用,我们只需要关心其业务,而不需要去关心其工作流的实现。
1.3、工作流系统
# 工作流系统
如果一个系统具备流程的自动化管理的功能,那么这个系统就可以被称为**工作流系统**
# 那么工作流系统可以如何来实现呢?举例一个请假的流程
流程定义:填写请假单->部门经理审批->人事经理审批->总经理审批->人事存档->请假成功
现在我们的流程定义弄出来了,我们如何设计表呢?
其实设计这个请假表的基础字段并不难,例如工号、部门、姓名等,重要的是除了这些基础字段
以外,我们还需要一个状态(state)字段来决定当前请假的状态,例如:
0:填写未提交,1:填写已提交
2:部门经理审批通过,3:部门经理审批未通过
4:总经理审批通过,5:总经理审批未通过
..........
这个时候我们如果要完成整个流程的代码实现,那么就需要在各个模块的代码里面来判断其state字段。
判断state字段后才知道当前流程到哪了,该谁来处理,这种方法肯定可以实现工作流。
但是手动编码实现会有一些问题:
1:如果流程中出现分支的情况(例如请假大于3天需要总经理审批,否则不需要经过总经理),那么处理较为繁琐。
2:如果流程中出现两个操作同时完成后再进入下一个操作的情况,编码实现较为复杂。
# 工作流系统适用行业
消费品行业,制造业,电信服务业,银证险等金融服务业,物流服务业,物业服务业,物业管理,大中型进出口贸易公司,政府事业机构,研究院所及教育服务业等,特别是大的跨国企业和集团公司。
# 具体有哪些应用的场景
1. 关键业务流程:订单、报价处理、合同审核、客户电话处理、供应链管理等
2. 行政管理类:出差申请、加班申请、请假申请、用车申请、各种办公用品申请、购买申请、日报周报等凡是原来手工流转处理的行政表单。
3. 人事管理类:员工培训安排、绩效考评、职位变动处理、员工档案信息管理等。
4. 财务相关类:付款请求、应收款处理、日常报销处理、出差报销、预算和计划申请等。
5. 客户服务类:客户信息管理、客户投诉、请求处理、售后服务管理等。
6. 特殊服务类: ISO 系列对应流程、质量管理对应流程、产品数据信息管理、贸易公司报关处理、物流公司货物跟踪处理等各种通过表单逐步手工流转完成的任务均可应用工作流软件自动规范地实施。
1.4、工作流的实现方式
# 在没有工作流引擎之前
在没有工作流引擎之前,我们只有靠一个state字段来判断当前流程状态,全程的逻辑都要紧紧依靠这个state字段,如果流程复杂,有分支,有共同操作这种,就很恼火了,不仅编码难度提高,且一旦更改需求,维护极其的困难。
# 有了工作流引擎之后
核心的流程控制交给工作流引擎来完成,我们不需要关心他到底是何如完成流程控制的,我们只管业务。
2、什么是Activiti7
2.1、Activiti介绍
# 介绍:
Alfresco软件在2010年5月17日宣布Activiti业务流程管理(BPM)开源项目的正式启动,其首席架构师由业务流程管理BPM的专家Tom Baeyens担任,Tom Baeyens就是原来jbpm 的架构师,而jbpm是一个非常有名的工作流引擎,当然Activiti也是一个工作流引擎。Activiti是一个工作流引擎,Activiti可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言(BPMN2.0)进行定义,业务系统按照预先定义的流程进行执行,实现了业务系统的业务流程由Activiti进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,从而提高系统的健壮性,同时也减少了系统开发维护成本。
# 官网:
https://www.activiti.org/
# 前面提到业务流程管理(BPM),那么BPM是什么
BPM(Business Process Management),即业务流程管理,是一种以规范化的构造端到端的卓越业务流程为中心,以持续的提高组织业务绩效为目的系统化方法,常见商业管理教育如 EMBA、MBA等均将BPM包含在内。
# 那么BPM软件是啥
BPM 软件就是根据企业中业务环境的变化,推进人与人之间、人与系统之间以及系统与系统之间的整合及调整的经营方法与解决方案的IT工具。通常以Internet方式实现信息传递、数据同步、业务监控和企业业务流程的持续升级优化,从而实现跨应用、跨部门、跨合作伙伴与客户的企业运作。通过 BPM 软件对企业内部及外部的业务流程的整个生命周期进行建模、自动化、管理监控和优化,使企业成本降低,利润得以大幅提升。BPM 软件在企业中应用领域广泛,凡是有业务流程的地方都可以BPM软件进行管理,比如企业人事办公管理、采购流程管理、公文审批流程管理、财务管理等。
# 上面提到BPMN2.0建模语言,那么它是啥
BPMN(Business Process Model And Notation)-业务流程模型和符号是由BPMI(BusinessProcess Management Initiative)开发的一套标准的业务流程建模符号,使用BPMN提供的符号可以创建业务流程。2004 年5月发布了BPMN1.0规范.BPMI于2005年9月并入OMG(The Object Management Group 对象管理组织)组织。OMG于2011年1月发布BPMN2.0的最终版本。
BPMN图形其实是用XML来存储表示的。
大概有这些图形:
https://img2020.cnblogs.com/blog/1597149/202008/1597149-20200816125024968-1065928745.png
不用每个图形非要知道的很详细的意思,慢慢用了就知道了。
2.2、如何去使用Activiti
# 1、部署Activiti
Activiti 是一个工作流引擎(其实就是一堆jar包API),业务系统使用 activiti 来对系统的业务流程进行自动化管理,为了方便业务系统访问(操作)activiti的接口或功能,通常将activiti环境与业务系统的环境集成在一起。
# 2、流程定义
使用Activiti流程建模工具(activity-designer)定义业务流程(.bpmn 文件)。
.bpmn文件就是业务流程定义文件,通过xml定义业务流程。
建模工具不只是这一个工具,其他的都可以,反正都会支持拖拽方式的操作。
# 3、流程部署
向Activiti部署业务流程文件(.bpmn文件)。
使用Activiti提供的API交给Activiti我们的bpmn文件(一般情况还得交一个png文件,png不交也行)。
# 4、启动一个流程实例(ProcessInstance)
启动一个流程实例表示开始一次业务流程的运行,比如员工请假流程部署完成,如果张三要请假就可以启动一个流程实例,如果李四要请假也启动一个流程实例,两个流程的执行互相不影响,就好比定义一个java类,实例化两个对象一样,部署的流程就好比java类,启动一个流程实例就好比new一个java对象。
# 5、用户查询待办任务(Task)
因为现在系统的业务流程已经交给activiti管理,通过activiti就可以查询当前流程执行到哪了,当前用户需要办理什么任务了,这些activiti帮我们管理了,而不像上边需要我们在sql语句中的where条件中判断状态(state)值是多少。
# 6、用户办理任务
用户查询待办任务后,就可以办理某个任务,如果这个任务办理完成还需要其它用户办理,比如采购单创建后由部门经理审核,这个过程也是由activiti帮我们完成了,不需要我们在代码中硬编码指定下一个任务办理人了。
# 7、流程结束
当任务办理完成没有下一个任务/结点了,这个流程实例就完成了。
3、环境准备
3.1、基本开发环境
# JDK1.8、MySQL5
3.2、Activiti环境
# 0、可以查看activiti示例工程学习
github地址:https://github.com/Activiti/activiti-examples
clone:https://github.com/Activiti/activiti-examples.git
# 1、环境依赖
依赖文件地址:files.cnblogs.com/files/daihang2366/activitidemo1.zip
# 2、需要数据库的支持
activiti运行需要有数据库的支持,支持的数据库有:h2,mysql,oracle,postgres,mssql,db2等.
我们这个案例使用MySQL,在数据库中建立表**activitidemo**
# 3、加入配置文件放置到resources下
文件地址:files.cnblogs.com/files/daihang2366/demo.zip
# 4、IDEA安装插件
插件名称:actiBPM,提示:2019.3的版本好像搜不到这个玩意,解决方案参考网上的一篇博客:
https://blog.csdn.net/weixin_44467567/article/details/103876746?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param
3.3、使用Activiti前提
3.3.1、Activiti支持的数据库
3.3.2、简述项目配置&创建表方式
简述配置:
首先哈,一定要准备一个数据库,我这里的名称叫做:activitidemo
然后我们安装上面的操作完成环境的搭建后。
简单的查看activiti.cfg.xml配置文件的内容,一个是配置连接池,一个是 processEngineConfiguration (流程引擎配置)对象,它用来创建ProcessEngine对象,在创建ProcessEngine的时候会执行数据库的操作。然后我们看里面配置了一个databaseSchemaUpdate的值为true,代表着如果数据库中没有activiti的表,那么将自动创建,关于databaseSchemaUpdate的取值有这些:
# false(默认):检查数据库表的版本和依赖库的版本, 如果版本不匹配就抛出异常。
# true: 构建流程引擎时,执行检查,如果需要就执行更新。 如果表不存在,就创建。
# create-drop: 构建流程引擎时创建数据库表, 关闭流程引擎时删除这些表。
# drop-create:先删除表再创建表。
# create: 构建流程引擎时创建数据库表, 关闭流程引擎时不删除这些表
编写代码来创建表:
public static void main(String[] args) {
/*
* 使用ProcessEngineConfiguration.createProcessEngineConfigurationFromResource方法加载配置文件
* 得到ProcessEngineConfiguration对象,然后调用buildProcessEngine去创建表这些操作
* */
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.
createProcessEngineConfigurationFromResource("activiti.cfg.xml");
/**
* 得到流程引擎对象
*/
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
System.out.println(processEngine);
}
/*
1、运行以上的程序即可完成activiti数据库的表工作,通过改变配置文件中配置processEngineConfiguration 的databaseSchemaUpdate的值来改变执行不同的数据库表策略。
2、上面在执行createProcessEngineConfigurationFromResource方法的时候,会去寻找id为processEngineConfiguration的bean,如果我们不想要bean的名称为processEngineConfiguration,也可以在其方法后加入一个String参数,加入的参数即为去寻找的bean的名称。
否则在执行程序的时候就会报错没有bean的名称为processEngineConfiguration 。
*/
执行上面的代码以后,如果没有报错,那么数据库将会多出25张表。
3.3.3、数据库表简述
# 注意
activiti中的表都是以act开头的。
第二部分是表示表的用途的两个字母标识。用途也和服务的API对应
# 表分别的用处
ACT_RE_*:'RE'表示repository。这个前缀的表包含了流程定义和流程静态资源(图片,规则,等等).
ACT_RU_*:'RU'表示runtime。这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti,只在流程实例执行过程中保存这些数据,在流程结束时就会删除这些记录。这样运行时 表可以一直很小速度很快。
ACT_HI_*:'HI'表示history。这些表包含历史数据,比如历史流程实例,变量,任务等等。
ACT_GE_*:GE表示general。通用数据,用于不同场景下。
4、Activiti结构
最上面的就是流程引擎配置对象,它需要配置文件,配置文件默认名称为activiti.cfg.xml,然后下面的就是流程引擎,然后我们实际用的时候,就是运用各种Service
注意:在新版本中IdentityService和FormService都被删了。
4.1、ProcessEngineConfiguration&activiti.cfg.xml
4.1.1、 StandaloneProcessEngineConfiguration
通过该对象我们的Activiti可以单独运行,使用它去创建ProcessEngine,Activiti会自己处理事务。
4.1.2、 SpringProcessEngineConfiguration
使用 SpringProcessEngineConfiguration 和Spring整合。
4.1.3、创建ProcessEngineConfiguration
指定配置文件:
ProcessEngineConfiguration configuration =ProcessEngineConfiguration
.createProcessEngineConfigurationFromResource("activiti.cfg.xml")
4.2、ProcessEngine
工作流引擎,相当于一个门面接口,通过ProcessEngineConfiguration创建processEngine,通过ProcessEngine创建各个service接口。
一般我们都直接使用流程引擎配置对象来获取
public static void main(String[] args) {
/*
* 使用ProcessEngineConfiguration.createProcessEngineConfigurationFromResource方法加载配置文件
* 得到ProcessEngineConfiguration对象,然后调用buildProcessEngine去创建表这些操作
* */
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
/**
* 得到流程引擎对象
*/
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
System.out.println(processEngine);
}
如果我们不指定配置文件:
那么其就会去我们的resources下找activiti.cfg.xml配置文件,且配置文件中必须有一个ProcessEngineConfiguration对象,且id为processEngineConfiguration,然后代码就是这样的:
public static void main(String[] args) {
/**
* 使用默认配置,直接获取流程引擎对象
*/
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
System.out.println(processEngine);
}
4.3、Service
Service是工作流引擎提供用于进行工作流部署,执行,管理的服务接口。
4.3.1、Service创建方式
通过ProcessEngine来获得Service,具体使用的方法是这样的:
processEngine.getXxxxxService(),这个Xxx就是具体的Service名称。
例如获取RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
4.3.2、Service总览
RepositoryService | Activiti的资源管理类 |
---|---|
RuntimService | Activiti的流程运行管理类 |
TaskService | Activiti的任务管理类 |
HistoryService | Activiti的历史管理类 |
ManagerService | Activiti引擎的管理类 |
注:Activiti7中去除了IdentityService和FormService。然后ManagerService为不常用的Service,其他的四个为常用的Service。
4.3.3、RepositoryService
Repository是Activiti的资源管理类,提供了管理和控制流程发布包和流程定义的操作。使用工作流建模工具设计的业务流程图需要使用此Service将流程定义文件的内容部署到计算机。
除了部署流程定义外还可以做:
查询引擎中的发布包和流程定义。
暂停或激活发布包,对应全部和特定流程定义。暂停意味着它不能再执行任何操作了,激活时对应的反向操作。
获得多种资源,比如包含在发布包里的文件,或引擎自动生成的流程图。
获得流程定义的Pojo版本,可以用来通过Java解析流程,而不必通过XML
4.3.4、RuntimeService
RuntimeService是流程运行管理类。可以从这个类中获取很多关于流程执行相关的信息。
4.3.5、TaskService
TaskService是任务管理类。可以从这个类中获取任务的信息。
4.3.6、HistoryService
HistoryService是历史管理类,可以查询历史信息,执行流程时,引擎会保存很多数据(可以配置修改),比如流程实例启动时间,任务的参与者,完成任务的时间,每个流程实例的执行路径等等。这个类主要用来查询这些数据。
4.3.7、ManagementService
ManagementService是引擎管理类,提供了对Activiti流程引擎的管理和维护工作,这些功能不在工作流驱动的应用程序中使用,主要是用于Activiti系统的日常维护。
5、Activiti入门体验
5.1、流程定义
我们要来体验一把Activiti的话,那么我们肯定要先来定义流程,比如说请假这种,先去干啥,后去干啥,这些都要进行定义,这里我们使用IDEA的acitBPM来做
5.1.1、使用工具建模
新建流程holiday,扩展名默认为bpmn:
然后出现如下界面:
左边的是当前选中节点的信息,中间是主界面,右边是流程定义使用的图形。
流程定义图形的大概介绍:
Connection—连接
Event---事件
Task---任务
Gateway---网关
Container—容器
Boundary event—边界事件
Intermediate event- -中间事件
基本使用:
我们肯定是开始,那么就需要一个StartEvent代表开始,然后使用UserTask代表一个任务,然后将StartEvent连接到UserTask上,然后再一个一个连接上,连接的方法就是用鼠标碰到StartEvent然后会有一个小黑点,然后按住拖拽到需要连接的节点上即可完成连接,最后当完成后需要一个EndEvent来结尾,我们来看一个很简单的绘制:
当然我们显示的文字也可以更改,双击即可更改,修改后可以变成这样:
5.1.2、绘制流程
上面已经说了绘制的方法,我们这里直接贴绘制好的样子:
bpmn文件:
png文件:
png文件的生成方式为:先将bpmn文件修改后缀为xml,然后点击 Desiger ,再点击上角的 Export to file 即可导出为png文件。
如果导出png的时候乱码, 解决方法参考此博客: https://blog.csdn.net/qq_37495786/article/details/82758570?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param
5.1.3、指定流程Key
流程定义 key 即流程定义的标识,在 eclipse 中通过 properties 视图查看流程的 key
建议:相同的业务流程,流程定义的 key 名字定义一样,比如,如果需要创建新的业务流程,请假流程则使用新的 key。
随便点击一个空白的地方即可设置流程的Key和Name,不同的流程定义最好不要设置为相同的Key。
5.1.4、指定任务的负责人
每一个人物都应该有一个自己的负责人,比如说填写请假申请单是zhangsan,部门经理审核是lisi这种,但是在我们的实际应用中,这些负责人应该是根据业务来指定的,这里我们为了体验一把,就直接写死了
我们选中一个节点,然后在左侧的Assignee中填写负责人名称,我们这里依次填入zhangsan、lisi、wangwu、zhaoliu。
5.2、部署流程定义
部署流程定义就是将上面绘制的图形,也就是流程定义(bpmn文件)部署到activiti工作流引擎中去,这里我们使用RepositoryService来完成部署的操作
首先我们定义一个方法用来获取ProcessEngine对象,所以我们后面这种代码我们就不在每次都手写了
public static ProcessEngine getProcessEngine(){
/*
使用这个方法的条件:
1、resources下游activiti.cfg.xml文件
2、配置了一个bean的名称为processEngineConfiguration
*/
return ProcessEngines.getDefaultProcessEngine();
}
然后就是我们的流程定义的部署代码
public static void main(String[] args) {
ProcessEngine processEngine = getProcessEngine();
/**
* 使用ProcessEngine对象来获得RepositoryService对象
* */
RepositoryService repositoryService = processEngine.getRepositoryService();
/**
* 使用RepositoryService来获取部署(Deployment)对象,然后指定我们的bpmn和png文件位置,指定流程名称,然后deploy方法完成部署
* */
Deployment deployment = repositoryService.createDeployment() //创建Deployment对象
.addClasspathResource("process/holiday.bpmn") // 加入我们的bpmn文件
.addClasspathResource("process/holiday.png") // 加入我们的png图片文件,也可以不见
.disableSchemaValidation() // 设置不进行框架校验,防止有时候bpmn文件报错
.name("请假流程") // 设置流程定义名称
.deploy(); // 部署
System.out.println("流程部署ID:" + deployment.getId()); // 获得流程部署ID
System.out.println("流程部署名称:" + deployment.getName()); // 获得流程部署名称
}
5.3、启动一个流程实例
流程定义部署在Activiti后就可以通过工作流管理业务流程,也就是说上面部署的流程可以使用了。
针对流程,我们需要启动一个流程来表示发起一个请假单,这就相当于Java类和Java对象的区别。
流程定义就好比一个模板,而流程实例则是根据此模板创建的具体实例
代码:
public static void main(String[] args) {
/*获得流程引擎*/
ProcessEngine processEngine = getProcessEngine();
/*获得RuntimeService*/
RuntimeService runtimeService = processEngine.getRuntimeService();
/*根据流程定义Key来启动流程实例,此处我们设置的key可以在表:act_re_procdef流程定义表中找到*/
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holiday");
System.out.println("流程定义iID:" + processInstance.getProcessDefinitionId());
System.out.println("流程实例ID:" + processInstance.getId());
}
运行后我们在act_hi_actinst表中发现有两条记录,一个是开始请假流程,一个是填写请假申请,两个钟后者没有结束时间,代表还没做完,我们还可以在act_ru_task表中发现当前需要执行的任务。
5.4、任务查询
实例启动后,各个人物的负责人就可以查询到当前自己需要处理的任务,查询出来的任务都是该用户的待办任务
代码:
public static void main(String[] args) {
/*任务执行人名称*/
String assigne = "zhangsan";
/*获得流程引擎*/
ProcessEngine processEngine = getProcessEngine();
/*获得任务的Service*/
TaskService taskService = processEngine.getTaskService();
/*通用TaskService获取查询对象后再查询到我们想要的任务信息*/
List holidayTaskList = taskService.createTaskQuery() // 创建任务查询对象
.processDefinitionKey("holiday") // 加入条件指定流程定义Key
.taskAssignee(assigne) // 加入条件指定任务执行人名称
.list(); // 返回list结果
/*循环遍历*/
for (Task task : holidayTaskList) {
System.out.println(task);
}
}
我们查询完成打印出来后我们会发现,这些信息都是对应着act_ru_task表的。
5.5、任务处理
使用TaskService的complete方法根据任务ID来处理任务
public static void main(String[] args) {
/*前面我们查询到的任务信息:Task[id=2505, name=填写请假申请]*/
String taskId = "2505";
/*获得流程引擎*/
ProcessEngine processEngine = getProcessEngine();
/*获得任务的Service*/
TaskService taskService = processEngine.getTaskService();
/*处理任务ID*/
taskService.complete(taskId);
}
这里执行后我们看act_hi_actinst表:
我们可以看到。现在已经完成了填写请假申请的任务,然后到了部门经理审核的步骤。当我们全部的任务都走完后,就是这个样子:
初体完了后,我们就开始后续的学习
6、流程定义
6.1、流程定义
6.1.1、什么是流程定义
流程定义是线下按照bpmn2.0标准去描述业务流程,通常使用专门的工具进行绘制,但是都会遵守BPMN2.0标准。本文的案例都是使用IDEA插件进行绘制。我们一般绘制完.bpmn文件后都会生成png文件,不同工具生成png的方式不同,具体自行百度。
6.1.2、.bpmn文件
.bpmn文件是流程定义的源文件,实际上就是一个xml,其中保存了流程的所有内容,我们部署的时候就是将此文件部署到activiti中,activiti就会自动解析此文件。
6.1.3、.png图片文件
我们可以将.bpmn文件导出为png文件,导出后就是一张普通的图片,不同的工具具体导出的方法不一样,这个可以自行百度。
6.2、流程定义部署
6.2.1、什么是流程定义部署
将线下定义的流程部署到activiti数据库中,这就是流程定义部署,通过调用activiti的api将流程定义的bpmn和png两个文件添加部署到activiti中,也可以将这个两个文件打成zip包进行部署。
6.2.2、单个文件部署方式
分别将bpmn和png文件进行部署:
public static void main(String[] args) {
ProcessEngine processEngine = getProcessEngine();
/**
* 使用ProcessEngine对象来获得RepositoryService对象
* */
RepositoryService repositoryService = processEngine.getRepositoryService();
/**
* 使用RepositoryService来获取部署(Deployment)对象,然后指定我们的bpmn和png文件位置,指定流程名称,然后deploy方法完成部署
* */
Deployment deployment = repositoryService.createDeployment() // 创建Deployment对象
.addClasspathResource("process/holiday.bpmn") // 加入我们的bpmn文件
.addClasspathResource("process/holiday.png") // 加入我们的png图片文件,也可以不见
.disableSchemaValidation() // 设置不进行框架校验,防止有时候bpmn文件报错
.name("请假流程") // 设置流程定义名称
.deploy(); // 部署
System.out.println("流程部署ID:" + deployment.getId()); // 获得流程部署ID
System.out.println("流程部署名称:" + deployment.getName()); // 获得流程部署名称
}
6.2.3、压缩包部署方式
首先将这bpmn和png压缩到zip中:
public static void main(String[] args) {
ProcessEngine processEngine = getProcessEngine();
/**
* 使用ProcessEngine对象来获得RepositoryService对象
* */
RepositoryService repositoryService = processEngine.getRepositoryService();
/**
* 获取holiday.zip文件为ZipInputStream
* */
ZipInputStream zipInputStream = new ZipInputStream(Test6.class.getClassLoader().getResourceAsStream("process/holidayZip.zip"));
/**
* */
Deployment deployment = repositoryService.createDeployment() // 创建Deployment对象
.addZipInputStream(zipInputStream) // 将输入流加入到Activiti
.disableSchemaValidation() // 设置不进行框架校验,防止有时候bpmn文件报错
.name("请假流程") // 设置流程定义名称
.deploy(); // 部署
System.out.println("流程部署ID:" + deployment.getId()); // 获得流程部署ID
System.out.println("流程部署名称:" + deployment.getName()); // 获得流程部署名称
}
6.2.4、操作数据表
流程定义部署后操作的表有这几个:
SELECT * FROM act_re_deployment; # 流程定义部署表,记录流程部署信息
SELECT * FROM act_re_procdef; # 流程定义表,记录流程定义信息
SELECT * FROM act_ge_bytearray; # 资源表
注意deployment和procdef是一对多关系,就是说一次部署可以部署多个流程定义,那么如果一次部署多个流程定义,那么deploymen中只会有一条记录,而procdef因为多个流程定义所以多个表。
但是我们通常都是一次部署一个流程定义,尽量一对一。
6.3、流程定义查询
查询部署的流程定义:
public static void main(String[] args) {
/*流程定义的Key,这个key可以在act_re_procdef表中找到*/
String processDefinitionKey = "holiday";
/*获得流程引擎*/
ProcessEngine processEngine = getProcessEngine();
/*获得RepositoryService*/
RepositoryService repositoryService = processEngine.getRepositoryService();
/*获得查询流程定义的对象*/
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
/*查询结果,一个结果是一个流程定义对象*/
List processDefinitionList = processDefinitionQuery
.processDefinitionKey(processDefinitionKey) // 指定流程定义key
.orderByProcessDefinitionVersion() // 按照流程定义版本来排序
.desc() // 指定排序规则为desc降序
.list(); // 返回list结果
/*循环遍历结果*/
for (ProcessDefinition processDefinition : processDefinitionList) {
System.out.println("流程定义ID:"+processDefinition.getId());
System.out.println("流程定义名称:"+processDefinition.getName());
System.out.println("流程定义版本:"+processDefinition.getVersion());
System.out.println("流程定义资源文件:"+processDefinition.getResourceName());
System.out.println("流程定义PNG文件:"+processDefinition.getDiagramResourceName());
}
}
6.4、流程定义删除
删除已经部署的流程:
public static void main(String[] args) {
/*部署ID*/
String deploymentId = "2501";
/*获得流程引擎*/
ProcessEngine processEngine = getProcessEngine();
/*如果该流程实例没有启动,则可以直接使用这个方法*/
// processEngine.getRepositoryService().deleteDeployment(deploymentId);
/*如果流程实例已经启动那么删除的时候就会报错,提前外键啥玩意的,那么这个时候就需要级联删除,使用这个方法,在后面加一个true*/
processEngine.getRepositoryService().deleteDeployment(deploymentId,true);
}
6.5、流程定义资源查询
通过流程定义对象获取流程定义资源,获取bpmn和png文件:
public static void main(String[] args) throws Exception {
/*流程定义ID*/
String processDefinitionKey = "holiday";
/*获得流程引擎*/
ProcessEngine processEngine = getProcessEngine();
/*获取到RepositoryService*/
RepositoryService repositoryService = processEngine.getRepositoryService();
/*获得流程定义对象*/
ProcessDefinition processDefinition = repositoryService
.createProcessDefinitionQuery()
.processDefinitionKey(processDefinitionKey)
.singleResult();
/*获取bpmn文件名称和png文件名称*/
String bpmnFileName = processDefinition.getResourceName();
String pngFileName = processDefinition.getDiagramResourceName();
/*调用repositoryService.getResourceAsStream的方法传入部署ID和资源名,可以获得对应资源的输入流*/
InputStream bpmnFileInputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), bpmnFileName);
InputStream pngFileInputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), pngFileName);
/*然后定义两个输出流,将这两个文件写入到我们的磁盘中去*/
FileOutputStream bpmnFileOutputStream = new FileOutputStream("D:\\" + bpmnFileName);
FileOutputStream pngFileOutputStream = new FileOutputStream("D:\\" + pngFileName);
/*为了限制代码长度,写入的代码我们直接调用方法,此处调用方法的代码就不贴出来了,相信你也会写*/
copy(bpmnFileInputStream, bpmnFileOutputStream);
copy(pngFileInputStream, pngFileOutputStream);
}
其实不管你怎么做,只要你能拿到该流程定义的部署ID和文件名,那你就可以拿文件。以上的操作方式并不是唯一拿到部署ID的方法。
6.6、流程历史信息的查看
即使流程定义已经删除了,流程执行的历史信息通过前面的分析,依然保存在 activiti 的 act_hi_*相 关的表中。所以我们还是可以查询流程执行的历史信息,可以通过 HistoryService 来查看相关的历史 记录。
public static void main(String[] args) throws Exception {
/*获得流程引擎*/
ProcessEngine processEngine = getProcessEngine();
/*流程实例ID*/
String instanceId = "10001";
/*获得历史信息查询对象*/
HistoricActivityInstanceQuery historicActivityInstanceQuery = processEngine.getHistoryService().createHistoricActivityInstanceQuery()
.processInstanceId(instanceId);
/*获得查询结果*/
List historicActivityInstanceList = historicActivityInstanceQuery.list();
/*遍历*/
for (HistoricActivityInstance historicActivityInstance : historicActivityInstanceList) {
System.out.println(historicActivityInstance);
}
}
当然我们不仅仅只能用流程实例ID来查询,也可以使用流程定义Key来查询,具体翻翻HistoricActivityInstanceQuery的API就知道了,此处不作详细解释。