流程符号详解:
创建Activiti工作流的主要步骤包含以下几步:
1. 定义流程。按照BPMN的规范,使用流程定义工具,将整个流程描述出来。
2. 部署流程。把画好的BPMN流程定义文件加载到数据库中,生成相关的表数据。
3. 启动流程。使用java代码来操作数据库表中的内容。
部署请假流程:
整体代码如下:
package com.nanjing;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.zip.ZipInputStream;
/**
* @author :楼兰
* @date :Created in 2021/4/7
* @description:
**/
public class ActivitiDemo {
/**
* 部署流程定义 文件上传方式
*/
@Test
public void testDeployment(){
// 1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到RepositoryService实例
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、使用RepositoryService进行部署
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("leave.bpmn20.xml") // 添加bpmn资源
//png资源命名是有规范的。Leave.myleave.png|jpg|gif|svg 或者Leave.png|jpg|gif|svg
.addClasspathResource("leave.png") // 添加png资源
.name("请假申请流程")
.deploy();
// 4、输出部署信息
System.out.println("流程部署id:" + deployment.getId());
System.out.println("流程部署名称:" + deployment.getName());
}
/**
* zip压缩文件上传方式
*/
@Test
public void deployProcessByZip() {
// 定义zip输入流
InputStream inputStream = this
.getClass()
.getClassLoader()
.getResourceAsStream(
"leave.zip");
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
// 获取repositoryService
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine
.getRepositoryService();
// 流程部署
Deployment deployment = repositoryService.createDeployment()
.addZipInputStream(zipInputStream)
.deploy();
System.out.println("流程部署id:" + deployment.getId());
System.out.println("流程部署名称:" + deployment.getName());
}
/**
* 启动流程实例
*/
@Test
public void testStartProcess(){
// 1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
// 3、根据流程定义Id启动流程
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey("myleave");
// 输出内容
System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
System.out.println("流程实例id:" + processInstance.getId());
System.out.println("当前活动Id:" + processInstance.getActivityId());
}
/**
* 查询当前个人待执行的任务
*/
@Test
public void testFindPersonalTaskList() {
// 任务负责人
String assignee = "worker";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 创建TaskService
TaskService taskService = processEngine.getTaskService();
// 根据流程key 和 任务负责人 查询任务
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey("myleave") //流程Key
.taskAssignee(assignee)//只查询该任务负责人的任务
.list();
for (Task task : list) {
System.out.println("流程实例id:" + task.getProcessInstanceId());
System.out.println("任务id:" + task.getId());
System.out.println("任务负责人:" + task.getAssignee());
System.out.println("任务名称:" + task.getName());
}
}
// 完成任务
@Test
public void completTask(){
// 获取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskService
TaskService taskService = processEngine.getTaskService();
// 根据流程key 和 任务的负责人 查询任务
// 返回一个任务对象
Task task = taskService.createTaskQuery()
.processDefinitionKey("myleave") //流程Key
.taskAssignee("worker") //要查询的负责人
.singleResult();
// 完成任务,参数:任务id
taskService.complete(task.getId());
}
/**
* 查询流程定义
*/
@Test
public void queryProcessDefinition(){
// 获取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 得到ProcessDefinitionQuery 对象
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
// 查询出当前所有的流程定义
// 条件:processDefinitionKey =evection
// orderByProcessDefinitionVersion 按照版本排序
// desc倒叙
// list 返回集合
List<ProcessDefinition> definitionList = processDefinitionQuery.processDefinitionKey("myleave")
.orderByProcessDefinitionVersion()
.desc()
.list();
// 输出流程定义信息
for (ProcessDefinition processDefinition : definitionList) {
System.out.println("流程定义 id="+processDefinition.getId());
System.out.println("流程定义 name="+processDefinition.getName());
System.out.println("流程定义 key="+processDefinition.getKey());
System.out.println("流程定义 Version="+processDefinition.getVersion());
System.out.println("流程部署ID ="+processDefinition.getDeploymentId());
}
}
/**
* 查询流程实例
*/
@Test
public void queryProcessInstance() {
// 流程定义key
String processDefinitionKey = "myleave";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
List<ProcessInstance> list = runtimeService
.createProcessInstanceQuery()
.processDefinitionKey(processDefinitionKey)//
.list();
for (ProcessInstance processInstance : list) {
System.out.println("----------------------------");
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());
}
}
@Test
public void deleteDeployment() {
// 流程部署id
String deploymentId = "1";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 通过流程引擎获取repositoryService
RepositoryService repositoryService = processEngine
.getRepositoryService();
//删除流程定义,如果该流程定义已有流程实例启动则删除时出错
repositoryService.deleteDeployment(deploymentId);
//设置true 级联删除流程定义,即使该流程有流程实例启动也可以删除,设置为false非级别删除方式,如果流程
// repositoryService.deleteDeployment(deploymentId, true);
}
@Test
public void queryBpmnFile() throws IOException {
// 1、得到引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、得到查询器:ProcessDefinitionQuery,设置查询条件,得到想要的流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myleave")
.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("/Users/zhou/myleave.png");
File file_bpmn = new File("/Users/zhou/leave.bpmn20.xml");
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();
}
/**
* 查看历史信息
*/
@Test
public void findHistoryInfo(){
// 获取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取HistoryService
HistoryService historyService = processEngine.getHistoryService();
// 获取 actinst表的查询对象
HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
// 查询 actinst表,条件:根据 InstanceId 查询,查询一个流程的所有历史信息
instanceQuery.processInstanceId("2501");
// 查询 actinst表,条件:根据 DefinitionId 查询,查询一种流程的所有历史信息
// instanceQuery.processDefinitionId("myleave:1:22504");
// 增加排序操作,orderByHistoricActivityInstanceStartTime 根据开始时间排序 asc 升序
instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
// 查询所有内容
List<HistoricActivityInstance> activityInstanceList = instanceQuery.list();
// 输出
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("<==========================>");
}
}
}
1.部署流程,执行这个方法:testDeployment
也可以通过zip压缩文件上传方式,一次定义多个流程,这里我就不尝试了
2.启动流程实例,执行testStartProcess
一个业务流程部署到activiti后,就可以使用了。例如这个出差申请的流程部署完成 后,就可以启动
一个流程进行一次出差申请了。流程的执行过程主要通过 RuntimeService服务来管理。
3.任务查询
流程启动后,任务的负责人就可以查询自己当前需要处理的待办任务了。
任务相关 的服务都是由TaskService管理。
当前请假流程启动后,就该等待worker用户提交请假申请了。实际中的 请假申请流程应该是从
worker提交请假申请开始,但是在activiti工作流 中,都是从starter事件开始,这个关系要理清楚。
4.流程任务处理
任务负责人查询到代办任务后,可以选择任务进行处理,完成任务。
这个任务完成后,这一个请假流程就推动到了下一个步骤,部门经理审批了。后续
可以用不同的用户来推动流程结束。
其实在完成审批任务的过程中,可以针对这个taskId,进行其他一些补充操作。例 如添加
Comment,添加附件,添加子任务,添加候选负责人等等。具体可以看下 taskService的API。
5.流程定义信息查询
这一步可以查询流程相关信息,包含流程定义,流程部署,流程版本。
6.流程实例信息查询
7.删除流程
注:
1、这里只删除了流程定义,不会删除历史表信息
2、删除任务时,可以选择传入一个boolean型的变量cascade ,表示是 否级联删除。
默认是false,表示普通删除。
如果该流程下存在已经运行的流程,使用普通删除会报错,而级联删除
可以将流程及相关记录全部删除。删除没有完成的流程节点后,就可以
完全删除流程定义信息了。
项目开发中,级联删除操作一般只开放给管理员使用。
由于刚刚已经发起了流程,还没有走完,删除报错
8.流程资源下载
在流程执行过程中,可以上传流程资源文件。我们之前在部署流程时,已经将 bpmn和描述bpmn
的png图片都上传了,并且在流程执行过程中,也可以上传资源 文件。如果其他用户想要查看这些
资源文件,可以从数据库中把资源文件下载下 来。
但是文件是以Blob的方式存在数据库中的,要获取Blob文件,可以使用JDBC来处 理。也可以使用
activiti提供的api来辅助实现。我们这里采用activiti的方式来实现。
注: 在获取资源文件名时,png图片资源的文件名是
processDefinition.getDiagramResourceName(),他来自于ACT_RE_PROCDEF表中的
DGRM_RESOURCE_NAME字段。这个字段 的值是在部署流程时根据文件名后缀判断出来的。
支持的格式为 [ResourceName].[key].[png|jpg|gif|svg]或者[ResourceName]. [png|jpg|gif|svg]
而bpmn文件的文件名是processDefinition.getResourceName(),他 来自于ACT_RE_PROCDEF表
中的RESOURCE_NAME字段。
9.流程历史信息查看
流程的历史信息都保存在activiti的act_hi_*相关的表中,我们可以查询流程执行的历 史信息。
这里需要通过HistoryService来查看相关的历史记录。
注:
1、关于流程历史信息,要注意,在删除流程时,如果是采取级联删 除的方式,那这个历史信息也
会随着一起删除。而普通删除方式不会删 除历史信息。
2、历史信息有不同的种类,具体可以通过historyService构建不同类型 的Query对象来获取结果。