该代码在上一篇博客的基础上开发。
Activiti工作流入门
在resources目录下新建一个diagram文件夹来存放我们绘制的bpmn流程图
由于我的IDEA中已经安装了actiBPM插件,所以我们可以直接创建
然后利用IDEA中提供的组件来绘制流程图
为了方便测试,对应的3个流程处理的人员分别为zhangsan,lisi,wangwu。
我们可以点击对应的流程,在Assignee中指定任务负责人。
在IDEA中将bpmn格式的后缀改为.xml
导出png图片,最终效果如下:
部署流程定义就是要将上边绘制的图形即流程定义(.bpmn)部署在工作流程引擎 activiti 中,方法 如下:
/**
* 流程定义的部署
* 背后影响的表:
* act_re_deployment: 部署信息
* act_re_procdef: 流程定义
* act_ge_bytearray: 流程定义的bpmn文件和png文件
*/
public class ActivitiDeployment {
public static void main(String[] args) {
//1.创建ProcessEngineer对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.获取repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3.部署对象
Deployment deploy = repositoryService.createDeployment()
//添加bpmn资源
.addClasspathResource("diagram/holiday.bpmn")
//添加图片文件资源
.addClasspathResource("diagram/holiday.png")
.name("请假申请流程")
.deploy();
//4.输出部署的一些信息
System.out.println(deploy.getId());
System.out.println(deploy.getName());
}
}
我们还可以用zip压缩包部署
@Test
public void deployProcessByZip() {
//1.创建ProcessEngineer对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.获取repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3.定义zip输入流
InputStream inputStream = this.getClass() .getClassLoader() .getResourceAsStream(
" diagram/holiday.zip");
//4.部署对象
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
Deployment deploy = repositoryService.createDeployment()
.addZipInputStream(zipInputStream)
//5.输出部署的一些信息
System.out.println(deploy.getId());
System.out.println(deploy.getName());
}
流程定义部署在 activiti 后就可以通过工作流管理业务流程了,也就是说上边部署的请假申请流程可以使用了。
针对该流程,启动一个流程表示发起一个新的请假申请单,这就相当于 java 类与 java 对象的关 系,类定义好后需要 new 创建一个对象使用,当然可以 new 多个对象。对于请假申请流程,张三发起一个请假申请单需要启动一个流程实例。
/**
* 启动流程实例(前提是完成了流程定义的部署工作)
*
* 背后影响的表:
* act_hi_actinst: 已完成的活动信息
* act_hi_identitylink: 参与者信息
* act_hi_procinst: 流程实例
* act_hi_taskinst: 任务实例
* act_ru_execution: 执行表
* act_ru_identitylink: 参与者信息
* act_ru_task: 任务
*/
public class ActivitiStartInstance {
public static void main(String[] args) {
//1.创建ProcessEngineer对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.获取runtimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//3.创建流程实例
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holiday");
//4.输出实例的相关信息
System.out.println("流程部署id:" + processInstance.getDeploymentId());//null
System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());//holiday:1:4
System.out.println("流程实例id:" + processInstance.getId());//2501
System.out.println("流程活动id:" + processInstance.getActivityId());//null
}
}
流程启动后,各任务的负责人就可以查询自己当前需要处理的任务,查询出来的任务都是该用户的待办任务。
/**
* 查询当前用户的任务列表
*/
public class ActivitiTaskQuery {
//wangwu完成自己任务列表的查询
public static void main(String[] args) {
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到TaskService对象
TaskService taskService = processEngine.getTaskService();
//3.根据流程定义的key,负责人assignee来实现当前用户的任务列表查询
Task task = taskService.createTaskQuery()
.processDefinitionKey("holiday")
.taskAssignee("zhangsan")
.singleResult();
//4.任务列表的展示
System.out.println("流程实例ID:" + task.getProcessInstanceId());//2501
System.out.println("任务ID:" + task.getId()); //2505
System.out.println("任务负责人:" + task.getAssignee());//zhangsan
System.out.println("任务名称:" + task.getName());//填写请假申请单
}
任务负责人查询待办任务,选择任务进行处理,完成任务。
/**
* 处理当前用户的任务
* 背后操作的表:
* act_hi_actinst
act_hi_identitylink
act_hi_taskinst
act_ru_identitylink
act_ru_task
*/
public class ActivitiCompleteTask {
//查询当前用户wangwu的任务并处理掉
public static void main(String[] args) {
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到TaskService对象
TaskService taskService = processEngine.getTaskService();
//3.查询当前用户的任务
Task task = taskService.createTaskQuery()
.processDefinitionKey("holiday")
.taskAssignee("zhangsan")
.singleResult();
//4.处理任务,结合当前用户任务列表的查询操作的话,任务ID:task.getId()
taskService.complete(task.getId());
//5.输出任务的id
System.out.println(task.getId());
}
}
在处理过程中可以实时观察代码中标明的表的变化,下面列出了一些表的数据变化:
比如在zhangsan填写完请假申请单后act_hi_actinst表的变化
流程到了部门经理审批这一步,由于部门经理还没有处理,end_time为null
全部完成后的效果:
act_ru_task表,可以发现每处理一步,都会将处理完的数据删除掉,然后当前的数据为待处理的。等lisi和wangwu都处理完,没有任务后,该表的数据会为空。
全部完成后的效果:
/**
* 查询流程定义信息
*/
public class QueryProcessDefinition {
public static void main(String[] args) {
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.创建RepositoryService对象
RepositoryService repositoryService = processEngine.getRepositoryService();
//3.得到ProcessDefinitionQuery对象,可以认为它就是一个查询器
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
//4.设置条件,并查询出当前的所有流程定义 查询条件:流程定义的key=holiday
//orderByProcessDefinitionVersion() 设置排序方式,根据流程定义的版本号进行排序
List list = processDefinitionQuery.processDefinitionKey("holiday")
.orderByProcessDefinitionVersion()
.desc().list();
//5.输出流程定义信息
for(ProcessDefinition processDefinition :list){
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("流程部署的ID:"+processDefinition.getDeploymentId());
}
}
}
输出信息如下:
流程定义ID:holiday:1:4
流程定义名称:请假流程
流程定义的Key:holiday
流程定义的版本号:1
流程部署的ID:1
/**
* 删除已经部署的流程定义
*
* 背后影响的表:
* act_re_deployment: 部署信息
* act_re_procdef: 流程定义
* act_ge_bytearray: 流程定义的bpmn文件和png文件
*/
public class DeleteProcessDefinition {
/**
* 注意事项:
* 1.当我们正在执行的这一套流程没有完全审批结束的时候,此时如果要删除流程定义信息就会失败
* 2.如果公司层面要强制删除,可以使用repositoryService.deleteDeployment("1",true);
* //参数true代表级联删除,此时就会先删除没有完成的流程结点,最后就可以删除流程定义信息 false的值代表不级联
*
* @param args
*/
public static void main(String[] args) {
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.创建RepositoryService对象
RepositoryService repositoryService = processEngine.getRepositoryService();
//3.执行删除流程定义 参数代表流程部署的id
repositoryService.deleteDeployment("1");
}
}
通过流程定义对象获取流程定义资源,获取 bpmn 和 png。
/**
* 需求:
* 1.从Activiti的act_ge_bytearray表中读取两个资源文件
* 2.将两个资源文件保存到路径: /Users/apple/diagram/
*
* 技术方案:
* 1.第一种方式使用actviti的api来实现
* 2.第二种方式:其实就是原理层面,可以使用jdbc的对blob类型,clob类型数据的读取,并保存
* IO流转换,最好commons-io.jar包可以轻松解决IO操作
*
* 真实应用场景:用户想查看这个请假流程具体有哪些步骤要走?
*
*/
public class QueryBpmnFile {
public static void main(String[] args) throws IOException {
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到RepositoryService对象
RepositoryService repositoryService = processEngine.getRepositoryService();
//3.得到查询器:ProcessDefinitionQuery对象
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
//4.设置查询条件
processDefinitionQuery.processDefinitionKey("holiday");//参数是流程定义的key
//5.执行查询操作,查询出想要的流程定义
ProcessDefinition processDefinition = processDefinitionQuery.singleResult();
//6.通过流程定义信息,得到部署ID
String deploymentId = processDefinition.getDeploymentId();
//7.通过repositoryService的方法,实现读取图片信息及bpmn文件信息(输入流)
//getResourceAsStream()方法的参数说明:第一个参数部署id,第二个参数代表资源名称
//processDefinition.getDiagramResourceName() 代表获取png图片资源的名称
//processDefinition.getResourceName()代表获取bpmn文件的名称
InputStream pngIs = repositoryService
.getResourceAsStream(deploymentId,processDefinition.getDiagramResourceName());
InputStream bpmnIs = repositoryService
.getResourceAsStream(deploymentId,processDefinition.getResourceName());
//8.构建出OutputStream流
OutputStream pngOs =
new FileOutputStream("/Users/apple/"+processDefinition.getDiagramResourceName());
OutputStream bpmnOs =
new FileOutputStream("/Users/apple/"+processDefinition.getResourceName());
//9.输入流,输出流的转换 commons-io-xx.jar中的方法
IOUtils.copy(pngIs,pngOs);
IOUtils.copy(bpmnIs,bpmnOs);
//10.关闭流
pngOs.close();
bpmnOs.close();
pngIs.close();
bpmnIs.close();
}
}
即使流程定义已经删除了,流程执行的历史信息通过前面的分析,依然保存在 activiti 的 act_hi_*相关的表中。所以我们还是可以查询流程执行的历史信息,可以通过 HistoryService 来查看相关的历史记录。
/**
* 需求:
* 历史数据的查看
*/
public class HistoryQuery {
public static void main(String[] args) throws IOException {
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到HistoryService
HistoryService historyService = processEngine.getHistoryService();
//3.得到HistoricActivitiInstanceQuery对象
HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
historicActivityInstanceQuery.processInstanceId("2501");//设置流程实例的id
//4.执行查询
List list = historicActivityInstanceQuery
.orderByHistoricActivityInstanceStartTime().asc().list();//排序StartTime
//5.遍历查询结果
System.out.println("=============================");
for (HistoricActivityInstance instance : list) {
System.out.println(instance.getActivityId());
System.out.println(instance.getActivityName());
System.out.println(instance.getProcessDefinitionId());
System.out.println(instance.getProcessInstanceId());
System.out.println("=============================");
}
}
}
输出信息如下:
=============================
_holiday
请假流程
holiday:1:4
2501
=============================
_3
填写请假申请单
holiday:1:4
2501
=============================
_4
部门经理审批
holiday:1:4
2501
=============================
_5
总经理审批
holiday:1:4
2501
=============================
_6
结束
holiday:1:4
2501
=============================