• 工作流实战之Activiti7


    楔子

    本文主要介绍了 Activiti 的相关使用与集成,适合想要学习 Activiti 的读者食用。

    Activiti 介绍

    Activiti 是目前使用最为广泛的开源工作流引擎之一,在小七 2017 年走向程序员这一条不归路的时候,它就已经是开源工作流引擎的老大哥了。

    Activiti 官网

    学习一门新技术/新框架,我们第一件事就是从它的官网入手,下面贴出 Activiti 的官网

    Open Source Business Automation | Activiti

    在这里插入图片描述

    从官网的描述,我们可以知道 Activiti 是领先的轻量级的、以 java 为中心的开源 BPMN 引擎,可以支持现实世界的流程自动化需求。 Activiti Cloud 是新一代的业务自动化平台,提供了一组旨在在分布式基础架构上运行的云原生构建块。

    BPMN 建模语言

    官网既然提到了 BPMN,那么首先我们必须要知道什么是 BPM。BPM 即 Business Process Managemenet,业务流程管理。是一种规范化的构造端到端的业务流程,以持续的提高组织业务效率。在常见的商业管理教育如 EMBA、MBA 中都包含了 BPM 的课程。 说人话就是,比如你请假,需要向你老板提交一个申请,你老板批准后,你才能休假,这就是一个请假流程。

    而 BPMN 是 Business Process Model And Notation 业务流程模型和符号,用来描述业务流程的一种建模标准。说人话,就是“书同文,车同轨”,大家用统一的符号,来描述我们的各个业务流程,比如说请假流程,就可以抽象如下如所示:
    在这里插入图片描述

    这里贴出常用的图形所代表的意义,让各位读者先混个眼熟。
    在这里插入图片描述

    Activiti 使用步骤

    新建一个 Maven 项目,项目目录结构如下:
    在这里插入图片描述

    引入依赖

    在最外层 pom 中统一定义依赖

    <properties>
        <maven.compiler.source>8maven.compiler.source>
        <maven.compiler.target>8maven.compiler.target>
        <slf4j.version>1.6.6slf4j.version>
        <log4j.version>1.2.12log4j.version>
        <activiti.version>7.1.0.M6activiti.version>
        <activiti.cloud.version>7.0.0.Beta1activiti.cloud.version>
        <mysql.version>8.0.20mysql.version>
        <java.version>1.8java.version>
        <slf4j.version>1.6.6slf4j.version>
        <log4j.version>1.2.12log4j.version>
        <mybatis.version>3.4.5mybatis.version>
        <junit.version>4.12junit.version>
        <commonsio.version>2.6commonsio.version>
        <dbcp.version>1.4dbcp.version>
    properties>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在 BaseActivitiDemo 项目下的 pom 中引入依赖

    <dependencies>
        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-engineartifactId>
            <version>${activiti.version}version>
        dependency>
        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-springartifactId>
            <version>${activiti.version}version>
        dependency>
        
        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-bpmn-modelartifactId>
            <version>${activiti.version}version>
        dependency>
        
        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-bpmn-converterartifactId>
            <version>${activiti.version}version>
        dependency>
        
        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-json-converterartifactId>
            <version>${activiti.version}version>
        dependency>
        
        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-bpmn-layoutartifactId>
            <version>${activiti.version}version>
        dependency>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>${mysql.version}version>
        dependency>
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>${mybatis.version}version>
        dependency>
        
        <dependency>
            <groupId>commons-dbcpgroupId>
            <artifactId>commons-dbcpartifactId>
            <version>${dbcp.version}version>
        dependency>
        <dependency>
            <groupId>commons-iogroupId>
            <artifactId>commons-ioartifactId>
            <version>${commonsio.version}version>
        dependency>
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>${junit.version}version>
        dependency>
        
        <dependency>
            <groupId>log4jgroupId>
            <artifactId>log4jartifactId>
            <version>${log4j.version}version>
        dependency>
        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-apiartifactId>
            <version>${slf4j.version}version>
        dependency>
        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-log4j12artifactId>
            <version>${slf4j.version}version>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    添加配置

    日志配置

    在 BaseActivitiDemo 项目的 resource 下新建 log4j.properties 文件,并添加配置

    # 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:\activiti7.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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Activiti 配置

    在 BaseActivitiDemo 项目的 resource 下新建 activiti.cfg.xml 文件,并添加配置

    
    <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.cj.jdbc.Driver" />
            <property name="url" value="jdbc:mysql://localhost:3306/activiti?serverTimezone=GMT%2B8" />
            <property name="username" value="root" />
            <property name="password" value="123456" />
            <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 name="databaseSchemaUpdate" value="true"/>
        bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    初始化数据库表

    新建数据库 activiti

    在这里插入图片描述

    新建单元测试类 TestCreateTable

    在这里插入图片描述

    内容如下:

    public class TestCreateTable {
        /**
         * 生成 activiti 的数据库表
         */
        @Test
        public void testCreateDbTableByDefault() {
            // 默认创建方式
            ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
            System.out.println(processEngine);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    执行测试代码后,控制台会打印许多 sql 语句,再次观察 activiti 数据库,我们会发现多了 25 张表。
    在这里插入图片描述

    加餐

    我们没有指定配置文件,程序是怎么创建这些表的呢?

    我们跟进 getDefaultProcessEngine 方法可以发现,它其实是个包装方法,内部调用的是 getProcessEngine(string)。

    public static ProcessEngine getDefaultProcessEngine() {
      return getProcessEngine(NAME_DEFAULT);
    }
    
    • 1
    • 2
    • 3

    继续看 getProcessEngine(string),因为我们现在并没有初始化,所以会调用 init()方法。

    public static ProcessEngine getProcessEngine(String processEngineName) {
      if (!isInitialized()) {
        init();
      }
      return processEngines.get(processEngineName);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    从 init()方法中圈红的地方我们可以知道,框架默认会去读取 classpath:下的 activiti.cfg.xml 和 activiti-context.xml 两个配置文件的。

    表结构解析

    总览

    让我们再来看一下这25张表
    在这里插入图片描述

    虽然表很多,但是仔细观察,我们会发现Activiti 使用到的表都是 ACT_ 开头的。表名的第二部分用两个字母表明表的用途。

    • ACT_RE :'RE’表示 repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
    • ACT_RU:'RU’表示 runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。Activiti 只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。保证了框架的运行速度。
    • ACT_HI:'HI’表示 history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
    • ACT_GE : GE 表示 general。 通用数据及其设置,全局适用。

    详解

    用途归类表名解释
    全局通用数据表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_deadletter_job
    存放失败的执行任务
    act_ru_event_subscr
    存放运行时的事件
    act_ru_execution
    存放运行时的流程实例
    act_ru_identitylink
    存放运行时的流程人员与任务节点的关联信息
    act_ru_integration
    存放运行时积分
    act_ru_job
    存放运行时定时任务数据
    act_ru_suspended_job
    存放暂停的执行任务
    act_ru_task
    存放运行时的任务节点
    act_ru_timer_job
    存放运行时定时器作业
    act_ru_variable
    存放运行时流程变量
    其他act_evt_log
    存放事件日志
    act_procdef_info
    存放流程定义的动态变更信息

    核心类解析

    类名解释
    RepositoryService
    是activiti的资源管理类,提供了管理和控制流程发布包和流程定义的操作。
    RuntimeService
    Activiti的流程运行管理类。可以从这个类中获取流程执行的信息
    TaskService
    Activiti的任务管理类。可以从这个类中获取任务的信息。
    HistoryService
    Activiti的历史管理类,可以查询历史信息。
    ManagerService
    Activiti的引擎管理类,提供了对 Activiti 流程引擎的管理和维护功能。

    安装插件

    这里主要讲idea的插件,直接在Plugins中搜索Activiti BPMN visualizer和JBoss jBPM,安装即可。

    注:actiBPM在idea里的使用体验实在不好,这里就不推荐大家安装了。
    在这里插入图片描述

    常用API介绍

    定制流程

    首先我们定义一个简单的请假流程。

    在resources下新建Leave.bpmn20.xml文件
    在这里插入图片描述

    右键选择view bpmn(Activiti) Diagram
    在这里插入图片描述

    可以看到以下界面
    在这里插入图片描述

    在红框中点击右键,开始画图,这里我们先选择一个开始事件
    在这里插入图片描述

    选择一个user task
    在这里插入图片描述

    选择user task方框填入以下属性
    在这里插入图片描述

    再创建一个user task,并填入以下属性
    在这里插入图片描述

    再创建一个user task,并填入以下属性
    在这里插入图片描述

    选择结束事件
    在这里插入图片描述

    最后我们得到了这样一个流程图

    在这里插入图片描述

    同时我们可以看到,左侧的xml文件发生了变化
    在这里插入图片描述

    部署流程

    接下来新建测试类ActivitiDemo并添加以下内容

    /**
     * 部署流程定义
     */
    @Test
    public void testDeployment() {
        // 1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2、得到RepositoryService实例
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3、使用RepositoryService进行部署
        Deployment deployment = repositoryService.createDeployment()
                // 添加bpmn资源
                .addClasspathResource("bpmn/Leave.bpmn20.xml")
                // 添加png资源
                .addClasspathResource("bpmn/Leave.png")
                .name("请假申请流程")
                .deploy();
        System.out.println("流程部署id:" + deployment.getId());
        System.out.println("流程部署名称:" + deployment.getName());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    运行测试方法后,我们可以看到控制台打印了一些sql,整个部署过程操作了三张数据表:
    act_ge_bytearray 流程资源表 ,每个流程定义对应两个资源记录,bpmn和png。
    在这里插入图片描述

    act_re_deployment 流程定义部署表,每部署一次增加一条记录 。

    在这里插入图片描述

    act_re_procdef 流程定义表,部署每个新的流程定义都会在这张表中增加一条记录。
    在这里插入图片描述

    启动实例

    接下来我们启动流程实例

    /**
     * 启动流程实例
     */
    @Test
    public void testStartProcess() {
        // 1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2、获取RunTimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 3、根据流程定义Id启动流程
        ProcessInstance processInstance = runtimeService
                .startProcessInstanceByKey("Leave");
        System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例id:" + processInstance.getId());
        System.out.println("当前活动Id:" + processInstance.getActivityId());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    同样我们观察控制台日志,发现涉及插入语句的的表如下

    2022-08-15 21:45:39,919 1252  [           main] DEBUG ti.engine.impl.db.DbSqlSession  - inserting: org.activiti.engine.impl.persistence.entity.HistoricTaskInstanceEntityImpl@3174cb09
    2022-08-15 21:45:39,919 1252  [           main] DEBUG mpl.insertHistoricTaskInstance  - ==>  Preparing: insert into ACT_HI_TASKINST ( ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, NAME_, PARENT_TASK_ID_, DESCRIPTION_, OWNER_, ASSIGNEE_, START_TIME_, CLAIM_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TASK_DEF_KEY_, FORM_KEY_, PRIORITY_, DUE_DATE_, CATEGORY_, TENANT_ID_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 
    2022-08-15 21:45:39,921 1254  [           main] DEBUG mpl.insertHistoricTaskInstance  - ==> Parameters: 2505(String), Leave:1:4(String), 2501(String), 2502(String), 创建出差申请(String), null, 创建出差申请(String), null, employee(String), 2022-08-15 21:45:39.918(Timestamp), null, null, null, null, sid-d0797050-fe53-4ff7-8506-855ba3059d8d(String), null, 50(Integer), null, null, (String)
    2022-08-15 21:45:39,922 1255  [           main] DEBUG mpl.insertHistoricTaskInstance  - <==    Updates: 1
    2022-08-15 21:45:39,922 1255  [           main] DEBUG ti.engine.impl.db.DbSqlSession  - inserting: HistoricProcessInstanceEntity[superProcessInstanceId=null]
    2022-08-15 21:45:39,922 1255  [           main] DEBUG .insertHistoricProcessInstance  - ==>  Preparing: insert into ACT_HI_PROCINST ( ID_, PROC_INST_ID_, BUSINESS_KEY_, PROC_DEF_ID_, START_TIME_, END_TIME_, DURATION_, START_USER_ID_, START_ACT_ID_, END_ACT_ID_, SUPER_PROCESS_INSTANCE_ID_, DELETE_REASON_, TENANT_ID_, NAME_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 
    2022-08-15 21:45:39,922 1255  [           main] DEBUG .insertHistoricProcessInstance  - ==> Parameters: 2501(String), 2501(String), null, Leave:1:4(String), 2022-08-15 21:45:39.893(Timestamp), null, null, null, sid-0302a100-d63d-4daa-8e3a-fbce9d28485a(String), null, null, null, (String), null
    2022-08-15 21:45:39,923 1256  [           main] DEBUG .insertHistoricProcessInstance  - <==    Updates: 1
    2022-08-15 21:45:39,934 1267  [           main] DEBUG InsertHistoricActivityInstance  - ==>  Preparing: insert into ACT_HI_ACTINST ( ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, ACT_ID_, TASK_ID_, CALL_PROC_INST_ID_, ACT_NAME_, ACT_TYPE_, ASSIGNEE_, START_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TENANT_ID_ ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) , (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
    2022-08-15 21:45:39,935 1268  [           main] DEBUG InsertHistoricActivityInstance  - ==> Parameters: 2503(String), Leave:1:4(String), 2501(String), 2502(String), sid-0302a100-d63d-4daa-8e3a-fbce9d28485a(String), null, null, null, startEvent(String), null, 2022-08-15 21:45:39.909(Timestamp), 2022-08-15 21:45:39.91(Timestamp), 1(Long), null, (String), 2504(String), Leave:1:4(String), 2501(String), 2502(String), sid-d0797050-fe53-4ff7-8506-855ba3059d8d(String), 2505(String), null, 创建出差申请(String), userTask(String), employee(String), 2022-08-15 21:45:39.911(Timestamp), null, null, null, (String)
    2022-08-15 21:45:39,936 1269  [           main] DEBUG InsertHistoricActivityInstance  - <==    Updates: 2
    2022-08-15 21:45:39,936 1269  [           main] DEBUG ti.engine.impl.db.DbSqlSession  - inserting: org.activiti.engine.impl.persistence.entity.HistoricIdentityLinkEntityImpl@4d411036
    2022-08-15 21:45:39,936 1269  [           main] DEBUG mpl.insertHistoricIdentityLink  - ==>  Preparing: insert into ACT_HI_IDENTITYLINK (ID_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_) values (?, ?, ?, ?, ?, ?) 
    2022-08-15 21:45:39,936 1269  [           main] DEBUG mpl.insertHistoricIdentityLink  - ==> Parameters: 2506(String), participant(String), employee(String), null, null, 2501(String)
    2022-08-15 21:45:39,937 1270  [           main] DEBUG mpl.insertHistoricIdentityLink  - <==    Updates: 1
    2022-08-15 21:45:39,938 1271  [           main] DEBUG EntityImpl.bulkInsertExecution  - ==>  Preparing: insert into ACT_RU_EXECUTION (ID_, REV_, PROC_INST_ID_, BUSINESS_KEY_, PROC_DEF_ID_, ACT_ID_, IS_ACTIVE_, IS_CONCURRENT_, IS_SCOPE_,IS_EVENT_SCOPE_, IS_MI_ROOT_, PARENT_ID_, SUPER_EXEC_, ROOT_PROC_INST_ID_, SUSPENSION_STATE_, TENANT_ID_, NAME_, START_TIME_, START_USER_ID_, IS_COUNT_ENABLED_, EVT_SUBSCR_COUNT_, TASK_COUNT_, JOB_COUNT_, TIMER_JOB_COUNT_, SUSP_JOB_COUNT_, DEADLETTER_JOB_COUNT_, VAR_COUNT_, ID_LINK_COUNT_, APP_VERSION_) values (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) , (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
    2022-08-15 21:45:39,939 1272  [           main] DEBUG EntityImpl.bulkInsertExecution  - ==> Parameters: 2501(String), 2501(String), null, Leave:1:4(String), null, true(Boolean), false(Boolean), true(Boolean), false(Boolean), false(Boolean), null, null, 2501(String), 1(Integer), (String), null, 2022-08-15 21:45:39.893(Timestamp), null, false(Boolean), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), null, 2502(String), 2501(String), null, Leave:1:4(String), sid-d0797050-fe53-4ff7-8506-855ba3059d8d(String), true(Boolean), false(Boolean), false(Boolean), false(Boolean), false(Boolean), 2501(String), null, 2501(String), 1(Integer), (String), null, 2022-08-15 21:45:39.908(Timestamp), null, false(Boolean), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), null
    2022-08-15 21:45:39,940 1273  [           main] DEBUG EntityImpl.bulkInsertExecution  - <==    Updates: 2
    2022-08-15 21:45:39,940 1273  [           main] DEBUG ti.engine.impl.db.DbSqlSession  - inserting: Task[id=2505, name=创建出差申请]
    2022-08-15 21:45:39,940 1273  [           main] DEBUG tity.TaskEntityImpl.insertTask  - ==>  Preparing: insert into ACT_RU_TASK (ID_, REV_, NAME_, BUSINESS_KEY_, PARENT_TASK_ID_, DESCRIPTION_, PRIORITY_, CREATE_TIME_, OWNER_, ASSIGNEE_, DELEGATION_, EXECUTION_ID_, PROC_INST_ID_, PROC_DEF_ID_, TASK_DEF_KEY_, DUE_DATE_, CATEGORY_, SUSPENSION_STATE_, TENANT_ID_, FORM_KEY_, CLAIM_TIME_, APP_VERSION_) values (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 
    2022-08-15 21:45:39,941 1274  [           main] DEBUG tity.TaskEntityImpl.insertTask  - ==> Parameters: 2505(String), 创建出差申请(String), null, null, 创建出差申请(String), 50(Integer), 2022-08-15 21:45:39.911(Timestamp), null, employee(String), null, 2502(String), 2501(String), Leave:1:4(String), sid-d0797050-fe53-4ff7-8506-855ba3059d8d(String), null, null, 1(Integer), (String), null, null, null
    2022-08-15 21:45:39,941 1274  [           main] DEBUG tity.TaskEntityImpl.insertTask  - <==    Updates: 1
    2022-08-15 21:45:39,941 1274  [           main] DEBUG ti.engine.impl.db.DbSqlSession  - inserting: IdentityLinkEntity[id=2506, type=participant, userId=employee, processInstanceId=2501]
    2022-08-15 21:45:39,941 1274  [           main] DEBUG kEntityImpl.insertIdentityLink  - ==>  Preparing: insert into ACT_RU_IDENTITYLINK (ID_, REV_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_, PROC_DEF_ID_) values (?, 1, ?, ?, ?, ?, ?, ?) 
    2022-08-15 21:45:39,942 1275  [           main] DEBUG kEntityImpl.insertIdentityLink  - ==> Parameters: 2506(String), participant(String), employee(String), null, null, 2501(String), null
    2022-08-15 21:45:39,943 1276  [           main] DEBUG kEntityImpl.insertIdentityLink  - <==    Updates: 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    act_hi_actinst
    在这里插入图片描述

    act_hi_identitylink
    在这里插入图片描述

    act_hi_procinst
    在这里插入图片描述

    act_hi_taskinst
    在这里插入图片描述

    act_ru_execution
    在这里插入图片描述

    act_ru_identitylink

    在这里插入图片描述

    act_ru_task

    在这里插入图片描述

    任务查询

        /**
         * 查询当前个人待执行的任务
         */
        @Test
        public void testFindPersonalTaskList() throws Exception {
            // 任务负责人
    // String assignee = "employee";
            ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
            // 创建TaskService
            TaskService taskService = processEngine.getTaskService();
            // 根据流程key和任务负责人查询任务
            List<Task> list = taskService.createTaskQuery()
                    //流程Key
                    .processDefinitionKey("Leave")
                    //只查询该任务负责人的任务
    //         .taskAssignee(assignee)
                    .list();
            for (Task task : list) {
                System.out.println("流程实例id:" + task.getProcessInstanceId());
                System.out.println("任务id:" + task.getId());
                System.out.println("任务负责人:" + task.getAssignee());
                System.out.println("任务名称:" + task.getName());
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    任务处理

        // 完成任务
        @Test
        public void completTask() {
            // 获取引擎
            ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
            // 获取taskService
            TaskService taskService = processEngine.getTaskService();
            Task task = taskService.createTaskQuery()
                    // 流程Key
                    .processDefinitionKey("Leave")
                    // 要查询的负责人
    //         .taskAssignee("employee")  
                    .singleResult();
            taskService.complete(task.getId());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    流程查询

    /**
     * 查询流程定义
     */
    @Test
    public void queryProcessDefinition() {
        // 获取引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        List<ProcessDefinition> definitionList = processDefinitionQuery.processDefinitionKey("Leave")
                .orderByProcessDefinitionVersion()
                .desc()
                .list();
        for (ProcessDefinition processDefinition : definitionList) {
            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());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    /**
     * 查询流程实例
     */
    @Test
    public void queryProcessInstance() {
        // 流程定义key
        String processDefinitionKey = "Leave";
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取RunTimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        List<ProcessInstance> list = runtimeService
                .createProcessInstanceQuery()
                .processDefinitionKey(processDefinitionKey)//
                .list();
    
        for (ProcessInstance processInstance : list) {
            System.out.println("----------------------------");
            System.out.println("流程实例id:"
                    + processInstance.getProcessInstanceId());
            System.out.println("所属流程定义id:"
                    + processInstance.getProcessDefinitionId());
            System.out.println("是否执行完成:" + processInstance.isEnded());
            System.out.println("是否暂停:" + processInstance.isSuspended());
            System.out.println("当前活动标识:" + processInstance.getActivityId());
            System.out.println("业务关键字:" + processInstance.getBusinessKey());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    流程历史信息查询

    /**
     * 查看历史信息
     */
    @Test
    public void findHistoryInfo() {
        // 获取引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取HistoryService
        HistoryService historyService = processEngine.getHistoryService();
        HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
        instanceQuery.processInstanceId("2501");
        instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
        List<HistoricActivityInstance> activityInstanceList = instanceQuery.list();
        for (HistoricActivityInstance hi : activityInstanceList) {
            System.out.println("============="+hi.getActivityId()+" START=============");
            System.out.println(hi.getActivityId());
            System.out.println(hi.getActivityName());
            System.out.println(hi.getProcessDefinitionId());
            System.out.println(hi.getProcessInstanceId());
            System.out.println("============="+hi.getActivityId()+" END=============");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    流程资源下载

    @Test
    public void downBpmnFile() throws IOException {
        // 1、得到引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2、获取repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 3、得到查询器:ProcessDefinitionQuery
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("Leave")
                .singleResult();
        // 4、通过流程定义信息,得到部署ID
        String deploymentId = processDefinition.getDeploymentId();
        // 5、通过repositoryService的方法,实现读取图片信息和bpmn信息
         InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
        // bpmn文件的流
        InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getResourceName());
        File file_png = new File("d:/Leave.png");
        File file_bpmn = new File("d:/Leave.bpmn20.xml");
        FileOutputStream bpmnOut = new FileOutputStream(file_bpmn);
        FileOutputStream pngOut = new FileOutputStream(file_png);
        IOUtils.copy(pngInput, pngOut);
        IOUtils.copy(bpmnInput, bpmnOut);
        pngOut.close();
        bpmnOut.close();
        pngInput.close();
        bpmnInput.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    Businesskey

    这一章节我们来介绍这个businessKey,顾名思义,也就是业务关键字的意思。它是Activiti给我们设计的一个拓展点,可以根据业务场景,设计成不同的数据格式,比如json等,但是要注意这个字段的长度为255。

    在这里插入图片描述

    /**
     * 添加业务key
     */
    @Test
    public void addBusinessKey() {
        // 1、获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2、获取RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 3、启动流程的过程中,添加businesskey
        ProcessInstance instance = runtimeService.
                startProcessInstanceByKey("Leave", "businessNo");
        System.out.println("businessKey==" + instance.getBusinessKey());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    流程变量

    小例

    再次回顾一下我们的流程图:
    在这里插入图片描述

    之前我们定义的请假流程,每个步骤都是非常固定的,但是生活中的业务流程,往往比较复杂。这里我们完善一下请假流程,请假3天以内由组长审批,3天以上需要增加经理审批。
    在这里插入图片描述

    针对这样的流程,就需要用到流程变量了。首先我们双击以下流程连线,填入UEL表达式。
    在这里插入图片描述

    在这里插入图片描述

    同时修改每个任务节点的责任人为UEL表达式。
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    添加测试代码

     /**
     * 启动流程的时候设置流程变量
     */
    @Test
    public void testStartProcessAndSetVariables() {
        // 1、获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2、获取RunTimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 3、流程定义的Key
        String key = "Leave";
        // 4、流程变量的map
        Map<String, Object> variables = new HashMap<>();
        // 5、设置流程变量
        Evection evection = new Evection();
        // 6、设置请假日期
        evection.setDay(2d);
        // 7、把流程变量的pojo放入map
        variables.put("evection", evection);
        // 8、设定任务的负责人
        variables.put("employee", "小七");
        variables.put("TeamLeader", "第七人格");
        variables.put("Manager", "老李");
        // 9、启动流程
        runtimeService.startProcessInstanceByKey(key, variables);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    /**
     * 完成个人任务
     */
    @Test
    public void completTaskByVariables() {
        completTaskByVariables("小七");
        completTaskByVariables("第七人格");
        completTaskByVariables("老李");
    }
    
    private void completTaskByVariables(String assingee) {
        // 1、流程定义的Key
        String key = "Leave";
        // 2、获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 3、获取taskService
        TaskService taskService = processEngine.getTaskService();
        // 4、查询任务
        Task task = taskService.createTaskQuery()
                .processDefinitionKey(key)
                .taskAssignee(assingee)
                .singleResult();
        if (task != null) {
            taskService.complete(task.getId());
            System.out.println(task.getId() + "----任务负责人:" + task.getAssignee() + "----任务已完成");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    作用域

    上一节我们讲了一个关于流程变量的例子,这一节我们讲一讲流程变量的作用域。

    • Global变量
      这个是流程变量的默认作用域,作用于流程实例。上节中的例子就是Global变量变量,关键代码为:

    启动流程时,设置变量

    runtimeService.startProcessInstanceByKey(key,variables);
    
    • 1

    办理任务时,设置变量

    taskService.complete(任务id,variables); 
    
    • 1

    通过当前流程实例,设置变量

    runtimeService.setVariable(流程实例id, key, pojo对象); 
    
    • 1

    通过当前任务,设置变量

    taskService.setVariable(任务id, "evection", pojo对象)); 
    
    • 1
    • Local 变量
      这个作用域只针对一个任务或一个执行实例的范围,没有流程实例大。

    关键代码为:

    办理任务时,设置变量

    taskService.setVariablesLocal(任务id,variables); 
    
    • 1

    通过当前任务,设置变量

    taskService.setVariableLocal(任务id, "evection", pojo对象)); 
    
    • 1

    加餐

    1、读者把出差时间变为2d试一试,看老李有没有进行审批。

    2、建议读者都实验一下上面的api,加深印象。

    网关

    在画布中单击右键,选择网关,我们可以看到有以下四种网关
    在这里插入图片描述

    排他网关Exclusive Gateway

    排他网关,顾名思义就是最终只会选择一个分支执行,是排他的。

    并行网关Parallel Gateway

    并行网关不会解析连线上的条件,并行网关中所有分支完成后,他才会走向下一个节点。

    包含网关Inclusive Gateway

    包含网关可以看做是排他网关和并行网关的结合体。有条件的分支选择条件执行,没有条件的分支,则必须执行。最终待这些分支完成后,他才会走向下一个节点。

    事件网关Event Gateway

    事件网关允许根据事件判断流向。这个网关生产中用的并不多,小七这里就不再展开了。

    任务组

    在流程变量那一节,我们给任务设置了负责人,但是在日常生活中,这个负责人有可能是指一类角色。

    我们去掉负责人,并添加候选人:组长1,组长2
    在这里插入图片描述

    启动流程

    /**
     * 启动流程的时候设置流程变量
     */
    @Test
    public void testStartProcessAndSetVariablesAboutGroup() {
        // 1、获取流程引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2、获取RunTimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 3、流程定义的Key
        String key = "Leave";
        // 4、流程变量的map
        Map<String, Object> variables = new HashMap<>();
        // 5、设置流程变量
        Evection evection = new Evection();
        // 6、设置请假日期
        evection.setDay(2d);
        // 7、把流程变量的pojo放入map
        variables.put("evection", evection);
        // 8、设定任务的负责人
        variables.put("employee", "小七");
        variables.put("Manager", "老李");
        // 9、启动流程
        runtimeService.startProcessInstanceByKey(key, variables);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    完成任务

    @Test
    public void completTaskByVariablesAboutGroup() {
        // 测试组任务时,只执行这一行代码
        completTaskByVariables("小七");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    查询任务

    /**
     * 查询组任务
     */
    @Test
    public void findGroupTaskList() {
        // 1、流程定义的Key
        String key = "Leave";
        // 2、任务候选人
        String candidateUser = "组长1";
        // 3、获取引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 4、获取TaskService
        TaskService taskService = processEngine.getTaskService();
        // 5、查询组任务
        List<Task> taskList = taskService.createTaskQuery()
                .processDefinitionKey(key)
                // 根据候选人查询任务
                .taskCandidateUser(candidateUser)
                .list();
        for (Task task : taskList) {
            System.out.println("============查询组任务============");
            System.out.println("流程实例ID=" + task.getProcessInstanceId());
            System.out.println("任务id=" + task.getId());
            System.out.println("任务名称:" + task.getName());
            System.out.println("任务负责人=" + task.getAssignee());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    绑定任务

    /**
     * 候选人绑定任务
     */
    @Test
    public void claimTask() {
        // 1、获取引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2、获取TaskService
        TaskService taskService = processEngine.getTaskService();
        // 3、当前任务的id
        String taskId = "5002";
        // 4、任务候选人
        String candidateUser = "组长1";
        // 5、查询任务
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskCandidateUser(candidateUser)
                .singleResult();
        if (task != null) {
            // 6、绑定任务
            taskService.claim(taskId, candidateUser);
            System.out.println("taskId-" + taskId + "-用户-" + candidateUser + "-绑定任务完成");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    归还任务

    /**
     * 候选人归还任务
     */
    @Test
    public void testAssigneeToGroupTask() {
        // 1、获取引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 2、获取TaskService
        TaskService taskService = processEngine.getTaskService();
        // 3、当前任务的id
        String taskId = "5002";
        // 4、任务负责人
        String assignee = "组长1";
        // 5、根据key 和负责人来查询任务
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .taskAssignee(assignee)
                .singleResult();
        if (task != null) {
            // 6、归还任务 ,就是把负责人设置为空
            taskService.setAssignee(taskId, null);
            System.out.println("taskId-" + taskId + "-用户-" + assignee + "-归还任务完成");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    Activiti与Spring整合

    Activiti与Spring整合的核心思想,就是将ProcessEngine的类交由Spring容器进行管理。

    我们新建maven项目ActivitiSpring
    在这里插入图片描述

    在ActivitiSpring模块的pom中引入以下依赖

    <dependencies>
        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-engineartifactId>
            <version>${activiti.version}version>
        dependency>
        
        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-springartifactId>
            <version>${activiti.version}version>
        dependency>
        
        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-bpmn-modelartifactId>
            <version>${activiti.version}version>
        dependency>
        
        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-bpmn-converterartifactId>
            <version>${activiti.version}version>
        dependency>
        
        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-json-converterartifactId>
            <version>${activiti.version}version>
        dependency>
        
        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-bpmn-layoutartifactId>
            <version>${activiti.version}version>
        dependency>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>${mysql.version}version>
        dependency>
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>${mybatis.version}version>
        dependency>
        
        <dependency>
            <groupId>commons-dbcpgroupId>
            <artifactId>commons-dbcpartifactId>
            <version>${dbcp.version}version>
        dependency>
        <dependency>
            <groupId>commons-iogroupId>
            <artifactId>commons-ioartifactId>
            <version>${commonsio.version}version>
        dependency>
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>${junit.version}version>
        dependency>
        
        <dependency>
            <groupId>log4jgroupId>
            <artifactId>log4jartifactId>
            <version>${log4j.version}version>
        dependency>
        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-apiartifactId>
            <version>${slf4j.version}version>
        dependency>
        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-log4j12artifactId>
            <version>${slf4j.version}version>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-testartifactId>
            <version>5.0.7.RELEASEversion>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    然后在resources下新建配置文件activiti-spring.xml,填入以下内容

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd">
        
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
            <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/activiti?serverTimezone=GMT"/>
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
            <property name="maxActive" value="3"/>
            <property name="maxIdle" value="1"/>
        bean>
        
        <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
            
            <property name="dataSource" ref="dataSource"/>
            
            <property name="transactionManager" ref="transactionManager"/>
            
            <property name="databaseSchemaUpdate" value="drop-create"/>
        bean>
        
        <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
            <property name="processEngineConfiguration" ref="processEngineConfiguration"/>
        bean>
        
        <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
        
        <bean id="runtimeService" factory-bean="processEngine"  factory-method="getRuntimeService"/>
        
        <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/>
        
        <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService"/>
        
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        bean>
        
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                
                <tx:method name="save*" propagation="REQUIRED"/>
                <tx:method name="insert*" propagation="REQUIRED"/>
                <tx:method name="delete*" propagation="REQUIRED"/>
                <tx:method name="update*" propagation="REQUIRED"/>
                <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
                <tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
            tx:attributes>
        tx:advice>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    新建测试类

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:activiti-spring.xml")
    public class ActivitiTest {
        @Autowired
        private RepositoryService repositoryService;
    
        @Test
        public void test01(){
            System.out.println("获取Spring代理的Activiti部署对象:"+repositoryService);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    执行测试方法,控制输出语句,说明Activiti集成Spring成功。

    在这里插入图片描述

    Activiti与SpringBoot整合

    首先新建项目ActivitiSpringBoot
    在这里插入图片描述

    然后添加pom依赖

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-dependenciesartifactId>
                <version>2.1.0.RELEASEversion>
                <type>pomtype>
                <scope>importscope>
            dependency>
        dependencies>
    dependencyManagement>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-securityartifactId>
        dependency>
    
        <dependency>
            <groupId>org.activitigroupId>
            <artifactId>activiti-spring-boot-starterartifactId>
            <version>${activiti.version}version>
        dependency>
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-jdbcartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    编写配置文件application.yml

    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/activiti?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT
        username: root
        password: 123456
      activiti:
        database-schema-update: true
        db-history-used: true
        history-level: full
        check-process-definitions: true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在resources下新建processes,并将我们上面用到的流程xml放在下面

    在这里插入图片描述

    编写启动类

    @SpringBootApplication
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class,args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    启动程序后,我们可以从启动日志中找到以下记录说明集成成功。

    Process deployed: {id: Leave:1:69859bff-1f03-11ed-9868-005056c00008, key: Leave, name: Leave }
    
    • 1

    在这里插入图片描述

    附件

    本文所示代码链接整合地址

    https://gitee.com/diqirenge/seven-activiti

  • 相关阅读:
    jq命令用法总结
    Android去除生成的二维码白边
    Python Akima 插值法教程 | 关键原理和实践
    微服务框架 SpringCloud微服务架构 20 RestClient 操作索引库 20.2 hotel 数据结构分析
    保姆级cat系统搭建过程
    AJAX学习笔记2发送Post请求
    spark学习记录-spark基础概念
    基于划分的聚类分析——K-means(机器学习)
    9、Spring之推断构造方法源码解析
    数据挖掘——matplotlib
  • 原文地址:https://blog.csdn.net/a18602320276/article/details/126377324