Activiti7基础

1.工作流介绍

相关概念

工作流:工作从开始到结束的一个流程,可以通过计算机实现流程自动化管理,比如钉钉请假审批

工作流引擎:能够实现流程自动化控制的工具(比如正在学的Activiti)

工作流系统:具有工作流功能的系统

工作流系统

适用于各个行业的流程处理

1.实现方式

  • 程序员编码(不灵活,流程变更就很难受), 比如请假 各级领导审批的状态使用数据库表某个字段记录即可(0同意 1不同意)
  • 使用第三方工作流框架 Activiti,哈哈哈,,,,,

2.工作流实现原理分析

如何可以做到我们在业务流程发生变更后,我们的业务系统代码可以不发生改变?

此时我们就来分 析一下原理。

具体分析过程如下图所示:

activiti工作流引擎 java activiti7工作流_xml

这张表就相当于activiti7中的 act_ru_task

2.Activiti7基础

Activiti是一个项目的名称,Alfresco软件在2010年5月17日宣布Activiti业务流程管理(BPM)开源项目的正式启动,其首席架构师由业务流程管理BPM的专家 Tom Baeyens担任

官网:https://www.activiti.org/

1.相关概念

  • BPM(Business Process Management),即业务流程管理。是一种以规范化的构造端到端的卓越 业务流程为中心,以持续的提高组织业务绩效为目的系统化方法
  • BPM软件:画业务流程图的软件(专业软件)
  • BPMN:(Business Process Model And Notation)- 业务流程模型和符号,BPM流程图的一种规范

2.Activiti使用步骤

步骤:

SaaS-IHRM

  • 1.整合Actviti
  • 2.实现业务流程建模,使用BPMN实现业务流程图
  • 3.部署业务流程到Activiti
  • 4.启动流程实例
  • 5.查询待办任务
  • 6.处理待办任务
  • 7.结束流程

3.IDEA画BPMN图

IDEA安装流程设计器Activitidesigner(actiBPM插件)

IDEA2021搜索不到。。。

activiti工作流引擎 java activiti7工作流_xml_02

1.去官网下载插件

https://plugins.jetbrains.com/

activiti工作流引擎 java activiti7工作流_activiti工作流引擎 java_03

发现该插件没有对2021版本的idea进行维护

将该插件下载到本地,然后IDEA去本地安装插件

activiti工作流引擎 java activiti7工作流_spring_04

activiti工作流引擎 java activiti7工作流_activiti工作流引擎 java_05

还是不行,要不降低版本到idea2019以下,要不找其他的画bpmn图的工具。。。。

4.画图软件

搞个第三方war包部署到tomcat中启动使用

5.准备工作(生成25张表)

支持的数据库:h2,mysql,oracle,postgres,db2,mssql

生成我们需要的25张表

步骤:

1.导入相关依赖

2.配置数据库,log4j.以及activiti要用的对象

3.测试 生成25张表

1.导入相关依赖

<dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-engine</artifactId>
            <version>7.0.0.Beta1</version>
        </dependency>

        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring</artifactId>
            <version>7.0.0.Beta1</version>
        </dependency>

        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-bpmn-model</artifactId>
            <version>7.0.0.Beta1</version>
        </dependency>

        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-bpmn-converter</artifactId>
            <version>7.0.0.Beta1</version>
        </dependency>

        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-json-converter</artifactId>
            <version>7.0.0.Beta1</version>
        </dependency>

        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-bpmn-layout</artifactId>
            <version>7.0.0.Beta1</version>
        </dependency>

        <dependency>
            <groupId>org.activiti.cloud</groupId>
            <artifactId>activiti-cloud-services-api</artifactId>
            <version>7.0.0.Beta1</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <!-- log start -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <!-- log end -->

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>

        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>

2.配置数据库,log4j.以及activiti要用的对象 (activiti.cfg.xml)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
						http://www.springframework.org/schema/contex http://www.springframework.org/schema/context/spring-context.xsd
						http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://47.107.93.172:3306/activiti7?useUnicode=true&characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
        <property name="maxActive" value="3"/>
        <property name="maxIdle" value="1"/>
    </bean>

    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <property name="dataSource" ref="dataSource"></property>
        <property name="databaseSchemaUpdate" value="true"/>
    </bean>

</beans>

3.测试 生成25张表

//生成25张表
    @Test
    public void test1(){
        //加载配置文件
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        //获取processEngine对象 生成25张表
        ProcessEngine processEngine = configuration.buildProcessEngine();
        System.out.println(processEngine);
    }

activiti工作流引擎 java activiti7工作流_spring_06

3.表结构设计说明

数据库表的命名规则

Activiti 的表都以 ACT_开头。 第二部分是表示表的用途的两个字母标识。 用途也和服务的 API 对 应。

  • ACT_RE_: 'RE'表示 repository。 这个前缀的表包含了流程定义和流程静态资源 (图片, 规则,等等)。
  • ACT_RU_: 'RU'表示 runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务, 等运行中的数据。 Activiti 只在流程实例执行过程中保存这些数据, 在流程结束时就会删 除这些记录。 这样运行时表可以一直很小速度很快。
  • ACT_HI_: 'HI'表示 history。 这些表包含历史数据,比如历史流程实例, 变量,任务等 等。
  • ACT_GE_: GE 表示 general。通用数据, 用于不同场景下。

4.Activiti 服务架构

activiti工作流引擎 java activiti7工作流_spring_07

activiti工作流引擎 java activiti7工作流_xml_08

我们就通过各个service来操作25张表(无需自己实现),进而简化开发

5.activiti 入门体验

1.定义流程

(画bpmn图),实际上就是一个xml文件

holiday.bpmn

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" 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" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1540200341676" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
  <process id="holiday" isClosed="false" isExecutable="true" name="请假流程" processType="None">
    <startEvent id="_2" name="StartEvent"/>
    <userTask activiti:assignee="zhangsan" activiti:exclusive="true" id="_3" name="填写请假申请单"/>
    <userTask activiti:assignee="lisi" activiti:exclusive="true" id="_4" name="部门经理审批"/>
    <userTask activiti:assignee="wangwu" activiti:exclusive="true" id="_5" name="总经理审批"/>
    <endEvent id="_6" name="EndEvent"/>
    <sequenceFlow id="_7" sourceRef="_2" targetRef="_3"/>
    <sequenceFlow id="_8" sourceRef="_3" targetRef="_4"/>
    <sequenceFlow id="_9" sourceRef="_4" targetRef="_5"/>
    <sequenceFlow id="_10" sourceRef="_5" targetRef="_6"/>
  </process>
  <bpmndi:BPMNDiagram documentation="background=#FFFFFF;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
    <bpmndi:BPMNPlane bpmnElement="holiday">
      <bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
        <omgdc:Bounds height="32.0" width="32.0" x="280.0" y="45.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
        <omgdc:Bounds height="55.0" width="85.0" x="255.0" y="140.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4">
        <omgdc:Bounds height="55.0" width="85.0" x="255.0" y="245.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5">
        <omgdc:Bounds height="55.0" width="85.0" x="255.0" y="350.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_6" id="Shape-_6">
        <omgdc:Bounds height="32.0" width="32.0" x="275.0" y="455.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="_7" id="BPMNEdge__7" sourceElement="_2" targetElement="_3">
        <omgdi:waypoint x="296.0" y="77.0"/>
        <omgdi:waypoint x="296.0" y="140.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_8" id="BPMNEdge__8" sourceElement="_3" targetElement="_4">
        <omgdi:waypoint x="297.5" y="195.0"/>
        <omgdi:waypoint x="297.5" y="245.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_9" id="BPMNEdge__9" sourceElement="_4" targetElement="_5">
        <omgdi:waypoint x="297.5" y="300.0"/>
        <omgdi:waypoint x="297.5" y="350.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_10" id="BPMNEdge__10" sourceElement="_5" targetElement="_6">
        <omgdi:waypoint x="291.0" y="405.0"/>
        <omgdi:waypoint x="291.0" y="455.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

对应的holiday.png

activiti工作流引擎 java activiti7工作流_bc_09

2.部署流程

单个文件部署方式

其实就是加载bpmn图,将流程相关信息加载到表中

---repositoryService

/**
     * 部署流程(加载bpmn图,解析流程信息,将数据添加到对应的表中)
     * 影响的表:
     * act_re_procdef  流程定义的信息
     * act_re_deployment  部署信息
     * act_ge_bytearray 流程定义的bpmn文件及png文件
     */
    @Test
    public void test2() {
        //创建ProcessEngine对象
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();

        //获取repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();

        //部署
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("diagram/holiday.bpmn")
                .addClasspathResource("diagram/holiday.png")
                .name("请假申请流程")
                .deploy();

        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
        System.out.println(deploy.getKey());
    }

压缩包方式部署

可以将所有的bpmn文件,png等文件放到压缩文件中,然后通过压缩包方式部署

3.启动一个流程实例

/**
 * 启动流程实例
 * 影响的表:
 * act_hi_actinst  已完成的活动信息
 * act_hi_identitylink 参与者信息
 * act_hi_procinst 流程实例
 * act_hi_taskinst 任务实例
 * act_ru_execution 执行表
 * act_ru_identitylink 参与者信息 任务
 * act_ru_task
 */
@Test
public void test3() {//创建ProcessEngine对象
    ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
    ProcessEngine processEngine = configuration.buildProcessEngine();

    RuntimeService runtimeService = processEngine.getRuntimeService();
    //启动流程实例
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holiday");

    //实例相关信息
    System.out.println(processInstance.getDeploymentId());//部署id
    System.out.println(processInstance.getId());//实例id
}

4.任务查询

@Test
    public void test4() {
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();

        TaskService taskService = processEngine.getTaskService();

        //查询用户任务列表
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey("holiday")
                .taskAssignee("zhangsan")
                .list();

        for (Task task : list) {
            System.out.println(task.getAssignee());//任务负责人
            System.out.println(task.getId());//任务id
            System.out.println(task.getName());
            System.out.println(task.getProcessInstanceId());//流程实例id
        }
    }

5.任务处理

//处理任务
    @Test
    public void test5(){
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();

        TaskService taskService = processEngine.getTaskService();

        //根据任务id  处理任务
        taskService.complete("2505");
    }

6.相关api

流程定义查询

@Test
    //查询流程定义信息
    public void test6(){
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();

        RepositoryService repositoryService = processEngine.getRepositoryService();
        //流程定义查询器
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();

        //根据版本号降序
        List<ProcessDefinition> list = processDefinitionQuery.processDefinitionKey("holiday")
                .orderByProcessDefinitionVersion()
                .desc().list();

        for (ProcessDefinition processDefinition : list) {
            System.out.println(processDefinition.getDeploymentId());
            System.out.println(processDefinition.getId());
            System.out.println(processDefinition.getKey());
            System.out.println(processDefinition.getName());
        }
    }

流程定义删除

@Test
    //流程定义删除
    public void test7(){
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();

        RepositoryService repositoryService = processEngine.getRepositoryService();
        //删除流程定义(根据流程定义id删除)
        //影响的表和流程定义的那几张表一样
       repositoryService.deleteDeployment("5001",true);
    }

注意事項:

  • 正在执行的流程没有结束的话,删除流程定义会失败
  • 如果需要强制删除的话,用repositoryService.deleteDeployment("5001",true);,这个时候会先删除没有执行完的流程,再删除流程定义信息

流程定义资源查询

查询png图片 和 bpmn文件,应用场景:用户想看查看需要经历哪些流程

在act_ge_bytearray表中查询

方案:

  1. 使用activiti7的api实现
  2. 使用jdbc操作blob类型,clob类型数据(原理层面)

activiti7的api实现:

@Test
    //流程定义资源查询
    public void test8() throws IOException {
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();

        RepositoryService repositoryService = processEngine.getRepositoryService();

        //查询器
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        //查询流程定义信息
        ProcessDefinition processDefinition = processDefinitionQuery.processDefinitionKey("holiday").singleResult();

        String deploymentId = processDefinition.getDeploymentId();//流程部署id

        //查询读取资源文件  bpmn   png等  ,读取到输入流
        //两个参数:部署id,资源名称
        InputStream bpmnIs = repositoryService.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
        InputStream pngIs = repositoryService.getResourceAsStream(deploymentId, processDefinition.getResourceName());

        //输出到指定目录
        FileOutputStream bpmnFis = new FileOutputStream("D:\\文件下载\\"+processDefinition.getDiagramResourceName());  //bpmn文件名\
        FileOutputStream pngFis = new FileOutputStream("D:\\文件下载\\"+processDefinition.getResourceName());//png文件名
        byte[] bytes = new byte[1024];
        int len;
        while ((len=bpmnIs.read(bytes))!=-1){
            bpmnFis.write(bytes,0,len);
        }
        while ((len=pngIs.read(bytes))!=-1){
            pngFis.write(bytes,0,len);
        }

        bpmnIs.close();
        bpmnFis.close();
        pngFis.close();
        pngIs.close();
        
    }

历史信息查询

历史信息包括 正在进行的任务和已经完成的任务

@Test
    //历史信息查询
    public void test9(){
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        ProcessEngine processEngine = configuration.buildProcessEngine();

        HistoryService historyService = processEngine.getHistoryService();

        //查询器
        HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
        //查询 根据开始时间升序
        historicActivityInstanceQuery.processInstanceId("7501");//流程实例id
        List<HistoricActivityInstance> list = historicActivityInstanceQuery.orderByHistoricActivityInstanceStartTime().asc().list();

        for (HistoricActivityInstance historicActivityInstance : list) {
            System.out.println(historicActivityInstance.getActivityId());//任务定义的key
            System.out.println(historicActivityInstance.getActivityName());//任务名称
            System.out.println(historicActivityInstance.getAssignee());//责任人
            System.out.println(historicActivityInstance.getId());//任务id
            System.out.println(historicActivityInstance.getProcessInstanceId());//实例id
            System.out.println(historicActivityInstance.getProcessDefinitionId());//流程定义id
        }
    }