文章目录
- 前言
- 流程图入库操作 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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexhttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/txhttp://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;
流程启动 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'
的报错问题!!
【注意点】每次执行创建流程的代码,都会以工作流流程图作为模板,构建一个新的实例
。
待处理任务查看 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(){// 指定工作流流程模板idString 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(){// 流程部署idString deployMentId = "5001";// 获取数据库的连接信息ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();// 当该已部署的流程,存在流程中的实例时,执行当前流程会报错!repositoryService.deleteDeployment(deployMentId);// 如果需要进行强制删除 则可以采取下列的方式进行//repositoryService.deleteDeployment(deployMentId,true);
}
如果当前已部署的流程存在流程中的实例时,执行删除操作会出现下面的报错信息。
查询流程的历史记录信息 HistoryService
在一般的审批详情列表中,通常需要展示一些已审批处理节点的记录信息,此时则可以使用 HistoryService 查询指定流程实例下的各个已处理的审批节点数据记录。
当然了,测试操作需要指定指定工作流模板的流程id,先查询可以测试的流程编号。
/*** 查询指定工作流模板中,哪些实例正在执行流程中*/
@Test
public void queryDoProcessInstance(){// 指定工作流流程模板idString 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);// 流程实例idhistoricActivityInstanceQuery.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("=============================");});}
}
执行成功后在控制台的日志中可以看到下列信息: