Activiti7&请假流程开发

day01-Activiti7入门&请假流程开发

目标

  • 能够简单的描述清楚工作流、BPMN、Activiti7专业概念
  • 能够熟悉Activiti7的开发流程的基本步骤
  • 能够动手搭建前后《开发者流程设计器》
  • 能够动手整合SpringBoot与Activiti7
  • 能够熟练使用所学的参数化单元测试
  • 能够自主完成相似流程的开发(入职流程的开发)

工作流项目介绍

行业背景

在众多软件开发的需求中,有一类比较特殊且常见的业务流程,比如在学习中奖学金申请、在公司中向领导请假审批,它们需要有人发起申请,然后有人审批,因此常被称为审批业务流程。例如:下图中养老人员申请入住养老院的业务流程:养老人员发起入住申请后,需要主管、副院长、院长等多人审批人,每个审批人还可以进行同意、拒绝、驳回等操作,不同的操作对应不同的程序流向,因此整个业务流程显得比较复杂,而这样的业务流程如果使用传统的硬编码方式来实现,代码实现逻辑比较复杂,且很难维护。因此就需要更好的方式来开发类似的审批业务流程,而工作流技术就是这样一种技术。

image-20231008104335374

工作流技术作为信息技术领域一项重要技术。在企业数字化转型中可以帮助企业提高效率、降低成本,同时改善客户体验;在企业产品中可以预定规则,从而提供企业产品的正确性和效率,进而提升产品优势;在企业内部协作和沟通中,还可以帮助团队成员传递任务、通知和信息,确保沟通畅通,任务不会被遗漏。总体来说,工作流技术在各个企业或者行业中都是一项重要的技术,能够有效的帮助企业自动化业务、提高效率、降低成本,以及快速的适应市场的变化。

工作流技术应用场景

工作流技术从198X年被提出发展至今,以及渗透发展到各行各业,比如企业服务、电商、制造业等,但是目前应用最广的还是企业服务行业,其OA、ERP、CRM等产品基本都包含工作流技术的应用,而OA(企业办公室自动化软件)相关的产品几乎是必用工作流技术,比如下图就是一个OA系统:

image-20240801165800572

别看OA系统界面上的功能菜单比较少,但是其可以新建的处理流程确是非常多,甚至还可以无限增加,而且每个流程的逻辑都不一样,这都需要工作流技术来处理,因此OA系统是看起来简约,做起来很复杂的一类系统。

image-20231008110744874

工作流技术前景

  • 企业服务行业是工作流技术的发源地
  • 工作流在各行各业中都有应用

image-20230815102253070

市场规模及预测

  • 2023年工作流技术的市场规模达到70亿元左右,同比增长25%。

  • 预计2023-2032年工作流将迎来快速增长,到2032年市场规模达千亿。

image-20230815100337844

课程背景

正是基于工作流技术的广泛应用和未来市场发展趋势的需要,研发了本《工作流组件》课程及项目,填补市场空白的技术课程,来帮助学员提升就业优势。

工作流组件既是课程也是传智自主研发的一个成熟且轻量级的开源项目(开源名:Hiss)。无论是单体架构还是微服务架构都适用。该组件旨在简化业务流程的设计、实施和管理,进而降低企业在工作流领域的使用和开发成本。该组件基于 Actviti 7 引擎进行二次开发,对 Actviti 7 在流程设计器、表单设计器等方面的缺陷进行了改进,并在底层通信、事件机制等方面进行了优化。这使得 Activiti 7 更加适用于微服务集成,符合微服务标准。

本着“让学员带着真本事到企业,能帮助企业解决问题”的目的,工作流组件课提供全面【流程引擎+低代码】的整合方案、及相关的工具。旨在让学员学完本课程不光有知识储备(主流的解决方案),还有高效的工具(Hiss开源项目),真正做到走进企业时是有本事的、有竞争力的!

业务架构

工作流组件可最终交付的内容分为一个组件库,两个系统端:

  • 组件库:提供了流程设计、低代码表单设计等相关的组件,可嵌入hiss-server、hiss-client两个系统中提高UI组件复用性
    • design-ui:提供了开发者、业务员可使用的流程设计器、状态图、办理页等功能UI
    • form-ui:提供业务员可使用的表单设计器、数据管理页等功能UI
  • 流程中心(hiss-center):主要集中管理多租户的流程、实例、表单等数据
  • 业务系统(hiss-client):泛指与流程中心进入的系统,在这些系统中可以直接嵌入流程办理、数据管理等相关的功能

image-20230815114501855

功能大纲

  • 流程中心的功能包括应用管理、用户管理、流程管理、实例管理、表单管理、快速集成等功能,这些功能中除了应用管理、用户管理之外的功能都可以集成到业务系统中
  • 在流程管理中办理页面还提供了前加签、后加签、跳转等22个办理功能

image-20230815141313271

技术架构

下图展现了本课程主要使用的技术:

image-20230815153009984

系统预演

下图展现了本项目的一些亮点功能演示:

image-20230815153009984

项目环境搭建

为便于后续的知识学习,再此我们先安装一下开发环境,本项目的开发环境部署到了CentOS7系统。

为了大家快速、方便的统一开发环境,我们在资料中提供了一套系统镜像,大家使用VMware软件来挂载即可快速启动。

在当前linux系统中包含的开发环境有:

  • Mysql:开发环境的数据库
  • Redis:开发环境的redis
  • Docker:开发环境的部署工具
  • Gogs:代码管理
  • nginx :代理服务

虚拟机说明

挂载虚拟机

找到资料中的虚拟机镜像文件夹,双击hiss.vmx即可挂载到你的虚拟机中(需提前安装虚拟机)

通过百度网盘分享的文件:工作流组件课-win虚拟机.zip
链接:https://pan.baidu.com/s/1IBZSPa67syX86oDI8vZsKQ?pwd=tmb0
提取码:tmb0
–来自百度网盘超级会员V5的分享

image-20230818095754807

设置虚拟网络

因为此虚拟机已设置静态的ip地址,目前网段就是192.168.126.0,所以为了减少环境网络的配置,可以手动设置虚拟机中NAT网卡的网段

设置步骤:

①:找到虚拟机的编辑按钮,打开虚拟网络编辑器

②:选中NAT模式的网卡,在下面的子网IP的输入框中手动设置为:192.168.126.0,确定保存即可

image-20230818100915287

③:右键虚拟机–>设置–>网络适配器–>自定义:选择NAT网卡连接模式

image-20230818101841305

④:启动服务器(网络设置完成后再启动服务器)

FinalShell客户端链接

此虚拟机的静态ip为:192.168.126.128,防火墙已关闭,可以直接使用客户端链接

以FinalSehll工具为例:

image-20230818102808038

注意:此虚拟机的用户名:root,密码:itcast

内置环境说明

在虚拟机中/root目录中内置了两套环境:

image-20230818140916993

  • data是数据库、代码仓库等重要数据,千万勿删!!

  • demo是整体项目演示的环境,方便大家快速启动查看项目效果,可选择删除。

  • dev是开环境的环境,本课程学习过程需要用到的环境,,千万勿删!!

配置本地hosts文件

在提供的服务器中,已经安装好了多个软件,为了让大家更方便的访问,在服务器内部已经配置了虚拟的服务器,并且指定了ip和端口,需要大家在本机中配置host文件,就可以在本地使用域名进行访问

操作步骤:

1,打开本地文件夹:C:\Windows\System32\drivers\etc

2,添加以下配置到hosts文件中,并且保存

1
2
3
4
5
6
7
8
# 【需启动dev环境】gogs代码托管访问地址
192.168.126.128 git.hiss.com
# 【需启动dev环境】开环境用到的流程设计器前端访问地址
192.168.126.128 dev.hiss.com
# 【需启动dev环境】开环境用到的流程中心前端访问地址
192.168.126.128 center.hiss.com
# 【需启动dev环境】开环境用到的智慧养老前端访问地址
192.168.126.128 zhyl.hiss.com

demo环境运行

环境信息

demo环境部署了最终项目的代码,以便于大家快速启动,预览到项目的效果。环境的部署信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
├── /root/demo                              
│ ├── ccenter.sh // 快速清理流程中心镜像的脚本
│ ├── czhyl.sh // 快速清理流程中心客户端镜像的脚本
│ ├── docker-compose-env.yml // 整个环境的编排文件
│ ├── DockerfileCenter // 流程中心镜像构建脚本
│ ├── DockerfileZhyl // 流程中心客户端镜像构建脚本
│ ├── easy-zhyl-web.jar // 流程中心客户端程序
│ ├── hiss-server-spring-boot-starter-1.0-SNAPSHOT.jar // 流程中心程序
│ ├── nginx // nginx资源
│ │ ├── hiss-center // 流程中心前端代码
│ │ ├── project-zhyl-admin-vue3-java // 流程中心客户端前端代码
│ │ ├── ppt // 流程中心演示代码
│ ├── start.sh // 一键启动脚本
│ ├── template // 【勿删】脚手架文件

启动&访问

在linux控制台中进入/root/demo目录,并直接运行sh start.sh,即可启动demo环境,启动后可以访问一下地址,进行系统功能查看:

dev环境运行

环境信息

dev环境部署了,开发或学习过程中用到的mysql8、redis、gogs等相关软件,是我们主要的学习环境,千万勿删。环境的部署信息如下:

1
2
3
4
5
6
7
├── /root/dev                              
│ ├── start.sh // 一键启动脚本
│ ├── docker-compose-dev.yml // 整个环境的编排文件
│ ├── nginx // nginx资源
│ │ ├── hiss-designer-ui // 流程设计器组件前端代码
│ │ ├── hiss-center-ui // 流程中心前端代码
│ │ ├── project-zhyl-admin-vue3-java // 智慧养老前端代码

启动&访问

在linux控制台中进入/root/dev,并直接运行sh start.sh,即可启动demo环境,启动后可以访问一下地址,进行系统功能查看:

Gogs使用说明

gogs是一款极易搭建的自助 Git 服务,Go 语言开发。

项目代码使用gogs来管理,主要原因是gogs系统所需要系统资源较小,功能相对完整。

环境地址及注册登录

在dev环境中已经内置了gogs项目,启动dev环境后,可以按照一下地址或步骤操作。

域名访问:http://git.hiss.com

默认账号:hiss 密码:hiss

注册登录账号,大家可以使用默认账号登录,也可以自己注册账号登录

image-20230818111335465

创建仓库

登录成功以后,可以点击”+”号,新建仓库

image-20230818111549948

使用图中的git地址拉取该仓库即可,后期可pull 、push代码

image-20230818112214159

创建组织

登录成功以后,可以点击”+”号,创建新的组织

image-20230818114506183

创建成功以后

image-20230818135446785

  • 可以在组织下去创建新的仓库
  • 可以邀请gogs中的其他用户加入该组织,该组织内的成员可以共享组织的仓库
  • 创建组织的人,默认为组织的管理员,可以对组织进行管理

导入后端代码

我们搭建完成了所需要的开发环境之后,下面就是正式开始代码部分的熟悉,为什么说熟悉呢?

是因为我们目前开发的项目是一个轻量级的1-2的项目,在提供的项目源码中已经开发了部分功能,我们一般到企业中去开发,95%以上的项目都是1-2的项目类型,所以,大家在开发之前,需要先熟悉已有代码。主要可以需要知道,项目中主要使用到了什么技术,以及代码的规范风格等等内容

环境准备

环境要求,一般项目组中有专门的文档进行说明,如果没有文档,可以找老手程序员做进一步的了解。

  1. 环境要求:

    • jdk11
    • maven 3.6.x 以上
    • mysql8
    • git
  2. maven仓库

    在资料中找到 ’responsitoy_hiss’ 文件夹

    image-20230820173839578

    把当前文件夹设置为maven的默认本地仓库,并在idea开发工具中设置

    注意:如果不使用资料中的本地仓库,也可以自行下载项目中所需要的依赖

    到了公司以后,可以咨询同事拷贝本地仓库,如果公司有maven的私服,也可以找同事要一份maven的settings文件,里面就包含了所有的配置,就包含了私服的地址和账户

  3. 代码拉取

    大家在gogs中使用hiss账户登录,找到hiss仓库,初始代码在dev/sprint01分支,然后使用下面git命令拉取代码:

    1
    2
    3
    4
    5
    6
    7
    // 拉取master分支代码
    git clone http://git.hiss.com/hiss/hiss.git

    cd hiss

    // 拉取dev/sprint0分支代码
    git checkout dev/sprint01

    注意:导入到idea后,需要检查jdk版本、maven路径是否正确。

    image-20230818161435145

代码结构

由于项目采用了命令模式来架构设计实现,并要支持HTTP、TCP等多种协议通信,因此整个工程的项目结构不同于之前的项目,再此先了解一下整体的结构,后续学习中再了解模块的具体结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
├── hiss-center                              
│ ├── hiss-api-appearance // ====================== cmd命令包装实现类
│ │ ├── hiss-api-apperance-client // 客户端cmd包装实现
│ │ ├── hiss-api-apperance-server // 服务端cmd包装实现
│ ├── hiss-api-web // ====================== 客户端后端模块化集成的快速实现代码
│ │ ├── hiss-api-web-oa // OA模块化功能实现代码
│ ├── hiss-core-common // ====================== 核心共用的代码
│ │ ├── hiss-core-common-cmd // cmd命令的责任链实现
│ │ ├── hiss-core-message-sender // 发送cmd命令的发送器责任链实现
│ │ ├── hiss-core-model // 通用实体类
│ ├── hiss-core-components // ====================== 核心组件的实现代码
│ │ ├── hiss-core-activiti // 流程相关核心实现代码
│ │ ├── hiss-core-form // 表单相关核心实现代码
│ ├── hiss-core-starter // ====================== 快速集成starter
│ │ ├── hiss-message-http-receiver-spring-boot-starter // http协议cmd请求接收实现
│ │ ├── hiss-message-http-sender-spring-boot-starter // http协议cmd请求发送实现
│ │ ├── hiss-message-tcp-client-spring-boot-starter // 基于tcp协议通信的客户端实现
│ │ ├── hiss-message-tcp-server-spring-boot-starter // 基于tcp协议通信的服务端实现
│ │ ├── hiss-server-spring-boot-starter // 基于tcp协议通信的服务端实现
│ ├── hiss-test // ====================== 测试父工程

启动项目

虽然项目代码非常多,但是能启动的项目只有hiss-server-spring-boot-starter,在其下面找到application.yml文件,适当修改相关配置,然后启动HissServerApplication类,即可启动项目

已实现的功能

以下展示了导入的代码已经完成的功能,大家可以结合下面的功能实现图,来找到对应的代码进行熟悉开发方式,整个项目执行过程。

注意:启动dev环境后,访问http://center.hiss.com即可浏览以下页面

  • 应用管理

  • 用户管理

  • 流程分类+列表

  • 登录

    目前已实现,流程中心没有复杂的权限机制,因此登录实现比较简单

  • 其他

    • 若依集成
    • 养老集成
  • 后端

    • Activiti的改造
    • TCP通信服务端
    • TCP通信客户端

运行前端环境

快速运行

为专注后端Activiti技术的学习,本项目前端将直接使用打包好的资料,并已经在192.168.126.128机器中部署,启动dev环境后,可访问以下地址

流程设计器:主要来画流程图、办理流程,是本项目的核心,也是本课程主要用到的前端界面。

流程中心:综合了所有的功能,并且流程设计器最终也会集成到流程中心。

智慧养老:流程中心设计的流程,最终都在业务系统中进行办理。

源码运行

项目用到的前端源码,同时也作为开源组件发布到了gitee ,对前端感兴趣的同学也可以自行下载学习。具体的运行方式详情开源项目下的说明文档。

《单人审批请假流程》开发

到此,我们已经准备好了课程要使用到的环境,接下我们就先通过一个简单的《单人审批请假流程》来快速入门Activiti,通过案例来重点掌握:

  • Activiti相关术语概念
  • Activiti的开发步骤
  • Activiti相关表结构

单人审批请假流程:

image-20230819113436637

首选看一下Activiti相关术语概念:

基本概念

Activiti是一款主流的工作流 流程引擎,再此我们就先从工作流、流程引擎概念说起。

什么是工作流

工作流( Workflow ):是一项将系统任务或操作抽取,再按照预定业务流程进行组织、协调、并自动化执行的技术。

我们也可以简单理解==工作流是一种简化审批业务流程开发的技术==,其主要是解决一些业务场景硬编码方式的成本高、效率低、变更慢等问题的技术。

复杂的业务流程,实现复杂度比较高,因此开发周期长,开发成本高,效率也低,如果发生需求变更,对之前复杂的代码进行修改,同样需要更长的时间,因此响应变更的速度呢也表现得慢。

image-20230819122330430

工作流技术来实现类似复杂的业务,只需要集成流程引擎、画出流程中使用的表单、最后画出整个业务流程图,交给流程引擎3步,即可完成需求的开发。在整个实现过程中,流程引擎是一个三方框架,不需要我们过多编码,而画表单、画流程就是在页面中进行一些拖拉拽的操作。因此整个过程下来我们编码量极少,需要的开发时间也极少,通过此方式呢就轻松的解决了开发周期长、成本高、效率低的问题,如果需求变更了,工作流技术只需要修复之前的表单或图即可,因此变更响应速度自然也必硬编码开发的速度要快。

image-20230819122620945

什么是流程引擎

流程引擎:是用于驱动或控制业务流程每一步自动执行的代码框架。

目前市面上主流的流程引擎框架有jBPMN、Activiti、Flowable、Camunda4款,其中Activiti开源度最大,因此是当下主流的首选流程引擎。

本课程则选择Activiti7作为我们的学习流程引擎,主要因素有:

  • Activiti开源度大,企业使用多
  • Activiti成熟度好,文档资料完善
  • 学习完成Activiti之后,可以快速上手Flowable、Camunda等基于Activitii二次开源的框架

image-20240801174522258

Activiti介绍

Activiti:是一个开源的轻量级工作流和业务流程管理与执行的引擎。2010年基于jBPM4实现首次开源,旨在帮助企业自动化和优化各种业务流程。

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

Activiti 的主要特点和优势:

  • 开源和跨平台:Activiti 是一个开源项目,可以在各种操作系统和平台上运行,提供灵活的部署选项。

  • 高度可定制:Activiti 提供了可视化的流程设计器,使用户能够轻松设计和定制各种业务流程。流程定义可以基于 BPMN 2.0 标准进行创建。

  • 强大的任务管理:Activiti 允许用户定义任务、分配任务给不同的用户或组,并支持任务的优先级和截止日期。

  • 工作流引擎:Activiti 提供了强大的工作流引擎,能够自动执行流程、处理任务、执行规则等。它支持顺序流、条件流、并行网关等流程控制元素。

  • 事件驱动:Activiti 支持事件驱动的流程,可以在特定的事件发生时触发流程的不同分支。

  • 可扩展性:Activiti 允许开发人员通过编写自定义 Java 类来扩展其功能,满足特定的业务需求。

  • 数据持久化:Activiti 使用关系型数据库来存储流程定义、流程实例、任务等信息,保证了数据的持久性和可靠性。

  • 集成支持:Activiti 可以与其他技术和系统集成,如 Spring、RESTful Web Services、JavaEE 等。

  • 监控和报告:Activiti 提供了流程实例的监控、报告和分析功能,使用户能够了解流程的状态和性能。

尽管Activiti很强大,其还是有一些劣势需要完善:

  • 提供的设计器只能开发者使用,而且体验不是很好
  • 不支持直接面向业务人员使用
  • 不支持表单
  • 不支持国产功能,比如会签、跳转等功能
  • 不支持流程状态图
  • 与SpringClound微服务集成方式不优雅
  • 使用门槛、成本比较高

image-20230819130820243

那么针对这些劣势的解决,本课程开源的hiss项目,都可以解决。课程最终除了让大家掌握Activiti技术,也会把hiss项目交给大家。让大家带着知识和工具到企业中帮助企业解决这些问题,成为企业需要的人才,进而提升同学们自身的就业竞争力!

需求说明

有了刚才的知识,接下来我们就开始分析《单人审批请假流程》的需求以及使用Activiti对其进行开发的步骤。

需求分析

在企业中,员工如果有事需要请假,一般都需要向上级请假,得到批准后,方可离开公司。而整个过程在企业中需要在系统中完成,以信息化员工的出勤信息,便于工资、奖金的结算,因此需要开发此功能,需求如下:

  • 员工:请假的员工需要先填写请假单,填写的字段有:请假人、请假天数、开始请假时间、请假事由;
  • 经理:审批员工的请假单,如果不同意,则需要说明不同意的理由;

image-20230819113436637

实现步骤

在这里我们主要是来了解一下基于Activiti如何来实现上述需求,其主要的实现步骤是什么?

在前面我们有提到工作流只需要下面3步即可,在此需求中虽然用到了表单,但在此需求实现过程中,我们先不学画表单,这步放到后面一点去学习。

image-20230819140812914

因此这个需求只需要集成流程引擎、画流程两步实现即可,但是之前我们有介绍到Activiti目前也有些功能还需要完善,在这个流程中我们要用到的一些功能它不支持:

  • 画好的流程图不支持直接保存,需要用代码来保存
  • 画好的流程图直接运行,需要用代码来发布执行
  • 不支持同意、不同意国产功能,需要自己设计开发

==那么此需求用Activiti的实现步骤呢,就变成以下5步:==

  • 1、集成流程引擎
  • 2、画流程
  • 3、保存流程图
  • 4、部署和运行流程图
  • 5、开发同意和不同意审批功能

在此我们学习呢也将按照上面5步,逐步展开对Activiti的知识学习。最后要补充说明一下,上述5步,在Hiss项目中,只需要前两步即可,后3步已经封装好了,因此和我们开始说的步骤是一致的。至于怎么样封装的,在稍后课程中会教给大家。

第一步:SpringBoot集成Activiti7

SpringBoot官方未提供直接的starter与Activiti集成,但是Activiti官网有帮我们提供,因此集成的过程也还是比较简单,按照下面4步即可完成。

PS:1、导依赖—>2、配置属性—>3、配置Bean—>4、启动测试。这4步是SpringBoot与任何框架集成的标准步骤,同学们可以牢记。

导入依赖

在hiss-test模块下创建demo-activiti工程,用于Activiti7与SpringBoot整合的测试与学习。

导入父POM

Activiti提供了自己POM,以简化我们使用activiti的依赖。在此我们选择了7.10.0版本,在hiss-center根下的pom.xml文件中导入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<properties>
<activiti.version>7.10.0</activiti.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-dependencies</artifactId>
<version>${activiti.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
设定Activiti仓库地址

Activiti有些jar包,未上传到中央仓库,因此使用的时候需要添加Activiti的仓库,这里推荐直接在hiss-center的pom.xml文件中添加,避免对其它项目影响:

1
2
3
4
5
6
<repositories>
<repository>
<id>activiti-releases</id>
<url>https://artifacts.alfresco.com/nexus/content/repositories/activiti-releases</url>
</repository>
</repositories>
导入Activiti依赖

有了前面2不小步,在要使用的Activiti的模块中直接导入下面starter即可导入Activiti的依赖。在这里我们在test模块下,建立一个demo-activiti的工程,然后引入下面的依赖。

1
2
3
4
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
</dependency>

另外Activiti需要使用到数据库,它支持Mysq、Oracle、Postgres等多种数据库,本课程选用常见的Mysql,因此还需要导入数据库驱动和Mybatis-Plus ORM依赖。

1
2
3
4
5
6
7
8
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

配置属性

配置属性就是指在application.yml或者bootstrap.yml文件中配置引入框架的常用属性,而在这里Activiti7的常用配置属性如下:

1
2
3
4
5
spring:
activiti:
database-schema-update: true #自动创建数据库
db-history-used: true # 开启流程历史记录
history-level: full # 历史流程数据全部记录到历史表中,支持none、activity、audit、full,4种粒度的数据,常用的就是full

配置数据源:

注意:url中的nullCatalogMeansCurrent参数需要设置成true,表示Activiti优先在url中指定的数据库中检查是否有创建过表,如果为false,则会遍历整个数据源中的每个数据库,检查是否有创建过activiti的表。

1
2
3
4
5
6
spring:
datasource:
password: 87sdhf298TYUUIz2!
username: root
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.126.128:3306/hiss-dev-demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&nullCatalogMeansCurrent=true

并新创建一个数据库:hiss-dev-demo

image-20230819163024408

配置Bean

在Activiti7中,它默认集成了SpringSecurity,内部还使用到了SpringSecurity系列的上下文代码,不能直接排除掉,因此在此还需要给定一些SpringSecurity的初始配置Bean。

image-20230819162416535

其实往往我们不想使用SpringSecurity,这里就强制我们使用,显得非常臃肿、不优雅。那么在本项目中,将合理避开对SpringSecurity的使用,因此直接把SpringSecurity相关配置置空即可,既把下面的Bean拷贝到启动类中,什么都不用改:

  • UserGroupManager:用于流程中获取用户的组、角色等信息
  • SecurityManager:用于获取当前操作授权的用户、组或角色等信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@Bean
public UserGroupManager userGroupManager() {
return new UserGroupManager() {
@Override
public List<String> getUserGroups(String s) {
return null;
}

@Override
public List<String> getUserRoles(String s) {
return null;
}

@Override
public List<String> getGroups() {
return null;
}

@Override
public List<String> getUsers() {
return null;
}
};
}

@Bean
public SecurityManager securityManager() {
return new SecurityManager() {
@Override
public String getAuthenticatedUserId() {
return "miukoo-user-1";
}

@Override
public List<String> getAuthenticatedUserGroups() throws SecurityException {
return null;
}

@Override
public List<String> getAuthenticatedUserRoles() throws SecurityException {
return null;
}
};
}

注意在这里可能会报错:

image-20240802170224872

解决方法:

1.删除

2.增加启动配置以我们的bean为主

image-20240802170643153

启动测试

到此,我们就完成了集成的主要工作,接下来就是先验证一下集成结果。针对Activiti7的集成验证,只需要启动服务,看看是否报错,是否创建成功表,如果控制台没有报错,并且数据库中也成功创建了表,那么就算集成成功了!

控制台:未报错,并且有输出创建表的日志

image-20230819164618161

数据库:成功的创建了相关25张表,这些表我们稍后去给大家介绍,这里只关注是否创建成功。

image-20230819164843010

第二步:画流程

项目集成完成Activiti7之后,就可以进行第二步,画流程了,在正式画之前,有必要给大家先介绍一下这里画涉及到的知识点BPMN。

BPMN介绍

BPMN:业务流程建模与标记语言(Business Process Model and Notation),是一种用于图形化表示和描述业务流程的标准化标记语言。目前主流的版本是BPMN2.0,由 Object Management Group(OMG)制定,并于2011年发布,发展至今,已被主流的流程引擎支持,并作为默认。

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

讲白了,BPMN和HTML类似都是标记语言,都是通过XML的格式来组织数据,供后端解析,也可转成图形化方式直观展示给用户看。

例:BPMN标准的流程文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bioc="http://bpmn.io/schema/bpmn/biocolor/1.0" xmlns:tns="http://www.activiti.org/testm1685269119653" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="hiss_flow_1695088765609" name="" targetNamespace="http://www.activiti.org/testm1685269119653">
<process id="hiss_process_12_1695088765717" name="hiss_process" isExecutable="true">
<startEvent id="StartEvent_1" />
<userTask id="Activity_1xi315o">
<incoming>Flow_109kst5</incoming>
</userTask>
<sequenceFlow id="Flow_109kst5" sourceRef="StartEvent_1" targetRef="Activity_1xi315o" />
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="hiss_process_12_1695088765717">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="173" y="102" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1xi315o_di" bpmnElement="Activity_1xi315o">
<dc:Bounds x="330" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_109kst5_di" bpmnElement="Flow_109kst5" bioc:stroke="#060606" bioc:fill="none">
<di:waypoint x="209" y="120" />
<di:waypoint x="330" y="120" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>

转成直观的图:

image-20230819170453556

BPMN设计器

虽然BPMN是一个标记语言,但是在实际中,我们很少直接去用它语法进行开发,而是直接使用流程设计器来画,而画用前端技术即可实现,在前端开源项目中有一个叫bpmn-js的开源项目,现在几乎成了画流程的标准,市面上的流程设计器基本都是基于它改造的。比如Activiti7官网提供的:https://github.com/activiti/activiti-modeling-app设计器,就是基于bpmn-js实现的。

img

但是因为其是英文版,使用习惯是按照西方人设计的,在使用体验上不好,因此在这里我们使用hiss产品中自研的设计器,也是基于bpmn-js实现的。它的面板介绍如下:

image-20230819173006479

绘制《单人审批请假流程》

在BPMN2.0中定义了很多图例,也就是主键面板上的那些图标,每种图例表示着不同的含义,那么在本案例中,我们需要用到以下3种图例:

  • 开始图例:表示一个流程的开始,一个流程可以有多个开始,但是至少需要一个开始图例
  • 结束图例:表示一个流程的结束,一个流程可以有多个结束,但是至少需要一个结束图例
  • 用户图例:也称用户任务,表示当前节点是需要人工参与的,比如需要人工审批、人工填写表单等

image-20230819174539575

有了上面的了解,那么就可以开始绘制:开始节点和填写请假单节点:

(画的方式一:拖拉画)拖拉组件面板中的图例,到画图区中,并配置办理人和连线即可。

图中表示请假单由张三填写。

image-20230819174133639

接着画经理审批和结束节点:

(画的方式二:快捷插入画)选中节点后,会在节点上弹出快捷操作,点击结束图例,即可快速在节点后面增加一个结束节点并自动连线。

图中经理审批节点的办理人为李四,表示张三填写的请假单由李四来审批。

image-20230819175745551

解读BPMN的xml文件

通过上面的操作我们就画出了《单人审批请假流程》,接下来我们来了解一下BPMN2.0的xml文件内容,做一个大概了解。

点击右上角的【设计模式】即可切换到【源码模式】,看见类似下图的界面。界面中就是BPMN2.0的xml内容,可见包括的内容如下:

  • 整个xml的根元素是definitions,它有两个子元素:
    - 流程节点信息使用process元素定义
    - 每种图例对应到xml中都是不同的元素,比如:
    - 开始图例对应startEvent元素
    - 结束图例对应endEvent元素
    - 用户任务对应userTask元素
    - 流程图中的线也是一种图例,对应sequenceFlow元素
    - 每种图例元素都一个唯一id属性
    - 在图中配置的办理人,其实是userTask元素的 activiti:assignee属性值

    • 流程展示的图形信息使用bpmndi:BPMNDiagram元素定义

image-20230819181018807

第三步:保存流程图

到此画完的流程图,还需要保存到磁盘或者数据库中,不然刷新网页就丢失了。而Activiti7在数据库层面给我们已经设计好了相关的表和API,直接调用即可。

保存到磁盘

在磁盘任意位置,新建一个bpmn-01.xml文件,并把上一步画的流程图的xml保存到改文件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bioc="http://bpmn.io/schema/bpmn/biocolor/1.0" xmlns:tns="http://www.activiti.org/testm1685269119653" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="hiss_flow_1692440641378" name="" targetNamespace="http://www.activiti.org/testm1685269119653">
<process id="hiss_process_12_1692440641431" name="hiss_process" isExecutable="true">
<startEvent id="StartEvent_1" />
<userTask id="Activity_1xi315o" name="填写请假单" activiti:assignee="张三">
<incoming>Flow_109kst5</incoming>
<outgoing>Flow_0wd9dr1</outgoing>
</userTask>
<sequenceFlow id="Flow_109kst5" sourceRef="StartEvent_1" targetRef="Activity_1xi315o" />
<userTask id="Activity_0xmqcac" name="经理审批" activiti:assignee="李四">
<incoming>Flow_0wd9dr1</incoming>
<outgoing>Flow_1s2a4e5</outgoing>
</userTask>
<sequenceFlow id="Flow_0wd9dr1" sourceRef="Activity_1xi315o" targetRef="Activity_0xmqcac" />
<endEvent id="Event_1qwztvn">
<incoming>Flow_1s2a4e5</incoming>
</endEvent>
<sequenceFlow id="Flow_1s2a4e5" sourceRef="Activity_0xmqcac" targetRef="Event_1qwztvn" />
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="hiss_process_12_1692440641431">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="173" y="102" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1xi315o_di" bpmnElement="Activity_1xi315o">
<dc:Bounds x="330" y="80" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0xmqcac_di" bpmnElement="Activity_0xmqcac">
<dc:Bounds x="560" y="80" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1qwztvn_di" bpmnElement="Event_1qwztvn">
<dc:Bounds x="792" y="102" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_109kst5_di" bpmnElement="Flow_109kst5" bioc:stroke="#060606" bioc:fill="none">
<di:waypoint x="209" y="120" />
<di:waypoint x="330" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0wd9dr1_di" bpmnElement="Flow_0wd9dr1" bioc:stroke="#060606" bioc:fill="none">
<di:waypoint x="430" y="120" />
<di:waypoint x="560" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1s2a4e5_di" bpmnElement="Flow_1s2a4e5" bioc:stroke="#060606" bioc:fill="none">
<di:waypoint x="660" y="120" />
<di:waypoint x="792" y="120" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>

保存到数据库

创建测试类

在demo-activiti模块的test代码中新建ProcessSaveTest类,注意包名需要和启动类包名一致。

image-20230820091511697

在新建的类中初始化下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.itcast.hiss;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ProcessSaveTest {

/**
* 流程保存测试
*/
@ParameterizedTest
@ValueSource(strings = {"C:\\Users\\lenovo\\Desktop\\bpmn-01.xml"})
public void testSaveFromFile(String file){

}

}

项目环境中自动导入了springboot的test依赖,所集成junit版本是5.8.2,支持一种参数化的测试(Parameterized Tests,简单理解就是测试的方法可以动态传参),这在企业中也是非常常用的一种写法,上述的代码就是参数化测试代码的一段实现:

  • @ParameterizedTest 注解标注testSaveFromFile方法是一个参数化测试方法
  • @ValueSource 注解标注要传给testSaveFromFile方法的参数值有那些,参数值的类型支持基本类型+String、Class

@ParameterizedTest不仅有标注的功能,还会依据@ValueSource的值的数量,动态为每个参数值生成一个测试案例:

例如:

1
2
3
4
5
@ParameterizedTest
@ValueSource(strings = {"1","2","3"})
public void test(String num){
System.out.println(num);
}

传入了3个值,则生成了3个案例,在企业中常常用来测试一段代码在多种输入值的情况下执行结果是否正确:

image-20230820092724945

代码实现&运行

在Activiti7中对于设计好的流程图,被称为模型(Model),保存代码实现参考以下,相关说明如下:

  • RepositoryService是非常常用的API,主要用来管理(CRUD)和操作模型、发布、流程定义等资源;
  • Model是一个接口不能直接new,其对应实现类是ModelEntityImpl,而repositoryService.newModel()方法正是返回一个新的ModelEntityImpl实例;
  • 保存时,除了xml内容之外,还可以附加一些名称、分类等信息;
  • 在Activiti7底层表设计原则是:所有大字段值都保存到一张表中,而Model的xml内容属于大字段,因此下面代码分别调用了saveModel(保存基本信息)和addModelEditorSource(保存大字段信息)方法;
  • assertNotNull是junit的断言方法,主要用来判断方法执行的结果是否符合预期,在这里预期是:插入成功则model的id应该不为null
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.itcast.hiss;

import cn.hutool.core.io.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@Slf4j
public class ProcessSaveTest {

@Autowired
RepositoryService repositoryService;

/**
* 流程保存测试
*/
@ParameterizedTest
@ValueSource(strings = {"C:\\Users\\lenovo\\Desktop\\bpmn-01.xml"})
public void testSaveFromFile(String file){
String xml = FileUtil.readUtf8String(file);
Model model = repositoryService.newModel();
model.setName("单人审批请假流程"); // 设置名称
model.setCategory("学习"); // 设置分类
repositoryService.saveModel(model);// 保存基本信息
repositoryService.addModelEditorSource(model.getId(),xml.getBytes());// 保存xml信息
assertNotNull(model.getId()); // 断言插入成功
log.info("new model id : {}", model.getId());
}

}

运行上述测试方法,出现下面情况,既模型数据就保存成功

image-20230820094524600

表分析

在上述保存方法执行成功后,数据实际上保存到了数据库中的act_re_model和act_ge_bytearray表中。

act_re_model

act_re_model表是用于存储流程模型(就是流程图)信息的表:

image-20230820101031997

序号 字段名 类型 长度 是否主键 注释
1 ID_ varchar 64 主键
2 REV_ int 10 数据更新乐观锁
3 NAME_ varchar 255 名称
4 KEY_ varchar 255 自定义业务主键
5 CATEGORY_ varchar 255 分类
6 CREATE_TIME_ timestamp 创建时间
7 LAST_UPDATE_TIME_ timestamp 更新时间
8 VERSION_ int 10 模型版本
9 META_INFO_ varchar 4000 附加信息
10 DEPLOYMENT_ID_ varchar 64 部署ID
11 EDITOR_SOURCE_VALUE_ID_ varchar 64 xml文件管理存储的数据ID
关联act_ge_bytearray中的ID
12 EDITOR_SOURCE_EXTRA_VALUE_ID_ varchar 64 附加信息存储的数据ID
关联act_ge_bytearray中的ID
13 TENANT_ID_ varchar 255 租户ID
act_ge_bytearray

在Activiti7底层大字段的存储原则是都存储到act_ge_bytearray表的BYTES_字段中。

image-20230820101212056

序号 字段名 类型 长度 是否主键 注释
1 ID_ varchar 64 主键
2 REV_ int 10 数据更新乐观锁
3 NAME_ varchar 255 名称
4 DEPLOYMENT_ID_ varchar 64 部署ID
5 BYTES_ longblob 4294967295 大字段内容
6 GENERATED_ tinyint 3 标识是否自动生成的记录

第四步:部署和运行流程图

在之前我们使用SpringBoot开发完一个web程序打成jar,然后需要把这个jar拷贝到测试或者生产环境,既部署,最后就可在不同机器上运行多个进程实例,如下图蓝色部分。而在Activiti中操作流程图的过程与其过程类似,需要先开发一个模型(model,也见流程图),然后把model的内容拷贝一份到Deployment对象中,这个过程也叫部署,最后就可以运行部署的流程,同时也支持运行多个流程实例。

一个流程图(模型)画好之后,需要发布(部署)之后才可以运行,这样的好处在于,流程图部署运行后,在去修改,不会影响到正在执行中的流程,是一种非常优秀的设计思想,具体实现呢,同学们也可以好好学习一下。

image-20230820113016984

创建测试类

在demo-activiti模块的test代码中新建ProcessRunTest类,注意包名需要和启动类包名一致。

image-20230820091511697

在新建的类中初始化下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.itcast.hiss;

import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
@Slf4j
public class ProcessRunTest {

@Autowired
RepositoryService repositoryService;

@Autowired
RuntimeService runtimeService;

/**
* 流程部署测试
*/
@Test
public void testDeployment(){

}

/**
* 运行测试
*/
@ParameterizedTest
@ValueSource(strings = {"流程定义key"})
public void testRun(String key){

}

}

部署实现

为避免画流程图时对运行流程影响,在部署时需要把画好的流程图复制一份到部署信息中这也是下面DeploymentBuilder对象所做的事情。除此之外还有几点说明如下:

  • repositoryService.createModelQuery()创建了一个针对act_re_model表查询的查询器,可以查询其表中的任何数据;
  • DeploymentBuilder部署资源中必须指定一个部署的流程图资源信息,并且资源信息的名称必须以*.bpmn20.xml结尾,否则部署的流程将不生效
  • 在act_re_model表中有一个DEPLOYMENT_ID_字段记录了部署ID,因此部署成功后需要修改Model表
  • RuntimeService:是非常常用的API,主要用于对流程实例(也就是运行中的流程)管理;
  • 在运行流程时,可以直接使用流程定义key运行一个流程,这个流程定义key可以在act_re_procdef表的KEY_中拷贝;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.itcast.hiss;

import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.Model;
import org.activiti.engine.runtime.ProcessInstance;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.assertNotNull;

@SpringBootTest
@Slf4j
public class ProcessRunTest {

@Autowired
RepositoryService repositoryService;

@Autowired
RuntimeService runtimeService;

/**
* 流程部署测试
*/
@Test
public void testDeployment(){
// 通过名称查询出之前保存的流程图
Model model = repositoryService.createModelQuery().modelName("单人审批请假流程").singleResult();
assertNotNull(model); // 断言查询成功
byte[] xml = repositoryService.getModelEditorSource(model.getId());// 获取内容
String xmlName = "itcast.bpmn20.xml";
DeploymentBuilder deploymentBuilder = repositoryService.createDeployment()
.key(model.getKey())
.name(model.getName())
.category(model.getCategory())
.enableDuplicateFiltering()// 自动去重
.tenantId(model.getTenantId())
.addBytes(xmlName, xml);// 设置部署的xml名称、内容
Deployment deploy = deploymentBuilder.deploy(); // 部署
assertNotNull(deploy.getId()); // 断言插入成功
model.setDeploymentId(deploy.getId());
repositoryService.saveModel(model); // 部署的id更新回Model对象
log.info("new deployment id : {}", model.getId());
}

/**
* 运行测试
*/
@ParameterizedTest
@ValueSource(strings = {"ID"})
public void testRun(String key){
}

}

运行上述testDeployment方法,出现下面情况,既部署成功

image-20230820104922522

运行上述testRun方法,出现下面情况,既运行成功

image-20230820113409998

部署表分析

在上述部署testDeployment方法执行成功后,数据实际上保存到了数据库中的act_re_deployment、act_re_procdef、act_ru_identitylink、act_ge_bytearray、act_re_model表中。

act_ge_bytearray和act_re_model表之前我们已经介绍过了,在此看一下数据即可:

act_ge_bytearray:表中增加了一条数据,BYTES_字段内容一模一样,不一样的就是NAME_字段,并且DEPLOYMENT_ID_字段存储了部署ID

image-20230820114619650

act_re_model:表中DEPLOYMENT_ID_字段也存储了部署ID

image-20230820114857638

act_re_deployment

act_re_deployment表是用于存储部署流程图信息:

image-20230820122639131

序号 字段名 类型 长度 是否主键 注释
1 ID_ varchar 64 主键
2 NAME_ varchar 255 名称
3 CATEGORY_ varchar 255 分类
4 KEY_ varchar 255 业务key
5 TENANT_ID_ varchar 255 租户ID
6 DEPLOY_TIME_ timestamp 部署时间
7 ENGINE_VERSION_ varchar 255 引擎版本,一般为空
8 VERSION_ int 10 部署版本
9 PROJECT_RELEASE_VERSION_ varchar 255 项目版本,一般为空
act_re_procdef

act_re_procdef表用于存储流程图中解析得到的流程信息:

image-20230820123040466

序号 字段名 类型 长度 是否必填 注释
1 ID_ varchar 64 主键
2 REV_ int 10 数据更新乐观锁
3 CATEGORY_ varchar 255 分类
4 NAME_ varchar 255 名称
5 KEY_ varchar 255 流程定义key
6 VERSION_ int 10 流程定义版本
7 DEPLOYMENT_ID_ varchar 64 关联部署ID
8 RESOURCE_NAME_ varchar 4000 流程定义存在的资源名称
9 DGRM_RESOURCE_NAME_ varchar 4000 流程图文件的资源名称,一般为空
10 DESCRIPTION_ varchar 4000 流程定义描述
11 HAS_START_FORM_KEY_ tinyint 3 是否启动表单,1是,0否,一般为0
12 HAS_GRAPHICAL_NOTATION_ tinyint 3 是否图形标记,1是,0否,可以理解成
xml中节点坐标等信息是否有
13 SUSPENSION_STATE_ int 10 挂起状态,1挂起,2未挂起
14 TENANT_ID_ varchar 255 租户ID
15 ENGINE_VERSION_ varchar 255 引擎版本,一般不用
16 APP_VERSION_ int 10 APP版本,一般不用

act_ru_identitylink表用于存储资源(比如:流程定义、流程实例、任务等资源)授权信息,拥有授权信息才可以使用对应资源:

这条数据可以理解为:ID为XXX的流程定义被授权给任意分组使用,既没有使用限定。

image-20230820123932599

序号 字段名 类型 长度 是否主键 注释
1 ID_ varchar 64 主键
2 REV_ int 10 数据更新乐观锁
3 GROUP_ID_ varchar 255 授权的分组ID
4 TYPE_ varchar 255 授权类型
5 USER_ID_ varchar 255 授权的用户ID
6 TASK_ID_ varchar 64 任务资源ID
7 PROC_INST_ID_ varchar 64 流程实例资源ID
8 PROC_DEF_ID_ varchar 64 流程定义资源ID

运行实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.itcast.hiss;

import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.Model;
import org.activiti.engine.runtime.ProcessInstance;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.assertNotNull;

@SpringBootTest
@Slf4j
public class ProcessRunTest {

@Autowired
RepositoryService repositoryService;

@Autowired
RuntimeService runtimeService;

/**
* 流程部署测试
*/
@Test
public void testDeployment(){
}

/**
* 运行测试
*/
@ParameterizedTest
@ValueSource(strings = {"hiss_process_12_1692440641431"})
public void testRun(String key){
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key);
assertNotNull(processInstance.getId()); // 断言插入成功
log.info("new processInstance id : {}", processInstance.getId());
}

}

运行表分析

  • 任务实例:就是流程图中的每个需要人工参与的节点
  • 流程实例:流程定义运行起来的流程被称为流程实例
  • 活动实例:就是流程图中的每个节点
  • 执行器:记录当前执行节点的信息

对部署好的流程图运行之后,得到流程实例(ProcessInstance),这个运行中的流程实例信息存储到了act_ru_identitylink、act_ru_execution、act_ru_task表中。

act_ru_identitylink:多出了一条记录,是因为我们启动流程后,开始节点会自动执行并到下一个节点既【填写请假单】,而请假单需要张三这个参与人来办理,因此在此表中就多出一条记录,表示流程实例ID为XXX的流程授权给张三操作。

这里通过观察我们还可发现,在之前设计流程图中,还有一步李四【经理审批】,而此表中没有出现李四的授权信息,则说明流程执行到那个节点才会在此表中添加授权信息

image-20230820124823258

image-20230819174133639

act_ru_execution

act_ru_execution用于存储运行中流程的节点信息。不仅存储流程实例信息,还存储流程实例的待执行节点信息。

刚才运行的流程实例,首选会在此表中创建一条流程实例信息(特点:PARENT_ID_字段为空),比如下图中的第1行数据。接着流程流转到【填写请假单】节点,因此在此表中还创建了一条待执行节点的信息,比如下图中的第2行数据。我们也可以通过ACT_ID_字段值与xml中节点元素的ID值比对印证。

同时我们通过观察还可以发现,在之前设计流程图中,还有一步李四【经理审批】,而此表中没有出现相关节点信息,则说明流程执行到那个节点才会在此表中添加节点信息

image-20230820125930243

序号 字段名 类型 长度 注释
1 ID_ varchar 64 主键
2 REV_ int 10 数据更新乐观锁
3 PROC_INST_ID_ varchar 64 流程实例ID
4 BUSINESS_KEY_ varchar 255 业务自定义key
5 PARENT_ID_ varchar 64 父执行ID
6 PROC_DEF_ID_ varchar 64 流程定义ID
7 ROOT_PROC_INST_ID_ varchar 64 根流程实例ID
8 ACT_ID_ varchar 255 正在活跃的活动ID,节点可以任务是时间或任务,ID对应画图时的ID
9 IS_ACTIVE_ tinyint 3 是否激活,1激活,2挂起
10 IS_CONCURRENT_ tinyint 3 是否是并行分支,1是,0否
11 IS_SCOPE_ tinyint 3 是否独立执行,1是,0不是,独立空间执行会有独立的变量等信息
12 IS_EVENT_SCOPE_ tinyint 3 是否独立事件执行,1是,0不是
13 IS_MI_ROOT_ tinyint 3 是否多实例,1是,0不是
14 SUSPENSION_STATE_ int 10 挂起状态,1激活,2挂起
15 CACHED_ENT_STATE_ int 10 缓存实体状态
16 TENANT_ID_ varchar 255 租户ID
17 NAME_ varchar 255 流程实例名称
18 START_TIME_ datetime 开始时间
19 START_USER_ID_ varchar 255 开始用户
20 LOCK_TIME_ timestamp 锁住的时间
21 IS_COUNT_ENABLED_ tinyint 3 是否能够计数
22 EVT_SUBSCR_COUNT_ int 10 订阅的事件数量
23 TASK_COUNT_ int 10 任务数量
24 JOB_COUNT_ int 10 作业数量
25 TIMER_JOB_COUNT_ int 10 定时作业数量,activiti自带定时作业功能
26 SUSP_JOB_COUNT_ int 10 挂了的作业数量
27 DEADLETTER_JOB_COUNT_ int 10 延迟任务数量
28 VAR_COUNT_ int 10 变量数量
29 APP_VERSION_ int 10 应用版本
act_ru_task

act_ru_task用于存储需要办理的任务信息。

在刚才运行的流程中,【填写请假单】节点需要张三办理,因此在此表中可以查到相关信息。另外在此表我们还是可以发现未执行节点,不会在此表中创建任务

image-20230820132031343

序号 字段名 类型 长度 注释
1 ID_ varchar 64 主键
2 REV_ int 10 数据修改乐观锁
3 EXECUTION_ID_ varchar 64 执行实例ID
4 PROC_INST_ID_ varchar 64 流程实例ID
5 PROC_DEF_ID_ varchar 64 流程定义ID
6 NAME_ varchar 255 当前任务名称
7 BUSINESS_KEY_ varchar 255 业务自定义KEY
8 PARENT_TASK_ID_ varchar 64 父任务ID
9 DESCRIPTION_ varchar 4000 任务描述,对应画图时的document
10 TASK_DEF_KEY_ varchar 255 任务定义KEY,流程图中的id字段值
11 OWNER_ varchar 255 任务拥有者
12 ASSIGNEE_ varchar 255 任务办理人
13 DELEGATION_ varchar 64 任务委托状态,任务被委托时,为PENDING,委托任务被解决后为RESOLVED
14 PRIORITY_ int 10 优先级,默认50
15 CREATE_TIME_ timestamp 创建时间
16 DUE_DATE_ datetime 截止时间
17 CATEGORY_ varchar 255 任务类别
18 SUSPENSION_STATE_ int 10 挂起状态,1激活,2挂起
19 TENANT_ID_ varchar 255 租户
20 FORM_KEY_ varchar 255 表单key,一般不用
21 CLAIM_TIME_ datetime 任务被认领的时间
22 APP_VERSION_ int 10 应用版本

-

第五步:开发同意和不同意审批功能

创建测试类

在demo-activiti模块的test代码中新建ProcessHandleTest类,注意包名需要和启动类包名一致。

image-20230820142607089

在新建的类中初始化下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.itcast.hiss;

import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
@Slf4j
public class ProcessHandleTest {

@Autowired
RepositoryService repositoryService;

@Autowired
RuntimeService runtimeService;

@Autowired
TaskService taskService;

/**
* 完成填写清单
*/
@ParameterizedTest
@ValueSource(strings = {"这里是任务ID"})
public void testCompleteNode2(String taskId){

}

/**
* 同意
*/
@ParameterizedTest
@ValueSource(strings = {"这里是任务ID"})
public void testAgree(String taskId){

}

/**
* 不同意,既拒绝
*/
@ParameterizedTest
@ValueSource(strings = {"这里是流程实例ID"})
public void testReject(String processInstanceId){

}

}

完成填写请假单任务

在上面运行的流程实例中,流程实例正等待填写请假单,那么假设我们此时填写完成了请假单,想继续下一步审批,该怎么办呢?

其实这个需求Activiti提供了相关API,可以直接标注某个任务执行完成,然后流程自动到下一步,相关实现代码如下:

  • TaskService:是一个常用的API,主要用来对任务进行各种操作
  • 调用complete方法,即可结束当前节点,并且流程会自动开启下一个节点的任务。同时在结束时还可以把填写的表单数据,作为流程变量(这些流程变量,后续再去讲解如何使用)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Autowired
TaskService taskService;

/**
* 完成填写清单
*/
@ParameterizedTest
@ValueSource(strings = {"这里替换成act_ru_task表中的id_"})
public void testCompleteNode2(String taskId){
// 把张三填写的请假单中的数据,作为流程变量,设置到流程中
Map<String, Object> variables = new HashMap<>();
variables.put("userName","张三");
variables.put("startDate","2024-1-1");
variables.put("days","1");
variables.put("reason","元旦回家");
// 标记任务完成
taskService.complete(taskId, variables);
}

执行上面testCompleteNode2方法后,可以在act_ru_execution表中发现,新增了【经理审批】待执行的节点,而完成的【填写请假单】节点被删除了。

image-20230820143520807

同时在act_ru_task表中,待办任务也变成了李四【经理审批】:

image-20230820143714186

代码中传入的表单数据,同时也作为流程变量存储到了act_ru_variable表中(详细字段含义,后续讲解)。

image-20230820144747919

经理同意

关于经理同意操作的实现,如果我们把【同意】看做是经理填写的【审批表单(包括:审批结果、审批意见)】中的一个字段,那么其实现和完成填写请假单任务的实现差不多,经理点击同意之后也需要完成当前节点执行下一结束节点。

image-20230819113436637

则同意操作的实现代码如下:

  • 调用complete方法时,把同意作为表单数据传入,也作为了流程变量数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 同意
*/
@ParameterizedTest
@ValueSource(strings = {"这里替换成act_ru_task表中的id_"})
public void testAgree(String taskId){
// 把【同意】看做是填写的【审批表单(包括:审批结果、审批意见)】中的approvalStatus字段
Map<String, Object> variables = new HashMap<>();
variables.put("approvalStatus","同意");//
variables.put("approvalNote","");
// 标记任务完成
taskService.complete(taskId, variables);
}

上述代码执行成功后,到数据库中查看act_ru_execution、act_ru_task、act_ru_variable中的数据,你会发现里面没有了相关流程实例的数据,那是因为【经理审批】节点执行完成之后,后面的结束节点也会自动执行,因此流程就执行完成了。而act_ru_开头的表只存储运行中的流程信息,不会存储流程结束了的信息,结束了的相关信息都转到act_hi开头的表中存储了,相关表稍后我们再去认识。

经理不同意

经理不同意和同意都是审批操作,那么不同意的实现就和同意的实现一样?不然,在这里不同意的需求要比同意的复杂一点,不同意则流程会终止执行。比如下面流程中,如果经理1审批不同意,那么经理2就不用审批了,整个流程就应该直接结束。因此不同意,则应该是终止流程而不是完成节点。

image-20230820150955034

综上需求所述,则不同意的实现代码如下:

  • 在这里,要终止流程,因此操作的是流程实例,因此使用的是runtimeService API,这里用到的是流程实例的ID,不是任务ID
  • 在删除流程时,同时也把审批不同意及理由,作为流程变量存储到流程变量中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 不同意,既拒绝
*/
@ParameterizedTest
@ValueSource(strings = {"这里替换成act_ru_execution表中的流程实例的id_"})
public void testReject(String processInstanceId){
String reason = "这里是不同意的理由";
// 把【同意】看做是填写的【审批表单(包括:审批结果、审批意见)】中的approvalStatus字段
Map<String, Object> variables = new HashMap<>();
variables.put("approvalStatus","不同意");
variables.put("approvalNote",reason);
//记录流程变量
runtimeService.setVariables(processInstanceId, variables);
// 添加流程变量,表示任务被拒绝
runtimeService.deleteProcessInstance(processInstanceId, reason);
}

要运行上面代码,我们需要重新发起一个流程实例,并完成【填写请假单】节点后,再实现,具体操作:

  • 直接运行ProcessRunTest类中的testRun方法,新启动一个实例
  • 修改ProcessHandleTest类中testCompleteNode2方法上的taskId值,并运行testCompleteNode2方法
  • 最后修改testReject上的流程实例ID,然后运行testReject方法即可

上述代码执行成功后,同样在数据库中act_ru_execution、act_ru_task、act_ru_variable中的看不到数据,应为整个流程都被删除了,也结束了,因此信息也被转到了act_hi开头的表中。

到此,《单人审批请假流程》的整个流程就基本实现完成了。

表分析

通过上面的学习我们知道了act_ru_开头的表只存储运行中的流程信息,而流程结束后,则信息都存储到act_hi开头的表中了,其实act_hi开头的表不管是运行中还是结束的流程实例信息都存储了

接下来,我们就一起来看看这些表。

act_ru_variable

act_ru_variable用于存储运行中流程的变量信息。

image-20230820144747919

序号 字段名 类型 长度 注释
1 ID_ varchar 64 主键
2 REV_ int 10 乐观锁
3 TYPE_ varchar 255 变量类型json\string\integer
4 NAME_ varchar 255 变量名
5 EXECUTION_ID_ varchar 64 执行ID
6 PROC_INST_ID_ varchar 64 流程实例ID
7 TASK_ID_ varchar 64 任务ID
8 BYTEARRAY_ID_ varchar 64 二进制数据管理的ID,关联BYTEARRAY表
9 DOUBLE_ double 22 存储变量类型为Double
10 LONG_ bigint 19 存储变量类型为long
11 TEXT_ varchar 4000 存储变量值类型为String 如此处存储持久化对象时,值jpa对象的class
12 TEXT2_ varchar 4000 此处存储的是JPA持久化对象时,才会有值。此值为对象ID
act_hi_actinst

act_hi_actinst用于存储流程实例每个节点信息,在activiti中把每个节点都称为活动,因此此表也叫活动信息表。

PS:活动与任务的区别:流程图中每个节点都被称为活动,但是并不是所有活动在流程实现执行过程中都会创建任务,比如开始节点就不会任务。

image-20230820160527454

序号 字段名 类型 长度 是否主键 注释
1 ID_ varchar 64 主键
2 PROC_DEF_ID_ varchar 64 流程定义ID
3 PROC_INST_ID_ varchar 64 流程实例ID
4 EXECUTION_ID_ varchar 64 执行ID
5 ACT_ID_ varchar 255 xml中活动节点id
6 TASK_ID_ varchar 64 任务ID
7 CALL_PROC_INST_ID_ varchar 64 调用的流程实例ID
8 ACT_NAME_ varchar 255 xml中活动节点的name
9 ACT_TYPE_ varchar 255 xml中活动节点的元素名
10 ASSIGNEE_ varchar 255 办理人
11 START_TIME_ datetime 开始时间
12 END_TIME_ datetime 结束时间
13 DURATION_ bigint 19 耗时
14 DELETE_REASON_ varchar 4000 删除原因
15 TENANT_ID_ varchar 255 租户ID
act_hi_detail

act_hi_detail表记录了整个流程运行过程中,对流程变量、表单数据、备注等操作的操作明细。被称为流程运行明细表。

image-20230820161209252

序号 字段名 类型 长度 是否主键 注释
1 ID_ varchar 64 主键
2 TYPE_ varchar 255 操作类型支持变量、表单数据、备注
3 PROC_INST_ID_ varchar 64 流程实例
4 EXECUTION_ID_ varchar 64 执行ID
5 TASK_ID_ varchar 64 任务ID
6 ACT_INST_ID_ varchar 64 活动实例ID
7 NAME_ varchar 255 变量名
8 VAR_TYPE_ varchar 255 变量类型
9 REV_ int 10 数据更新乐观锁
10 TIME_ datetime 操作时间
11 BYTEARRAY_ID_ varchar 64 大字段关联act_ge_bytearray表的ID
12 DOUBLE_ double 22 double类型的变量值
13 LONG_ bigint 19 long类型的变量值
14 TEXT_ varchar 4000 String类型的变量值

act_hi_identitylink比act_ru_identitylink表少了一个REV_字段,其它字段都一样。

image-20230820161732133

序号 字段名 类型 长度 是否主键 注释
1 ID_ varchar 64 主键
2 PROC_DEF_ID_ varchar 64 流程定义资源ID
3 GROUP_ID_ varchar 255 授权的分组ID
4 TYPE_ varchar 255 授权类型
5 USER_ID_ varchar 255 授权的用户ID
6 TASK_ID_ varchar 64 任务资源ID
7 PROC_INST_ID_ varchar 64 流程实例资源ID
act_hi_procinst

act_hi_procinst流程实例信息表,此表和之前act_ru_execution不一样,只存储了流程实例的信息,流程实例节点的信息没像act_ru_execution表一样存储。

image-20230820162635209

序号 字段名 类型 长度 是否主键 注释
1 ID_ varchar 64 主键
2 PROC_INST_ID_ varchar 64 流程实例ID
3 BUSINESS_KEY_ varchar 255 业务自定义KEY
4 PROC_DEF_ID_ varchar 64 流程定义ID
5 START_TIME_ datetime 开始时间
6 END_TIME_ datetime 结束时间
7 DURATION_ bigint 19 耗时
8 START_USER_ID_ varchar 255 发起人ID
9 START_ACT_ID_ varchar 255 开始活动xmlID
10 END_ACT_ID_ varchar 255 结束活动xmlID
11 SUPER_PROCESS_INSTANCE_ID_ varchar 64 父流程实例ID
12 DELETE_REASON_ varchar 4000 删除原因
13 TENANT_ID_ varchar 255 租户ID
14 NAME_ varchar 255 流程名称
act_hi_taskinst

act_hi_taskinst基本和act_ru_taskinst表相同,但又改变了一些字段比如结束时间、耗时等,记录了更明细的task任务信息。

image-20230820163034215

序号 字段名 类型 长度 是否必填 注释
1 ID_ varchar 64 主键
2 PROC_DEF_ID_ varchar 64 流程定义ID
3 TASK_DEF_KEY_ varchar 255 任务定义KEY,流程图中的id字段值
4 PROC_INST_ID_ varchar 64 流程实例ID
5 EXECUTION_ID_ varchar 64 执行实例ID
6 NAME_ varchar 255 任务名称
7 PARENT_TASK_ID_ varchar 64 父任务ID
8 DESCRIPTION_ varchar 4000 任务描述,对应画图时的document
9 OWNER_ varchar 255 归属人
10 ASSIGNEE_ varchar 255 办理人
11 START_TIME_ datetime 开始时间
12 CLAIM_TIME_ datetime 认领时间
13 END_TIME_ datetime 结束时间
14 DURATION_ bigint 19 耗时
15 DELETE_REASON_ varchar 4000 删除理由
16 PRIORITY_ int 10 优先级
17 DUE_DATE_ datetime 截止时间
18 FORM_KEY_ varchar 255 表单KEY
19 CATEGORY_ varchar 255 分类
20 TENANT_ID_ varchar 255 租户ID
act_hi_varinst

act_hi_varinst存储了流程实例过程中的所有变量数据,比act_ru_variable多了CREATE_TIME_、LAST_UPDATED_TIME_两个字段。

image-20230820163855253

序号 字段名 类型 长度 注释
1 ID_ varchar 64 主键
2 REV_ int 10 乐观锁
3 TYPE_ varchar 255 变量类型json\string\integer
4 NAME_ varchar 255 变量名
5 EXECUTION_ID_ varchar 64 执行ID
6 PROC_INST_ID_ varchar 64 流程实例ID
7 TASK_ID_ varchar 64 任务ID
8 BYTEARRAY_ID_ varchar 64 二进制数据管理的ID,关联BYTEARRAY表
9 DOUBLE_ double 22 存储变量类型为Double
10 LONG_ bigint 19 存储变量类型为long
11 TEXT_ varchar 4000 存储变量值类型为String 如此处存储持久化对象时,值jpa对象的class
12 TEXT2_ varchar 4000 此处存储的是JPA持久化对象时,才会有值。此值为对象ID
13 CREATE_TIME_ datetime 创建时间
14 LAST_UPDATED_TIME_ datetime 更新时间

作业

《入职审批流程》开发

需求:

新员工入职第一天,需要发起入职审批流程以办理入职,具体的流程如下:

  • HR发起一个入职审批流程
  • 员工在HR电脑处填写入职申请信息,包括归属部门、个人电话、工资银行卡、应急联系人姓名、应急联系人电话信息。
  • HR上传与员工签订的合同信息
  • 用人部门的经理进行同意或不同意的审批

所有涉及的办理人,均可按照课堂学习的先设置为固定的人员。

image-20230820165430805

接口开发

今天我们学习的保存流程图、部署及运行流程都是使用Test代码来完成的,其目的是便于带大家掌握Activiti的相关开发步骤和API,但是此中方式只适合学习,在企业中这些操作应该是有界面直接的操作按钮的,如下图,画完图形后,直接操作对应相关的按钮即可。

image-20240801174728866

因此接下来同学们需要研究现有项目的代码,并完成保存、部署、运行三个功能的开发。一些要求如下:

  • 所开发接口必须和现有的登录、APP管理等接口规范一致;
  • 所开发的接口请求参数必须按照前端传入的一致;

保存接口

注意事项一

如果遇见此错误:

image-20230820171852110

则在url中增加相关参数即可:

image-20230820172019295

注意事项二

实现该接口的过程中,你会发现图标和描述信息不能使用Model对象存储进入,而且在act_re_model表中也没有对应存储的字段,那么该怎么实现呢?

请和你的小组讨论并给出你的实现。

当前框架请求实现原理图

image-20231029171118851

请求参数

id:为命令唯一ID,前端固定值

messageAuth:为当前登录任务的信息,可以不用管

palyload:为当前接口真正传入的参数数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"id": "FLOW_M_SAVE_MODEL_FOR_DEV",
"messageAuth": {
"tenant": "zhyl_app",
"currentUser": {
"userId": "42376301c89b238420a7365bdf4f9797",
"userName": "智慧养老"
}
},
"palyload": {
"name": "头条头条拖拖拖拖拖拖",
"category": "35",
"modelId": "",
"key": "",
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<definitions xmlns=\"http://www.omg.org/spec/BPMN/20100524/MODEL\" xmlns:bpmndi=\"http://www.omg.org/spec/BPMN/20100524/DI\" xmlns:dc=\"http://www.omg.org/spec/DD/20100524/DC\" xmlns:di=\"http://www.omg.org/spec/DD/20100524/DI\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:activiti=\"http://activiti.org/bpmn\" xmlns:bioc=\"http://bpmn.io/schema/bpmn/biocolor/1.0\" xmlns:tns=\"http://www.activiti.org/testm1685269119653\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" id=\"hiss_flow_1692522885171\" name=\"\" targetNamespace=\"http://www.activiti.org/testm1685269119653\">\n <process id=\"hiss_process_12_1692522885203\" name=\"hiss_process\" isExecutable=\"true\">\n <startEvent id=\"StartEvent_1\" />\n <sequenceFlow id=\"Flow_109kst5\" sourceRef=\"StartEvent_1\" targetRef=\"Activity_1xi315o\" />\n <endEvent id=\"Event_15ugrje\">\n <incoming>Flow_115wg6x</incoming>\n </endEvent>\n <sequenceFlow id=\"Flow_115wg6x\" sourceRef=\"Activity_1xi315o\" targetRef=\"Event_15ugrje\" />\n <serviceTask id=\"Activity_1xi315o\" name=\"执行任务\" activiti:expression=\"${true}\">\n <extensionElements />\n <incoming>Flow_109kst5</incoming>\n <outgoing>Flow_115wg6x</outgoing>\n </serviceTask>\n </process>\n <bpmndi:BPMNDiagram id=\"BPMNDiagram_1\">\n <bpmndi:BPMNPlane id=\"BPMNPlane_1\" bpmnElement=\"hiss_process_12_1692522885203\">\n <bpmndi:BPMNShape id=\"_BPMNShape_StartEvent_2\" bpmnElement=\"StartEvent_1\">\n <dc:Bounds x=\"173\" y=\"102\" width=\"36\" height=\"36\" />\n </bpmndi:BPMNShape>\n <bpmndi:BPMNShape id=\"Event_15ugrje_di\" bpmnElement=\"Event_15ugrje\">\n <dc:Bounds x=\"552\" y=\"102\" width=\"36\" height=\"36\" />\n </bpmndi:BPMNShape>\n <bpmndi:BPMNShape id=\"Activity_0vhe9iu_di\" bpmnElement=\"Activity_1xi315o\">\n <dc:Bounds x=\"330\" y=\"80\" width=\"100\" height=\"80\" />\n <bpmndi:BPMNLabel />\n </bpmndi:BPMNShape>\n <bpmndi:BPMNEdge id=\"Flow_109kst5_di\" bpmnElement=\"Flow_109kst5\" bioc:stroke=\"#060606\" bioc:fill=\"none\">\n <di:waypoint x=\"209\" y=\"120\" />\n <di:waypoint x=\"330\" y=\"120\" />\n </bpmndi:BPMNEdge>\n <bpmndi:BPMNEdge id=\"Flow_115wg6x_di\" bpmnElement=\"Flow_115wg6x\" bioc:stroke=\"#060606\" bioc:fill=\"none\">\n <di:waypoint x=\"430\" y=\"120\" />\n <di:waypoint x=\"552\" y=\"120\" />\n </bpmndi:BPMNEdge>\n </bpmndi:BPMNPlane>\n </bpmndi:BPMNDiagram>\n</definitions>\n",
"tenant": "",
"description": "ss",
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAYAAAAehFoBAAAAAXNSR0IArs4c6QAABYJJREFUWEfVmWtsVEUYhp/ZK/QCFUmsRIsQgdKAJQRaTRSJQBQVEzSCBk0gwRAJQlAxxh9QTPwnRsBLjCJeIN5QUFFqjBdoQlqoqUZAEMGihSwRSoHS69k95ps5Z7u77Lal3Zbu/GizPed0n3nn/S4zR5EwbBvFWrysIawUduL1/vjcGYOKBbDL8MhnVUZEP/QhWYTx9wdk9Du8tPM4TSJWLI97PQosgPqmzQwCnsDmURSjgMH9CgzN2PyN4iPgbbWIFpdNiyk/orBbuAGL7dhMASJgFL8Kw3y3ohofc9Vj1LmMKgq7gSC5/AzcCrQB3qsMHAYCQCUXma6W06pZ7TJ8qgzLfo/l2KwH2qGffZt6CQ2LYoVayAbNGuPdPcAdgMxM1B0Iw2WpUIuYplm1hz8lh0scBfLlo+vtAUDssoTIZoyaR6MB3kweUAsMHaDA54Gb1CIaDPBbDCXAiQEN3MZItYTzaVBYgeoq+9lgS6a64uFaIkHhnlpCQkA4wt2o4D7Rphv3xc8pncACa0PwGsgbo6tP8qEg3AL1hwDLKVXdVjpdwMoABnJh9h4YNskseTJruH8/8DJUrgK/50rs0Vtg168K2i3IL4X7K6FmNYR2gz83HkZ5oe0cTH4Jcgpg22gjrZ6YTFrSbKejl8DyuAX4BCQMI0pgThWUz4Zj5RD0xkMoH7RYcPcHMGI6fFJg6GzHTl33gT0FdizgHwKlr0DeBLCajX+HFUPjCWi/AKJoXGDJcxZkjwRvEM5UGyt5A3BsCxx8DSQYU/o/WsSuMEuIUq0WFC2E2zcbFTWclqubhdG9z/ltNcIXhdB4Erwpfd1DhV3gSSug5FWItIL8TXwoqS0sPUonKUsm5/E5drGNh+WZryZB/WHw9RVw8VNQugEilgGQ8dPDcLIc/DkxAefCy4S8xi5T18G4JcYiMtlIG+yYCOf+7Evg5VC63gEWSyioWgGhH8GXbYB15HvA4zUqajWboXg1jJrXYSfJzV/eAueO9gOwq1JXSSnuuqO6zsuSJcIO8OE+9HCxo3AssAugPeyB0xVQuRQaa2HkQ1C4FIZPjQlMJ47OVsN390DTWfAnpMOOifYy6JIB60ThZI2/NsH3i2H4WMifDMd3QFML5BfC+GUweoEJzurn4Pd3IGsIBLPgQshsGeL28HEpqIdpLSmwI4Jkjq0j4LqpMOtb412pcrWfwR8b4dQByMk1m5mmBpi8EiasguC15nrVs+C5rEHqI4VdlXdMgEAe3FvRsX91+4v6X+HgOmgOQcl6yCty+g+BVLBrGtRVQCDOHn0E7Fpi72LYvwmK7oMZ28HjB1syhZOzY4NQUqP0pp6AAd85BU7XJDZH6QZ27dAGuxfAkW1wfRH8dwhunAkzvwavnMvENvBO0yPK6+aoAfY9A0feTVam0wXsqKazhR9q1kDVizB9IxQug4vHofZjKJgLQ8d3tJ561yGVzuk5pJ+ofh7On4Jg0mrXS+CJT8Jtb3RUKze9/fCgKR7z68AnFU+gEkJe7pW0J8rW18C+lfDPbqOq7iWStpo9BfaAFYG80TCrHLILDLQoJj1w3U7YNQcKZsDMbxzvSvkWfzogomrrWfhtLRx8EyzLBFicXS6rRD0E1k230wv7s2DwsJiW0AbPIGgJwaUmuPkBuOtzo6QuKtL0RODY+/DLC9AQMssvK9DnDby76UzsX50ih9cPze0wbj7cudV49UwV7H8a/t0bs/yOl7su7b1QOPrPnZYy8cvcbbzbio59BLKGw4HXza666+VPhp8CON0HKbrKSecm54/dXv7OgdN3kJJiXXXqcrZIXS99qjtSKJxJh4EZd9yauQfamfLKQHeG7hukTHgp44ZnRr32ikJn0ovFWKUH8qvb/wGyX0RcJRk4ugAAAABJRU5ErkJggg==",
"configJson": "{\"nodeConfig\":{},\"forms\":[]}",
"_tenant": "zhyl_app"
}
}
响应参数
1
2
3
4
5
6
7
8
9
10
{
"host": null,
"code": 200,
"errorMessage": "操作成功",
"id": null,
"data": {
"modelId": "22815c35-3f3a-11ee-9acb-024226f49cbe"
},
"success": true
}

部署接口

请求参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"id": "MODEL_TO_DEPLOYMENT",
"messageAuth": {
"tenant": "zhyl_app",
"currentUser": {
"userId": "42376301c89b238420a7365bdf4f9797",
"userName": "智慧养老"
}
},
"palyload": {
"name": "头条头条拖拖拖拖拖拖",
"category": "35",
"modelId": "22815c35-3f3a-11ee-9acb-024226f49cbe",
"key": "",
"tenant": "",
"configJson": "{\"nodeConfig\":{},\"forms\":[]}",
"_tenant": "zhyl_app"
}
}
响应参数
1
2
3
4
5
6
7
8
9
10
{
"host": null,
"code": 200,
"errorMessage": "操作成功",
"id": null,
"data": {
"deployId": "f2252ed7-3f3a-11ee-9acb-024226f49cbe"
},
"success": true
}

运行接口

注意事项一

课堂我们学习的是使用流程xml中定义的key来启动流程:

1
runtimeService.startProcessInstanceByKey(key);

则这里需要通过流程定义ID来启动,需要自行研究如何查询到act_re_procdef表的ID_值

1
runtimeService.startProcessInstanceById(流程定义ID, null, null);
请求参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"id": "FLOW_M_START_MODEL_FOR_DEV",
"messageAuth": {
"tenant": "zhyl_app",
"currentUser": {
"userId": "42376301c89b238420a7365bdf4f9797",
"userName": "智慧养老"
}
},
"palyload": {
"name": "头条头条拖拖拖拖拖拖",
"category": "35",
"modelId": "22815c35-3f3a-11ee-9acb-024226f49cbe",
"key": "",
"tenant": "",
"description": "ss",
"configJson": "{\"nodeConfig\":{},\"forms\":[]}",
"_tenant": "zhyl_app",
"operatorName": "发起",
"variables": {},
"type": "MSG",
"jumpTaskOrActivityId": "#start"
}
}
响应参数
1
2
3
4
5
6
7
8
9
10
{
"host": null,
"code": 200,
"errorMessage": "操作成功",
"id": null,
"data": {
"processInstanceId": "51b412dc-3f3b-11ee-9acb-024226f49cbe"
},
"success": true
}