1、部署流程定义
1.1、概述
将定义的流程部署到activiti数据库中,就是流程定义部署。
通过调用activiti的api将流程定义的bpmn和png两个文件一个一个添加部署到activiti中,也可以将两个文件打成zip包进行部署。
1.2、部署流程定义
/*部署流程定义*/
@Test
public void testDeployment() {
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、得到RepositoryService实例
RepositoryService repositoryService = processEngine.getRepositoryService();
//3、使用RepositoryService进行部署
Deployment deployment = repositoryService
.createDeployment()//创建一个部署对象
.name("HelloWorld入门程序")//添加部署的名称
.addClasspathResource("activiti/HelloWorld.bpmn20.xml")//从Classpath的资源中加载,一次只能加载一个文件
.addClasspathResource("activiti/HelloWorld.bpmn20.png")
.deploy();//完成部署
//4、输出部署信息
System.out.println(deployment.getId());
System.out.println(deployment.getName());
}
/*部署流程定义 方式二*/
@Test
public void deployProcessByZip() {
// 创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 定义zip输入流
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("activiti/HelloWorld.zip");
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
// 流程部署
Deployment deployment = repositoryService
.createDeployment()//创建一个部署对象
.addZipInputStream(zipInputStream)
.deploy();
System.out.println("流程部署id:" + deployment.getId());
System.out.println("流程部署名称:" + deployment.getName());
}
1.3、操作数据表
流程定义部署后操作activiti的3张表如下: act_re_deployment 流程定义部署表,记录流程部署信息,每部署一次增加一条记录 act_re_procdef 流程定义表,记录流程定义信息,部署每个新的流程定义都会在这张表中增加一条记录 act_ge_bytearray 流程资源表
注意:
act_re_deployment和act_re_procdef一对多关系,一次部署在流程部署表生成一条记录,但一次部署可以部署多个流程定义,每个流程定义在流程定义表生成一条记录。每一个流程定义在act_ge_bytearray会存在两个资源记录,bpmn
和png。
建议:
一次部署一个流程,这样部署表和流程定义表是一对一有关系,方便读取流程部署及流程定义信息。
2、 启动流程实例
2.1、概述
流程定义部署在activiti后就可以通过工作流管理业务流程了,也就是说上边部署的HelloWorld流程可以使用了。
针对该流程,启动一个流程表示发起一个新的申请单,这就相当于java类与java对象的关系,类定义好后需要new创建一个对象使用,当然可以new多个对象。对于申请流程,张三发起一个提交申请单需要启动一个流程实例,申请单发起一个审批【部门经理】也需要启动一个流程实例。
2.2、启动流程实例
/*启动流程实例*/
@Test
public void testStartProcess() {
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、得到RuntimeService实例
RuntimeService runtimeService = processEngine.getRuntimeService();
//3、根据流程定义Id启动流程
ProcessInstance processInstance = runtimeService
//使用流程定义的key启动流程实例,key对应helloworld.bpmn文件中ID的属性值
//使用key值启动,默认是按照最新版本的流程定义启动
.startProcessInstanceByKey("HelloWorld");
//4、输出信息
System.out.println("流程实例id:" + processInstance.getId());
System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
System.out.println("当前活动Id:" + processInstance.getActivityId());
}
执行结果

流程定义的key值

2.3、操作数据表
act_hi_actinst 流程实例执行历史
act_hi_identitylink 流程的参与用户历史信息
act_hi_procinst 流程实例历史信息
act_hi_taskinst 流程任务历史信息
act_ru_execution 流程执行信息
act_ru_identitylink 流程的参与用户信息
act_ru_task 任务信息
3、任务查询
3.1、概述
流程启动后,任务的负责人就可以查询自己当前需要处理的任务,查询出来的任务都是该用户的待办任务。
3.2、查询当前个人待执行的任务
/*查询当前个人待执行的任务*/
@Test
public void testFindPersonalTaskList() {
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、得到TaskService实例
TaskService taskService = processEngine.getTaskService();
//3、查询任务
List<Task> list = taskService
.createTaskQuery()//创建任务查询对象
.taskAssignee("张三")//指定个人任务查询,指定办理人
//.processDefinitionKey("HelloWorld") //指定流程Key,查询指定的流程任务
.list();
for (Task task : list) {
System.out.println("任务id:" + task.getId());
System.out.println("任务名称:" + task.getName());
System.out.println("任务的创建时间:" + task.getCreateTime());
System.out.println("任务办理人:" + task.getAssignee());
System.out.println("流程实例id:" + task.getProcessInstanceId());
System.out.println("执行对象id:" + task.getExecutionId());
System.out.println("流程定义id:" + task.getProcessDefinitionId());
}
}
4、流程任务处理(完成我的任务)
4.1、概述
任务负责人/办理人查询待办任务,选择任务进行处理,完成任务。
4.2、完成任务
/*完成我的任务*/
@Test
public void completTask() {
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、得到TaskService实例
TaskService taskService = processEngine.getTaskService();
//3、查询任务
Task task = taskService.createTaskQuery()
.taskAssignee("张三") //要查询的负责人
//.processDefinitionKey("HelloWorld") //指定流程Key,查询指定的流程任务
.singleResult();//返回一个任务对象
//4、 完成任务,参数:任务id
taskService.complete(task.getId());
System.out.println("完成任务,任务id:" + task.getId());
}
4.3、查询流程状态
/*查询流程状态*/
@Test
public void isProcessEnd(){
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、得到RuntimeService实例
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()//创建流程实例查询
.processDefinitionId("7502")//使用流程实例id查询
.singleResult();
if (processInstance == null){
System.out.println("流程已结束");
}else {
System.out.println("流程没有结束");
}
}
5、流程定义信息查询
5.1、概述
查询流程相关信息,包含流程定义,流程部署,流程定义版本
5.2、查询流程定义
/**
* 查询流程定义
*/
@Test
public void queryProcessDefinition() {
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、得到RepositoryService实例
RepositoryService repositoryService = processEngine.getRepositoryService();
//3、 根据跳槽查询出流程定义
List<ProcessDefinition> definitionList = repositoryService
.createProcessDefinitionQuery()//创建一个流程定义的查询
/*指定查询条件*/
//.deploymentId(deploymentId)//使用部署对象id查询
//.processDefinitionId(processDefinitionId)//使用流程定义id查询
//.processDefinitionNameLike(processDefinitionNameLike)//使用流程定义的名称模糊查询
.processDefinitionKey("HelloWorld")//指定流程Key,查询指定的流程任务
/*排序*/
//.orderByProcessDefinitionVersion().asc()//按照版本的升序排列
//.orderByProcessDefinitionName().desc()//按照流程定义的名称降序排列
.orderByProcessDefinitionVersion().desc()// 按照版本的降序排列
/*返回的结果集*/
//.singleResult()//返回唯一结果集
//.count()//返回结果集数量
//.listPage(firstResult,maxResult)//分页查询
.list();//返回一个list集合列表,封装流程定义
//5、 输出流程定义信息
for (ProcessDefinition processDefinition : definitionList) {
System.out.println("流程定义id:" + processDefinition.getId());
System.out.println("流程定义的名称:" + processDefinition.getName());
System.out.println("流程定义的key" + processDefinition.getKey());
System.out.println("流程定义的版本:" + processDefinition.getVersion());
System.out.println("资源名称bpmn文件:" + processDefinition.getResourceName());
System.out.println("资源名称png文件:" + processDefinition.getDiagramResourceName());
System.out.println("流程部署对象ID:" + processDefinition.getDeploymentId());
}
}
6、流程删除
/*流程删除*/
@Test
public void deleteDeployment() {
// 流程部署id
String deploymentId = "1";
//1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2、得到RepositoryService实例
RepositoryService repositoryService = processEngine.getRepositoryService();
//3、删除流程定义,如果该流程定义已有流程实例启动则删除时出错
repositoryService.deleteDeployment(deploymentId);
//设置true 级联删除流程定义,即使该流程有流程实例启动也可以删除,设置为false非级别删除方式,如果流程定义已有流程实例启动则删除时出错(默认false)
//repositoryService.deleteDeployment(deploymentId, true);
}
/*附件功能:查询最新版本的流程定义*/
@Test
public void findLastVersionProcessDefinition() {
List<ProcessDefinition> list = ProcessEngines.getDefaultProcessEngine()
.getRepositoryService()
.createProcessDefinitionQuery()
.orderByProcessDefinitionVersion().asc()//使用流程定义的版本升序排列
.list();
Map<String, ProcessDefinition> map = new LinkedHashMap<>();
if (list != null && list.size() > 0) {
for (ProcessDefinition pd : list) {
map.put(pd.getKey(), pd);
}
}
List<ProcessDefinition> pdList = new ArrayList<>(map.values());
if (pdList != null && pdList.size() > 0) {
for (ProcessDefinition pd : pdList) {
System.out.println("流程定义id:" + pd.getId());
System.out.println("流程定义的名称:" + pd.getName());
System.out.println("流程定义的key" + pd.getKey());
System.out.println("流程定义的版本:" + pd.getVersion());
System.out.println("资源名称bpmn文件:" + pd.getResourceName());
System.out.println("资源名称png文件:" + pd.getDiagramResourceName());
System.out.println("流程部署对象ID:" + pd.getDeploymentId());
}
}
}
说明:
- 使用repositoryService删除流程定义,历史表信息不会被删除。
- 如果该流程定义下没有正在运行的流程,则可以用普通删除。
如果该流程定义下存在已经运行的流程,使用普通删除报错,可用级联删除方法将流程及相关记录全部删除。
先删除没有完成流程节点,最后就可以完全删除流程定义信息。
项目开发中级联删除操作一般只开放给超级管理员使用。
7、流程资源下载
7.1、概述
现在我们的流程资源文件已经上传到数据库了,如果其他用户想要查看这些资源文件,可以从数据库中把资源文件下载到本地。
7.2、解决方案
1、jdbc对blob类型,clob类型数据读取出来,保存到文件目录
2、使用activiti的api来实现
使用commons-io.jar 解决IO的操作
引入commons-io依赖包
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
通过流程定义对象获取流程定义资源,获取bpmn和png
/*查看流程图*/
@Test
public void viewPic() throws IOException {
String deploymentId = "1";
// 1、得到引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取图片资源名称
List<String> list = processEngine
.getRepositoryService()
.getDeploymentResourceNames(deploymentId);
//3、定义图片资源名称
String resrourceName = "";
if (list != null && list.size() > 0) {
for (String name : list) {
if (list.indexOf(".png") >= 0) {
resrourceName = name;
//获取图片的输入流
InputStream in = processEngine.getRepositoryService()
.getResourceAsStream(deploymentId, resrourceName);
//将图片写入文件中
FileOutputStream out = new FileOutputStream("D:/" + resrourceName);
IOUtils.copy(in, out);
}
}
}
}
/*流程资源下载*/
@Test
public void queryBpmnFile() throws IOException {
// 1、得到引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、得到查询器:ProcessDefinitionQuery,设置查询条件,得到想要的流程定义
ProcessDefinition processDefinition =
repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("HelloWorld")//指定流程Key,查询指定的流程任务
.singleResult();
// 4、通过流程定义信息,得到部署ID
String deploymentId = processDefinition.getDeploymentId();
// 5、通过repositoryService的方法,实现读取图片信息和bpmn信息
// png图片的流
InputStream pngInput = repositoryService
.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
// bpmn文件的流
InputStream bpmnInput = repositoryService
.getResourceAsStream(deploymentId, processDefinition.getResourceName());
// 6、构造OutputStream流
File file_png = new File("d:/evectionflow01.png");
File file_bpmn = new File("d:/evectionflow01.bpmn");
FileOutputStream bpmnOut = new FileOutputStream(file_bpmn);
FileOutputStream pngOut = new FileOutputStream(file_png);
// 7、输入流,输出流的转换
IOUtils.copy(pngInput,pngOut);
IOUtils.copy(bpmnInput,bpmnOut);
// 8、关闭流
pngOut.close();
bpmnOut.close();
pngInput.close();
bpmnInput.close();
}
说明:
- deploymentId为流程部署ID
- resource_name为act_ge_bytearray表中NAME_列的值
- 使用repositoryService的getDeploymentResourceNames方法可以获取指定部署下得所有文件的名称
- 使用repositoryService的getResourceAsStream方法传入部署ID和资源图片名称可以获取部署下指定名称文件的输入流
- 最后将输入流中的图片资源进行输出
8、流程历史信息的查看
8.1、概述
即使流程定义已经删除了,流程执行的历史信息通过前面的分析,依然保存在activiti的act_hi_*相关的表中。所以我们还是可以查询流程执行的历史信息,可以通过HistoryService来查看相关的历史记录。
8.2、查看历史信息
/**
* 查看历史信息
*/
@Test
public void findHistoryInfo(){
// 1、得到引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取HistoryService
HistoryService historyService = processEngine.getHistoryService();
//3、 获取 actinst表的查询对象
HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
//4、 查询 actinst表,条件:根据 InstanceId 查询
// instanceQuery.processInstanceId("2501");
// 查询 actinst表,条件:根据 DefinitionId 查询
instanceQuery.processDefinitionId("HelloWorld:1:4");
// 增加排序操作,orderByHistoricActivityInstanceStartTime 根据开始时间排序 asc 升序
instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
//5、 查询所有内容
List<HistoricActivityInstance> activityInstanceList = instanceQuery.list();
//6、 输出
for (HistoricActivityInstance hi : activityInstanceList) {
System.out.println(hi.getActivityId());
System.out.println(hi.getActivityName());
System.out.println(hi.getProcessDefinitionId());
System.out.println(hi.getProcessInstanceId());
System.out.println("<==========================>");
}
}
8.3、查询历史任务
/*查询历史任务*/
@Test
public void findHistoryTask(){
// 1、得到引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取HistoryService
HistoryService historyService = processEngine.getHistoryService();
List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()//创建历史任务实例查询
.taskAssignee("张三")//指定历史任务的办理人
.list();
for (HistoricTaskInstance historicTaskInstance : list) {
System.out.println(historicTaskInstance.getId());
System.out.println(historicTaskInstance.getName());
System.out.println(historicTaskInstance.getProcessInstanceId());
System.out.println(historicTaskInstance.getStartTime());
System.out.println(historicTaskInstance.getEndTime());
System.out.println(historicTaskInstance.getDurationInMillis());
}
}
8.4、查询历史流程实例
/*查询历史流程实例*/
@Test
public void findHistoryProcessInstance(){
// 1、得到引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取HistoryService
HistoryService historyService = processEngine.getHistoryService();
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()//创建历史流程实例查询
.processInstanceId("2501")//使用流程实例id查询
.singleResult();
System.out.println(historicProcessInstance.getId());
System.out.println(historicProcessInstance.getProcessDefinitionId());
System.out.println(historicProcessInstance.getStartTime());
System.out.println(historicProcessInstance.getEndTime());
System.out.println(historicProcessInstance.getDurationInMillis());
}
}
2501
HelloWorld:1:4
Sat Jul 02 18:57:10 CST 2022
Sat Jul 02 19:10:42 CST 2022
812708
------------------------------------------------------------------------‘
Q.E.D.