一、概述
最近做一个项目用到了审批流,在网上找了一下,activity还是比较好用,对其简单整理,主要内容包括组件引入,审批流创建,代码开发等功能
二、引入Activity
通过gradle和maven都可引入activity,gradle的引入方式如下:
implementation("org.activiti:activiti-engine:7.1.0.M6")
implementation("org.activiti:activiti-spring:7.1.0.M6")
即使用其7.1.0.M6版本,通过maven的方式如下:
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>7.1.0.M6</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>7.1.0.M6</version>
</dependency>
只要依赖能下载下来,则引入就是成功的
三、创建流程文件
我们首先要创建一个流程文件,才能在后续的过程中使用这个文件,actiivity7据说是有一个在线的工具,不过不是太会用,这里使用的是eclipse的插件,要注意的是eclipse不能使用最新版本,根据官方的介绍,kepler 版本是可以的,这个不做过多介绍,eclipse的插件虽然已经不再维护了,但老版本也还是可以使用的,其效果如下:
对于每个任务节点来说,可以在Main config里配置审批人变量,在创建流程时对变量设置值。
四、创建流程表并初始化流程
actiivity的数据也是通过表来存储的,所以使用之前还需要建表,当然这个要先进行数据源配置,actiity的配置文件默认为actiity.cfg.xml,示例配置如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<property name="jdbcUrl" value="${yourJdbcUrl}" />
<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
<property name="jdbcUsername" value="${yourUsername}" />
<property name="jdbcPassword" value="${yourPassword}" />
<property name="databaseSchemaUpdate" value="true" />
<property name="asyncExecutorActivate" value="false" />
</bean>
</beans>
系统初始化的时候,要先进行建表,示例代码如下:
public class ActivityConnectionDB {
public static void main(String args[]){
//获取流程引擎配置
ProcessEngineConfiguration pec = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
//设置自动创建表和更新表
pec.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
//构建流程引擎,即获取流程引擎对象
ProcessEngine pe=pec.buildProcessEngine();
}
}
建好之后,系统里应该会有25张表,都是以ACT开头的,如下:
这个表又可以按前缀分为几类,这里以一个学生提交审批的简单流程为例进行介绍,介绍之前,要先对流程进行初始化,示例代码如下:
private static void deploy(ProcessEngine pe, String processName, String desc){
//获取流程引擎配置
DeploymentBuilder builder = pe.getRepositoryService().createDeployment();
builder.addClasspathResource("bpmn/" + processName + ".bpmn")
.name(desc)
.category("就业")
.addClasspathResource("bpmn/" + processName + ".png");
builder.deploy();
}
这样流程数据将会在相关表里保存。
1、ACT_RE_*:
’RE’表示repository(存储),RepositoryService接口所操作的表。带此前缀的表包含的是静态信息,如,流程定义,流程的资源(图片,规则等)。
从上面的截图看,一共有三张表,分别如下:
1)act_re_deployment:部署信息表,表示一个流程的静态定义,示例:
每部署一个流程,这个表里就会有流程的定义,它保存了流程名和ID
2)act_re_model 流程设计模型部署表,这个表可以为空,暂不清楚什么样的情况下会有数据
3)act_re_procdef 流程定义数据表,包含了流程的定义信息,如流程定义时的ID等,示例如下:
可以看到这张表中的deployment_id_引用的id正是act_re_deployment中的id
2、ACT_GE_*:
全局通用数据及设置(general),各种情况都使用的数据。从上图可以看到一共有两张表
1)act_ge_bytearray: 二进制数据表,存储流程定义的文件及图片的二进制形式
两条记录,一条存储流程文件,一条存储图片,有需要时,可以读出来
2)act_ge_property:流程引擎的全局属性,这个与具体某个流程无关,属于配置信息,固定4条:
3、ACT_RU_*:
‘RU’表示runtime,运行时表-RuntimeService。这是运行时的表存储着流程变量,用户任务,变量,职责(job)等运行时的数据。Activiti只存储实例执行期间的运行时数据,当流程实例结束时,将删除这些记录。这就保证了这些运行时的表小且快。
相关示例后面给出
4、ACT_HI_*:
’HI’表示history,历史数据表,HistoryService。就是这些表包含着流程执行的历史相关数据,如结束的流程实例,变量,任务,等等
相关示例后面给出。除此之外还有两个表,介绍如下:
5、ACT_EVT_LOG:流程引擎事件表,目前无记录
6、ACT_PROCDEF_INFO:流程动态信息表,目前无记录
五、启动流程并审批
这里我们把启动和审批放在一起,以便于对表的分析,代码如下:
ProcessEngine pe = ProcessEngines.getDefaultProcessEngine();
ProcessInstance processInstance =
pe.getRuntimeService().startProcessInstanceByKey(applying.getProcess(), paramMap);
//完成第一个节点
Task task = pe.getTaskService()
.createTaskQuery().taskAssignee(firstAssignee).singleResult();
if(task != null) {
pe.getTaskService().complete(task.getId(), paramMap); //完成
}
这样就创建了一个流程实例,并完成了第一个节点的审核,根据前面的介绍,这个数据在act_ru相关表中存在,先看来看这些表:
1、ACT_RU_*:
这个系列下表示实时任务,有10张表,介绍如下:
1)ACT_RU_DEADLETTER_JOB : 作业死信表-作业失败超过重试次数,正常情况下,不会有数据
2)ACT_RU_EVENT_SUBSCR:运行时事件监听,如果没有事件,这个也为空
3)ACT_RU_EXECUTION:运行时流程执行实例表,在启动一个流程并完成一个节点之后,可以看到本表数据如下:
从表的定义来看,这里第一条记录为流程实例,第二条记录表示当前待执行的节点,可以看到是departmentApprove,表示学院审核,但为什么没有第一个节点的信息呢,因为节点1已经完成,被删除了。
4)ACT_RU_IDENTITYLINK: 运行时人员流程表,数据如下:
U002表示当前待审批人员
5)ACT_RU_INTEGRATION:这个表应该是activity7新增的,没有数据,暂时不清楚其用途
6)ACT_RU_JOB:运行时定时任务数据表,没有定时任务这个也是空的
7)ACT_RU_SUSPENDED_JOB:运行时作业暂停表,通常也为空
8)ACT_RU_TASK:运行时任务,存储当前待处理的任务,这个比较重要,同样完成之后就会删除,数据如下:
execution_id表示要执行哪个流程,assignee表示应该由谁来执行
9)ACT_RU_TIMER_JOB : 运行时定时器作业表,这个也没用到
10)ACT_RU_VARIABLE:运行时变量表,存储实际运行时,可以使用哪些变量
从上表可以看出来任务112501时,可以使用两个变量,值都为U002,用来定义审批人。流程112504没有对应的变量
2、ACT_HI_*:
本系列下一共有8张表,介绍如下:
1)ACT_HI_ACTINST:历史的活动节点表,这个表记录了流程的审批节点历史,介绍如下:
从这个表里可以看到审批人,节点名,开始与结束时间,持续时间等
2)ACT_HI_ATTACHMENT:历史的流程附件,本例无记录
3)ACT_HI_COMMENT:历史的说明性信息,本例也没有记录
4)ACT_HI_DETAIL:历史的流程运行中的细节信息,本例也无记录
5)ACT_HI_IDENTITYLINK:历史的流程运行过程中用户关系,这个和ACT_RU_IDENTITYLINK 相对应
6)ACT_HI_PROCINST:历史的流程实例,记录之前发生的流程
因为流程在结束后会删除掉,所以要查历史流程只能在这里查
7)ACT_HI_TASKINST:历史的任务实例
前面是历史节点信息,本表为历史任务信息,同样记录了任务的开始,结束,持续时间,如果是查流程,这个更为合理。
8)ACT_HI_VARINST:历史的流程运行中的变量信息
从上表可以看到流程节点112501有两个变量。
六、审批与打回
activity 只有审批的动作,没有打回的动作,想要打回,要么自己通过复杂的代码实现,要么就是通过流程图中加判断条件来控制,不同分支上加不同变量,比如本例就是如此,相关设计如下:
如上图,在处理本任务节点时,如果想实现打回的效果,传入变量flag的值为0,其它值为通过。
审批方法如下:
public boolean approve(String actProcessId, ApproveAction approveAction,
String reason, String userId,Map<String, Object> paramMap) {
ProcessEngine pe = ProcessEngines.getDefaultProcessEngine();
Task task = pe.getTaskService()
.createTaskQuery()
.taskAssignee(userId)
.processInstanceId(actProcessId)
.singleResult();
if(task == null) {
logger.warn("没有找到{}的审批任务", userId);
return false;
}
int flag = approveAction == ApproveAction.PASS ? 1 : 0;
paramMap.put("reason", reason);
paramMap.put("flag", flag);
pe.getTaskService().complete(task.getId(), paramMap);
return true;
}
我们先试一下打回之后,再看下数据的变化,通过对前面的分析,我们主要关注ru和hi的几个表:
ru表的变化如下:
ACT_RU_EXECUTION
可以看到执行流程已经变为提交人了,原学院审批人节点完成后,已经删除了
ACT_RU_IDENTITYLINK
这个和原来没变化,因为审批人都是同一个
ACT_RU_TASK
待执行任务表,已变成第一个任务了
ACT_RU_VARIABLE
这个表里增加了两个变量,看来变量是流程级别的?
再来看来历史表的变化
ACT_HI_ACTINST
可以看到各个节点都记录了,exclusivegateway1 表示选择节点,虽然没有审核,但也记录了
ACT_HI_IDENTITYLINK
这个没变化,另外 ACT_HI_PROCINST 表示历史流程,因为没结束,所以也没变化
ACT_HI_TASKINST
这个保存了所有任务
ACT_HI_VARINST
这个保存了所有变量
七、流程结束
结束并没有特别的动作,只要流程走完end节点之后就结束了。本例中,再次提交审核,这次选择通过,就可以实现结束。这里我们看下结束后,表的变化,由于ACT_RU的都已经结束,所以这里只分析ACT_HI,即历史表,各表情况如下:
再来看来历史表的变化
ACT_HI_ACTINST
可以看到所有节点都记录了
ACT_HI_IDENTITYLINK:无变化
ACT_HI_PROCINST :可以看到已经有结束时间了
ACT_HI_TASKINST
可以看到所有的审批节点
ACT_HI_VARINST
这个保存了所有变量信息。但这些变量看起来和任务并不关联
八、展示审批节点
通过分析,我们可以看到如果要展示审批节点,可以根据实例ID查 ACT_HI_TASKINST表,但该表中未记录审批动作是通过还是驳回,且也无法通过关联变量来实现。所以,只能考虑把这些信息在审批时就加到这个表里,看了下结构,description_是可以来记录这个信息的,字段类型为4000个varchar, 应该说足够了,剩下就是怎么放的问题。这个可以直接save。相当于是自定义一个json字符串放到description_里,取出来时再解析。
不过在网上查资料时,发现了一个更好的方式,就是加批注,这个对应ACT_HI_COMMENT,不仅如此,如果我们希望审批节点时存一些文件,也可以使用ACT_HI_ATTACHMENT。这就完美解决了问题。
示例代码如下:
if(task != null) {
pe.getTaskService().addComment(task.getId(),
processInstance.getProcessInstanceId(),
ApproveAction.COMMIT.toString(),
assignee.getName() + "|" );
pe.getTaskService().complete(task.getId(), paramMap);
}
这里没有单独放审批人名字的字段,所以将其放在理由里,显示时,再解析。该表中的数据如下:
那么结合ACT_HI_TASKINST,显示审批记录将是一件非常容易做到的事。
九、结语
本文对activity中的简单用法做了分析,重点介绍了其关键表结构,并结合实例进行了演示和数据分析,相信读完本文,会对activity的功能有较好的理解