vlambda博客
学习文章列表

工作流引擎之activiti会签逻辑实现

什么是会签任务?

使用工作流的时候有时会遇到这样的一种情况就是一个任务需要几个人一起审批,人数不定。这时常规的用户任务就无法满足要求,我们称这种任务为会签任务。

何如利用activiti实现会签?

百度来的大多数的例子,大多数是利用多实例来实现,其BPMN文件格式形如下:

 
   
   
 
  1. <userTask id="usertask2" name="领导审批" activiti:assignee="${leader}">

  2.      <extensionElements>

  3.        <activiti:taskListener event="complete" class="com.demo.activiti.SignTaskListener"></activiti:taskListener>

  4.      </extensionElements>

  5.      <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="${leaderList}" activiti:elementVariable="leader">

  6.        <completionCondition>${nrOfCompletedInstances/nrOfInstances == 1}</completionCondition>

  7.      </multiInstanceLoopCharacteristics>

  8.    </userTask>

【说明】:

1、isSequential=”false” 表示这是非串行会签,即为并行会签,如三个人参与会签,是三个人同时收到待办,任务实例是同时产生的。

2、activiti:collection 表示是会签的参与人员集合,用户可以通过定义自身的服务类来获取

3、completionCondition 表示是任务往下跳转的完成条件,返回true是,表示条件成立,流程会跳至下一审批环节。

我们根据配置这些条件,进行会签逻辑开发。我一开始也是用这种方式进行开发,后面发现挖坑了,activiti多实例它一开始就初始化好跟activiti:collection个数相同的task,后续无法做到任意加人会签,activiti可能有提供实现,是我用的姿势不对。而且一个审批流程还涉及退回、召回等审批业务逻辑,如果对于新入门activiti的工作流的程序员来说,在没那么多时间研究情况下,工期又那么紧,无异于雪上加霜。

基于上面的种种弊端,后面我决定脱离activiti的多实例方案,自己通过设计扩展表配合activiti提供的一些入门级别的api的方案实现会签功能,用自己熟悉的方式填补预防一些未知的坑点。我设计了2张表,act_re_sign_ext和act_hi_vars_sign_ext

act_re_sign_ext

会签扩展信息表,主要存放会签Task任务的一些基本信息,参与会签的总用户ID以及总个数,以及完成的会签任务个数和会签用户ID

 
   
   
 
  1. CREATE TABLE `act_re_sign_ext` (

  2.  `ID` varchar(32) NOT NULL COMMENT '主键',

  3.  `PROC_DEF_ID` varchar(64) DEFAULT NULL COMMENT '流程定义主键',

  4.  `TASK_DEF_KEY` varchar(64) DEFAULT NULL COMMENT '流程任务KEY',

  5.  `PROC_INST_ID` varchar(64) DEFAULT NULL COMMENT '流程实例KEY',

  6.  `EXECUTION_ID` varchar(64) DEFAULT NULL COMMENT '流程运行主键',

  7.  `NAME` varchar(255) DEFAULT NULL COMMENT '流程节点名称',

  8.  `NR_OF_INSTANCES_USER_IDS` varchar(5000) DEFAULT NULL COMMENT '会签签用户列表,多个用,隔开',

  9.  `NR_OF_INSTANCES` int(11) DEFAULT NULL COMMENT '会签总用户数',

  10.  `NR_OF_COMPLETED_INSTANCES_USER_IDS` varchar(5000) DEFAULT NULL COMMENT '已经完成的会签签用户,多个用,隔开',

  11.  `NR_OF_COMPLETED_INSTANCES` int(11) DEFAULT NULL COMMENT '已经完成的会签签用户数',

  12.  `TENANT_ID` varchar(32) DEFAULT NULL COMMENT '域名',

  13.  `CREATE_TIME` datetime DEFAULT NULL COMMENT '创建时间',

  14.  `OPERATOR` varchar(64) DEFAULT NULL COMMENT '操作人',

  15.  `UPDATE_TIME` datetime DEFAULT NULL COMMENT '更新时间',

  16.  PRIMARY KEY (`ID`)

  17. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

通过NR_OF_INSTANCES和NR_OF_COMPLETED_INSTANCES作为跳转下一步审批的条件,比如完成个数超过60%作为执行跳转下一步审批节点的步骤,则NR_OF_COMPLETED_INSTANCES/NR_OF_INSTANCES > 60%,如果符合条件执行taskService.complete(task.getId(), variables);完成任务

act_hi_vars_sign_ext

会签参数扩展信息表,主要用来存放一些会签task任务信息和已经审批的会签task流转状态,为什么会设计这样一张表,是因为我们扩展的会签表的审批过程中,其他会签用户在activiti的历史流转表是找不到的,而我们页面需要展示这些用户审批信息

 
   
   
 
  1. CREATE TABLE `act_hi_vars_sign_ext` (

  2.  `ID` varchar(32) NOT NULL COMMENT '主键',

  3.  `PROC_DEF_ID` varchar(64) DEFAULT NULL COMMENT '流程定义主键',

  4.  `TASK_DEF_KEY` varchar(64) DEFAULT NULL COMMENT '流程任务KEY',

  5.  `PROC_INST_ID` varchar(64) DEFAULT NULL COMMENT '流程实例KEY',

  6.  `EXECUTION_ID` varchar(64) DEFAULT NULL COMMENT '流程运行主键',

  7.  `NAME` varchar(255) DEFAULT NULL COMMENT '流程节点名称',

  8.  `COMMENT` varchar(5000) DEFAULT NULL COMMENT '评论',

  9.  `ASSIGNEE` varchar(255) DEFAULT NULL COMMENT '办理人',

  10.  `TENANT_ID` varchar(32) DEFAULT NULL COMMENT '域名',

  11.  `CREATE_TIME` datetime DEFAULT NULL COMMENT '创建时间',

  12.  `TASK_ID` varchar(64) DEFAULT NULL COMMENT '任务主键',

  13.  `END_TIME` datetime DEFAULT NULL COMMENT '结束时间',

  14.  `TASK_STATUS` int(1) DEFAULT NULL COMMENT '审批状态,0、进行中,1、同意,2、退回,3、召回,4、拒绝,6、委托',

  15.  `SHOW_SIGN` int(1) DEFAULT '1' COMMENT '是否显示会签标识,1、是,0、否',

  16.  `IS_DELETED` int(1) DEFAULT '0' COMMENT '删除标记,0未删除,1删除',

  17.  PRIMARY KEY (`ID`)

  18. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

通过act_hi_vars_sign_ext和activiti自带的ACT_HI_ACTINST的表关联实现完整的用户审批列表展示,如果不想用表关联,也可以用historyService.createHistoricActivityInstanceQuery()查出activiti的历史任务流转信息,再查出扩展参数信息列表,再按完成时间排序,再渲染到列表展示

总结

现在很多框架基本上都是开箱即用,上网一找都有一堆例子,但并非所有例子都适用我们,有时候可以试着转换点思路,而非一定要用大家觉得非常厉害的技术,合适原则优先,技术是为业务服务,不要为了技术而技术