Activiti7&请假流程开发

Activiti7&请假流程开发
Flaw《单人审批请假流程》开发
到此,我们已经准备好了课程要使用到的环境,接下我们就先通过一个简单的《单人审批请假流程》来快速入门Activiti,通过案例来重点掌握:
- Activiti相关术语概念
- Activiti的开发步骤
- Activiti相关表结构
单人审批请假流程:
首选看一下Activiti相关术语概念:
基本概念
Activiti是一款主流的工作流 流程引擎,再此我们就先从工作流、流程引擎概念说起。
什么是工作流
工作流( Workflow ):是一项将系统任务或操作抽取,再按照预定业务流程进行组织、协调、并自动化执行的技术。
我们也可以简单理解==工作流是一种简化审批业务流程开发的技术==,其主要是解决一些业务场景硬编码方式的成本高、效率低、变更慢等问题的技术。
复杂的业务流程,实现复杂度比较高,因此开发周期长,开发成本高,效率也低,如果发生需求变更,对之前复杂的代码进行修改,同样需要更长的时间,因此响应变更的速度呢也表现得慢。
工作流技术来实现类似复杂的业务,只需要集成流程引擎、画出流程中使用的表单、最后画出整个业务流程图,交给流程引擎3步,即可完成需求的开发。在整个实现过程中,流程引擎是一个三方框架,不需要我们过多编码,而画表单、画流程就是在页面中进行一些拖拉拽的操作。因此整个过程下来我们编码量极少,需要的开发时间也极少,通过此方式呢就轻松的解决了开发周期长、成本高、效率低的问题,如果需求变更了,工作流技术只需要修复之前的表单或图即可,因此变更响应速度自然也必硬编码开发的速度要快。
什么是流程引擎
流程引擎:是用于驱动或控制业务流程每一步自动执行的代码框架。
目前市面上主流的流程引擎框架有jBPMN、Activiti、Flowable、Camunda4款,其中Activiti开源度最大,因此是当下主流的首选流程引擎。
本课程则选择Activiti7作为我们的学习流程引擎,主要因素有:
- Activiti开源度大,企业使用多
- Activiti成熟度好,文档资料完善
- 学习完成Activiti之后,可以快速上手Flowable、Camunda等基于Activitii二次开源的框架
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微服务集成方式不优雅
- 使用门槛、成本比较高
那么针对这些劣势的解决,本课程开源的hiss项目,都可以解决。课程最终除了让大家掌握Activiti技术,也会把hiss项目交给大家。让大家带着知识和工具到企业中帮助企业解决这些问题,成为企业需要的人才,进而提升同学们自身的就业竞争力!
需求说明
有了刚才的知识,接下来我们就开始分析《单人审批请假流程》的需求以及使用Activiti对其进行开发的步骤。
需求分析
在企业中,员工如果有事需要请假,一般都需要向上级请假,得到批准后,方可离开公司。而整个过程在企业中需要在系统中完成,以信息化员工的出勤信息,便于工资、奖金的结算,因此需要开发此功能,需求如下:
- 员工:请假的员工需要先填写请假单,填写的字段有:请假人、请假天数、开始请假时间、请假事由;
- 经理:审批员工的请假单,如果不同意,则需要说明不同意的理由;
实现步骤
在这里我们主要是来了解一下基于Activiti如何来实现上述需求,其主要的实现步骤是什么?
在前面我们有提到工作流只需要下面3步即可,在此需求中虽然用到了表单,但在此需求实现过程中,我们先不学画表单,这步放到后面一点去学习。
因此这个需求只需要集成流程引擎、画流程两步实现即可,但是之前我们有介绍到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 | <properties> |
设定Activiti仓库地址
Activiti有些jar包,未上传到中央仓库,因此使用的时候需要添加Activiti的仓库,这里推荐直接在hiss-center的pom.xml文件中添加,避免对其它项目影响:
1 | <repositories> |
导入Activiti依赖
有了前面2不小步,在要使用的Activiti的模块中直接导入下面starter即可导入Activiti的依赖。在这里我们在test模块下,建立一个demo-activiti的工程,然后引入下面的依赖。
1 | <dependency> |
另外Activiti需要使用到数据库,它支持Mysq、Oracle、Postgres等多种数据库,本课程选用常见的Mysql,因此还需要导入数据库驱动和Mybatis-Plus ORM依赖。
1 | <dependency> |
配置属性
配置属性就是指在application.yml或者bootstrap.yml文件中配置引入框架的常用属性,而在这里Activiti7的常用配置属性如下:
1 | spring: |
配置数据源:
注意:url中的nullCatalogMeansCurrent参数需要设置成true,表示Activiti优先在url中指定的数据库中检查是否有创建过表,如果为false,则会遍历整个数据源中的每个数据库,检查是否有创建过activiti的表。
1 | spring: |
并新创建一个数据库:hiss-dev-demo
配置Bean
在Activiti7中,它默认集成了SpringSecurity,内部还使用到了SpringSecurity系列的上下文代码,不能直接排除掉,因此在此还需要给定一些SpringSecurity的初始配置Bean。
其实往往我们不想使用SpringSecurity,这里就强制我们使用,显得非常臃肿、不优雅。那么在本项目中,将合理避开对SpringSecurity的使用,因此直接把SpringSecurity相关配置置空即可,既把下面的Bean拷贝到启动类中,什么都不用改:
- UserGroupManager:用于流程中获取用户的组、角色等信息
- SecurityManager:用于获取当前操作授权的用户、组或角色等信息
1 |
|
注意在这里可能会报错:
解决方法:
1.删除
2.增加启动配置以我们的bean为主
启动测试
到此,我们就完成了集成的主要工作,接下来就是先验证一下集成结果。针对Activiti7的集成验证,只需要启动服务,看看是否报错,是否创建成功表,如果控制台没有报错,并且数据库中也成功创建了表,那么就算集成成功了!
控制台:未报错,并且有输出创建表的日志
数据库:成功的创建了相关25张表,这些表我们稍后去给大家介绍,这里只关注是否创建成功。
第二步:画流程
项目集成完成Activiti7之后,就可以进行第二步,画流程了,在正式画之前,有必要给大家先介绍一下这里画涉及到的知识点BPMN。
BPMN介绍
BPMN:业务流程建模与标记语言(Business Process Model and Notation),是一种用于图形化表示和描述业务流程的标准化标记语言。目前主流的版本是BPMN2.0,由 Object Management Group(OMG)制定,并于2011年发布,发展至今,已被主流的流程引擎支持,并作为默认。
讲白了,BPMN和HTML类似都是标记语言,都是通过XML的格式来组织数据,供后端解析,也可转成图形化方式直观展示给用户看。
例:BPMN标准的流程文件内容:
1 |
|
转成直观的图:
BPMN设计器
虽然BPMN是一个标记语言,但是在实际中,我们很少直接去用它语法进行开发,而是直接使用流程设计器来画,而画用前端技术即可实现,在前端开源项目中有一个叫bpmn-js的开源项目,现在几乎成了画流程的标准,市面上的流程设计器基本都是基于它改造的。比如Activiti7官网提供的:https://github.com/activiti/activiti-modeling-app设计器,就是基于bpmn-js实现的。
但是因为其是英文版,使用习惯是按照西方人设计的,在使用体验上不好,因此在这里我们使用hiss产品中自研的设计器,也是基于bpmn-js实现的。它的面板介绍如下:
绘制《单人审批请假流程》
在BPMN2.0中定义了很多图例,也就是主键面板上的那些图标,每种图例表示着不同的含义,那么在本案例中,我们需要用到以下3种图例:
- 开始图例:表示一个流程的开始,一个流程可以有多个开始,但是至少需要一个开始图例
- 结束图例:表示一个流程的结束,一个流程可以有多个结束,但是至少需要一个结束图例
- 用户图例:也称用户任务,表示当前节点是需要人工参与的,比如需要人工审批、人工填写表单等
有了上面的了解,那么就可以开始绘制:开始节点和填写请假单节点:
(画的方式一:拖拉画)拖拉组件面板中的图例,到画图区中,并配置办理人和连线即可。
图中表示请假单由张三填写。
接着画经理审批和结束节点:
(画的方式二:快捷插入画)选中节点后,会在节点上弹出快捷操作,点击结束图例,即可快速在节点后面增加一个结束节点并自动连线。
图中经理审批节点的办理人为李四,表示张三填写的请假单由李四来审批。
解读BPMN的xml文件
通过上面的操作我们就画出了《单人审批请假流程》,接下来我们来了解一下BPMN2.0的xml文件内容,做一个大概了解。
点击右上角的【设计模式】即可切换到【源码模式】,看见类似下图的界面。界面中就是BPMN2.0的xml内容,可见包括的内容如下:
整个xml的根元素是definitions,它有两个子元素:
- 流程节点信息使用process元素定义
- 每种图例对应到xml中都是不同的元素,比如:
- 开始图例对应startEvent元素
- 结束图例对应endEvent元素
- 用户任务对应userTask元素
- 流程图中的线也是一种图例,对应sequenceFlow元素
- 每种图例元素都一个唯一id属性
- 在图中配置的办理人,其实是userTask元素的 activiti:assignee属性值- 流程展示的图形信息使用bpmndi:BPMNDiagram元素定义
第三步:保存流程图
到此画完的流程图,还需要保存到磁盘或者数据库中,不然刷新网页就丢失了。而Activiti7在数据库层面给我们已经设计好了相关的表和API,直接调用即可。
保存到磁盘
在磁盘任意位置,新建一个bpmn-01.xml文件,并把上一步画的流程图的xml保存到改文件中。
1 |
|
保存到数据库
创建测试类
在demo-activiti模块的test代码中新建ProcessSaveTest类,注意包名需要和启动类包名一致。
在新建的类中初始化下面的代码:
1 | package com.itcast.hiss; |
项目环境中自动导入了springboot的test依赖,所集成junit版本是5.8.2,支持一种参数化的测试(Parameterized Tests,简单理解就是测试的方法可以动态传参),这在企业中也是非常常用的一种写法,上述的代码就是参数化测试代码的一段实现:
- @ParameterizedTest 注解标注testSaveFromFile方法是一个参数化测试方法
- @ValueSource 注解标注要传给testSaveFromFile方法的参数值有那些,参数值的类型支持基本类型+String、Class
@ParameterizedTest不仅有标注的功能,还会依据@ValueSource的值的数量,动态为每个参数值生成一个测试案例:
例如:
1 |
|
传入了3个值,则生成了3个案例,在企业中常常用来测试一段代码在多种输入值的情况下执行结果是否正确:
代码实现&运行
在Activiti7中对于设计好的流程图,被称为模型(Model),保存代码实现参考以下,相关说明如下:
- RepositoryService是非常常用的API,主要用来管理(CRUD)和操作模型、发布、流程定义等资源;
- Model是一个接口不能直接new,其对应实现类是ModelEntityImpl,而repositoryService.newModel()方法正是返回一个新的ModelEntityImpl实例;
- 保存时,除了xml内容之外,还可以附加一些名称、分类等信息;
- 在Activiti7底层表设计原则是:所有大字段值都保存到一张表中,而Model的xml内容属于大字段,因此下面代码分别调用了saveModel(保存基本信息)和addModelEditorSource(保存大字段信息)方法;
- assertNotNull是junit的断言方法,主要用来判断方法执行的结果是否符合预期,在这里预期是:插入成功则model的id应该不为null
1 | package com.itcast.hiss; |
运行上述测试方法,出现下面情况,既模型数据就保存成功
表分析
在上述保存方法执行成功后,数据实际上保存到了数据库中的act_re_model和act_ge_bytearray表中。
act_re_model
act_re_model表是用于存储流程模型(就是流程图)信息的表:
| 序号 | 字段名 | 类型 | 长度 | 是否主键 | 注释 |
|---|---|---|---|---|---|
| 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_字段中。
| 序号 | 字段名 | 类型 | 长度 | 是否主键 | 注释 |
|---|---|---|---|---|---|
| 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对象中,这个过程也叫部署,最后就可以运行部署的流程,同时也支持运行多个流程实例。
一个流程图(模型)画好之后,需要发布(部署)之后才可以运行,这样的好处在于,流程图部署运行后,在去修改,不会影响到正在执行中的流程,是一种非常优秀的设计思想,具体实现呢,同学们也可以好好学习一下。
创建测试类
在demo-activiti模块的test代码中新建ProcessRunTest类,注意包名需要和启动类包名一致。
在新建的类中初始化下面的代码:
1 | package com.itcast.hiss; |
部署实现
为避免画流程图时对运行流程影响,在部署时需要把画好的流程图复制一份到部署信息中这也是下面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 | package com.itcast.hiss; |
运行上述testDeployment方法,出现下面情况,既部署成功
运行上述testRun方法,出现下面情况,既运行成功
部署表分析
在上述部署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
act_re_model:表中DEPLOYMENT_ID_字段也存储了部署ID
act_re_deployment
act_re_deployment表是用于存储部署流程图信息:
| 序号 | 字段名 | 类型 | 长度 | 是否主键 | 注释 |
|---|---|---|---|---|---|
| 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表用于存储流程图中解析得到的流程信息:
| 序号 | 字段名 | 类型 | 长度 | 是否必填 | 注释 |
|---|---|---|---|---|---|
| 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
act_ru_identitylink表用于存储资源(比如:流程定义、流程实例、任务等资源)授权信息,拥有授权信息才可以使用对应资源:
这条数据可以理解为:ID为XXX的流程定义被授权给任意分组使用,既没有使用限定。
| 序号 | 字段名 | 类型 | 长度 | 是否主键 | 注释 |
|---|---|---|---|---|---|
| 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 | package com.itcast.hiss; |
运行表分析
- 任务实例:就是流程图中的每个需要人工参与的节点
- 流程实例:流程定义运行起来的流程被称为流程实例
- 活动实例:就是流程图中的每个节点
- 执行器:记录当前执行节点的信息
对部署好的流程图运行之后,得到流程实例(ProcessInstance),这个运行中的流程实例信息存储到了act_ru_identitylink、act_ru_execution、act_ru_task表中。
act_ru_identitylink:多出了一条记录,是因为我们启动流程后,开始节点会自动执行并到下一个节点既【填写请假单】,而请假单需要张三这个参与人来办理,因此在此表中就多出一条记录,表示流程实例ID为XXX的流程授权给张三操作。
这里通过观察我们还可发现,在之前设计流程图中,还有一步李四【经理审批】,而此表中没有出现李四的授权信息,则说明流程执行到那个节点才会在此表中添加授权信息。
act_ru_execution
act_ru_execution用于存储运行中流程的节点信息。不仅存储流程实例信息,还存储流程实例的待执行节点信息。
刚才运行的流程实例,首选会在此表中创建一条流程实例信息(特点:PARENT_ID_字段为空),比如下图中的第1行数据。接着流程流转到【填写请假单】节点,因此在此表中还创建了一条待执行节点的信息,比如下图中的第2行数据。我们也可以通过ACT_ID_字段值与xml中节点元素的ID值比对印证。
同时我们通过观察还可以发现,在之前设计流程图中,还有一步李四【经理审批】,而此表中没有出现相关节点信息,则说明流程执行到那个节点才会在此表中添加节点信息。
| 序号 | 字段名 | 类型 | 长度 | 注释 |
|---|---|---|---|---|
| 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用于存储需要办理的任务信息。
在刚才运行的流程中,【填写请假单】节点需要张三办理,因此在此表中可以查到相关信息。另外在此表我们还是可以发现未执行节点,不会在此表中创建任务。
| 序号 | 字段名 | 类型 | 长度 | 注释 |
|---|---|---|---|---|
| 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类,注意包名需要和启动类包名一致。
在新建的类中初始化下面的代码:
1 | package com.itcast.hiss; |
完成填写请假单任务
在上面运行的流程实例中,流程实例正等待填写请假单,那么假设我们此时填写完成了请假单,想继续下一步审批,该怎么办呢?
其实这个需求Activiti提供了相关API,可以直接标注某个任务执行完成,然后流程自动到下一步,相关实现代码如下:
- TaskService:是一个常用的API,主要用来对任务进行各种操作
- 调用complete方法,即可结束当前节点,并且流程会自动开启下一个节点的任务。同时在结束时还可以把填写的表单数据,作为流程变量(这些流程变量,后续再去讲解如何使用)。
1 |
|
执行上面testCompleteNode2方法后,可以在act_ru_execution表中发现,新增了【经理审批】待执行的节点,而完成的【填写请假单】节点被删除了。
同时在act_ru_task表中,待办任务也变成了李四【经理审批】:
代码中传入的表单数据,同时也作为流程变量存储到了act_ru_variable表中(详细字段含义,后续讲解)。
经理同意
关于经理同意操作的实现,如果我们把【同意】看做是经理填写的【审批表单(包括:审批结果、审批意见)】中的一个字段,那么其实现和完成填写请假单任务的实现差不多,经理点击同意之后也需要完成当前节点执行下一结束节点。
则同意操作的实现代码如下:
- 调用complete方法时,把同意作为表单数据传入,也作为了流程变量数据。
1 | /** |
上述代码执行成功后,到数据库中查看act_ru_execution、act_ru_task、act_ru_variable中的数据,你会发现里面没有了相关流程实例的数据,那是因为【经理审批】节点执行完成之后,后面的结束节点也会自动执行,因此流程就执行完成了。而act_ru_开头的表只存储运行中的流程信息,不会存储流程结束了的信息,结束了的相关信息都转到act_hi开头的表中存储了,相关表稍后我们再去认识。
经理不同意
经理不同意和同意都是审批操作,那么不同意的实现就和同意的实现一样?不然,在这里不同意的需求要比同意的复杂一点,不同意则流程会终止执行。比如下面流程中,如果经理1审批不同意,那么经理2就不用审批了,整个流程就应该直接结束。因此不同意,则应该是终止流程而不是完成节点。
综上需求所述,则不同意的实现代码如下:
- 在这里,要终止流程,因此操作的是流程实例,因此使用的是runtimeService API,这里用到的是流程实例的ID,不是任务ID
- 在删除流程时,同时也把审批不同意及理由,作为流程变量存储到流程变量中
1 | /** |
要运行上面代码,我们需要重新发起一个流程实例,并完成【填写请假单】节点后,再实现,具体操作:
- 直接运行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用于存储运行中流程的变量信息。
| 序号 | 字段名 | 类型 | 长度 | 注释 |
|---|---|---|---|---|
| 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:活动与任务的区别:流程图中每个节点都被称为活动,但是并不是所有活动在流程实现执行过程中都会创建任务,比如开始节点就不会任务。
| 序号 | 字段名 | 类型 | 长度 | 是否主键 | 注释 |
|---|---|---|---|---|---|
| 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表记录了整个流程运行过程中,对流程变量、表单数据、备注等操作的操作明细。被称为流程运行明细表。
| 序号 | 字段名 | 类型 | 长度 | 是否主键 | 注释 |
|---|---|---|---|---|---|
| 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_hi_identitylink比act_ru_identitylink表少了一个REV_字段,其它字段都一样。
| 序号 | 字段名 | 类型 | 长度 | 是否主键 | 注释 |
|---|---|---|---|---|---|
| 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表一样存储。
| 序号 | 字段名 | 类型 | 长度 | 是否主键 | 注释 |
|---|---|---|---|---|---|
| 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任务信息。
| 序号 | 字段名 | 类型 | 长度 | 是否必填 | 注释 |
|---|---|---|---|---|---|
| 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_两个字段。
| 序号 | 字段名 | 类型 | 长度 | 注释 |
|---|---|---|---|---|
| 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 | 更新时间 |



























































