文章目录
- 前言
- 流程图入库操作 RepositoryService
- 项目结构
- 数据库连接配置文件
- 入库Java测试代码
- zip 方式进行流程的批量部署
- 流程启动 RuntimeService
- 待处理任务查看 TaskService
- 流程状态的扭转
- 查询流程定义信息 RepositoryService
- 查询正在执行的流程实例 RuntimeService
- 已部署流程删除
- 查询流程的历史记录信息 HistoryService
前言
之前的博客中,重点说明了activiti表的创建,以及第一张流程图的绘制。但是绘制的第一张流程图并非存在于对应的数据库中,今天需要做的就是将绘制的流程图,使用activiti的代码自动的填充进对应的数据表中。然后做一个简单的状态流转。
流程图入库操作 RepositoryService
项目结构
依旧是基于之前的项目依赖与结构。
数据库连接配置文件
其中数据库的连接配置文件activiti.cfg.xml
,配置内容如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://xxxx:3306/activiti_02?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true"/>
<property name="jdbcUsername" value="root"/>
<property name="jdbcPassword" value="root"/>
<property name="databaseSchemaUpdate" value="true"/>
</bean>
<!-- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://xxxx:3306/activiti?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8" />
<property name="username" value="root" />
<property name="password" value="root" />
<property name="maxActive" value="3" />
<property name="maxIdle" value="1" />
</bean>
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<property name="dataSource" ref="dataSource" />
<property name="databaseSchemaUpdate" value="true"/>
</bean>-->
</beans>
配置文件中的一些注意事项在前面的博客中做了一些说明,此处不进行额外的讲解,有问题的参考之前的博客内容。
入库Java测试代码
编写一个测试类,其中的入库逻辑如下所示:
// 单个任务的部署
@Test
public void addTable(){
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
Deployment demo1 = repositoryService.createDeployment()
.addClasspathResource("bpmn/demo01.bpmn") // 添加流程图
.addClasspathResource("bpmn/demo01.png") // 对应的流程图片 支持 png|jpg|gif|svg
.name("第一个流程测试用例")
.deploy();
System.out.println("流程部署id===》"+demo1.getId());
System.out.println("流程部署name===》"+demo1.getName());
}
虽然都是使用
addClasspathResource
关联xml与png 图片,但是其中的底层原理则是根据文件后缀,自动去判断识别存入对应的数据表字段中。
查看控制台输出日志与数据库,可以发现能够将对应的流程图xml与流程图进行入库处理。
查看数据库是否存在对应的数据信息。
select * from ACT_RE_DEPLOYMENT;
select * from ACT_RE_PROCDEF;
上传后的文件内容存储表,可以通过查找act_ge_bytearray
看见。
【注意点】
除了流程图的最初部署,会将流程图存入
act_ge_bytearray
表之外。
在流程审批的各个节点中,都能将对应的文件进行存储,方便后续进行文件的回显。
zip 方式进行流程的批量部署
将对应的 流程图 png 与 xml 汇总打包成一个zip文件,此时则需要注意 两个文件除了后缀不同之外,一定要保证前面的文件名称一致。
编写代码逻辑,将zip创建数据流,并使用activiti的Deployment
的addZipInputStream
,将zip数据流解析并存入数据表中。
/**
* zip 包方式批量上传流程图与流程xml文件
*/
@Test
public void zipInsertTable(){
// 获取zip文件流
InputStream inputStream = this.getClass()
.getClassLoader()
.getResourceAsStream("bpmn/activitis.zip");
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
.addZipInputStream(zipInputStream)
.deploy();
System.out.println("流程部署id===》"+deploy.getId());
System.out.println("流程部署name===》"+deploy.getName());
}
代码执行后,观察控制台打印日志信息与数据表的查询。
select * from ACT_RE_PROCDEF;
流程的部署操作,是将文件 xml 、png
解析并存入到activiti对应的数据表的字段中。上述两种方式,分别就单一与批量进行了验证,通过查看执行的日志信息,可以发现其中受影响的表有以下几种:
act_re_deployment
流程定义部署表 。每执行一次部署,则会增加一条记录;若文件相同,则version字段递增。act_re_procdef
流程定义表。部署每个新的流程定义都会在该表中新增记录。act_ge_bytearray
流程资源表。 主要记录对应文件的 bytearray 信息,数据字段类型为 blob。
流程启动 RuntimeService
当对应的流程图的结构信息已经进行了入库操作,此时就可以编写代码进行流程的启动测试了。
启动流程的逻辑如下所示:
/**
* 流程启动 初次启动
* 注意: 每次执行一次 就是以当前的流程图模板 创建了一个新的 activiti 的对象
*/
@Test
public void startFlow(){
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
// 注意此处的 key 就是流程图的 id
ProcessInstance demo01 = runtimeService.startProcessInstanceByKey("demo01");
System.out.println("流程定义 id===》"+demo01.getProcessDefinitionId());
System.out.println("流程实例 id===》"+demo01.getId());
System.out.println("当前活动 id===》"+demo01.getActivityId());
}
代码执行后查看控制台的相关日志输出。
【注意点】startProcessInstanceByKey("demo01") 指定的 key 必须与 流程图中的 id 一致
。
如果不一致,则会出现org.activiti.engine.ActivitiObjectNotFoundException: no processes deployed with key 'demoxxxx'
的报错问题!!
【注意点】每次执行创建流程的代码,都会以工作流流程图作为模板,构建一个新的实例
。
在文件部署并填充至activiti数据表中后,执行上述的代码,则会根据已部署好的信息,构建一个新的流程实例。通过执行后的控制台日志,可以发现受影响的表有以下:
act_hi_actinst
流程实例执行历史act_hi_identitylink
流程的参与用户历史信息act_hi_procinst
流程实例历史信息act_hi_taskinst
流程任务历史信息act_ru_execution
流程执行信息act_ru_identitylink
流程的参与用户信息act_ru_task
任务信息
待处理任务查看 TaskService
流程启动,在有些项目中的首页,需要展示当前登录者的待处理任务列表信息。
进行了启动工作流操作,此时的工作流中的节点流转,如下:
此时可以通过TaskService
查看,下面是一个简单的例子。
/**
* 查询当前个人待执行的任务
*/
@Test
public void viewReDoTask(){
// 工作流从启动开始 就会流转至 第一个 UserTask 节点,
// 此时可以通过配置的 Assignee 查询指定的人的 一些待处理 任务信息
String assignee = "worker";
// 数据库连接配置操作
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// 根据对应的流程 查询当前指定人的待处理任务信息
TaskService taskService = defaultProcessEngine.getTaskService();
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey("demo01") // 指定哪个流程图模板
.taskAssignee(assignee) // 指定是谁负责待处理的任务
.list();
if(!CollectionUtil.isEmpty(list)){
list.forEach(x->{
System.out.println("流程实例 id "+x.getProcessInstanceId());
System.out.println("任务 id "+x.getId());
System.out.println("任务负责人 "+x.getAssignee());
System.out.println("任务名称"+x.getName());
System.out.println("===========================================");
});
}
}
测试代码运行后,在控制台中可以看到以下的信息。
这里有两个流程实例,是因为为了验证启动流程是否同实例对象,执行了两次开启流程的代码逻辑。
流程状态的扭转
在work
节点中,上面进行了待处理任务的查看操作,如果用户进行了处理,需要将状态进行向下扭转,如何扭转任务的节点,接下来看下面的代码逻辑。
/**
* 工作流的节点与状态的扭转
*/
@Test
public void doTask(){
// 获取数据库的连接信息
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = defaultProcessEngine.getTaskService();
// 完成当前节点的任务 并向下推进
String taskId = "7505";
taskService.complete(taskId);
}
当任务进行推进操作后,再执行查询当前登录人员需要待处理的任务节点,那么任务id为 7505
的相关任务不能查询到。查询一下。
任务编号为
7505
的已经成功推进!
查询流程定义信息 RepositoryService
再上面的startFlow()
执行后,就会依据对应的工作流模板,创建一个工作流流程实例。查看指定的流程模板下已创建的相关流程实例信息,可以使用下面的代码逻辑实现。
/**
* 查询流程定义 的一些内容
*/
@Test
public void queryProcessDefinition(){
// 获取数据库的连接信息
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
// 指定需要查询哪个流程模板信息
String flowId = "demo01";
List<ProcessDefinition> list = processDefinitionQuery
.processDefinitionKey(flowId) // 指定是哪个流程模板
.orderByProcessDefinitionVersion() // 排序字段
.desc()
.list();
if(!CollectionUtil.isEmpty(list)){
list.forEach(process->{
System.out.println("流程定义 id "+process.getId());
System.out.println("流程定义 name "+process.getName());
System.out.println("流程定义 key "+process.getKey());
System.out.println("流程定义 version "+process.getVersion());
System.out.println("流程部署 id "+process.getDeploymentId());
System.out.println("=============================");
});
}
}
查看控制台执行后的日志信息,如下所示:
查询正在执行的流程实例 RuntimeService
如果需要查询当前指定的流程模板,存在哪些流程实例处于流程中的状态,以及对应的流程实例的信息,以达到随时跟踪任务的执行情况。
可以使用如下方式进行查看:
/**
* 查询指定工作流模板中,哪些实例正在执行流程中
*/
@Test
public void queryDoProcessInstance(){
// 指定工作流流程模板id
String flowId= "demo01";
// 获取数据库的连接信息
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
List<ProcessInstance> list = runtimeService.createProcessInstanceQuery()
.processDefinitionKey(flowId)
.list();
if(!CollectionUtil.isEmpty(list)){
list.forEach(processInstance->{
System.out.println("流程实例 id "+processInstance.getProcessInstanceId());
System.out.println("所属流程定义 id "+processInstance.getProcessDefinitionId());
System.out.println("是否执行完成 "+processInstance.isEnded());
System.out.println("是否暂停 "+processInstance.isSuspended());
System.out.println("当前活动标识 "+processInstance.getActivityId());
System.out.println("业务关键字 "+processInstance.getBusinessKey());
System.out.println("=============================");
});
}
}
已部署流程删除
有些已经部署后的流程,需要进行删除操作,则可以使用下列的逻辑实现。
这里说的
已部署
,是指已经执行了addTable()
做了流程文件的上传操作。
/**
* 删除 已部署 的流程实例。
* 注意:如果当前流程实例并未执行完成,进行删除时会出现报错。
*/
@Test
public void deleteDeployment(){
// 流程部署id
String deployMentId = "5001";
// 获取数据库的连接信息
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
// 当该已部署的流程,存在流程中的实例时,执行当前流程会报错!
repositoryService.deleteDeployment(deployMentId);
// 如果需要进行强制删除 则可以采取下列的方式进行
//repositoryService.deleteDeployment(deployMentId,true);
}
如果当前已部署的流程存在流程中的实例时,执行删除操作会出现下面的报错信息。
查询流程的历史记录信息 HistoryService
在一般的审批详情列表中,通常需要展示一些已审批处理节点的记录信息,此时则可以使用 HistoryService 查询指定流程实例下的各个已处理的审批节点数据记录。
当然了,测试操作需要指定指定工作流模板的流程id,先查询可以测试的流程编号。
/**
* 查询指定工作流模板中,哪些实例正在执行流程中
*/
@Test
public void queryDoProcessInstance(){
// 指定工作流流程模板id
String flowId= "demo01";
// 获取数据库的连接信息
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
List<ProcessInstance> list = runtimeService.createProcessInstanceQuery()
.processDefinitionKey(flowId)
.list();
if(!CollectionUtil.isEmpty(list)){
list.forEach(processInstance->{
System.out.println("流程实例 id "+processInstance.getProcessInstanceId());
System.out.println("所属流程定义 id "+processInstance.getProcessDefinitionId());
System.out.println("是否执行完成 "+processInstance.isEnded());
System.out.println("是否暂停 "+processInstance.isSuspended());
System.out.println("当前活动标识 "+processInstance.getActivityId());
System.out.println("业务关键字 "+processInstance.getBusinessKey());
System.out.println("=============================");
});
}
}
使用对应的流程实例id
,这里使用10001
。
使用下列代码进行历史数据的检索:
/**
* 查询 历史信息
*/
@Test
public void queryHistoryInfo(){
String processInstanceId = "10001";
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
HistoryService historyService = defaultProcessEngine.getHistoryService();
HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
historicActivityInstanceQuery.processInstanceId(processInstanceId);// 流程实例id
historicActivityInstanceQuery.orderByHistoricActivityInstanceStartTime().asc();
List<HistoricActivityInstance> list = historicActivityInstanceQuery.list();
if(!CollectionUtil.isEmpty(list)){
list.forEach(hi->{
System.out.println(hi.getActivityId());
System.out.println(hi.getActivityName());
System.out.println(hi.getProcessDefinitionId());
System.out.println(hi.getProcessInstanceId());
System.out.println("=============================");
});
}
}
执行成功后在控制台的日志中可以看到下列信息: