相关推荐recommended
前后端分离Springboot 整合使用activiti7教程(一)(全网最细)
作者:mmseoamin日期:2024-04-30

activiti7关于SpringBoot前后端分离项目的详细教程

文章目录

  • activiti7关于SpringBoot前后端分离项目的详细教程
    • 一、Activiti工作流概述
      • 1.1 什么是工作流
      • 1.2 工作流应用场景
      • 1.3 什么是Activiti
      • 1.4 Activiti开发流程
      • 1.5 BPMN 2.0规范是什么
      • 1.6 BPMN 2.0 基本流程符号
      • 二、Activiti环境搭建和流程基础入门
        • 2.1 框架版本号
        • 2.2 JDK
        • 2.2 MySQL
        • 2.3 Maven 3.9配置
        • 2.4 基于 mave 构建项目
        • 2.7 pom.xml添加依赖坐标
        • 2.8 activiti.cfg.xml核心配置
        • 2.9 log4j.properties配置日志
        • 2.10 创建ProcessEngine流程引擎实例和数据表
        • 2.11 Activiti 25张数据表分析
        • 2.12 Activiti API服务接口
        • 三、Activiti流程实操入门
          • 3.1 IDEA安装actiBPM插件
          • 3.2 绘制流程定义模型
          • 3.3 解决中文乱码问题
          • 3.4 部署流程定义
          • 3.5 查询流程定义
          • 3.6 启动流程实例代码
          • 3.7 查询办理人待办任务
          • 3.8 完成待办任务
          • 3.9 查询流程实例历史节点信息
          • 四、SpringBoot 与 Activiti7 整合
            • 4.1 创建模块 activiti-boot
            • 4.2 pom.xml 依赖坐标
            • 4.3 创建application.yml配置文件
            • 4.4 创建数据库activiti-boot
            • 4.5 整合SpringSecurity
            • 4.6 创建启动类
            • 4.7 测试Activiti流程
            • 五、整合流程模型设计器Activiti Modeler
              • 5.1 下载源码
              • 5.2 拷贝目标源码
              • 5.3 修改上下文路径
              • 5.4 汉化Activiti Modeler
              • 5.5 创建空的流程模型
              • 5.6 绘制请假流程定义模型
              • 六、流程定义模型管理Model
                • 6.1 查询已绘制的所有流程模型数据:
                • 6.2 删除流程模型
                • 6.3 导出下载模型图zip压缩包
                • 6.4 导出下载模型 xml 文件
                • 七、流程定义部署管理 Deployment
                  • 7.1 通过 .zip 压缩包 部署 流程定义
                  • 7.2 通过 .bpmn 或 .bpmn.xml 文件 部署 流程定义
                  • 7.3 删除流程定义部署信息
                  • 八、流程定义管理 ProcessDefifinition
                    • 8.1 分页条件查询流程定义
                    • 8.2 激活或挂起流程定义
                    • 8.3 下载流程定义的 xml 和 png 文件

                      本篇文章是从网上购买的教程然后整理出来的笔记,供大家一起学习参考。

                      一、Activiti工作流概述

                      这一章节就是对工作流的基础概述,对此比较熟悉的可以直接跳过。

                      1.1 什么是工作流

                      工作流的简单概念就是用于流程审批的。

                      如:请假审批流程、报销审批流程、出差审批流程、合同审批流程等。

                      工作流(Workflflow),就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在多个参与者 之间按照某种预定义的规则传递文档、信息或任务的过程自动进行,从而实现某个预期的业务目标,或者促使此目标的实现”。 工作流引擎,主要是为了帮忙我们实现流程自动化控制,对应的Activiti引擎就可以实现自动化控制。 工作流管理系统是一个软件系统,它完成工作量的定义和管理,并按照在系统中预先定义好的工作流规则进行工作

                      1.2 工作流应用场景

                      工作流应用场景:

                      • 业务类:合同审批流程、订单处理流程、出入库审批流程等。
                      • 行政类:请假流程、出差流程、用车流程、办公用品申请流程等。
                      • 财务类:报销流程、支付流程等。
                      • 客户服务类:售后跟踪、客户投诉等。

                        1.3 什么是Activiti

                        Activiti 是由 jBPM (BPM,Business Process Management 即业务流程管理) 的创建者 Tom Baeyens 离开 JBoss 之后建立的项目,构建在开发 jBPM 版本 1 到 4 时积累的多年经验的基础之上,旨在创建下一代的 BPM 解 决方案。 Activiti 是一个开源的工作流引擎,它实现了BPMN 2.0规范,可以发布设计好的流程定义,并通过api进行流程调 度。 Activiti 作为一个遵从 Apache 许可的工作流和业务流程管理开源平台,其核心是基于Java的超快速、超稳定的BPMN2.0 流程引擎,强调流程服务的可嵌入性和可扩展性,同时更加强调面向业务人员。

                        Activiti 流程引擎重点关注在系统开发的易用性和轻量性上。每一项 BPM 业务功能 Activiti 流程引擎都以服务的形 式提供给开发人员。通过使用这些服务,开发人员能够构建出功能丰富、轻便且高效的 BPM 应用程序。

                        Activiti是一个针对企业用户、开发人员、系统管理员的轻量级工作流业务管理平台,其核心是使用Java开发的快 速、稳定的BPMN 2.0流程引擎。Activiti是在ApacheV2许可下发布的,可以运行在任何类型的Java程序中,例如服 务器、集群、云服务等。Activiti可以完美地与Spring集成。同时,基于简约思想的设计使Activiti非常轻量级。

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

                        1.4 Activiti开发流程

                        1、画流程定义模型

                        遵守BPMN的流程规范,使用BPMN的流程定义工具,通过 流程符号 把整个业务流程定义出来,可以将流程定义文件字节流保存到模型数据表中(Model)。 其实用可视化工具画出来的每一个流程图都是一个.bpmn文件,在idea中也可以随时使用插件把bpmn文件进行可视化查看。

                        2、部署流程定义:

                        加载画好的流程定义文件,将它转换成流程定义数据(ProcessDefifinition),保存到流程定义数据表中。

                        3、启动流程(提交流程申请):

                        生成流程实例数据(ProcessInstance),生成第1个节点的任务数据(Task);

                        4、处理人审批流程节点任务:

                        完成任务审批,生成审批结果,生成下一节点任务数据。直至满足条件,流程走到结束节点。

                        1.5 BPMN 2.0规范是什么

                        其实就是使用bpmn的规范来定义画流程图,最终会形成一个bpmn文件。

                        业务流程模型注解(Business Process Modeling Notation - BPMN)是业务流程模型的一种标准图形注解。这个 标准是由对象管理组(Object Management Group - OMG)维护的。

                        标准的早期版本(1.2版以及之前)仅仅限制在模型上, 目标是在所有的利益相关者之间形成通用的理解, 在文 档,讨论和实现业务流程之上。 BPMN标准证明了它自己,现在市场上许多建模工具都使用了BPMN标准中的元素和结构。 BPMN规范的2.0版本,当前已经处于最终阶段了, 允许添加精确的技术细节在BPMN的图形和元素中, 同时制定 BPMN元素的执行语法。 通过使用XML语言来指定业务流程的可执行语法, BPMN规范已经演变为业务流程的语 言, 可以执行在任何兼容BPMN2的流程引擎中, 同时依然可以使用强大的图形注解。 目BPMN2.0是最新的版本,它用于在BPM上下文中进行布局和可视化的沟通。BPMN 2.0是使用一些符号来明确 业务流程设计流程图的一整套符号规范,它能增进业务建模时的沟通效率。

                        1.6 BPMN 2.0 基本流程符号

                        先了解在流程设计中常见的符号:

                        事件Event

                        前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第1张

                        活动 Activity

                        活动是工作或任务的一个通用术语。一个活动可以是一个任务,还可以是一个当前流程的子处理流程; 其次,你还可以为活动指定不同的类型。常见活动如下:

                        前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第2张

                        网关 Gateway

                        网关用来处理决策:

                        前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第3张

                        排他网关(x)

                        **只有一条路径会被选择。**流程执行到该网关时,按照输出流的顺序逐个计算,当条件的计算结果为true时,继

                        续执行当前网关的输出流; 如果多条线路计算结果都是 true,则会执行第一个值为 true 的线路。如果所有网关计算结果没有true,则引 擎会抛出异常。 排他网关需要和条件顺序流结合使用,default 属性指定默认顺序流,当所有的条件不满足时会执行默认顺序流。

                        并行网关(+)

                        所有路径会被同时选择 。

                        分支: 并行执行所有输出顺序流,为每一条顺序流创建一个并行执行线路。

                        汇聚 :所有从并行网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下执行。

                        包容网关(o)

                        可以同时执行多条线路,也可以在网关上设置条件。

                        分支:计算每条线路上的表达式,当表达式计算结果为true时,创建一个并行线路并继续执行

                        汇聚:所有从并行网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下执行。

                        事件网关(o+)

                        专门为中间捕获事件设置的,允许设置多个输出流指向多个不同的中间捕获事件。当流程执行到事件网关后,流程处于等待状态,需要等待抛出事件才能将等待状态转换为活动状态。

                        定时器事件

                        前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第4张

                        • 开始定时器事件:

                          可以设置时间,定时开始启动流程实例。

                        • 中间定时器事件:

                          设定延迟时间,当完成任务1后,到达延时时间,流程才会走向任务2。

                        • 边界定时器事件:

                          用于向某节点上添加边界定时事件。在设定时间内没有完成,流程实例则自动走向下一节点。

                          二、Activiti环境搭建和流程基础入门

                          2.1 框架版本号

                          依赖版本
                          Spring Boot2.5.0
                          Activiti7.1.0.M6

                          2.2 JDK

                          JDK1.8

                          2.2 MySQL

                          MySQL5.7

                          Activiti 通过数据库的数据表来进行控制业务流程,对应支持的数据库如下:

                          Activiti数据库类型JDBC连接示例备注
                          h2jdbc:h2:tcp://localhost/activiti默认配置的数据库
                          mysqljdbc:mysql://localhost:3306/activiti?autoReconnect=true使用mysql-connector- java数据库驱动程序进行 测试
                          oraclejdbc:oracle:thin:@localhost:1521:xe
                          postgresjdbc:postgresql://localhost:5432/activiti
                          db2jdbc:db2://localhost:50000/activiti
                          mssqljdbc:sqlserver://localhost:1433;databaseName=activiti使用Microsoft JDBC驱动程序4.0(sqljdbc4.jar)和JTDS驱动程序进行了测

                          在mysql服务器中创建一个activiti01数据库。注意配置好数据库之后,执行流程引擎是会自动创建数据库表的。

                          2.3 Maven 3.9配置

                          这里就不粘贴maven的配置了,网上都有各种教程。

                          2.4 基于 mave 构建项目

                          1. 使用 idea 创建一个空工程 study-activiti

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第5张

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第6张

                          1. 创建基于maven的项目,项目名: activiti-demo1

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第7张

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第8张

                          2.7 pom.xml添加依赖坐标

                          
                          
                              4.0.0
                              com.mengxuegu
                              activiti-demo1
                              1.0-SNAPSHOT
                              
                                  
                                  
                                      org.activiti
                                      activiti-engine
                                      7.1.0.M6
                                  
                                  
                                  
                                      mysql
                                      mysql-connector-java
                                      8.0.23
                                  
                                  
                                  
                                      org.mybatis
                                      mybatis
                                      3.4.5
                                  
                                  
                                  
                                      org.slf4j
                                      slf4j-log4j12
                                      1.7.26
                                  
                                  
                                      org.slf4j
                                      jcl-over-slf4j
                                      1.7.26
                                  
                                  
                                  
                                      junit
                                      junit
                                      4.12
                                      test
                                  
                                  
                                      commons-io
                                      commons-io
                                      2.6
                                  
                              
                          
                          

                          2.8 activiti.cfg.xml核心配置

                          Activiti流程引擎通过名为的XML文件进行配置 activiti.cfg.xml 。

                          在 resources 目录下创建 activiti.cfg.xml 文件

                          
                              
                              
                                  
                                  
                                  
                                  
                                  
                                  
                                  
                                  
                              
                          
                          

                          注意:防止插入中文数据乱码,要加上字符集 characterEncoding=utf8

                          如果报错:Table ‘activiti01.act_ge_property’ doesn’t exist

                          解决:jdbcUrl的后面加上 nullCatalogMeansCurrent=true

                          2.9 log4j.properties配置日志

                          如果想在控制台打印执行的sql日志,需要配置日志输出格式等,在 resources 目录下创建 log4j.properties 文件: 注意:记得修改日志文件路径。

                          log4j.rootCategory=debug, CONSOLE, LOGFILE
                          log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
                          log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
                          log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
                          log4j.appender.CONSOLE.layout.ConversionPattern=%d{HH:mm:ss.SSS} %p [%t] %C.%M(%L) | %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:/03-projectCode/ideaProject/study-activiti/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
                          

                          2.10 创建ProcessEngine流程引擎实例和数据表

                          加载类路径上的 activiti.cfg.xml ,并根据该文件中的配置构造一个流程引擎,和创建数据表。

                          方式如下:

                          import org.activiti.engine.ProcessEngine; import org.activiti.engine.ProcessEngines; import org.junit.Test; 
                          public class ActivitiTest01 { 
                           /*** 创建ProcessEngine流程引擎,自动创建 activiti 数据表 */ @Test public void getProcessEngine() { 
                               // 方式一:使用activiti提供的工具类ProcessEngines, 
                               // 调用 getDefaultProcessEngine 会默认读取resource下的activiti.cfg.xml文件, 
                               // 并创建 Activiti 流程引擎 和 创建数据库表 
                               ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();                  System.out.println(processEngine); 
                               // 方式二:以编程方式创建ProcessEngineConfiguration对象 
                               // 1. 等同于方式一 
                               //ProcessEngineConfiguration configuration =ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault(); //ProcessEngine processEngine = configuration.buildProcessEngine(); 
                               // 2. 自定义配置路径和文件名, 但流程引擎bean的id要等于processEngineConfiguration //ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml"); 
                               // 3.自定义:配置路径、文件名和流程引擎bean的id //ProcessEngineConfiguration configuration =ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml", "processEngineConfiguration"); } }
                          

                          2.11 Activiti 25张数据表分析

                          Activiti 会自动创建25张数据表。(可能不同版本生成的表的数量也会不同。)

                          数据库表命名

                          Acitiviti数据库中表的命名都是以 ACT_ 开头的。第二部分是一个两个字符用例表的标识。此用例大体与服务API是

                          匹配的。

                          ACT_GE_* GE 表示 general 。通用数据,各种情况都使用的数据 ,如存放资源文件(图片,规则等)。

                          ACT_HI_xxx : HI 表示history。就是这些表包含着历史的相关数据,如结束的流程实例(变量,任务等)。

                          ACT_RE_xxx : RE 表示repository。带此前缀的表包含的是静态信息,如,流程定义,流程的资源(图片,规则 等)。 Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直 很小速度很快。

                          ACT_RU_xxx : RU 表示 runtime。这是运行时的表存储着流程变量,用户任务,变量,职责(job)等运行时的 数据。Activiti只存储实例执行期间的运行时数据,当流程实例结束时,将删除这些记录。这就保证了这些运行时的表小且快。

                          ACT_EVT_ :EVT表示EVENT,流程引擎的通用事件日志记录表*,方便管理员跟踪处理。

                          表分类表名说明
                          通用数据
                          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_subscrthrowEvent、catchEvent时间监听信息表
                          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_procdef_info流程定义的动态变更信息
                          act_evt_log流程引擎的通用事件日志记录表

                          完善表字段

                          1. Activiti 7的M4以上版本,部署流程定义时,报错如下:

                          报错: MySQLSyntaxErrorException: Unknown column ‘VERSION_’ in ‘field list’

                          解决:因为 ACT_RE_DEPLOYMENT 表缺少 VERSION_ 和 PROJECT_RELEASE_VERSION_ 字段,执行以下语句

                          添加

                          ALTER TABLE ACT_RE_DEPLOYMENT ADD COLUMN VERSION_ VARCHAR(255); ALTER TABLE ACT_RE_DEPLOYMENT ADD COLUMN PROJECT_RELEASE_VERSION_ VARCHAR(255);
                          

                          在 Activiti7.1.0.M6已经有了这些,不用执行上面sql。

                          2.12 Activiti API服务接口

                          前言

                          Activiti

                          Process Engine API 和服务

                          引擎 API 是与 Activiti 交互的最常见方式。 您可以从ProcessEngine中获取包含工作流/ BPM方法的各种服务。 ProcessEngine和服务对象是线程安全的。因此,您可以为整个服务器保留对其中之一的引用。

                          Service 是工作流引擎提供用于进行工作流部署、执行、管理的服务接口,我们使用对应Service接口可以操作对应的数据表。也就是说它提供了几个基础的service,里面包含的api供我们对流程进行操作。

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第9张

                          Activiti7的Servcie核心接口

                          Service接口说明
                          RuntimeService运行时 Service,可以处理所有正在运行状态的流程实例和任务等
                          RepositoryService流程仓库 Service,主要用于管理流程仓库,比如流程定义的控制管理(部 署、删除、挂起、激活…)
                          DynamicBpmnServiceRepositoryService可以用来部署流程定义(使用xml形式定义好的),一旦 部署到Activiti(解析后保存到DB),那么流程定义就不会再变了,除了修改xml定义文件内容;而DynamicBpmnService就允许我们在程序运行过程中去修改流程定义,例如:修改流程定义中的分配角色、优先级、流程流转的条件。
                          TaskService任务 Service,用于管理和查询任务,例如:签收、办理等
                          HistoryService历史Service,可以查询所有历史数据,例如:流程实例信息、参与者信息、完成时间…
                          ManagementService引擎管理Service,和具体业务无关,主要用于对Activiti流程引擎的管理和维护。
                          1. 核心 Service 接口实例获取方式如下:
                          // 会在首次调用时初始化并构建一个流程引擎,此后始终返回相同的流程引擎。
                          ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 
                          // 引擎管理类
                          ManagementService managementService = processEngine.getManagementService();
                          // 动态修改流程管理类
                          DynamicBpmnService dynamicBpmnService = processEngine.getDynamicBpmnService(); 
                          // 流程运行管理类 
                          RuntimeService runtimeService = processEngine.getRuntimeService(); 
                          // 流程仓库管理类 
                          RepositoryService repositoryService = processEngine.getRepositoryService(); 
                          // 任务管理类
                          TaskService taskService = processEngine.getTaskService(); 
                          // 历史管理类
                          HistoryService historyService = processEngine.getHistoryService(); 
                          // activiti 7 没有IdentityService和FormService接口 
                          //IdentityService identityService = processEngine.getIdentityService(); 
                          // FormService formService = processEngine.getFormService();
                          

                          三、Activiti流程实操入门

                          3.1 IDEA安装actiBPM插件

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第10张

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第11张

                          官网下载地址

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第12张

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第13张

                          3.2 绘制流程定义模型

                          1. 在 /resources 目录下创建 processes 目录,用于存放流程图

                          2. 创建BPMN文件:右击 processes 目录,点击【New】–>【BpmnFile】

                          3. 输入文件名称 leave ,点击【OK】按钮

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第14张

                          绘制请假申请流程图

                          将 xxxx.bpmn 文件放在 /resources/processes/ 目录下,即 /resources/processes/leave.bpmn

                          1. 鼠标左键拖拽右侧 开始事件 符号,将其拖下左侧界面上,同样的方式再拖拽其他图标

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第15张

                          1. 添加人工任务符号,修改 Name 节点名称 领导审批,和 Assignee 节点处理人:meng

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第16张

                          1. 添加人工任务符号:修改 Name 节点名称:总经理审批,和 Assignee 节点处理人:xue

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第17张

                          1. 添加结束事件符号

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第18张

                          1. 流程连线:点击图标的中心,会变成黑白色扇形,拖拽到另一图标,即可连接

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第19张

                          1. 点击流程图的空白处(不是点击流程符号):

                          设置当前流程图唯一标签 ID (也称为:流程的KEY):leaveProcess ,流程名称:请假流程。

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第20张

                          1. 最后检查,每个人工任务节点的 Name 和 Assignee 是否也上面一致。

                          3.3 解决中文乱码问题

                          1. 打开 Settings 窗口,点击 Editor > File Encodings > 将字符编码均设置为 UTF-8

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第21张

                          1. 打开idea安装目录,在 idea.exe.vmoptions (32位系统)和 idea64.exe.vmoptions (64位系统)文件最后

                          追加一行命令。 (C:\User\mengxuegu\.IntelliJIdea\config )

                          注意:不能有空格,不然idea重启后打不开

                          -Dfile.encoding=UTF-8
                          
                          1. 如果上面修改后,重启idea重新打开bpmn文件,还是乱码,则查找: C:\Users\Administrator\AppData\Roaming\JetBrains\IntelliJIdea2020.

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第22张

                          生成png图片

                          将 bpmn 文件不方便随处打开提供给用户看,为了方便将流程图转成图片格式,方便随处打开演示;

                          并在部署流程时也需要 png 图片。

                          1. 将 leave.bpmn 文件复制一份为 leave.xml

                          2. 右击 leave.xml 文件,选择【Diagrams】–>【Show BPMN 2.0 Diagrams…】

                          3. 如果找不到 Diagrams ,则重启 IDEA 工具

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第23张

                          1. 打开后,点击上方导出按钮,保存即可。

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第24张

                          1. 将生成的 leave.png 图片拷贝到 resources/processes 目录下

                          前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第25张

                          1. 可以把 leave.xml 文件删除

                          3.4 部署流程定义

                          概述

                          将上面在设计器中定义的流程部署到activiti数据库中,就是流程定义部署。

                          一般情况下,流程定义(Process Definition)是在流程设计和开发阶段完成的,它描述了工作流程的规则、流程节点、流程步骤、流程之间的转移条件等信息。流程定义通常以一种特定的格式或者规范进行定义,如 BPMN(Business Process Model and Notation)等。

                          而流程部署(Process Deployment)是在流程准备运行阶段完成的,它将流程定义部署到流程引擎中以便执行。在流程部署过程中,流程定义会被加载到流程引擎中,并在流程引擎中生成对应的流程实例。

                          通常流程部署与流程定义是一对多的关系,比如一组相关联的业务可以做成多个流程图定义,然后把他们打包成zip后统一部署。

                          通过调用activiti的api将流程定义的 .bpm 和 png 两个文件一个一个添加部署到activiti中,也可以将两个文件打成 zip包进行部署。

                          .bpmn 流程定义文件部署

                          1. 代码如下:
                          package com.mengxuegu.test; 
                          import org.activiti.engine.*; 
                          import org.activiti.engine.impl.util.ReflectUtil; 
                          import org.activiti.engine.repository.Deployment; 
                          import org.activiti.engine.runtime.ProcessInstance; 
                          import org.activiti.engine.task.Task; 
                          import org.activiti.engine.task.TaskQuery; 
                          import org.junit.Test; 
                          import java.io.IOException; 
                          import java.io.InputStream; 
                          import java.util.HashMap; 
                          import java.util.List; 
                          import java.util.Map; 
                          import java.util.zip.ZipInputStream; 
                          public class ActivitiTest02 { 
                              /*** 部署流程: 
                              * 1. ACT_RE_DEPLOYMENT 流程部署表,每执行一次部署,会插入一条记录 
                              * 2. ACT_RE_PROCDEF 生成流程定义信息 
                              * 其中 ACT_RE_DEPLOYMENT 与 ACT_RE_PROCDEF 表是一对多的关系, 
                              * ACT_RE_PROCDEF 每条记录对应一个流程的定义信息(如:小梦、小谷请假申请) 
                              * 3. ACT_GE_BYTEARRAY 流程资源表,插入资源数据,当前插入两条记录(.bpmn和.png资源) */ 
                              @Test public void deployByFile() {
                                  // 1. 实例化流程引擎实例 
                                  ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 
                                  // 2. 获取流程定义和部署对象相关的
                                  Service RepositoryService repositoryService = processEngine.getRepositoryService(); 
                                  // 3. 创建部署对象进行流程的部署,定义一个流程的名字,把 .bpmn 和 .png 部署到数据库中   
                                  Deployment deployment = repositoryService.createDeployment() .name("请假申请流程") .addClasspathResource("processes/leave.bpmn") .addClasspathResource("processes/leave.png") .deploy(); 
                                  // 4. 输出部署信息 
                                  System.out.println("部署ID:" + deployment.getId() ); 
                                  System.out.println("部署名称:" + deployment.getName() ); } }
                          

                          解决报错找不到字段

                          解决: ACT_RE_DEPLOYMENT 表缺少 VERSION_ 和 PROJECT_RELEASE_VERSION_ 字段,执行下面添加表字

                          ALTER TABLE ACT_RE_DEPLOYMENT ADD COLUMN VERSION_ VARCHAR(255); ALTER TABLE ACT_RE_DEPLOYMENT ADD COLUMN PROJECT_RELEASE_VERSION_ VARCHAR(255);
                          

                          .zip 流程定义压缩包部署

                          将 leave.bpmn和 leave.png 压缩成 leave.zip ,放在类路径下的 processes/leave.zip 。 (所以正如上面所说,部署与定义是一对多的关系)

                          * 通过zip压缩包部署流程定义 */ 
                              @Test public void deployByZip() { 
                              // 1. 实例化流程引擎实例 
                              ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 
                              // 2. 获取流程定义和部署对象相关的Service
                              RepositoryService repositoryService = processEngine.getRepositoryService(); 
                              // 3. 流程部署 
                              // 读取zip资源包,构成 InputStream 输入流 
                              InputStream inputStream = ReflectUtil.getResourceAsStream("processes/leave.zip"); 
                              // 封装 ZipInputStream 输入流进行流程部署 
                              ZipInputStream zipInputStream = new ZipInputStream(inputStream); 
                              Deployment deployment = repositoryService.createDeployment() .addZipInputStream(zipInputStream) .name("请假申请流程-压缩包") .deploy(); 
                              // 4. 输出部署信息 
                              System.out.println("部署ID:" + deployment.getId()); 
                              System.out.println("部署名称:" + deployment.getName() ); }
                          

                          运行后,压缩包中的 .bpm 文件和 图片文件会保存在activiti数据表中。

                          部署涉及的数据表

                          流程定义部署会涉及 activiti 的3张表:

                          • act_re_deployment 流程定义部署表,每部署一次增加一条记录
                          • act_re_procdef 流程定义表,部署每个新的流程定义都会在这张表中增加一条记录

                            注意:表中字段 KEY 是不同流程定义的唯一标识。

                            • act_ge_bytearray 流程资源表,bpmn的 xml 串和 流程图片,每次增加对应资源数据

                              注意:

                              act_re_deployment 和 act_re_procdef 一对多关系,一次部署在流程部署表生成一条记录,但一次部署可以部署 多个流程定义,每个流程定义在流程定义表生成一条记录。每一个流程定义在 act_ge_bytearray 会存在两个资源 记录,bpmn 和 png。

                              建议:

                              一次部署一个流程,这样部署表和流程定义表是一对一有关系,方便读取流程部署及流程定义信息。

                              3.5 查询流程定义

                              查询部署的流程定义数据 ACT_RE_PROCDEF :

                              /*** 查询部署的流程定义数据 ACT_RE_PROCDEF */ 
                              @Test public void getProcessDefinitionList() { 
                                  // 1. 实例化流程引擎实例 
                                  ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 
                                  // 2. 获取 RepositoryService 
                                  RepositoryService repositoryService = processEngine.getRepositoryService(); 
                                  // 3. 获取 ProcessDefinitionQuery 这里的leaveProcess就是画流程图时指定的唯一的key
                                  ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery(); List definitionList = query.processDefinitionKey("leaveProcess") .orderByProcessDefinitionVersion() 
                                      // 按版本号排序 
                                      .desc() 
                                      // 降序 
                                      .list();
                                  for (ProcessDefinition pd : definitionList) 
                                  { 
                                      System.out.println("流程部署ID:" + pd.getDeploymentId());
                                      System.out.println("流程定义ID:" + pd.getId()); 
                                      System.out.println("流程定义Key:" + pd.getKey()); 
                                      System.out.println("流程定义名称:" + pd.getName()); 
                                      System.out.println("流程定义版本号:" + pd.getVersion()); 
                                  }
                              }
                              

                              输出内容:

                              流程部署ID:1

                              流程定义ID:leaveProcess:1:4

                              流程定义Key:leaveProcess

                              流程定义名称:请假流程

                              流程定义版本号:1

                              启动流程实例(提交申请)

                              流程定义部署后,然后可以通过 activiti 工作流管理业务流程了。例如上面部署好了请假流程,可以申请请假了。 针对部署好的流程定义,每次用户发起一个新的请假申请,就对应的启动一个新的请假流程实例;

                              类似于 java 类与 java 对象(实例)的关系,定义好类后,使用 new 创建一个对象(实例)使用,当然可以 new 多个对象(实例)。

                              例如:请假流程,小梦发起一个请假申请单,对应的就启动一个针对小梦的新流程实例;小王发起一个请假申请 单,也启动针对小王的新流程实例。

                              3.6 启动流程实例代码

                              /** * 启动流程实例(提交申请) */
                              @Test public void startProcessInstance() {
                                  // 1. 实例化流程引擎实例 
                                  ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 
                                  // 2. 获取 RuntimeService 
                                  RuntimeService runtimeService = processEngine.getRuntimeService(); 
                                  // 开启流程实例 (流程设计图唯一标识key) 
                                  ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leaveProcess"); 
                                  System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());             System.out.println("流程实例id:" + processInstance.getId()); 
                              }
                              

                              输出内容:

                              流程定义id:leaveProcess:1:4

                              流程实例id:2501

                              流程实例涉及的数据表

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

                                3.7 查询办理人待办任务

                                启动流程实例后,每个任务的办理人就可以查询自己当前的待办任务,然后进行办理任务。

                                /*** 查询指定人员的待办任务 */ 
                                @Test public void taskListByAssignee() { 
                                // 1. 实例化流程引擎实例
                                ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 
                                    // 2. 获取 TaskService 
                                    TaskService taskService = processEngine.getTaskService(); 
                                    // 3. 根据流程唯一标识 key 和 任务办理人 查询任务 
                                    List list = taskService.createTaskQuery().processDefinitionKey("leaveProcess") 
                                    .taskAssignee("meng")
                                    .list(); 
                                    for (Task task : list) { 
                                        System.out.println("流程实例id:" + task.getProcessInstanceId());                           System.out.println("任务id:" + task.getId()); 
                                        System.out.println("任务名称:" + task.getName()); 
                                        System.out.println("任务办理人:" + task.getAssignee()); 
                                    } 
                                }
                                

                                输出内容:

                                流程实例id:2501

                                任务id:2505

                                任务负责人:meng

                                任务名称:领导审批

                                3.8 完成待办任务

                                任务办理人查询待办任务,将待办任务进行完成。

                                1. 先查询 meng 办理人任务,然后完成任务

                                2. 再查询 xue 办理人任务,然后完成任务

                                3. 这样此流程实例就完成结束。

                                /*** 完成待办任务 */ @Test public void completeTask() { 
                                    // 1. 实例化流程引擎实例 
                                    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 
                                    // 2. 获取 TaskService 
                                    TaskService taskService = processEngine.getTaskService(); 
                                    // 3. 根据流程唯一标识 key 和 任务办理人 查询任务 
                                    Task task = taskService.createTaskQuery() .processDefinitionKey("leaveProcess") 
                                        // 流程 Key 
                                       .taskAssignee("meng") 
                                        // 查询 meng 的任务 
                                        .taskAssignee("xue") 
                                        .singleResult(); 
                                    // 目前只有一条任务,则可以只获取一条 
                                    // 4. 完成任务(任务id) 
                                    taskService.complete(task.getId());
                                }
                                

                                3.9 查询流程实例历史节点信息

                                查询流程办理历史信息,通过 HistoryService 历史数据对象来获取 HistoricActivityInstanceQuery 历史节点查询 对象。

                                /*** 查看流程办理历史信息 */ 
                                @Test public void historyInfo(){ 
                                    // 1. 实例化流程引擎实例 
                                    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 
                                    // 2. 获取 HistoryService 
                                    HistoryService historyService = processEngine.getHistoryService(); 
                                    // 3. 获取节点历史记录查询对象 ACT_HI_ACTINST 表 
                                    HistoricActivityInstanceQuery query = historyService.createHistoricActivityInstanceQuery(); 
                                    // 实例 id 
                                    String processInstanceId = "10001"; 
                                    List list = query.processInstanceId(processInstanceId) .orderByHistoricActivityInstanceStartTime() 
                                        // 根据开始时间排序 asc 升序 
                                        .asc() 
                                        .list(); 
                                    for (HistoricActivityInstance hi : list) {
                                        System.out.print("流程定义ID: " + hi.getProcessDefinitionId());                             System.out.print(",流程实例ID: " + hi.getProcessInstanceId());                             System.out.print(",节点ID: " + hi.getActivityId()); 
                                        System.out.print(",节点名称: " + hi.getActivityName()); 
                                        System.out.print(",任务办理人:" + hi.getAssignee()); 
                                        System.out.print(",开始时间:" + hi.getStartTime()); 
                                        System.out.println("结束时间:" + hi.getEndTime()); 
                                    } 
                                }
                                

                                四、SpringBoot 与 Activiti7 整合

                                测试完基础的功能,终于到了重头戏了,好多网上的文档斌没有教你如何把activi7如何整合到你的实际项目中。

                                4.1 创建模块 activiti-boot

                                模块名:activiti-boot

                                前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第26张

                                4.2 pom.xml 依赖坐标

                                
                                
                                    4.0.0
                                    com.mengxuegu
                                    activiti-boot
                                    1.0-SNAPSHOT
                                    
                                        org.springframework.boot
                                        spring-boot-starter-parent
                                        2.5.0
                                        
                                    
                                    
                                        7.1.0.M6
                                        3.3.1
                                    
                                    
                                        
                                        
                                            org.activiti
                                            activiti-spring-boot-starter
                                            ${activiti.version}
                                        
                                        
                                        
                                            org.activiti
                                            activiti-image-generator
                                            ${activiti.version}
                                        
                                        
                                        
                                            org.activiti
                                            activiti-json-converter
                                            ${activiti.version}
                                        
                                        
                                        
                                            org.apache.xmlgraphics
                                            batik-all
                                            1.10
                                        
                                        
                                        
                                            org.springframework.boot
                                            spring-boot-starter-web
                                        
                                        
                                            mysql
                                            mysql-connector-java
                                        
                                        
                                        
                                            com.baomidou
                                            mybatis-plus-boot-starter
                                            ${mybatis-plus.version}
                                        
                                        
                                        
                                            org.springframework.boot
                                            spring-boot-starter-security
                                        
                                        
                                            org.springframework.boot
                                            spring-boot-starter-test
                                            test
                                        
                                        
                                    
                                    
                                        
                                            
                                                org.springframework.boot
                                                spring-boot-maven-plugin
                                            
                                        
                                    
                                
                                

                                4.3 创建application.yml配置文件

                                1. 创建 application.yml 文件,activiti 7 相关配置如下:
                                server:
                                  port: 8080
                                  servlet:
                                    context-path: /workflow
                                spring:
                                  datasource:
                                    driver-class-name: com.mysql.cj.jdbc.Driver
                                    url: jdbc:mysql://127.0.0.1:3306/activiti-boot?nullCatalogMeansCurrent=true&useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&allowMultiQueries=true
                                    username: root
                                    password: root
                                  # activiti配置
                                  activiti:
                                    #自动更新数据库结构
                                    # true:适用开发环境,默认值。activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建
                                    # false:适用生产环境。activiti在启动时,对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常
                                    # create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)
                                    # drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)
                                    database-schema-update: true
                                    # activiti7与springboot整合后默认不创建历史表,需要手动开启
                                    db-history-used: true
                                      # 记录历史等级 可配置的历史级别有none, activity, audit, full
                                      # none:不保存任何的历史数据,因此,在流程执行过程中,这是最高效的。
                                      # activity:级别高于none,保存流程实例与流程行为,其他数据不保存。
                                      # audit:除activity级别会保存的数据外,还会保存全部的流程任务及其属性。
                                      # full:保存历史数据的最高级别,除了会保存audit级别的数据外,还会保存其他全部流程相关的细节数据,包括一些流程参数等。
                                    history-level: full
                                    # 是否自动检查resources下的processes目录的流程定义文件
                                    check-process-definitions: false
                                    # smtp服务器地址
                                    mail-server-host: smtp.qq.com
                                    # SSL端口号
                                    mail-server-port: 465
                                    # 开启ssl协议
                                    mail-server-use-ssl: true
                                    # 默认的邮件发送地址(发送人),如果activiti流程定义中没有指定发送人,则取这个值
                                    mail-server-default-from: w736486962@qq.com
                                    # 邮件的用户名
                                    mail-server-user-name: w736486962@qq.com
                                    # qq的smtp服务相关的授权码
                                    mail-server-password: xxx填写自己qq邮箱的smtp授权码
                                    # 关闭不自动添加部署数据 SpringAutoDeployment
                                    #deployment-mode: never-fail
                                # 日志级别是debug才能显示SQL日志
                                logging:
                                  level:
                                    org.activiti.engine.impl.persistence.entity: debug
                                

                                4.4 创建数据库activiti-boot

                                只有你自己创建了数据库建立了驱动连接,才会自动生成工作流的表。这里就不讲解怎么创建数据库了。

                                4.5 整合SpringSecurity

                                1. activiti7 与 SpringSecurity 强耦合,

                                创建安全认证配置类 com.mengxuegu.config.SpringSecurityConfig 类

                                注意:activiti7 任务办理人,必须是当前可查询到的用户名

                                package com.mengxuegu.workflow.config;
                                import org.slf4j.Logger;
                                import org.slf4j.LoggerFactory;
                                import org.springframework.context.annotation.Bean;
                                import org.springframework.context.annotation.Configuration;
                                import org.springframework.security.config.annotation.web.builders.HttpSecurity;
                                import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
                                import org.springframework.security.core.authority.SimpleGrantedAuthority;
                                import org.springframework.security.core.userdetails.User;
                                import org.springframework.security.core.userdetails.UserDetailsService;
                                import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
                                import org.springframework.security.crypto.password.PasswordEncoder;
                                import org.springframework.security.provisioning.InMemoryUserDetailsManager;
                                import org.springframework.security.provisioning.UserDetailsManager;
                                import java.util.Arrays;
                                import java.util.List;
                                import java.util.stream.Collectors;
                                @Configuration
                                public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
                                    private Logger logger = LoggerFactory.getLogger(SpringSecurityConfig.class);
                                    /**
                                     * 内存 UserDetailsManager
                                     */
                                    @Bean
                                    public UserDetailsService myUserDetailsService() {
                                        InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
                                        // 初始化账号角色数据
                                        addGroupAndRoles(inMemoryUserDetailsManager);
                                        return inMemoryUserDetailsManager;
                                    }
                                    private void addGroupAndRoles(UserDetailsManager userDetailsManager) {
                                        // 注意:后面流程办理人,必须是当前存在的用户 username,这些都是为了后面指定流程班里人做准备
                                        String[][] usersGroupsAndRoles = {
                                                {"meng", "123456", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
                                                {"xue", "123456", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
                                                {"gu", "123456", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
                                                {"小梦", "123456", "ROLE_ACTIVITI_ADMIN", "GROUP_otherTeam"},
                                                {"小学", "123456", "ROLE_ACTIVITI_ADMIN", "GROUP_otherTeam"},
                                                {"小谷", "123456", "ROLE_ACTIVITI_ADMIN", "GROUP_otherTeam"}
                                        };
                                        for (String[] user : usersGroupsAndRoles) {
                                            List authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user, 2, user.length));
                                            logger.info("> Registering new user: " + user[0] + " with the following Authorities[" + authoritiesStrings + "]");
                                            userDetailsManager.createUser(new User(user[0], passwordEncoder().encode(user[1]),
                                                    authoritiesStrings.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList())));
                                        }
                                    }
                                    @Override
                                    protected void configure(HttpSecurity http) throws Exception {
                                        http.csrf().disable();
                                    }
                                    @Bean
                                    public PasswordEncoder passwordEncoder() {
                                        return new BCryptPasswordEncoder();
                                    }
                                }
                                

                                4.6 创建启动类

                                创建项目启动类 com.mengxuegu.workflflow.WorkFlowApplication

                                package com.mengxuegu.workflow; 
                                import org.springframework.boot.SpringApplication; 
                                import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication 
                                public class WorkFlowApplication { 
                                    public static void main(String[] args) { 
                                        SpringApplication.run(WorkFlowApplication.class, args);                               } 
                                }
                                

                                4.7 测试Activiti流程

                                相关的 Activiti 服务接口,都直接依赖注入即可使用。

                                1. 将上面的 activiti-demo1 工程中绘制的bpmn流程图文件,拷贝如下工程的 resources 目录下

                                前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第27张

                                1. 在 src/test 目录下创建测试类 com.mengxuegu.workflflow.test.ActivitiTest01
                                package com.mengxuegu.workflow.test; 
                                import org.activiti.engine.ProcessEngine; 
                                import org.activiti.engine.RepositoryService; import org.activiti.engine.repository.Deployment; 
                                import org.junit.jupiter.api.Test; 
                                import org.springframework.beans.factory.annotation.Autowired; 
                                import org.springframework.boot.test.context.SpringBootTest; 
                                @SpringBootTest public class ActivitiTest01 {
                                    @Autowired ProcessEngine processEngine; 
                                    @Autowired RepositoryService repositoryService;
                                    /*** 获取 ProcessEngine 流程引擎,自动创建 activiti 数据表 */ 
                                    @Test public void getProcessEngine() { 
                                        // 获取 Activiti 流程引擎 和 创建数据库表, 
                                        // 并在 ACT_RE_DEPLOYMENT 插入一条无用的数据 
                                        SpringAutoDeployment System.out.println(processEngine); 
                                    }
                                    /*** 部署流程: */ 
                                    @Test public void deployByFile() { 
                                        // 1. 创建部署对象进行流程的部署,定义一个流程的名字,把 .bpmn 和 .png 部署到数据库中 
                                        Deployment deployment = repositoryService.createDeployment() .name("请假申请流程") .addClasspathResource("processes/leave.bpmn") .addClasspathResource("processes/leave.png") .deploy(); 
                                        // 2. 输出部署信息 
                                        System.out.println("部署ID:" + deployment.getId() ); 
                                        System.out.println("部署名称:" + deployment.getName() ); 
                                    } 
                                }
                                

                                如果报错如下:

                                Cause: java.sql.SQLSyntaxErrorException: Unknown column 'VERSION_' in 'field list'

                                Cause: java.sql.SQLSyntaxErrorException: Unknown column 'PROJECT_RELEASE_VERSION_' in 'field

                                解决: ACT_RE_DEPLOYMENT 表缺少 VERSION_ 和 PROJECT_RELEASE_VERSION_ 字段,执行下面添加表字

                                ALTER TABLE ACT_RE_DEPLOYMENT ADD COLUMN VERSION_ VARCHAR(255); ALTER TABLE ACT_RE_DEPLOYMENT ADD COLUMN PROJECT_RELEASE_VERSION_ VARCHAR(255);
                                

                                五、整合流程模型设计器Activiti Modeler

                                为什么要整合

                                上面我们在 idea 上设计的流程模型,而每次要设计都要打开 idea 或其他设计流程工具来进行操作,这样不太方 便。 而实际上 Activiti 官方提供了 Web 版的流程设计工具 Activiti Modeler,可以直接整合到我们项目中。

                                在 Activiti 5.10 版本把原本独立的 Activiti Modeler 模块整合到了 Activiti Explorer 模块中,两者相结合使用起来 很方便, 通过 Modeler 设计的流程模型可以直接部署到引擎,也可以把已经部署的流程转换为Model从而在Modeler中编 辑。 在实际应用中也有这样的需求,把 Modeler 整合到业务系统中可以供管理员使用,或者作为BPM流程管理平台的 一部分存在。

                                但是在 Activiti 官方没有给出如何整合Modeler的文档,要我们自己整合。

                                前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第28张

                                5.1 下载源码

                                首先需要从 Github下载 Activiti 5.22 版本源码

                                访问:https://github.com/Activiti/Activiti/releases/tag/activiti-5.22.0

                                下载 zip 格式的压缩包:https://github.com/Activiti/Activiti/archive/activiti-5.22.0.zip

                                前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第29张

                                如果解压过程中出现文件名过程问题可以换一个解压软件,比如7Zip。

                                5.2 拷贝目标源码

                                1. 解压 Activiti-activiti-5.22.0.zip ,然后进入 Activiti-activiti-5.22.0/modules 目录,

                                2. 复制 activiti-webapp-explorer2 工程中如下图画红框的文件夹和文件,

                                前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第30张

                                粘贴到 activiti-boot 工程的 resources/static 目录下(static 目录创建)

                                前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第31张

                                1. 找到 activiti-modeler 工程下的 3个类,如下:

                                前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第32张

                                拷贝到 com.mengxuegu.workflflow.activiti 包下面,如下图:

                                前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第33张

                                5.3 修改上下文路径

                                1. 找到 static/editor-app/confifiguration/url-confifig.js ,修改文件中的项目上下文路径,这样才能请求到上面的3 个接口

                                上下文路径对应 application.yml 文件中配置的 server.servlet.context-path=/workflow

                                在前端请求接口路径配置文件可参见:static/editor-app/confifiguration/url-confifig.js,

                                ACTIVITI.CONFIG = { 
                                'contextRoot' : '/workflow' // '/activiti-explorer/service', 
                                };
                                

                                前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第34张

                                5.4 汉化Activiti Modeler

                                汉化文件为两个json文件stencilset.json和zh-CN.json

                                需要的自取:

                                链接:https://pan.baidu.com/s/1az50zQQ6U-o-owqOfgt3RQ

                                提取码:1111

                                1. 汉化页面文字,在 resources/static/ 目录下添加 stencilset.json 文件。

                                2. 需要修改 StencilsetRestResource.java 类中 stencilset.json 为 static/stencilset.json (最前面不

                                要有 / );

                                InputStream stencilsetStream = this.getClass().getClassLoader().getResourceAsStream("static/stencilset.json");
                                

                                前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第35张

                                1. 汉化按钮文字,添加zh-CN.json 文件

                                在 resources/static/editor-app/i18n 目录下添加 zh-CN.json 文件

                                前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第36张

                                修改 resources/static/editor-app/app.js 文件,将第51行的 $translateProvider.preferredLanguage(‘en’); 替换为以下内容:

                                // $translateProvider.preferredLanguage('en'); 
                                // 多语言支持 
                                if("zh-CN" == navigator.language){ 
                                    $translateProvider.preferredLanguage('zh-CN'); 
                                }else { 
                                    $translateProvider.preferredLanguage('en'); 
                                }
                                

                                启动项目时报错:

                                Error:Kotlin: Module was compiled with an incompatible version of Kotlin. The binary version of

                                its metadata is 1.5.1, expected version is 1.1.16.

                                解决:如下图重新编译下,然后再启动项目

                                前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第37张

                                5.5 创建空的流程模型

                                1. 创建一个 ModelController 模型控制器,用于创建空流程模型和跳转到模型设计页面 modeler.html
                                package com.mengxuegu.workflow.controller; 
                                import com.fasterxml.jackson.databind.ObjectMapper; 
                                import com.fasterxml.jackson.databind.node.ObjectNode; 
                                import org.activiti.editor.constants.ModelDataJsonConstants; 
                                import org.activiti.engine.RepositoryService; 
                                import org.activiti.engine.repository.Model; 
                                import org.springframework.beans.factory.annotation.Autowired; 
                                import org.springframework.stereotype.Controller; 
                                import org.springframework.web.bind.annotation.*; 
                                import javax.servlet.http.HttpServletRequest; 
                                import javax.servlet.http.HttpServletResponse;
                                /*** 流程模型管理 */ 
                                @Controller 
                                @RequestMapping("/model") 
                                public class ModelController {
                                    @Autowired RepositoryService repositoryService;
                                    @Autowired ObjectMapper objectMapper;
                                    /*** 创建空模型窗口: 
                                    * 创建模型对象 
                                    * 设置对象值 
                                    * 存储模型对象(表act_re_model) 
                                    * 存储模型对象基础数据(表act_ge_bytearray) 
                                    * 跳转到ActivitiModeler,编辑流程图,存储流程图片和流程定义等(表act_ge_bytearray) 
                                    */ 
                                    @GetMapping("/create") 
                                    public void create(HttpServletRequest request, HttpServletResponse response) {
                                        try {
                                            String name = "请假流程模型"; 
                                            String key = "leaveProcess"; 
                                            String desc = "请输入描述信息~"; 
                                            int version = 1; 
                                            //初始化一个空模型 
                                            Model model = repositoryService.newModel(); 
                                            model.setName(name); 
                                            model.setKey(key); 
                                            model.setVersion(version); 
                                            // 封裝模型json对象 
                                            ObjectNode modelObjectNode = objectMapper.createObjectNode();                             modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name);                             modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 0);                           modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, desc);                     model.setMetaInfo(modelObjectNode.toString()); 
                                            // 存储模型对象(表 ACT_RE_MODEL ) 
                                            repositoryService.saveModel(model); 
                                            // 封装模型对象基础数据json串 {"id":"canvas","resourceId":"canvas","stencilset": {"namespace":"http://b3mn.org/stencilset/bpmn2.0#"},"properties":{"process_id":"未定义"}} 
                                            ObjectNode editorNode = objectMapper.createObjectNode(); 
                                            //editorNode.put("resourceId", "canvas"); 
                                            ObjectNode stencilSetNode = objectMapper.createObjectNode();                             stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");                   editorNode.replace("stencilset", stencilSetNode); 
                                            // 标识key 
                                            ObjectNode propertiesNode = objectMapper.createObjectNode();                             propertiesNode.put("process_id", key); 
                                            editorNode.replace("properties", propertiesNode); 
                                            // 存储模型对象基础数据(表 ACT_GE_BYTEARRAY )                                 
                                            repositoryService.addModelEditorSource(model.getId(),                                     editorNode.toString().getBytes("utf-8")); 
                                            // 编辑流程模型时,只需要直接跳转此url并传递上modelId即可                     
                                            response.sendRedirect(request.getContextPath() + "/modeler.html?modelId=" + model.getId()); 
                                        } catch (Exception e) {
                                            e.printStackTrace(); 
                                        }
                                    }
                                }
                                
                                1. 重启mengxuegu-activiti-boot项目,

                                2. 访问 http://localhost:8080/workflflow/model/create ,

                                会重定向到 http://localhost:8080/workflflow/modeler.html?modelId=xxxxxxxx

                                前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第38张

                                如果按钮文字是英文,而不是中文,则清除缓存重新打开浏览器访问 。

                                5.6 绘制请假流程定义模型

                                绘制流程定义模型涉及表

                                • ACT_RE_MODEL 流程模型基本信息表
                                • ACT_GE_BYTEARRAY 流程模型描述 json 串(注意不是xml串)和 流程图字节码。

                                  1、绘制请假流程:

                                  领导审批:办理人 meng

                                  总经理审批:办理人 xue

                                  前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第39张

                                  前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第40张

                                  前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第41张

                                  1. 点击 保存 按钮,会将绘制的 流程图 提交给后台进行保存操作(当前会报400错误,提交不成功)

                                  保存请求路径:http://localhost:8080/workflflow/model/{modelId}/save

                                  1. 上面点击保存,会报400错误,

                                  原因: ModelSaveRestResource 类中使用 @RequestBody MultiValueMap 接收参数无法接收到。

                                  解决:将 @RequestBody MultiValueMap 改为 @RequestParam MultiValueMap ,如下图:

                                  前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第42张

                                  1. 重启项目,再次保存测试 ok

                                  六、流程定义模型管理Model

                                  上面已经整合Web 端Activiti Modeler流程模型设计器,并完成创建和保存流程模型设计图。 下面对流程定义模型进行查询、删除、导出模型zip压缩包、xml 文件、部署流程定义。

                                  6.1 查询已绘制的所有流程模型数据:

                                  package com.mengxuegu.workflow.test; 
                                  import org.activiti.engine.RepositoryService; 
                                  import org.activiti.engine.repository.Model; 
                                  import org.activiti.engine.repository.ModelQuery; 
                                  import org.junit.jupiter.api.Test; 
                                  import org.springframework.beans.factory.annotation.Autowired; 
                                  import org.springframework.boot.test.context.SpringBootTest; 
                                  import java.util.List; 
                                  @SpringBootTest 
                                  public class ActivitiTest02Model { 
                                      @Autowired RepositoryService repositoryService;
                                      /*** 查询所有流程模型 ACT_RE_MODEL */ 
                                      @Test public void modelList() { 
                                          // 获取模型查询对象 
                                          ModelQuery query = repositoryService.createModelQuery(); 
                                          // 按模型创建时间 降序 排列 
                                          List list = query.orderByCreateTime() .desc() .list();
                                          for (Model model : list) {
                                              System.out.print("模型id:" + model.getId()); 
                                              System.out.print(",模型名称:" + model.getName()); 
                                              System.out.print(",模型描述:" + model.getMetaInfo()); 
                                              System.out.print(",模型标识key:" + model.getKey()); 
                                              System.out.print(",模型版本号:" + model.getVersion()); 
                                              System.out.print(",创建时间:" + model.getCreateTime()); 
                                              System.out.println("更新时间:" + model.getLastUpdateTime()); 
                                          } 
                                      } 
                                  }
                                  

                                  6.2 删除流程模型

                                  通过模型ID删除模型:

                                  /*** 删除模型: * 涉及表:ACT_RE_MODEL、ACT_GE_BYTEARRAY */ 
                                  @Test public void deleteModel(){ 
                                      // 模型id 
                                      String id = "f2cd384f-c826-11eb-bbf0-2abb00fc727d";                                       repositoryService.deleteModel(id);
                                      System.out.println("删除成功"); 
                                  }
                                  

                                  6.3 导出下载模型图zip压缩包

                                  导出下载模型图zip压缩包,压缩包中有 .bpmn20.xml 流程描述和 .png 图片资源, 在流程部署时,可以使用上传流程模型图zip压缩包进行部署.

                                  /*** 导出下载模型图zip压缩包(.bpmn20.xml流程描述和.png图片资源) */ 
                                  @Test public void exportZip() throws Exception{ 
                                      // 模型id 
                                      String id = "1c3b7d73-c833-11eb-98fd-ee5b4f08d062"; 
                                      // 查询模型信息 
                                      Model model = repositoryService.getModel(id); 
                                      if(model != null) { 
                                          // 获取流程图 json 字节码 
                                          byte[] bpmnJsonBytes = repositoryService.getModelEditorSource(id); 
                                          // 流程图 json 字节码转 xml 字节码
                                          byte[] xmlBytes = bpmnJsonToXmlBytes(bpmnJsonBytes); 
                                              if(xmlBytes == null) { 
                                                  System.out.println("模型数据为空-请先设计完整流程-再导出"); }else 
                                              { 
                                                  // 压缩包文件名 
                                                  String zipName = model.getName() + "." + model.getKey() + ".zip"; 
                                                  // 文件输出流 
                                                  File file = new File("D:/" + zipName); 
                                                  FileOutputStream outputStream = new FileOutputStream(file); 
                                                  // 实例化zip压缩对象输出流 
                                                  ZipOutputStream zipos = new ZipOutputStream(outputStream); 
                                                  // 指定压缩包里的 name.bpmn20.xml 文件名 
                                                  zipos.putNextEntry(new ZipEntry(model.getName() + ".bpmn20.xml")); 
                                                  // 将xml写入压缩流 
                                                  zipos.write(xmlBytes); 
                                                  // 查询png图片, 
                                                  byte[] pngBytes = repositoryService.getModelEditorSourceExtra(id); if(pngBytes != null) { 
                                                  // 指定压缩包里的 name.key.png 文件名 
                                                  zipos.putNextEntry(new ZipEntry(model.getName() + "." + model.getKey() + ".png")); 
                                                  // 图片文件写到压缩包中 
                                                  zipos.write(pngBytes); 
                                         }
                                                  zipos.closeEntry(); 
                                                  zipos.close(); 
                                                  System.out.println("导出成功"); 
                                              } 
                                      }else  { 
                                          System.out.println("模型不存在");
                                      } 
                                  }
                                      @Autowired ObjectMapper objectMapper; 
                                  /*** 流程图保存的时候是json串,引擎认识的却是符合bpmn2.0规范的xml, 
                                  * json 字节码转 xml 字节码 
                                  * @param jsonBytes * @return 
                                  */ 
                                  private byte[] bpmnJsonToXmlBytes(byte[] jsonBytes) throws IOException { 
                                      if(jsonBytes == null) {
                                          return null; 
                                      }
                                      // json转回BpmnModel对象 
                                      JsonNode modelNode = objectMapper.readTree(jsonBytes); 
                                      BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(modelNode);            if(bpmnModel.getProcesses().size() == 0) {
                                          return null;
                                      }
                                      // BpmnModel对象转xml字节数组 
                                      return new BpmnXMLConverter().convertToXML(bpmnModel); 
                                  }
                                  

                                  运行后,生成 请假流程模型.leaveProcess.zip 压缩后,解压后如下:

                                  前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第43张

                                  6.4 导出下载模型 xml 文件

                                  在流程部署时,可以只上传流程模型图 xml 文件进行部署

                                  /*** 导出下载模型 xml 文件 */ 
                                  @Test public void exportXml() throws Exception{
                                      // 模型id 
                                      String id = "1c3b7d73-c833-11eb-98fd-ee5b4f08d062"; 
                                      ByteArrayInputStream in = null; 
                                      // 获取流程图 json 字节码 
                                      byte[] bytes = repositoryService.getModelEditorSource(id); 
                                      // json转xml字节数组 
                                      String filename = null; 
                                      if(bytes != null) {
                                          JsonNode modelNode = objectMapper.readTree(bytes);
                                          BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(modelNode);                 if(bpmnModel.getProcesses().size() != 0) { 
                                              // 转xml字节数组 
                                              byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(bpmnModel); in = new ByteArrayInputStream(bpmnBytes);
                                              // 如果流程名称为空,则取流程定义key 
                                              filename = StringUtils.isEmpty(bpmnModel.getMainProcess().getName()) ? bpmnModel.getMainProcess().getId() : bpmnModel.getMainProcess().getName(); 
                                          } 
                                      }if(filename == null) {
                                          filename = "模型数据为空,请先设计流程,再导出"; 
                                          in = new ByteArrayInputStream(filename.getBytes("UTF-8")); 
                                      }
                                      // 文件输出流 
                                      FileOutputStream out = new FileOutputStream(new File("D:/" + filename + ".bpmn20.xml"));
                                      // 输入流,输出流的转换 
                                      IOUtils.copy(in, out); 
                                      // 关闭流
                                      out.close(); 
                                      in.close(); 
                                      System.out.println("下载模型 xml 文件成功"); 
                                  }
                                  

                                  运行后,生成文件: 请假申请流程.bpmn20.xml

                                  前后端分离Springboot 整合使用activiti7教程(一)(全网最细),外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传,第44张

                                  通过模型数据 部署 流程定义

                                  注意事项:

                                  每个流程定义模型可以多次流程定义部署,activiti 通过流程定义模型中的标识 key 来判断是否为同一流程模型, 相同标识key则视为同一流程定义模型。

                                  相同的标识key流程定义模型,每部署一次对应的新增一条流程定义数据,对应流程定义版本号会基于之前的加1。

                                  上面注意事项,针对下一章讲解的通过 zip 和 xml 文件进行部署流程定义也是要一样的。

                                  /** 
                                  * 通过流程模型 进行 流程定义部署 
                                  * 流程图保存的时候是json串,引擎认识的却是符合bpmn2.0规范的xml, 
                                  * 所以在首次的部署的时候要将json串转换为BpmnModel, 
                                  * 再将BpmnModel转换成xml保存进数据库,以后每次使用就直接将xml转换成BpmnModel,
                                  * 这套操作确实有点啰嗦,实际项目中如果不用activiti自带的设计器,可以考虑用插件,直接生成的是 xml,
                                  * 或者自己开发设计器,在后端生成节点及其属性,引擎有现成的节点实体,如:开始节点StartEvent, 线SequenceFlow等。
                                  * 涉及表: 
                                  * ACT_RE_PROCDEF 新增数据: 流程定义数据 
                                  * ACT_RE_DEPLOYMENT 新增数据: 流程部署数据 
                                  * ACT_GE_BYTEARRAY 新增数据:将当前流程图绑定到此流程定义部署数据上 
                                  * ACT_RE_MODEL 更新部署id 
                                  */ 
                                  @Test public void deploy() throws Exception {
                                      // 模型id 
                                      String id = "1c3b7d73-c833-11eb-98fd-ee5b4f08d062"; 
                                      // 获取流程图 json 字节码 
                                      byte[] jsonBytes = repositoryService.getModelEditorSource(id); 
                                      if (jsonBytes == null) {
                                          System.out.println("模型数据为空,请先设计流程并成功保存,再进行发布。");
                                          return;
                                      }
                                      // 转xml字节数组
                                      byte[] xmlBytes = bpmnJsonToXmlBytes(jsonBytes); 
                                      if(xmlBytes == null){
                                          System.out.println("数据模型不符要求,请至少设计一条主线流程。"); 
                                          return; 
                                      }
                                      // 流程图片字节码 
                                      byte[] pngBytes = repositoryService.getModelEditorSourceExtra(id); 
                                      // 获取模型
                                      Model model = repositoryService.getModel(id); 
                                      // 流程定义xml名称
                                      String processName = model.getName() + ".bpmn20.xml"; 
                                      // 流程定义png名称
                                      String pngName = model.getName() +"." + model.getKey() + ".png"; 
                                      // 流程部署 
                                      Deployment deployment = repositoryService.createDeployment() .name(model.getName()) .addString(processName, new String(xmlBytes, "UTF-8"))
                                          // xml文件 
                                          .addBytes(pngName, pngBytes ) 
                                          // 图片
                                          .deploy(); 
                                      // 更新 部署id 到模型对象(将模型与部署数据绑定) 
                                      model.setDeploymentId(deployment.getId()); 
                                      repositoryService.saveModel(model); 
                                      System.out.println("部署完成"); 
                                  }
                                  

                                  部署流程定义涉及表:

                                  • ACT_RE_PROCDEF 新增数据: 流程定义数据
                                  • ACT_RE_DEPLOYMENT 新增数据: 流程部署数据
                                  • ACT_GE_BYTEARRAY 新增数据:流程定义 xml 和 png 保存下来,对应绑定到此流程定义数据上
                                  • ACT_RE_MODEL 更新部署id

                                    部署流程报错:

                                    1. 报错:元素 ‘sequenceFlow’ 中必须包含属性 ‘targetRef’

                                    解决:流程唯一标识 不能以数字开头,以字母开头

                                    前后端分离Springboot 整合使用activiti7教程(一)(全网最细),第45张

                                    1. 报错:元素’sequenceFlow’ 中必须包含属性’sourceRef’

                                    解决:两个图标箭头连线,箭头来源和目标多拉一点到图标上。

                                    (Ctrl+A全选流程设计图,移动一下哪根连线没动说明这根有问题)

                                    七、流程定义部署管理 Deployment

                                    概要

                                    通过流程定义模型,进行部署流程定义,部署后会生成流程定义数据(相当于java类),此时生成的流程定义数据

                                    主要用于生成流程实例(相当于java对象),一个流程定义 Java 类对应的可以创建无数个 java 流程实例对象。

                                    7.1 通过 .zip 压缩包 部署 流程定义

                                    package com.mengxuegu.workflow.test;
                                    import org.activiti.engine.RepositoryService; 
                                    import org.activiti.engine.repository.DeploymentBuilder; 
                                    import org.junit.jupiter.api.Test;
                                    import org.springframework.beans.factory.annotation.Autowired; 
                                    import org.springframework.boot.test.context.SpringBootTest; 
                                    import java.io.*; 
                                    import java.util.zip.ZipInputStream; 
                                    @SpringBootTest 
                                    public class ActivitiTest03Deployment { 
                                        @Autowired RepositoryService repositoryService;
                                        /*** 通过 .zip 流程压缩包进行部署的流程定义 */ 
                                        @Test public void deployByZip() throws Exception { 
                                            File file = new File("D:/请假流程模型.leaveProcess.zip"); 
                                            String filename = file.getName();
                                            // 压缩包输入流
                                            ZipInputStream zipis = new ZipInputStream(new FileInputStream(file));
                                            // 创建部署实例 
                                            DeploymentBuilder deployment = repositoryService.createDeployment(); 
                                            // 添加zip流 
                                            deployment.addZipInputStream(zipis); 
                                            // 部署名称 
                                            deployment.name(filename.substring(0, filename.indexOf(".")));
                                            // 执行部署流程定义
                                            deployment.deploy(); 
                                            System.out.println("zip压缩包方式部署流程定义完成"); 
                                        }
                                    

                                    部署流程定义涉及表:

                                    ACT_RE_PROCDEF 新增数据: 流程定义数据
                                    ACT_RE_DEPLOYMENT 新增数据: 流程部署数据 
                                    ACT_GE_BYTEARRAY 新增数据:将当前流程图绑定到此流程定义部署数据上 
                                    ACT_RE_MODEL 更新部署id
                                    

                                    7.2 通过 .bpmn 或 .bpmn.xml 文件 部署 流程定义

                                    /**
                                    * 通过 .bpmn 或 .bpmn20.xml 流程文件进行部署的流程定义 
                                    * 缺陷:没有png流程图 
                                    */ 
                                    @Test
                                    public void deployByBpmnFile() throws Exception { 
                                        // .bpmn 文件 
                                        File file = new File("D:/leave.bpmn"); 
                                        // .bpmn20.xml 文件 
                                        //File file = new File("D:/请假流程模型.bpmn20.xml"); 
                                        String filename = file.getName(); 
                                        // 输入流 
                                        FileInputStream input = new FileInputStream(file); 
                                        // 创建部署实例
                                        DeploymentBuilder deployment = repositoryService.createDeployment(); 
                                        // bpmn20.xml 或 .bpmn (activiti5.10版本以上支持) 
                                        deployment.addInputStream(filename, input); 
                                        // 部署名称
                                        //deployment.name(filename.substring(0, filename.indexOf("."))); 
                                        // 执行流程定义部署 
                                        deployment.deploy(); System.out.println("通过 .bpmn 或 .bpmn20.xml 部署完成"); 
                                    }
                                    

                                    7.3 删除流程定义部署信息

                                    /**
                                    * 根据部署ID删除流程定义部署信息:
                                    * ACT_GE_BYTEARRAY、
                                    * ACT_RE_DEPLOYMENT、
                                    * ACT_RU_IDENTITYLINK、 
                                    * ACT_RE_PROCDEF、 
                                    * ACT_RU_EVENT_SUBSCR 
                                    */ 
                                    @Test 
                                    public void delete() {
                                        try {
                                            // 部署ID 
                                            String deploymentId = "9a14702d-c996-11eb-8eef-02466359b284"; 
                                            // 不带级联的删除:如果有正在执行的流程,则删除失败抛出异常;不会删除 ACT_HI_和 历史表数据  
                                            repositoryService.deleteDeployment(deploymentId); 
                                            // 级联删除:不管流程是否启动,都能可以删除;并删除历史表数据。                            
                                            //repositoryService.deleteDeployment(deploymentId, true);
                                            System.out.println("删除流程定义部署信息成功"); 
                                        } catch (Exception e) {
                                            e.printStackTrace(); 
                                            if(e.getMessage().indexOf("a foreign key constraint fails") > 0) {                             System.out.println("有正在执行的流程,不允许删除"); 
                                           }else { 
                                                System.out.println("删除失败,原因:" + e.getMessage());
                                                }
                                        } 
                                    }
                                    

                                    八、流程定义管理 ProcessDefifinition

                                    概要

                                    部署好流程定义后,则可以进行查询、激活(启动)、挂起(暂停)、删除流程定义数据(上面讲的删除流程定义 部署信息就是),下载流程定义对应的 xml文件和 png 文件。

                                    8.1 分页条件查询流程定义

                                    package com.mengxuegu.workflow.test;
                                    import org.activiti.engine.RepositoryService; 
                                    import org.activiti.engine.repository.ProcessDefinition;
                                    import org.activiti.engine.repository.ProcessDefinitionQuery;
                                    import org.junit.jupiter.api.Test; 
                                    import org.springframework.beans.factory.annotation.Autowired; 
                                    import org.springframework.boot.test.context.SpringBootTest;
                                    import java.util.List; 
                                    @SpringBootTest 
                                    public class ActivitiTest04ProcessDefinition {
                                        @Autowired RepositoryService repositoryService;
                                        /**
                                        * 查询部署的流程定义数据 ACT_RE_PROCDEF
                                        * 需求:如果有多个相同流程定义标识key的流程时,只查询其最新版本 
                                        */ 
                                        @Test 
                                        public void getProcessDefinitionList() { 
                                            // 1. 获取 ProcessDefinitionQuery 
                                            ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery(); 
                                            // 条件查询 
                                            query.processDefinitionNameLike("%请假%"); 
                                            // 有多个相同标识key的流程时,只查询其最新版本
                                            query.latestVersion(); 
                                            // 按流程定义key升序排列
                                            query.orderByProcessDefinitionKey()
                                                .asc();
                                            // 当前查询第几页 
                                            int current = 1; 
                                            // 每页显示多少条数据 
                                            int size = 5; 
                                            // 当前页第1条数据下标 
                                            int firstResult = (current-1) * size; 
                                            // 开始分页查询
                                            List definitionList = query.listPage(firstResult, size); 
                                            for (ProcessDefinition pd : definitionList) {
                                                System.out.print("流程部署ID:" + pd.getDeploymentId());
                                                System.out.print(",流程定义ID:" + pd.getId()); 
                                                System.out.print(",流程定义Key:" + pd.getKey()); 
                                                System.out.print(",流程定义名称:" + pd.getName());
                                                System.out.print(",流程定义版本号:" + pd.getVersion());
                                                System.out.println(",状态:" + (pd.isSuspended() ? "挂起(暂停)": "激活(开启)") );
                                            }
                                            // 用于前端显示页面,总记录数
                                            long total = query.count(); 
                                            System.out.println("满足条件的流程定义总记录数:" + total); 
                                        } 
                                    }
                                    

                                    8.2 激活或挂起流程定义

                                    • 流程定义被挂起:此流程定义下的所有流程实例不允许继续往后流转了,就被停止了。

                                    • 流程定义被激活:此流程定义下的所有流程实例允许继续往后流转。

                                    • 为什么会被挂起?

                                      可能当前公司的请假流程发现了一些不合理的地方,然后就把此流程定义挂起。

                                      ​ 流程不合理解决办法:

                                      • **方式一:**可以先挂起流程定义,然后更新流程定义,然后激活流程定义。
                                      • **方式二:**挂起了就不激活了,重新创建一个新的请假流程定义。
                                        /**
                                        * 通过流程定义id,挂起或激活流程定义
                                        */ 
                                        @Test 
                                        public void updateProcessDefinitionState() { 
                                            // 流程定义ID
                                            String definitionId = "leaveProcess:2:b9227310-c8f4-11eb-acbf-aa2e2e85fc05"; 
                                            // 流程定义对象
                                            ProcessDefinition processDefinition =repositoryService.createProcessDefinitionQuery()
                                                .processDefinitionId(definitionId) 
                                                .singleResult();
                                            // 获取当前状态是否为:挂起 
                                            boolean suspended = processDefinition.isSuspended(); 
                                            if (suspended) { 
                                                // 如果状态是:挂起,将状态更新为:激活, 
                                                // 参数1: 流程定义id;参数2:是否级联激活该流程定义下的流程实例;参考3:设置什么时间激活这 个流程定义,如果 null 则立即激活) 
                                                repositoryService.activateProcessDefinitionById(definitionId, true, null);
                                            } else { 
                                                // 如果状态是:激活,将状态更新为:挂起 
                                                // 参数 (流程定义id,是否挂起,激活时间) 
                                                repositoryService.suspendProcessDefinitionById(definitionId, true,null); 
                                            } 
                                        }
                                        

                                        对应 act_re_procdef 表中的 SUSPENSION_STATE_ 字段,1是激活,2是挂起

                                        8.3 下载流程定义的 xml 和 png 文件

                                        下载流程定义的 xml 和 png 文件,方便用户浏览当前流程定义是怎样的。

                                        /**
                                        * 导出下载流程定义想着文件(.bpmn20.xml流程描述或.png图片资源) 
                                        */ 
                                        @Test 
                                        public void exportProcessDefinitionFile() throws Exception{ 
                                            // 流程定义ID 
                                            String definitionId = "leaveProcess:2:b9227310-c8f4-11eb-acbf-aa2e2e85fc05"; 
                                            // 查询流程定义数据
                                            ProcessDefinition processDefinition = repositoryService.getProcessDefinition(definitionId); 
                                            // xml 文件名
                                            //String filename = processDefinition.getResourceName(); 
                                            // png 图片名
                                            String filename = processDefinition.getDiagramResourceName(); 
                                            // 获取对应文件输入流 
                                            InputStream input = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), filename);
                                            // 创建输出流
                                            File file = new File("/Users/mengxuegu/" + filename); 
                                            FileOutputStream output = new FileOutputStream(file); 
                                            // 流拷贝
                                            IOUtils.copy(input, output); 
                                            // 关闭流 
                                            input.close(); 
                                            output.close(); 
                                            System.out.println("流程定义文件导出成功:" + filename);
                                        }
                                        

                                        由于文章字数限制,后续会有继续的更新,请关注订阅专栏~