1.概述

我们知道,activiti是一个不错的流程引擎,它有自身的人员组织架构,但仅限于用户、用户组的管理,流程产生的任务(UserTask),就涉及到任务的所属人(Owner),任务的执行人(assignee),还有任务的候选人、候选用户等。而在中国的流程业务需求里,仅靠这块的人员查找是没有办法满足目前的业务需求的。举个请假流程的例子,其流程如下所示:

【说明】:其中上级主管、及所在部门的领导都跟发起人所有的组织架构有关,这种查找算法可以理解为汇报线的查找处理。另外在国内的流程处理方案中,还存在一些如其他业务的人员查找算法。因此,我们一般都是需要使用我们的业务的组织架构来实现流程的处理。

2.让Activiti引擎挂接自身的组织架构

要实现流程中的与组织架构有关的整合,我们需要先了解一下目前在哪些业务需求上使用了组织架构的需求,在我们以往的大量实施国内的业务流程的基础上,我们总结有以下几点:

  1. 任务的执行人员的分配
  2. 任务的代理
  3. 任务的通知
  4. 流程启动的权限

而Activiti在流程引擎与组织架构的整合过程中,只有第一项跟组织架构是有关的,其他的方面只需要通过我们自身的扩展表来实现即可。

2.1 任务的处理人分配

2.1.1. activiti中对与人员的组织挂接的默认处理

在Activiti中,跟组织架有关的只有以下几个表,我们把它的表结构展示如下:

CREATE TABLE `act_ru_task` (
`ID_` varchar(64) COLLATE utf8_bin NOT NULL DEFAULT '',
`REV_` int(11) DEFAULT NULL,
`EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,
`PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,
`PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,
`NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`PARENT_TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,
`DESCRIPTION_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,
`TASK_DEF_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`OWNER_` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`ASSIGNEE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`DELEGATION_` varchar(64) COLLATE utf8_bin DEFAULT NULL,
`PRIORITY_` int(11) DEFAULT NULL,
`CREATE_TIME_` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`DUE_DATE_` datetime(3) DEFAULT NULL,
`CATEGORY_` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`SUSPENSION_STATE_` int(11) DEFAULT NULL,
`TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '',
`FORM_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`CREATE_BY_` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '创建人ID',
`UPDATE_BY_` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '更新人ID',
`UPDATE_TIME_` datetime DEFAULT NULL COMMENT '更新时间',
`SOL_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '业务解决方案ID',
`AGENT_USER_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '代理人ID',
PRIMARY KEY (`ID_`),
KEY `ACT_IDX_TASK_CREATE` (`CREATE_TIME_`),
KEY `ACT_FK_TASK_EXE` (`EXECUTION_ID_`),
KEY `ACT_FK_TASK_PROCINST` (`PROC_INST_ID_`),
KEY `ACT_FK_TASK_PROCDEF` (`PROC_DEF_ID_`),
CONSTRAINT `ACT_FK_TASK_EXE` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`),
CONSTRAINT `ACT_FK_TASK_PROCDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`),
CONSTRAINT `ACT_FK_TASK_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `act_ru_execution` (`ID_`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; CREATE TABLE `act_ru_identitylink` (
`ID_` varchar(64) COLLATE utf8_bin NOT NULL DEFAULT '',
`REV_` int(11) DEFAULT NULL,
`GROUP_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,
`PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,
`PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`ID_`),
KEY `ACT_IDX_IDENT_LNK_USER` (`USER_ID_`),
KEY `ACT_IDX_IDENT_LNK_GROUP` (`GROUP_ID_`),
KEY `ACT_IDX_ATHRZ_PROCEDEF` (`PROC_DEF_ID_`),
KEY `ACT_FK_TSKASS_TASK` (`TASK_ID_`),
KEY `ACT_FK_IDL_PROCINST` (`PROC_INST_ID_`),
CONSTRAINT `ACT_FK_ATHRZ_PROCEDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`),
CONSTRAINT `ACT_FK_IDL_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `act_ru_execution` (`ID_`),
CONSTRAINT `ACT_FK_TSKASS_TASK` FOREIGN KEY (`TASK_ID_`) REFERENCES `act_ru_task` (`ID_`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

【说明】其中act_ru_task中的owner,assignee为任务的所属人与执行人,而act_ru_identitylink为任务的人员关联表,里面的字段,groupId为用户组Id,userId为用户Id,taskId为关联的任务Id,type为用户参与任务的类型。

若我们为了更加简化人员对任务的参与算法,可以不需要act_ru_identitylink表,进而扩展自己的参与表,不过这个表从目前来说是可以满足我们对任务的人员计算需求的。

2.1.2.任务的人员授予

如何通过activiti原生的api来实现人员的授予?首先我们来说授予的时机,activiti的任务产生是在流程的状态跳至某个任务节点时,其会产生一条记录至act_ru_task表中,这时我们需要在其产生的时候,通过流程定义的人员配置属性,结合自身的组织架构及业务查找(如汇报线)计算出参与该任务的人与组,从而把任务分配给这些用户。另外是任务手工进行分配授权。
我们来说第一种,任务产生时进行人员授权

activiti提供了任务的创建事件,所以我们可以在它的这个事件上定义一个监听即可,如何配置这个监听,请参考我们另一个文章

Activiti的事件机制及其监听处理

关于activiti的全局事件定义,我们只需要定义以下任务创建监听器(TaskCreateListener),并且获得任务的实体对象TaskEntity,通过setAssignee及setOwner改变任务的执行人、任务的所属人即可。

taskEntity.setAssignee(nodePath.getAssignee());
taskEntity.setOwner(userId);
taskEntity.addCandidateUsers(Arrays.asList(uIds));
taskEntity.addCandidateGroup(identityInfo.getIdentityInfoId());

现在来说另一种:任务产生时进行任务手工分配

这种方式就需要通过taskService以下api实现即可

2.2.扩展自身的人员查找架构

流程的节点的人员配置很难提供一组通用的配置规则以实现用户的查找,因为,我们只为节点的人员查找设置config的属性配置,开发用户则根据这些配置实现对应的定义分类,并且实现自己的流程查找方式。

流程的配置方式如下所示:

我们提供一个总的人员计算分类,以使得我们在流程节点的人员配置中可以显示如下的人员配置分类列表:

package com.redxun.bpm.core.identity.service;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map; import org.springframework.beans.factory.InitializingBean; /**
* 实体类型分类服务类
* @author csx
*
*/
public class IdentityTypeService implements InitializingBean{
//流程任务人员计算服务类映射
private Map<String, IdentityCalService> identityCalServicesMap=new LinkedHashMap<String, IdentityCalService>();
//程任务人员计算服务类
private List<IdentityCalService> identityCalServices=new ArrayList<IdentityCalService>(); @Override
public void afterPropertiesSet() throws Exception {
for(IdentityCalService service:identityCalServices){
identityCalServicesMap.put(service.getTypeKey(), service);
}
} public List<IdentityCalService> getIdentityCalServices() {
return identityCalServices;
} public void setIdentityCalServices(List<IdentityCalService> identityCalServices) {
this.identityCalServices = identityCalServices;
} public Map<String, IdentityCalService> getIdentityCalServicesMap() {
return identityCalServicesMap;
} }
同时以根据流程的节点配置,实现用户的信息计算,以获得人员配置的信息,由用户根据这个人员的配置实现人员的查找,其接口的定义如下:
import java.util.Collection; import com.redxun.org.api.model.IdentityInfo; /**
* 任务人员计算服务接口类
* @author mansan
*
*/
public interface IdentityCalService {
//人员计算类型
public String getTypeKey();
//人员计算名称
public String getTypeName();
//人员计算描述
public String getDescp(); /**
* 计算节点返回的人员实体
* @param idCalConfig
* @return
*/
public Collection<IdentityInfo> calIdentities(IdentityCalConfig idCalConfig);
}
其中用户组的配置及人员查找如下所示:
package com.redxun.bpm.core.identity.service; /**
* 抽象的实体计算服务类
* @author csx
*
*/
public abstract class AbstractIdentityCalService implements IdentityCalService {
//分类Key
protected String typeKey;
//分类名称
protected String typeName;
//分类描述
protected String description;
//处理的类名
protected String handlerClass; public String getTypeKey() {
return typeKey;
} public void setTypeKey(String typeKey) {
this.typeKey = typeKey;
}
public String getTypeName() {
return typeName;
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
} @Override
public String getDescp() {
return this.description;
} }
package com.redxun.bpm.core.identity.service.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import javax.annotation.Resource; import org.apache.commons.lang3.StringUtils; import com.redxun.bpm.core.identity.service.AbstractIdentityCalService;
import com.redxun.bpm.core.identity.service.IdentityCalConfig;
import com.redxun.core.constants.MBoolean;
import com.redxun.org.api.model.IdentityInfo;
import com.redxun.saweb.context.ContextUtil;
import com.redxun.sys.org.entity.OsGroup;
import com.redxun.sys.org.entity.OsRelType;
import com.redxun.sys.org.entity.OsUser;
import com.redxun.sys.org.manager.OsGroupManager;
import com.redxun.sys.org.manager.OsRelTypeManager;
import com.redxun.sys.org.manager.OsUserManager;
/**
* 用户组计算
* @author mansan
*
*/
public class GroupCalServiceImpl extends AbstractIdentityCalService{
@Resource
private OsGroupManager osGroupManager;
@Resource
private OsRelTypeManager osRelTypeManager;
@Resource
private OsUserManager osUserManager; @Override
public Collection<IdentityInfo> calIdentities(IdentityCalConfig idCalConfig) {
OsRelType osRelType=osRelTypeManager.getBelongRelType();
//是否需要计算用户
boolean isCalUsers=MBoolean.YES.name().equals(idCalConfig.getIsCalUser()); List<IdentityInfo> identityList=new ArrayList<IdentityInfo>();
//获得流程的节点配置信息,并且根据节点获得用户或组
String jsonConfig=idCalConfig.getJsonConfig();
if(StringUtils.isNotEmpty(jsonConfig)){
String[] groupIds=jsonConfig.split("[,]");
for(String gId:groupIds){
if(isCalUsers){//计算用户
List<OsUser> users=osUserManager.getByGroupIdRelTypeId(gId, osRelType.getId());
identityList.addAll(users);
}else{//仅计算其用户组
OsGroup osGroup=osGroupManager.get(gId);
if(osGroup!=null){
identityList.add(osGroup);
}
}
}
}
return identityList;
} }

2.3.自定义查找我的待办

虽然TaskService有提供按人员的查找任务API,但从我的个人来看,那些是不能满足我们的查找算法的,因此,很有必要自定义查找我的任务列表。查找无非是按Activiti的act_ru_task表来查,若结合了用户对应的用户组,还需要结合act_ru_identitylink来查找。这块看你的底层的数据库访问的采用是什么ORM框架,在JSAAS中,我们的界面如下,提供按时间、事项名称、状态等来查找我的待办列表,并且分页返回,其界面如下:

其查找的自定义Sql如下所示:

<!-- 按用户及条件查找待办列表 -->
<select id="getByUserIdRelTypeId" parameterType="java.util.Map" resultMap="BpmTask">
SELECT V.* FROM(
SELECT T.* FROM ACT_RU_TASK T WHERE T.ASSIGNEE_=#{userId}
UNION
SELECT T.* FROM ACT_RU_TASK T LEFT JOIN ACT_RU_IDENTITYLINK I ON T.ID_=I.TASK_ID_ WHERE I.USER_ID_=#{userId} AND I.TYPE_='candidate' AND T.ASSIGNEE_ IS NULL
UNION
SELECT T.* FROM ACT_RU_TASK T,ACT_RU_IDENTITYLINK I,OS_REL_INST R WHERE T.ASSIGNEE_ IS NULL AND T.ID_=I.TASK_ID_ AND I.GROUP_ID_=R.PARTY1_ and R.PARTY2_=#{userId} and I.TYPE_='candidate' AND R.REL_TYPE_ID_=#{relTypeId}
) V
WHERE 1=1
<if test="name!=null">
and NAME_ like #{name}
</if>
<if test="description!=null">
and DESCRIPTION_ like #{description}
</if>
<if test="createtime1">
and CREATE_TIME_ &gt;= #{createtime1}
</if>
<if test="createtime2">
and CREATE_TIME_ &lt;= #{createtime2}
</if>
<if test="orderByClause!=null">
ORDER BY ${orderByClause}
</if>
</select>

SAAS项目,业务审批项目,更多交流请联系QQ:1361783075

在Activiti中如何使用自定义的组织架构的更多相关文章

  1. 谈谈Activiti中流程对象之间的关系

    详细见:http://www.kafeitu.me/activiti/2012/03/22/workflow-activiti-action.html (咖啡兔好牛!) 详细见: http://blo ...

  2. YbSoftwareFactory 代码生成插件【二十四】:MVC中实现动态自定义路由

    上一篇介绍了 公文流转系统 的实现,本篇介绍下MVC下动态自定义路由的实现. 在典型的CMS系统中,通常需要为某个栏目指定个友链地址,通过指定友链地址,该栏目的地址更人性化.方便记忆,也有利用于搜索引 ...

  3. HTML5 UI框架Kendo UI Web中如何创建自定义组件(二)

    在前面的文章<HTML5 UI框架Kendo UI Web自定义组件(一)>中,对在Kendo UI Web中如何创建自定义组件作出了一些基础讲解,下面将继续前面的内容. 使用一个数据源 ...

  4. 【持续集成】[Jenkins]Job中如何传递自定义变量

    [Jenkins]Job中如何传递自定义变量 来自dweiwei   2015-06-27 18:37:19|  分类: 自动化测试 |举报 |字号大中小 订阅 用微信  “扫一扫” 将文章分享到朋友 ...

  5. ArcGIS中添加进自定义的ttf字符标记符号

    原文:ArcGIS中添加进自定义的ttf字符标记符号 ArcGIS系统中的样式可能不能满足实际生产需要,为了实现快速制图,可自定义一些样式,以便重复利用. 1.   制作的符号库 使用 FontCre ...

  6. activiti 中的签收与委托 操作

    原文:http://my.oschina.net/acitiviti/blog/350957 先看看activiti中关于TASK的数据库表: 其中有两个字段:OWNER_,ASSIGNEE_ 这两个 ...

  7. 如何使用XE2及更高版本中提供的自定义皮肤(样式)功能

    源:如何使用XE2及更高版本中提供的自定义皮肤(样式)功能 1. 制作样式文件: 点击 XE2+ 的 IDE 菜单上的 Tools-->Bitmap Style Designer, 打开设计器. ...

  8. Activiti中的log4j(slf4j)的配置

    今天试了一下在Activiti中使用log4j来进行配置发现这个会出现问题,其实Activiti中的日志系统是采用的是slf4j而不是log4j 然后使用slf4j驱动log4j来做的 通过Proce ...

  9. django中怎么使用自定义管理后台xadmin

    django中怎么使用自定义管理后台xadmin 2018年05月19日 15:48:08 LH_python 阅读数:1001   首先创建基本的django项目,配置好基本的model ,url, ...

随机推荐

  1. 【UWP】拖拽列表项的排序功能实现

    在一些允许用户自定义栏目顺序的app(如:凤凰新闻.网易云音乐等),我们可以方便地拖拽列表项来完成列表的重新排序,进而完成对栏目顺序的重排.这个功能很人性化,而实现起来其实很简单(甚至都不用写什么后台 ...

  2. 剑指offer编程题Java实现——二维数组中的查找

    题目描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数.   下面是我实现的代码 ...

  3. C#中运算符的使用

    通过学习知道了知道了运算符的分类及使用方法 运算符用于执行程序代码运算,会针对一个或一个以上操作数项目来进行运算.例如:2+3,其操作数是2和3,而运算符则是“+”. C#语言把除了控制语句和输入输出 ...

  4. 移动H5开发入门知识,CSS的单位汇总与用法

    说到css的单位,大家应该首先想到的是px,也就是像素,我们在网页布局中一般都是用px,但是近年来自适应网页布局越来越多,em和百分比也经常用到了.然后随着手机的流行,web app和hybrid a ...

  5. Javaweb之Servlet入门

    1. 什么是Servlet? Java Servlet 是运行在 Web 服务器或应用服务器上的程序:他是浏览器(HTTP客户端)请求和HTTP服务器上资源(访问数据库)之间的中间层. 2. 什么是S ...

  6. JS中的this 指向问题

    我发现在对JS的学习中有很多朋友对this的指向问题还是有很大的误区或者说只是大致了解,但是一旦遇到复杂的情况就会因为this指向问题而引发各种bug. 对于之前学习过c或者是Java的朋友来说可能这 ...

  7. JMX简单入门

    在一个系统中常常会有一些配置信息,比如服务的IP地址,端口号什么的,那么如何来来处理这些可配置项呢? 程序新手一般是写死在程序里,到要改变时就去改程序,然后再编译发布: 程序熟手则一般把这些信息写在一 ...

  8. CSS揭秘 技巧(五):条纹背景

    条纹背景 https://github.com/FannieGirl/ifannie/问题:条纹背景 在设觉设计中无处不在,我们真的可以用css 创建图案吗? 这一章相对还是比较复杂的哦!一起get. ...

  9. 算法模板——Dinic网络最大流 2

    实现功能:同Dinic网络最大流 1 这个新的想法源于Dinic费用流算法... 在费用流算法里面,每次处理一条最短路,是通过spfa的过程中就记录下来,然后顺藤摸瓜处理一路 于是在这个里面我的最大流 ...

  10. 3384/1750: [Usaco2004 Nov]Apple Catching 接苹果

    3384/1750: [Usaco2004 Nov]Apple Catching 接苹果 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 18  Solv ...