该代码在上一篇博客的基础上开发。
Activiti工作流入门
1.绘制bpmn流程图
在resources目录下新建一个diagram文件夹来存放我们绘制的bpmn流程图
由于我的IDEA中已经安装了actiBPM插件,所以我们可以直接创建
然后利用IDEA中提供的组件来绘制流程图
为了方便测试,对应的3个流程处理的人员分别为zhangsan,lisi,wangwu。
我们可以点击对应的流程,在Assignee中指定任务负责人。
2.将bpmn转为png图片
在IDEA中将bpmn格式的后缀改为.xml
导出png图片,最终效果如下:
3.部署流程定义
部署流程定义就是要将上边绘制的图形即流程定义(.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.获取repositoryServiceRepositoryService 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压缩包部署
@Testpublic void deployProcessByZip() {//1.创建ProcessEngineer对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//2.获取repositoryServiceRepositoryService 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());}
4.启动一个流程实例
流程定义部署在 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.获取runtimeServiceRuntimeService runtimeService = processEngine.getRuntimeService();//3.创建流程实例ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holiday");//4.输出实例的相关信息System.out.println("流程部署id:" + processInstance.getDeploymentId());//nullSystem.out.println("流程定义id:" + processInstance.getProcessDefinitionId());//holiday:1:4System.out.println("流程实例id:" + processInstance.getId());//2501System.out.println("流程活动id:" + processInstance.getActivityId());//null}}
5.任务查询
流程启动后,各任务的负责人就可以查询自己当前需要处理的任务,查询出来的任务都是该用户的待办任务。
/*** 查询当前用户的任务列表*/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());//2501System.out.println("任务ID:" + task.getId()); //2505System.out.println("任务负责人:" + task.getAssignee());//zhangsanSystem.out.println("任务名称:" + task.getName());//填写请假申请单}
6.任务处理
任务负责人查询待办任务,选择任务进行处理,完成任务。
/*** 处理当前用户的任务* 背后操作的表:* act_hi_actinstact_hi_identitylinkact_hi_taskinstact_ru_identitylinkact_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()plete(task.getId());//5.输出任务的idSystem.out.println(task.getId());}}
在处理过程中可以实时观察代码中标明的表的变化,下面列出了一些表的数据变化:
比如在zhangsan填写完请假申请单后act_hi_actinst表的变化
流程到了部门经理审批这一步,由于部门经理还没有处理,end_time为null
全部完成后的效果:
act_ru_task表,可以发现每处理一步,都会将处理完的数据删除掉,然后当前的数据为待处理的。等lisi和wangwu都处理完,没有任务后,该表的数据会为空。
全部完成后的效果:
7.流程定义查询
/*** 查询流程定义信息*/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<ProcessDefinition> 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
8.流程定义删除
/*** 删除已经部署的流程定义** 背后影响的表:* 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.执行删除流程定义 参数代表流程部署的idrepositoryService.deleteDeployment("1");}}
9.流程定义资源查询
通过流程定义对象获取流程定义资源,获取 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.通过流程定义信息,得到部署IDString 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();}}
10.流程历史信息的查看
即使流程定义已经删除了,流程执行的历史信息通过前面的分析,依然保存在 activiti 的 act_hi_*相关的表中。所以我们还是可以查询流程执行的历史信息,可以通过 HistoryService 来查看相关的历史记录。
/*** 需求:* 历史数据的查看*/public class HistoryQuery {public static void main(String[] args) throws IOException {//1.得到ProcessEngine对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//2.得到HistoryServiceHistoryService historyService = processEngine.getHistoryService();//3.得到HistoricActivitiInstanceQuery对象HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();historicActivityInstanceQuery.processInstanceId("2501");//设置流程实例的id//4.执行查询List<HistoricActivityInstance> 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:42501=============================_3填写请假申请单holiday:1:42501=============================_4部门经理审批holiday:1:42501=============================_5总经理审批holiday:1:42501=============================_6结束holiday:1:42501=============================