(4)Activiti 流程定义操作—Activiti入门教程学习笔记

(4)Activiti 流程定义操作---Activiti入门教程学习笔记

一、什么是流程定义

流程定义是线下按照 bpmn2.0 标准去描述 业务流程,通常使用 activiti-explorer(web 控制台)或 activiti-eclipse-designer 插件对业务流程进行建模,这两种方式都遵循 bpmn2.0 标准。本教程使用activiti-eclipse-designer 插件完成流程建模。使用 designer 设计器绘制流程,会生成两个文件:.bpmn和.png

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
  <process id="holiday" name="holiday" isExecutable="true">
    <startEvent id="sid-4b7dde5e-76f4-4523-b85a-e9b6b9121742"/>
    <userTask id="sid-a974627b-411f-4476-8291-152a97fb24dd" name="填写请假单" activiti:assignee="zhangsan"/>
    <userTask id="sid-02f0a0dc-c66b-4cb1-bb7d-0c93c2b8f656" name="部门经理审批" activiti:assignee="lisi"/>
    <userTask id="sid-244ec10f-b963-4250-8685-c2bbea5c8978" name="总经理审批" activiti:assignee="wangwu"/>
    <endEvent id="sid-fb4ee57e-d6b7-4d35-bc62-7c0663754591"/>
    <sequenceFlow id="sid-3afcfa32-99de-456d-9cd0-f4332e044ff3" sourceRef="sid-4b7dde5e-76f4-4523-b85a-e9b6b9121742" targetRef="sid-a974627b-411f-4476-8291-152a97fb24dd"/>
    <sequenceFlow id="sid-ce0f52ac-55d5-47ef-ba00-e453dd50a562" sourceRef="sid-a974627b-411f-4476-8291-152a97fb24dd" targetRef="sid-02f0a0dc-c66b-4cb1-bb7d-0c93c2b8f656"/>
    <sequenceFlow id="sid-f37e21e6-c18a-4b79-ac3b-61de52822f5e" sourceRef="sid-02f0a0dc-c66b-4cb1-bb7d-0c93c2b8f656" targetRef="sid-244ec10f-b963-4250-8685-c2bbea5c8978"/>
    <sequenceFlow id="sid-a5dcdb25-d594-45d5-ad67-3dec14d87bae" sourceRef="sid-244ec10f-b963-4250-8685-c2bbea5c8978" targetRef="sid-fb4ee57e-d6b7-4d35-bc62-7c0663754591"/>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_holiday">
    <bpmndi:BPMNPlane bpmnElement="holiday" id="BPMNPlane_holiday">
      <bpmndi:BPMNShape id="shape-44920f81-b800-48b5-a7bf-34eb9ee72346" bpmnElement="sid-4b7dde5e-76f4-4523-b85a-e9b6b9121742">
        <omgdc:Bounds x="50.0" y="-15.0" width="30.0" height="30.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-3bd97d4e-6b69-4028-8eb7-3027e4fe1ba5" bpmnElement="sid-a974627b-411f-4476-8291-152a97fb24dd">
        <omgdc:Bounds x="150.0" y="-25.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-cbb6e54a-c071-4415-96e6-02c7c4fff75e" bpmnElement="sid-02f0a0dc-c66b-4cb1-bb7d-0c93c2b8f656">
        <omgdc:Bounds x="340.0" y="-25.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-5e6deff4-ba08-4f93-bb97-0779255e8f47" bpmnElement="sid-244ec10f-b963-4250-8685-c2bbea5c8978">
        <omgdc:Bounds x="515.0" y="-25.0" width="100.0" height="80.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="shape-a8156f64-4f61-4719-9feb-d86fddcf1d3a" bpmnElement="sid-fb4ee57e-d6b7-4d35-bc62-7c0663754591">
        <omgdc:Bounds x="695.0" y="0.0" width="30.0" height="30.0"/>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="edge-317cb2e8-fa8b-4905-8e7e-ea4c6eb8a7b7" bpmnElement="sid-3afcfa32-99de-456d-9cd0-f4332e044ff3">
        <omgdi:waypoint x="80.0" y="-7.5"/>
        <omgdi:waypoint x="150.0" y="-5.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-fa838e8a-31e5-4aea-9eaf-dbb496fedf95" bpmnElement="sid-ce0f52ac-55d5-47ef-ba00-e453dd50a562">
        <omgdi:waypoint x="250.0" y="15.0"/>
        <omgdi:waypoint x="340.0" y="15.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-d8f28788-da77-4baa-bd10-fc60d7c76ab8" bpmnElement="sid-f37e21e6-c18a-4b79-ac3b-61de52822f5e">
        <omgdi:waypoint x="440.0" y="15.0"/>
        <omgdi:waypoint x="515.0" y="15.0"/>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="edge-47ff9047-c23d-4bf6-a06b-a81ade328f81" bpmnElement="sid-a5dcdb25-d594-45d5-ad67-3dec14d87bae">
        <omgdi:waypoint x="615.0" y="15.0"/>
        <omgdi:waypoint x="695.0" y="15.0"/>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

BPMN 2.0 根节点是 definitions 节点。 这个元素中,可以定义多个流程定义(不过我们建议每个文件只包含一个流程定义, 可以简化开发过程中的维护难度)。 注意,definitions 元素 最少也要包含 xmlns 和 targetNamespace 的声明。 targetNamespace 可以是任意值,它用来对流程实例进行分类。

流程定义部分:定义了流程每个结点的描述及结点之间的流程流转。

流程布局定义:定义流程每个结点在流程图上的位置坐标等信息。

二、流程定义部署

2.1什么是流程定义部署

将线下定义的流程部署到 activiti 数据库中,这就是流程定义部署,通过调用 activiti 的 api 将流程定义的 bpmn 和 png 两个文件一个一个添加部署到 activiti 中,也可以将两个文件打成 zip 包进行部署。

2.2流程定义部署的方式

单个文件部署:

    @Test
    public void deployProcess() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deploy = repositoryService.createDeployment().
                addClasspathResource("bpmn/holiday.bpmn20.xml").
                addClasspathResource("bpmn/holiday.bpmn20.png").
                name("请假申请流程").deploy();
        System.out.println("流程部署id:"+deploy.getId());
        System.out.println("流程部署名称:"+deploy.getName());
        System.out.println("流程部署key:"+deploy.getKey());

    }

压缩包部署:

    @Test
    public void deployProcess2() {

        //1.创建ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.得到RepositoryService实例
        RepositoryService repositoryService = processEngine.getRepositoryService();

        //3.转化出ZipInputStream流对象
        InputStream is = ActivitiDeployment.class.getClassLoader().getResourceAsStream("diagram/holidayBPMN.zip");

        //将 inputstream流转化为ZipInputStream流
        ZipInputStream zipInputStream = new ZipInputStream(is);

        //3.进行部署
        Deployment deployment = repositoryService.createDeployment()
                .addZipInputStream(zipInputStream)
                .name("请假申请单流程")
                .deploy();

        //4.输出部署的一些信息
        System.out.println(deployment.getName());
        System.out.println(deployment.getId());

    }

三、流程定义查询

   @Test
    public void queryProcessDefinition(){
        //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());

        }
    }

四、流程定义删除

@Test
    /**
     * 删除已经部署的流程定义
     *
     * 背后影响的表:
     act_ge_bytearray
     act_re_deployment
     act_re_procdef
     */
    public void deleteProcessDefinition(){

        /*
        *   * 注意事项:
         *     1.当我们正在执行的这一套流程没有完全审批结束的时候,此时如果要删除流程定义信息就会失败
         *     2.如果公司层面要强制删除,可以使用repositoryService.deleteDeployment("1",true);
         *     //参数true代表级联删除,此时就会先删除没有完成的流程结点,最后就可以删除流程定义信息  false的值代表不级联
         * */


        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.创建RepositoryService对象
        RepositoryService repositoryService = processEngine.getRepositoryService();

        //3.执行删除流程定义  参数代表流程部署的id
        repositoryService.deleteDeployment("1");
    }

说明:

1) 使用 repositoryService 删除流程定义

2) 如果该流程定义下没有正在运行的流程,则可以用普通删除。

3) 如果该流程定义下存在已经运行的流程,使用普通删除报错,可用级联删除方法将流程及相关

记录全部删除。项目开发中使用级联删除的情况比较多,删除操作一般只开放给超级管理员使用。

五、流程定义资源查询

/**
     *
     * 查询流程定义的资源
     *
     *
     * 需求:
     * 1.从Activiti的act_ge_bytearray表中读取两个资源文件
     * 2.将两个资源文件保存到路径:   G:\Activiti7开发计划\Activiti7-day03\资料
     *
     * 技术方案:
     *     1.第一种方式使用actviti的api来实现
     *     2.第二种方式:其实就是原理层面,可以使用jdbc的对blob类型,clob类型数据的读取,并保存
     *        IO流转换,最好commons-io.jar包可以轻松解决IO操作
     *
     * 真实应用场景:用户想查看这个请假流程具体有哪些步骤要走?
     *
     *
     */
    @Test
    public void queryResources() throws  Exception{
        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.得到RepositoryService对象
        RepositoryService repositoryService = processEngine.getRepositoryService();

        //3.得到查询器:ProcessDefinitionQuery对象
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();

        //4.设置查询条件
        processDefinitionQuery.processDefinitionKey("holiday2");//参数是流程定义的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("D:\\StudyProject\\"+processDefinition.getDiagramResourceName());

        OutputStream bpmnOs =
                new FileOutputStream("D:\\StudyProject\\"+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 来查看相关的历史记录。

 /**
     * 需求:
     *  *   历史数据的查看
     */
    @Test
    public void queryHistrory(){
        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.得到HistoryService
        HistoryService historyService = processEngine.getHistoryService();

        //3.得到HistoricActivitiInstanceQuery对象
        HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();

        historicActivityInstanceQuery.processInstanceId("2501");//设置流程实例的id

        //4.执行查询
        List<HistoricActivityInstance> list = historicActivityInstanceQuery
                .orderByHistoricActivityInstanceStartTime().asc().list();//排序StartTime

        //5.遍历查询结果
        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("=============================");
        }

    }

七、关于流程定义的全部代码

package com.devtao;

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.apache.commons.io.IOUtils;
import org.junit.Test;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.zip.ZipInputStream;


public class ActivitiDefinitionTest {


    /**
     * 测试25张表的生成,初始化数据库方式1
     */
    @Test
    public void testGenTable(){
        //1.创建ProcessEngineConfiguration对象  第一个参数:配置文件名称  第二个参数是processEngineConfiguration的bean的id
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration
                .createProcessEngineConfigurationFromResource("activiti.cfg.xml","processEngineConfiguration");
        //2.创建ProcesEngine对象
        ProcessEngine processEngine = configuration.buildProcessEngine();

        //3.输出processEngine对象
        System.out.println(processEngine);

    }


    /**
     * 测试25张表的生成,初始化数据库方式2
     */
    @Test
    public void testGenTable2(){
        //条件:1.activiti配置文件名称:activiti.cfg.xml   2.bean的id="processEngineConfiguration"
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        System.out.println(processEngine);

    }


    /**
     * 部署流程定义 方式1,单个文件
     */
    @Test
    public void deployProcess() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deploy = repositoryService.createDeployment().
                addClasspathResource("bpmn/holiday.bpmn20.xml").
                addClasspathResource("bpmn/holiday.png").
                name("请假申请流程").deploy();
        System.out.println("流程部署id:"+deploy.getId());
        System.out.println("流程部署名称:"+deploy.getName());
        System.out.println("流程部署key:"+deploy.getKey());

    }

    /**
     * 部署流程定义 方式2  压缩包
     */
    @Test
    public void deployProcess2() {

        //1.创建ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.得到RepositoryService实例
        RepositoryService repositoryService = processEngine.getRepositoryService();

        //3.转化出ZipInputStream流对象
        InputStream is = ActivitiDeployment.class.getClassLoader().getResourceAsStream("diagram/holidayBPMN.zip");

        //将 inputstream流转化为ZipInputStream流
        ZipInputStream zipInputStream = new ZipInputStream(is);

        //3.进行部署
        Deployment deployment = repositoryService.createDeployment()
                .addZipInputStream(zipInputStream)
                .name("请假申请单流程")
                .deploy();

        //4.输出部署的一些信息
        System.out.println(deployment.getName());
        System.out.println(deployment.getId());

    }


    /**
     * 查询流程定义
     */
    @Test
    public void queryProcessDefinition(){
        //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());

        }
    }

    @Test
    /**
     * 删除已经部署的流程定义
     *
     * 背后影响的表:
     act_ge_bytearray
     act_re_deployment
     act_re_procdef
     */
    public void deleteProcessDefinition(){

        /*
        *   * 注意事项:
         *     1.当我们正在执行的这一套流程没有完全审批结束的时候,此时如果要删除流程定义信息就会失败
         *     2.如果公司层面要强制删除,可以使用repositoryService.deleteDeployment("1",true);
         *     //参数true代表级联删除,此时就会先删除没有完成的流程结点,最后就可以删除流程定义信息  false的值代表不级联
         * */


        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.创建RepositoryService对象
        RepositoryService repositoryService = processEngine.getRepositoryService();

        //3.执行删除流程定义  参数代表流程部署的id
        repositoryService.deleteDeployment("15001");
    }



    /**
     *
     * 查询流程定义的资源
     *
     *
     * 需求:
     * 1.从Activiti的act_ge_bytearray表中读取两个资源文件
     * 2.将两个资源文件保存到路径:   G:\Activiti7开发计划\Activiti7-day03\资料
     *
     * 技术方案:
     *     1.第一种方式使用actviti的api来实现
     *     2.第二种方式:其实就是原理层面,可以使用jdbc的对blob类型,clob类型数据的读取,并保存
     *        IO流转换,最好commons-io.jar包可以轻松解决IO操作
     *
     * 真实应用场景:用户想查看这个请假流程具体有哪些步骤要走?
     *
     *
     */
    @Test
    public void queryResources() throws  Exception{
        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.得到RepositoryService对象
        RepositoryService repositoryService = processEngine.getRepositoryService();

        //3.得到查询器:ProcessDefinitionQuery对象
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();

        //4.设置查询条件
        processDefinitionQuery.processDefinitionKey("holiday2");//参数是流程定义的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("D:\\StudyProject\\"+processDefinition.getDiagramResourceName());

        OutputStream bpmnOs =
                new FileOutputStream("D:\\StudyProject\\"+processDefinition.getResourceName());

        //9.输入流,输出流的转换  commons-io-xx.jar中的方法
        IOUtils.copy(pngIs,pngOs);
        IOUtils.copy(bpmnIs,bpmnOs);
        //10.关闭流
        pngOs.close();
        bpmnOs.close();
        pngIs.close();
        bpmnIs.close();
    }

    /**
     * 需求:
     *  *   历史数据的查看
     */
    @Test
    public void queryHistrory(){
        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.得到HistoryService
        HistoryService historyService = processEngine.getHistoryService();

        //3.得到HistoricActivitiInstanceQuery对象
        HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();

        historicActivityInstanceQuery.processInstanceId("2501");//设置流程实例的id

        //4.执行查询
        List<HistoricActivityInstance> list = historicActivityInstanceQuery
                .orderByHistoricActivityInstanceStartTime().asc().list();//排序StartTime

        //5.遍历查询结果
        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("=============================");
        }

    }

}
大T笔记所有文章均为本人原创,转载请您注明来源,并留下原文链接地址,是对我的尊重,也是对知识的尊重,谢谢!
大T笔记 » (4)Activiti 流程定义操作—Activiti入门教程学习笔记

大T笔记-我的个人互联网创业和自由职业之路

关于我 我的百宝箱
大T笔记-专注个人互联网创业和自由职业