工作流 - 基本应用

suaxi
2023-05-23 / 0 评论 / 71 阅读 / 正在检测是否收录...

1. 基本使用

(1)创建Maven应用

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.sw</groupId>
    <artifactId>ActivitiDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <slf4j.version>1.6.6</slf4j.version>
        <log4j.version>1.2.12</log4j.version>
        <activiti.version>7.0.0.Beta1</activiti.version>
        <mysql.version>8.0.26</mysql.version>
        <mybatis.version>3.5.13</mybatis.version>
        <dbcp.version>1.4</dbcp.version>
        <junit.version>4.12</junit.version>
        <commons-io.version>2.6</commons-io.version>
    </properties>

    <dependencies>
        <!-- activiti core -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-engine</artifactId>
            <version>${activiti.version}</version>
        </dependency>
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring</artifactId>
            <version>${activiti.version}</version>
        </dependency>

        <!-- bpmn 模型处理 -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-bpmn-model</artifactId>
            <version>${activiti.version}</version>
        </dependency>

        <!-- bpmn 转换 -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-bpmn-converter</artifactId>
            <version>${activiti.version}</version>
        </dependency>

        <!-- bpmn json转换 -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-json-converter</artifactId>
            <version>${activiti.version}</version>
        </dependency>

        <!-- bpmn 布局 -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-bpmn-layout</artifactId>
            <version>${activiti.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>com.github.jgraph</groupId>
                    <artifactId>jgraphx</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- bpmn cloud -->
        <dependency>
            <groupId>org.activiti.cloud</groupId>
            <artifactId>activiti-cloud-services-api</artifactId>
            <version>${activiti.version}</version>
        </dependency>

        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>

        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>${mybatis.version}</version>
        </dependency>

        <!-- dbcp -->
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>${dbcp.version}</version>
        </dependency>

        <!-- junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
        </dependency>

        <!-- log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>

        <!-- sl4j -->
        <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>

        <!-- commons-io -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>${commons-io.version}</version>
        </dependency>
    </dependencies>

</project>

(2)log4j

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=D:\logs\act\activiti.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n

(3)添加Activiti配置文件

在resources下创建 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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration" id="processEngineConfiguration">
        <!--<property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver"/>-->
        <!--<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/activiti?characterEncoding=utf-8&amp;nullCatalogMeansCurrent=true&amp;serverTimezone=UTC"/>-->
        <!--<property name="jdbcUsername" value="root"/>-->
        <!--<property name="jdbcPassword" value="123456"/>-->
        <property name="databaseSchemaUpdate" value="true"/>
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean class="org.apache.commons.dbcp.BasicDataSource" id="dataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/activiti?characterEncoding=utf-8&amp;nullCatalogMeansCurrent=true&amp;serverTimezone=UTC"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="maxActive" value="3"/>
        <property name="maxIdle" value="2"/>
    </bean>
</beans>

(4)单元测试自动生成表结构

通过单元测试调用 Activiti API 来生成需要的表

@Test
public void test01() {
    //使用classpath下的activiti.cfg.xml中的配置来创建ProcessEngine
    ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
    System.out.println(engine);
}

2. 表结构介绍

(1)表的命名规则和作用

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

(2)数据表介绍

表分类表名解释
一般数据ACT_GE_BYTEARRAY通用的流程定义和流程资源
ACT_GE_PROPERTY系统相关属性
流程历史记录ACT_HI_ACTINST历史的流程实例
ACT_HI_ATTACHMENT历史的流程附件
ACT_HI_COMMENT历史的说明性信息
ACT_HI_DETAIL历史的流程运行中的细节信息
ACT_HI_IDENTITYLINK历史的流程运行过程中用户关系
ACT_HI_PROCINST历史的流程实例
ACT_HI_TASKINST历史的任务实例
ACT_HI_VARINST历史的流程运行中的变量信息
流程定义表ACT_RE_DEPLOYMENT部署单元信息
ACT_RE_MODEL模型信息
ACT_RE_PROCDEF已部署的流程定义
运行实例表ACT_RU_EVENT_SUBSCR运行时事件
ACT_RU_EXECUTION运行时流程执行实例
ACT_RU_IDENTITYLINK运行时用户关系信息,存储任务节点与参与者的相关信息
ACT_RU_JOB运行时作业
ACT_RU_TASK运行时任务
ACT_RU_VARIABLE运行时变量表

3. ProcessEngine创建方式

前面使用的是 getDefaultProcessEngine() 方法来加载 classpath 下的 activiti.cfg.xml 文件,还可以通过自定义的方式加载配置文件

@Test
public void test02() {
    //创建ProcessEngineConfiguration对象
    ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
    //创建ProcessEngine对象
    ProcessEngine engine = configuration.buildProcessEngine();
    System.out.println(engine);
}

4. Service服务接口

Service是工作流引擎提供用于进行工作流部署、执行、管理的服务接口,使用这些接口就是操作服务对应的数据表

(1)创建方式

通过 ProcessEngine 创建 Service

//RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();

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

//TaskService
TaskService taskService = processEngine.getTaskService();

(2)Service总览

名称作用
RepositoryService资源管理
RuntimeService流程运行管理
TaskService任务管理
HistoryService历史管理
ManagementService引擎管理
  • RepositoryService:是 activiti 的资源管理类,提供了管理和控制流程发布包和流程定义的操作。使用工作流建模工具设计的业务流程图需要使用此 service 将流程定义文件的内容进行部署。除了部署流程定义以外还可以:

    • 查询引擎中的发布包和流程定义
    • 暂停或激活发布包,对应全部和特定流程定义,暂停意味着它们不能再执行任何操作了,激活是对应的反向操作
    • 获得多种资源,像是包含在发布包里的文件,或引擎自动生成的流程图。获得流程定义的pojo版本,可以用来通过java解析流程,而不必通过xml
  • RuntimeService:获取很多关于流程执行相关的信息
  • TaskService:获取任务的信息
  • HistoryService:查询历史信息,执行流程时,引擎会根据配置保存很多数据,如:流程实例启动时间,任务的参与者,完成任务的时间,每个流程实例的执行路径等等
  • ManagementService:提供了对 Activiti 流程引擎的管理和维护功能,这些功能主要用于 Activiti 系统的日常维护,而不在工作流驱动的应用程序中使用

5. 流程绘制

(1)绘制插件

IDEA在2019版本之后没有再维护 Activiti 的流程设计工具,此处使用 Eclipse 来进行流程设计

1.Eclipse.png

2.创建.png

(2)绘制流程

指定流程主键

3.指定流程主键.png

指定任务负责人

4.指定任务负责人.png

(3)图标介绍

流程符号 BPMN 2.0是业务流程建模符号2.0的缩写,它由Business Process Management Initiative这个非营利协会创建并不断发展。作为一种标识,BPMN 2.0是使用一些符号来明确业务流程设计流程图的一整套符号规范,它能增进业务建模时的沟通效率。 目前BPMN2.0是最新的版本,它用于在BPM上下文中进行布局和可视化的沟通。

BPMN 2.0的基本符号主要包含:

  • 事件 Event

    5.事件符号.png

  • 活动 Activity

    6.活动符号.png

  • 网关 GateWay

    网关用来处理决策,常用网关有:

    7.网关符号.png

  • 排他网关:只有一条路径会被选择,流程执行到该网关时,按照输出流的顺序逐个计算,当条件的计算结果为 true 时,继续执行当前网关的输出流; 如果多条线路计算结果都是 true,则会执行第一个值为 true 的线路,如果所有网关计算结果没有 true,则引擎会抛出异常。 排他网关需要和条件顺序流结合使用,default 属性指定默认顺序流,当所有的条件不满足时会执行默认顺序流
  • 并行网关:所有路径会被同时选择:

    • 拆分:并行执行所有输出顺序流,为每一条顺序流创建一个并行执行线路
    • 合并:所有从并行网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下执行
  • 包容网关:可以同时执行多条线路,也可以在网关上设置条件

    • 拆分:计算每条线路上的表达式,当表达式计算结果为 true 时,创建一个并行线路并继续执行
    • 合并:所有从包容网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下 执行
  • 事件网关:专门为中间捕获事件设置的,允许设置多个输出流指向多个不同的中间捕获事件。当流程执行到事 件网关后,流程处于等待状态,需要等待抛出事件才能将等待状态转换为活动状态
  • 流向 Flow

    流是连接两个流程节点的连线,常见的流向有以下几种:

    8.流向符号.png

  • Palette(画板)

    • Connection 连接 Event事件
    • Task 任务
    • Gateway 网关
    • Container 容器
    • Boundary event 边界事件
    • Intermediate event 中间事件

6. 流程操作

(1)流程部署

流程部署即将流程设计器中定义的流程部署到 activiti 数据库中

单文件部署
@Test
public void deploy() {
    //1.获取ProcessEngine对象
    ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
    //2.获取RepositoryService
    RepositoryService service = engine.getRepositoryService();
    //3.部署
    Deployment deploy = service.createDeployment()
        .addClasspathResource("bpmn/evection.bpmn")
        .addClasspathResource("bpmn/evection.png")
        .name("出差申请流程")
        .deploy();
    System.out.println("id: " + deploy.getId());
    System.out.println("name: " + deploy.getName());
}
压缩包文件部署

将bpmn和png文件打包为 .zip 文件,进行部署

@Test
public void test04(){
    //定义zip文件的输入流
    InputStream inputStream =this.getClass().getClassLoader().getResourceAsStream("bpmn/evection.zip");
    //对inputStream做装饰
    ZipInputStream zipInputStream = new ZipInputStream(inputStream);
    ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
    RepositoryService repositoryService = engine.getRepositoryService();
    Deployment deploy = repositoryService.createDeployment()
                        .addZipInputStream(zipInputStream)
                        .name("出差申请流程")
                        .deploy();
    // 4.输出流程部署的信息
    System.out.println("流程部署的id:" + deploy.getId());
    System.out.println("流程部署的名称:" + deploy.getName());
}

流程定义部署后操作activiti中的三张表:

  • act_re_deployment:流程定义部署表,每部署一次就增加一条记录
  • act_re_procdef :流程定义表,部署每个新的流程定义都会在这张表中增加一条记录
  • act_ge_bytearray :流程资源表,流程部署的bpmn文件和png图片会保存在该表中

(2)启动流程实例

启动一个流程表示发起一个新的出差申请单

@Test
public void start() {
    //1.获取ProcessEngine对象
    ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
    //2.RuntimeService
    RuntimeService service = engine.getRuntimeService();
    //3.启动
    ProcessInstance instance = service.startProcessInstanceByKey("evection");
    System.out.println("流程定义id: " + instance.getProcessDefinitionId());
    System.out.println("流程实例id: " + instance.getProcessInstanceId());
    System.out.println("当前活动id: " + instance.getActivityId());
}

启动流程实例涉及到的表:

  • act_hi_actinst 流程实例执行历史
  • act_hi_identitylink 流程的参与用户的历史信息
  • act_hi_procinst 流程实例历史信息
  • act_hi_taskinst 流程任务历史信息
  • act_ru_execution 流程执行信息
  • act_ru_identitylink 流程的参与用户信息
  • act_ru_task 任务信息

(3)任务查找

流程启动后,对应的任务负责人就可以查询自己当前能够处理的任务,查询出来的任务都是当前用户的待办任务

@Test
public void queryTask() {
    //1.获取ProcessEngine对象
    ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
    //2.TaskService
    TaskService service = engine.getTaskService();
    //3.根据流程key、任务负责人查询
    List<Task> list = service.createTaskQuery().processDefinitionKey("evection").taskAssignee("zhansan").list();
    for (Task task : list) {
        System.out.println("流程定义id: " + task.getProcessDefinitionId());
        System.out.println("任务id: " + task.getId());
        System.out.println("任务负责人: " + task.getAssignee());
        System.out.println("任务名称: " + task.getName());
    }
}

(4)流程任务处理

任务负责人查询出来了待办的任务,选择任务进行处理,即完成任务

@Test
public void dealTask() {
    //1.获取ProcessEngine对象
    ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
    //2.TaskService
    TaskService service = engine.getTaskService();
    //3.根据流程key、任务负责人查询
    Task task = service.createTaskQuery().processDefinitionKey("evection").taskAssignee("孙笑川").singleResult();
    //4.处理任务
    service.complete(task.getId());
}

孙笑川 处理完成之后,任务流转到药水哥处,接着由药水哥登录系统进行处理

(5)查询流程定义

查询流程相关的信息:流程的定义,流程的部署,流程定义的版本

@Test
public void queryProcessDefinition() {
    //1.获取ProcessEngine对象
    ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
    //2.RepositoryService
    RepositoryService service = engine.getRepositoryService();
    List<ProcessDefinition> list = service.createProcessDefinitionQuery().processDefinitionKey("evection").orderByProcessDefinitionVersion().desc().list();
    for (ProcessDefinition processDefinition : list) {
        System.out.println("流程定义id: " + processDefinition.getId());
        System.out.println("流程定义name: " + processDefinition.getName());
        System.out.println("流程定义key: " + processDefinition.getKey());
        System.out.println("流程定义version: " + processDefinition.getVersion());
        System.out.println("流程部署id: " + processDefinition.getDeploymentId());
    }
}

(6)删除流程

@Test
public void deleteProcess() {
    //1.获取ProcessEngine对象
    ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
    //2.RepositoryService
    RepositoryService service = engine.getRepositoryService();
    //如果该流程定义已经有启动了的流程实例,则无法删除
    service.deleteDeployment("1");
    //级联删除,设置为true时同时删除流程定义、运行中的流程实例
    //service.deleteDeployment("1", true);
}

级联删除权限一般只开放给系统管理员

(7)流程资源下载

用户想要查看流程定义相关的信息时,可以从数据库中下载对应资源到本地(数据库直接查询blob类型数据或通过api下载资源文件,二选一即可)

@Test
public void readFileFromDatabase() throws IOException {
    //1.获取ProcessEngine对象
    ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
    //2.RepositoryService
    RepositoryService service = engine.getRepositoryService();
    //3.查询器
    ProcessDefinition definition = service.createProcessDefinitionQuery().processDefinitionKey("evection").singleResult();
    //4.流程部署id
    String deploymentId = definition.getDeploymentId();
    //png
    InputStream pngIs = service.getResourceAsStream(deploymentId, definition.getDiagramResourceName());
    //bpmn
    InputStream bpmnIs = service.getResourceAsStream(deploymentId, definition.getResourceName());
    //5.保存
    File pngFile = new File("d:/evection.png");
    File bpmnFile = new File("d:/evection.bpmn");
    FileOutputStream pngOs = new FileOutputStream(pngFile);
    FileOutputStream bpmnOs = new FileOutputStream(bpmnFile);
    IOUtils.copy(pngIs, pngOs);
    IOUtils.copy(bpmnIs, bpmnOs);

    //6.关闭流
    pngIs.close();
    pngOs.close();
    bpmnIs.close();
    bpmnOs.close();
}

(8)查看历史流程信息

即使流程定义已经被删除了,流程执行的实例信息依然保存在Activiti的 act_hi_* 相关的表中

@Test
public void processHistoryInfo() {
    //1.获取ProcessEngine对象
    ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
    //2.HistoryService
    HistoryService service = engine.getHistoryService();
    HistoricActivityInstanceQuery instanceQuery = service.createHistoricActivityInstanceQuery().processDefinitionId("evection:1:4").orderByHistoricActivityInstanceStartTime().desc();
    List<HistoricActivityInstance> list = instanceQuery.list();
    for (HistoricActivityInstance hi : list) {
        System.out.println(hi.getActivityId());
        System.out.println(hi.getActivityName());
        System.out.println(hi.getActivityType());
        System.out.println(hi.getAssignee());
        System.out.println(hi.getProcessDefinitionId());
        System.out.println(hi.getProcessInstanceId());
        System.out.println("--------------------------------");
    }
}
0

评论 (0)

取消