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());
    }

1656751796036

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());
    }

执行结果
1656759592596
流程定义的key值
1656771266587-1656771323642

1656753465336

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());
        }
    }

1656759723875
image-1656759773407

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());
    }

1656759957830
image-1656760115697

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());
        }
    }

1656771371918

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());
            }
        }
    }

说明:

  1. 使用repositoryService删除流程定义,历史表信息不会被删除。
  2. 如果该流程定义下没有正在运行的流程,则可以用普通删除。
    如果该流程定义下存在已经运行的流程,使用普通删除报错,可用级联删除方法将流程及相关记录全部删除。
    先删除没有完成流程节点,最后就可以完全删除流程定义信息。
    项目开发中级联删除操作一般只开放给超级管理员使用。

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();
    }

说明:

  1. deploymentId为流程部署ID
  2. resource_name为act_ge_bytearray表中NAME_列的值
  3. 使用repositoryService的getDeploymentResourceNames方法可以获取指定部署下得所有文件的名称
  4. 使用repositoryService的getResourceAsStream方法传入部署ID和资源图片名称可以获取部署下指定名称文件的输入流
  5. 最后将输入流中的图片资源进行输出

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
1656775473238
------------------------------------------------------------------------‘
1656775528887

Q.E.D.