UCML工作流系统与现有应用系统集成
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
The best solution for
how to develop WEB application on .Net quickly and efficiently
UCML工作流系统与现有应用系统
集成实现方案说明
金富瑞(北京)科技有限公司
Goldframe Technologies Co., Ltd.
一总体说明
工作流系统是国内领先的工作流平台,涵盖了从流程开发、发布、管理配置到运行、监控的整个过程。
UCML工作流系统主要包括可视化的流程设计环境、独立的工作流引擎服务、WEB客户端管理、可视化的流程监控、流程套路生产线几个部分,是.Net领域用户最多,覆盖面最广的工作流平台。
一方面,UCML工作流系统与UCML平台其它部分(业务单元开发,Web 报表)无缝集成,可以完成复杂的业务处理及流程流转;另一方面,UCML 工作流系统与业务之间采用松耦合设计,不仅可以与UCML业务系统集成,还可以与其它现成的应用系统实现无缝集成。
UCML工作流在与其它应用系统集成时,一般有两种方式:
第一种:保留UCML现有的组织机构、用户及权限体系
第二种:完全屏蔽UCML提供的组织机构、用户及权限体系,完全采用客户原有的组织机构权限体系。
对于第一种方式,需要另外实现UCML系统与客户现有应用系统之间的数据同步,具体方法可采用程序同步方式,在这里就不详细介绍了。
下面主要介绍一下采用第二种方式时的处理方法。
二UCML Workflow会话编程接口
UCML Workflow 提供了WorkFlow.WorkFlowSession会话类来访问工作流引擎, WorkFlow.WorkFlowSession以.Net Remoting服务形式形式存在于工作流引擎的独立进程中,客户端可以创建WorkFlow.WorkFlowSession的Client端来来调用服务端的接口。
创建工作流会话对象
WorkFlow.WorkFlowSession FlowSession = (WorkFlow.WorkFlowSession)Activator.GetObject(typeof(WorkFlow.WorkFlowSession), "tcp://"+WorkFlow.UCMLInitEnv.WorkflowEngineAddr+":"+WorkFlow.UCMLInitEnv.Workflow EnginePort+"/WorkFlowSession");
程序启动工作流程
public Guid CreateInstance(string FlowID,Object UserOID,Object PostnOID, Object DivisionOID,Object ORGOID, bool startNow)
通过调用CreateInstance函数,可以启动指定的工流程。
返回值:流程实例句柄。
参数名称类型参数说明
FlowID string要启动的流程编号
UserOID Object起动流程的用户OID,实际类型为GUID
PostnOID Object起动流程的员工OID,实际类型为GUID
DivisionOID Object起动流程的员工所在部门的OID,实际类型为GUID
ORGOID Object起动流程的员工所在组织的OID,实际类型为GUID
startNow Bool==true 流程是马上启动; ==false 流程暂不启动,
要启动流程需调用StartInstance函数,这种情况一般
用于在业务(如客户订单)提交成功后,先写入订单号
到流程实例中,然后在启动流程。
向流程全局数据写入数据
public void WriteFlowData(string FlowID, Object InstanceID, string FieldName,Object
Value)
参数名称类型参数说明
FlowID string数据项所属的流程编号
InstanceID Object流程的实例句柄,实际类型为GUID
FieldName string数据的属性名称
Value Object数据的属性的值
从流程全局数据读出数据
public Object ReadFlowData(string FlowID, Guid InstanceID, string FieldName)
返回值:读取数据属性的值
参数名称类型参数说明
FlowID string数据项所属的流程编号
InstanceID Object流程的实例句柄,实际类型为GUID
FieldName string数据的属性名称
向流程局部数据写入数据
public void WriteActivityData(string FlowID, Guid InstanceID,string ActivityID, string FieldName,Object Value)
参数名称类型参数说明
FlowID string数据项所属的流程编号
InstanceID Object流程的实例句柄,实际类型为GUID
ActivityID string活动节点的编号
FieldName string数据的属性名称
Value Object数据的属性的值
从流程局部数据读出数据
public Object ReadActivityData(string FlowID, Guid InstanceID,string ActivityID, string FieldName)
返回值:读取数据属性的值
参数名称类型参数说明
FlowID string数据项所属的流程编号
InstanceID Object流程的实例句柄,实际类型为GUID
ActivityID string活动节点的编号
FieldName string数据的属性名称
完成已分配的任务
public string FinishTask(string strAssignTaskID)
FinishTask代表设置已分配出去的任务已完成
返回值:提示信息
参数名称类型参数说明
strAssignTaskID string分配任务的唯一标志号
设置任务结果及状态
public void SetTaskResolution(Guid TaskID,TTaskResolution Resolution)
设置任务执行结果,代表任务执行完毕
参数名称类型参数说明
TaskID Guid任务的Key值
Resolution TtaskResolution任务的状态{UNRESOLVED,SUCCESS,FAIL,EXCEPTION} 含
义分别为{未处理,成功,失败,异常}
编写节点分支条件
UCML Workflow用abstract public class Transition类来描述一个分支条件
类属性名称类型可见度属性说明
TransResult Boolean protected TransResult==true 则代表流程分支条
成立
TransResult==false 则代表流程分支条
不成成立
FromActivity WorkFlowActivity public分支来源节点对象实例
ToActivity WorkFlowActivity public分支目标节点对象实例
FlowModel WorkFlowModel的子
类public其实是流程模型的实例对象,通过它可以
访问流程所有属性(或状态)数据
方法名称类型可见度方法说明
OutgoingCondition()bool public virtual public bool
OutgoingCondition()
在UCML Workflow里,节点的一条流出
分支是否成立完全取决于这个函数,编
程人员员可以它的子类里编写它的具
体实现代码,在编写代码时可以结合流
程的状态数据。
在这函数中一定要设置
TransResult的值,也就是说如果
TransResult==true 分支成,否则分支
不成立,也就不走这条分支。
IncomingCondition bool public virtual public bool
IncomingCondition()
OutgoingCondition()这函数是在Transition的子类中已覆盖函数形式实现,在UCML 环境里的流出条件编辑,就是实现此函数。
如下图示:
9. 编程实现智能任务分配
wm_assign()-UCML Workflow提供回调函数,为开发者提供完成复杂分配的可能,详见回调函数接口
10. 终止流程
方法名称类型可见度方法说明
Abort ()void public public void Abort(string FlowID, Guid
InstanceID)
终止某个流程实例
9. 挂起流程
方法名称类型可见度方法说明
Pause ()void public public virtual void Pause()
暂时挂起一个流程
10. 唤醒流程
方法名称类型可见度方法说明
Resume ()void public public void Resume(string FlowID,
Guid InstanceID)
重新运转流程
11. 节点手动跳转
方法名称类型可见度方法说明
GotoActivity ()void public public void GotoActivity(string
FlowID, Guid InstanceID,string
FromActivityID,string
ToActivityID,string Performers)
作用 : 流程跳转
FlowID:流程ID
InstanceID:流程实例句柄
FromActivityID:来源活动名称
ToActivityID:目标活动名称
Performers:执行人的群组串.
回退任务
/// <summary>
/// 回退任务
/// </summary>
/// <param name="TaskID">任务ID</param>
public void Rollback(Guid TaskID)
回收任务
/// <summary>
/// 收回任务
/// </summary>
/// <param name="TaskID">任务ID</param>
获取某个活动节点执行人
/// <summary>
/// 获取某个活动节点执行人
/// </summary>
/// <param name="ActivityID">活动节点ID</param>
/// <returns></returns>
public string GetActivityPerformer( string ActivityID)
获取当前节点即将流向的目标节点,如果是并发输出将会多个流向。
用于在当前节点完成时,马上选择下一节点执行人
/// <summary>
/// 获取当前节点即将流向的目标节点,如果是并发输出将会多个流向
/// 用于在当前节点完成时,马上选择下一节点执行人
/// </summary>
/// <param name="FlowID">流程ID</param>
/// <param name="InstanceID">实例ID</param>
/// <param name="ActivityID">活动ID</param>
/// <returns>返回要输出的节点ID数组</returns>
public string[] GetOutgoingActivitys(string FlowID, Guid InstanceID, string ActivityID)
获取节点状态
/// <summary>
/// 获取节点状态
/// </summary>
/// <param name="FlowID"></param>
/// <param name="InstanceID"></param>
/// <param name="ActivityID"></param>
/// <returns></returns>
public int GetActivityStatus(string FlowID, Object InstanceID, string ActivityID)
修改节点状态
/// <summary>
/// 修改节点状态
/// </summary>
/// <param name="FlowID"></param>
/// <param name="InstanceID"></param>
/// <param name="ActivityID"></param>
/// <param name="ActivityStatus"></param>
public void ChangeActivityStatus(string FlowID, Object InstanceID, string ActivityID, int ActivityStatus)
不结束当前节点,而激活下一节点
/// <summary>
/// 不结束当前节点,而激活下一节点
/// </summary>
/// <param name="FlowID">流程ID</param>
/// <param name="InstanceID">流程实例ID</param>
/// <param name="FromActivityID">流转到活动ID</param>
/// <param name="ToActivityID">来自活动ID</param>
/// <param name="Performers">流转到活动节点执行人</param>
public void GotoActivityNotFinishTask(string FlowID, Guid InstanceID, string FromActivityID, string ToActivityID, string Performers)
完成已分配的任务,但不流转
/// <summary>
/// 完成已分配的任务,但不流转
/// </summary>
/// <param name="Activity">工作流活动节点对象</param>
/// <returns></returns>
public string FinishTaskNotRun(WorkFlowActivity Activity)
加签或者转签
/// <summary>
/// 加签或者转签
/// </summary>
/// <param name="FlowID">流程ID</param>
/// <param name="InstanceID">实例ID</param>
/// <param name="AssignTaskOID">任务ID</param>
/// <param name="CurrentUserOID">当前用户OID</param>
/// <param name="SignPerformers">执行人</param>
/// <param name="fSignOneByeOne">按照顺序执行</param>
/// <param name="InsertBefore">true:加签;false:转签</param>
/// <param name="IsDeleteSigner"></param>
/// <param name="MessageType">消息类型</param>
/// <param name="MessageContent">消息内容</param>
public void AddSignPerformer(string FlowID, Guid InstanceID, Guid AssignTaskOID, Guid CurrentUserOID, string SignPerformers, bool fSignOneByeOne, bool InsertBefore, bool IsDeleteSigner,
int MessageType,string MessageContent)
协办或会签
/// <summary>
/// 协办或会签
/// </summary>
/// <param name="FlowID">流程ID</param>
/// <param name="InstanceID">实例ID</param>
/// <param name="AssignTaskOID">任务ID</param>
/// <param name="CurrentUserOID">当前用户OID</param>
/// <param name="SignPerformers">执行人</param>
/// <param name="MessageType">消息类型</param>
/// <param name="MessageContent">消息内容</param>
/// <param name="TaskKind">3:协办;1:会签</param>
public void AssignSignPerformer(string FlowID, Guid InstanceID, Guid AssignTaskOID, Guid CurrentUserOID, string SignPerformers,int MessageType, string MessageContent,int TaskKind)
手工正常分配任务
/// <summary>
/// 手工正常分配任务
/// </summary>
/// <param name="TaskTicketOID"></param>
/// <param name="Performer"></param>
public void MansualAssignTask(string TaskTicketOID,string Performer)
分配参阅任务
/// <summary>
/// 分配参阅任务
/// </summary>
/// <param name="TaskTicketOID"></param>
/// <param name="Performer"></param>
public void MansualAssignReadTask(string TaskTicketOID,string Performer)
悔签任务,对在任务分配表AssignTask中acceptFlag置为1的标记设为4悔签
/// <summary>
/// 悔签任务,对在任务分配表AssignTask中acceptFlag置为1的标记设为4悔签
/// </summary>
/// <param name="assignTaskID"></param>
public void RepentSignforTask(string assignTaskID)
任务跳回到执行人
/// <summary>
/// 任务跳回到执行人
/// </summary>
/// <param name="FlowID">流程ID</param>
/// <param name="InstanceID">流程实例句柄</param>
/// <param name="ActivityID">节点ID</param>
public void TaskReturn(string FlowID, Guid InstanceID, string ActivityID)
获取某个已完成节点的执行人
/// <summary>
/// 获取某个已完成节点的执行人
/// </summary>
/// <param name="FlowID">流程ID</param>
/// <param name="InstanceID">流程实例句柄</param>
/// <param name="ActivityID">节点ID</param>
/// <returns>返回执行人OID数组</returns>
public Guid[] GetExecuteUser(string FlowID, Guid InstanceID, string ActivityID)
唤醒已完成的任务
/// <summary>
/// 唤醒已完成的任务
/// </summary>
/// <param name="AssignTaskOID"></param>
public void WakeFinishedAssignTask(string AssignTaskOID)
12. 任务超时处理及编程
UCML Workflow 的是否超时由下图的完成期限和延长时间两个属性决定:
当完成期限不填内容时,代表这个活动节点产生的任务没有时间限制
延长时间代表完成期限倒了之后,还可以再延长多少时间
●即将超时处理
当完成期限到了之后,会回调wm_willtimeout函数,如果想在此时放个邮件通知或短信,就可在wm_willtimeout函数内调用。
●超时处理
同样的当完成期限到了之后,如果有延长时间,而且延长时间也到了,会回调wm_deadline函数,如果想在此时放个邮件通知或者短信,就可在wm_deadline 函数内调用。
如下图示:
如果任务在截止期限和延长时间内都没有完成,此时任务做超时处理,流程是继
续流转还是停止由截止期限到达时系统行为这个属性决定,如为SYNCHR(同
步),则流程停在这里,如果为ASYNCHR(异步) 则流程继续流转。
三UCML工作流开放性介绍
UCML 引擎底层框架的基类源码不开放,包括引擎调度代码和流程类、活动类和分支类基类代码。
而根据定义可以直接生成引擎源码都是开放的,可以在这些源码的框架扩展时刻(回调函数)之内注入C#代码来进行,如下面活动节点代码的时刻函数
任务分配时刻函数
override public void wm_assign(Object taskTicketID,Object[] UserList,ref Object[] AssignUserList,ref int[] TaskKindList,Boolean reassignFlag)
{
}
任务分配后时刻函数
override public void wm_afterAssignTask(Object assignTaskID,Object UserOID)
{
base.wm_afterAssignTask(assignTaskID,UserOID);
}
任务分配前时刻函数
override public void wm_beforeAssignTask(SysDBModel.AssignTaskInfo AssignTaskInfo)
{
}
任务完成时刻函数
override public void wm_afterTaskFinish(Object taskTicketID,TTaskResolution TaskResolution) {
}
任务超时时刻函数
override public void wm_deadline(Object taskTicketID)
{
}
任务完成规则函数
override public bool wm_finishTaskRule(SysDBModel.TaskTicketInfo taskTicketInfo)
{
return false;
}
任务创建函数
override public void wm_createTask(SysDBModel.TaskTicketInfo taskTicketInfo)
{
}
任务回滚前函数
override public void wm_beforerollback(Object taskTicketID)
{
}
任务回滚后函数
override public void wm_afterrollback(Object taskTicketID)
{
}
override public void wm_onactivate()
{
}
override public void wm_willtimeout(SysDBModel.TaskTicketInfo taskTicketInfo)
{
}
override public bool wm_activityInComeCondi()
{
return false;
}
}
}
四集成方案
在采用客户已有的人员权限体系时,主要用到UCML工作流系统的可视化流程设计环境、工作流引擎服务、工作流标准表结构、流程API、可视化的流程监控(可选)等。
在集成时可能需要修改客户已有的Web系统或表的结构,主要是修改以下地方:
●修改人员信息表
●引入流程接口(UCML工作流API)
●客户登陆会话的改变
●加入工作流引擎需要的初始化程序
●增加一个待办事宜模块
●引入平台中的可视化的流程监控模块(如果需要可视化流程监控那么就需要引入)
在平台中主要有以下注意点:
●在平台中设计工作流模型
●添加流程状态数据
●在任务分配函数-wm_assign()中设置任务的执行人
●修改人工节点上的业务标识符为为自己的页面
1、 修改人员信息表
需要在客户现有的用户表(存储登录帐号、密码表)中增加一个Guid类型的字段,这个字段的值唯一标记一个用户,不影响客户现有的应用体系,起到与UCML工作
流衔接作用。
这个字段的字段名命名规范为:客户表名+OID,即“客户表名OID”,字段类型为
GUID类型,在MSSQL Server中是Uniqueidentifier,Oracle中为VARCHAR类型。
在客户业务系统中客户的登录ID代表客户的身份,如果整合中客户表中有现存的
数据需要手工给“客户表名OID”赋值;另外,在增加用户的程序中要同时给“客
户表名OID”赋值。
2、 引入流程接口(UCML工作流API)
●在客户现有系统的工程文件中引入UCML工作流API,并引用一个专门为第三方业
务开发包装的接口源程序WorkflowClient.cs。
●相关工作流API:DBLayer.dll,SysDBModel.dll,UCMLBase.dll,WorkFlow.dll
●把Workflow\bin 目录下的UCMLConf.xml,DBLayer.xml文件拷贝到客户工程的bin
目录下,注意:如果不是在客户工程的本机运行工作流引擎,则需要把
UCMLConf.xml文件中引用工作流引擎地址的IP改为运行工作流引擎主机的IP地
址。
3、 客户登陆会话的改变
在用户登陆的程序中,在取得用户表中各项数据时,把用户表中新增的字段也读出
来,并把该项也放入用户登陆会话中。
4、 加入工作流引擎需要的初始化程序
在使用客户的应用程序中与工作流引擎打交道之前的任意时刻加入如下程序:
UCMLCommon.UCMLInitEnv.fInServer=true;
UCMLCommon.UCMLInitEnv.LoadEnvVariable();
new DBLayer.LogicDBModel();
UCMLCommon.UCMLLogicDBModelApp x = new UCMLCommon.UCMLLogicDBModelApp();
x.PrepareModel();
5、 增加一个待办事宜模块
待办事宜也叫待办任务。
需要客户自己新增一个待办事宜模块,其数据来源是UCML提供的任务分配表
AssignTask,开发者可根据记录(任务)的完成与否状态过滤数据到待办任务模块
内。
6、 引入平台中的可视化的流程监控模块(如果需要可视化流程监控那么就需要引入)
可视化流程监控的页面在平台中的业务模块是:BPO_FlowTrace
可以将BPO_FlowTrace相关文件拷贝到项目下:
BPO_FlowTrace.aspx
BPO_FlowTrace.aspx.cs
BPO_FlowTrace.asmx
BPO_FlowTrace.asmx.cs
BPO_FlowTrace.htc
7、 在平台中设计工作流模型
在平台中设计工作流模型,可以参考“工作流设计手册”。
8、 添加流程状态数据
UCML工作流引擎和业务之间是松耦合处理模式,工作流和业务之间是通过流程状
态数据进行交互。
流程状态数据是指工作流在运转过程中流程流转所需要的保存在流程实例中的数
据,一般有三类业务数据要保存在流程中,一是业务单据的关键字段,用它可以决
定一个任务对应的业务单据号,在UCML里一般把表单主键存到流程里;二是决定
流程分支走向的数据,有可能是领导意见,也有可能是单据金额,这些数据是为了
工作流引擎内部调用的;三是流程执行人信息。
流程和业务之间的状态数据交互方法很简单,如下所示:
写入流程状态数据:即把业务的数据写入到流程中去,调用的方法是
WriteFlowData;
读出流程状态数据:即把流程状态读出来赋给业务,调用的方法是ReadFlowData。
写入流程状态数据一般在数据提交时进行,读出流程状态数据一般在初始化时进
行,读时可以把流程状态数据赋给业务中的某个属性,以方便业务中调用。
9、在任务分配函数-wm_assign()中设置任务的执行人
在工作流中任务分配的方式有几种:
通过群组配置分配任务
回调函数分配任务
手工执行执行人
由于组织机构等均不采用平台自带的组织框架,所以无法采用“通过群组配置分配
任务”的方式,只能采用“回调函数分配任务”或
10、自己实现执行人群组解析接口,可以继续使用基于配置的任务分配
基于流程模型的执行人配置可以避免在wm_assign里写程序做任务分配,但必须必
需特定某个组织机构,在这个组织机构基础之上可以定义群组,来描述人员、部门
和岗位集合,也可以定义相对执行人如申请人的部门主管、申请人公司总经理等,
只要实现自己的群组解析接口,就可以自己的群组串配置UCML的工作流执行人的
字段里,就可以实现基于配置的任务分配实现步骤如下:
自定义类实现如下接口
public interface IGroupParser
{
Object[] UserOIDList(string GroupStr, Object Starter, Object StartPostn, Object StartDivision, Object StartORG,
Object Performer, Object PerformerPostn, Object PerformerDivision, Object PerformerORG);
Object[] UserOIDList(string GroupStr);
}
///<summary>
///根据组定义获取用户列表
///</summary>
///<param name="GroupStr">群组字符串</param>
///<param name="Starter">流程启动者GUID</param>
///<param name="StartPostn">流程启动岗位GUID</param>
///<param name="StartDivision">流程启动部门GUID</param>
///<param name="StartORG">流程启动企业GUID</param>
///<param name="Performer">当前执行人GUID</param>
///<param name="PerformerPostn">当前执行人岗位GUID</param>
///<param name="PerformerDivision">当前执行人部门GUID</param>
///<param name="PerformerORG">当前执行人企业GUID</param>
///<returns>返回GUID类型的用户ID</returns>
在UCMLCONF.XML文件里添加如下节点:
<fCustomGroupParser>true</fCustomGroupParser>
<GroupParserAssembly>dll名称</GroupParserAssembly>
<GroupParserClass>类名称</GroupParserClass>
11、修改人工节点上的业务标识符为为自己的页面
12、工作流计算工作日客户自定义接口
1.自定义类实现如下接口
public interface IWorkDay
{
///<summary>
///计算任务完成期限,用于扩展节假日等非工作日的完成时间的计算
///</summary>
///<param name="startTime">任务开始时间</param>
///<param name="delayTime">任务计划用时,单位为秒</param>
///<param name="UserOID">任务执行人OID</param>
///<returns>返回任务最终完成时间</returns>
DateTime GetLimitDateTime(DateTime startTime, long delayTime, Guid UserOID); }
2.在UCMLCONF.XML文件里添加如下节点:
< fCustomWorkDay>true</ fCustomWorkDay>
< WorkDayAssembly>dll名称</ WorkDayAssembly>
< WorkDayClass>类名称</ WorkDayClass>
13、工作流时刻切面接口
1.自定义类实现如下接口
///<summary>
///流程切面时刻
///</summary>
public interface IWorkFlowRuntime
{
///<summary>
///流程创建时刻
///</summary>
///<param name="FlowInstance"></param>
///<param name="CreateTime"></param>
void OnCreateInstance(WorkFlowModel FlowInstance, DateTime CreateTime);
///<summary>
///流程完成时刻
///</summary>
///<param name="FlowInstance"></param>
///<param name="EndTime"></param>
void OnFinishInstance(WorkFlowModel FlowInstance, DateTime EndTime);
///<summary>
///流程终止时刻
///</summary>
///<param name="FlowInstance"></param>
///<param name="AbortTime"></param>
void OnAbortInstance(WorkFlowModel FlowInstance, DateTime AbortTime);
}
///<summary>
///活动节点切面接口时刻
///</summary>
public interface IActivityRunTime
{
///<summary>
///任务创建时刻
///</summary>
///<param name="FlowInstance"></param>
///<param name="Activity"></param>
///<param name="CreateTime"></param>
void OnCreateTask(WorkFlowModel FlowInstance, WorkFlowActivity Activity, DateTime CreateTime);
///<summary>
///完成任务分配时刻
///</summary>
///<param name="FlowInstance"></param>
///<param name="Activity"></param>
///<param name="FinishTime"></param>
void OnFinishAssignTask(WorkFlowModel FlowInstance, WorkFlowActivity Activity, DateTime FinishTime);
///<summary>
///完成整个任务时刻
///</summary>
///<param name="FlowInstance"></param>
///<param name="Activity"></param>
///<param name="FinishTime"></param>
void OnFinishTask(WorkFlowModel FlowInstance, WorkFlowActivity Activity, DateTime FinishTime);
}。