资源描述
二十六 .net工作流系统之扩展性
.net工作流系统之扩展性
最近为用户做工作流实施时,都无一例外的提出工作流系统的扩展性问题。
事件一:eworkflow工作流系统预置了一些系统的条件,前置后置函数等。如果这些不能满足业务需要,用户需要定制自己的业务规则,业务过程,该如何做?
解决方案:eworkflow系统预置了很多系统的条件类,前置后置函数类。简单一些的业务规则,可以直接用自定义脚本,写个表达式的方式来实现。
如条件类的:判断用户是否有某个角色 .fcsoft.workflow.util.UserHasRoleCondition
判断是否是竞争型任务的签收人 .fcsoft.workflow.util.CompetitionTaskCondition
....
事件类:将指定步骤的执行人保存到mostRecentCaller变量中 .fcsoft.workflow.util.MostRecentCaller
...
打开我们的任意一个条件类 ,可以看到,条件类必须实现Condition接口,实现passesCondition()方法
/// <summary> 判断调用者caller是否属于role参数所指的角色
/// caller: userid role: roleid
/// </summary>
public class UserHasRoleCondition : Condition
{
//~ Methods ////////////////////////////////////////////////////////////////
public virtual bool passesCondition(System.Collections.IDictionary transientVars, System.Collections.IDictionary args, PropertySet ps)
....
流程的上下文、相关的业务参数、数据库连接、当前操作员id等,均可以在passesCondition的三个参数中获得。
因 此在需要扩展业务规则的时候,可以扩展这种条件类,只需要在用户的应用系统中引用eworkflow.dll(java版的就是引入 eworkflow.jar),新建业务规则类,实现Condition接口,在passesCondition方法中写业务规则就可以了,所有和流程相 关的信息,节点定义的属性,业务参数,均可以从passesCondition方法的三个参数中获得。
将写好的条件类注册到 WF_DSN_CLASS表中,在流程定义的时候,从节点的属性页中选择出这些扩展的业务规则,挂接到流程的节点上。在流程实例运行到此节点的时候,就会执行这些节点上定义的业务规则类,作出规则判断。
下面是一个判断 当前操作员用户,是否属于某个区域的业务规则的判断
-----------------------------------------条件和事件的分隔线-----------------------------------------------
打开任意一个事件函数类,可以看到,事件函数类的,必须实现FunctionProvider接口,实现execute()方法
public class MostRecentCaller : FunctionProvider
{
//~ Methods ////////////////////////////////////////////////////////////////
public virtual void execute(System.Collections.IDictionary transientVars, System.Collections.IDictionary args, PropertySet ps)
和条件类的接口一样,流程的上下文、相关的业务参数、数据库连接、当前操作员id等,均可以在execute的三个参数中获得。集成开发文档中会有这三个参数的详细描述。
在 需要扩展业务事件,业务过程的时候,只需要在用户的应用系统中引用eworkflow项目或者eworkflow.dll((java版的就是引入 eworkflow.jar),新建这种事件类,实现FunctionProvider接口,在execute()方法中写业务实现,所有和流程相关的信 息,节点定义的属性,业务参数,均可以从execute方法的三个参数中获得。
将写好的类注册到 WF_DSN_CLASS 表中,在流程定义的时候,从节点的属性页中选择出这些扩展的业务事件类,挂接到流程上。这样流程实例运行的时候,流转到相应的节点,就会执行节点上定义的这些业务事件。
例如将当前操作员信息保存到流程的上下文中:
事件二:我们的eworkflow工作流系统的 待办任务列表 只有流程相关的信息,业务信息部分较少,集成到用户系统时,用户希望能自定义一些业务列信息。
解决方案:
eworkflow工作流系统的任务表中,任务名称,是支持表达式的,在表达式中可以引入业务信息。例如任务名称为:审核 业务部 李明 的报销单。 业务部 李明 这两个信息均来自表达式,获取的是报销单中的记录信息。
如果这样还是不能满足用户的需要,用户需要扩展列出多列业务表中的记录值。那就只能通过调用流程的获取待办任务列表的api函数来做了。
具体过程如下:
先通过调用工作流的api函数,获取待办任务列表
ArrayList getCurrentTasks(System.String type, System.String wfId, System.String stepId);
得到的是一个list,list的每一条是对应一条任务表的一个 IDictionary对象(java版的就是map对象),任务表的字段名为key,记录值为value。
任务表中会记录任务信息关联的流程实例id, 通过流程实例id获得 和业务表的关联,找到业务表的记录,然后取出业务表中的多列信息,和任务信息 一起返回到页面显示,这样就获得了一个 包含多列具体业务信息的待办任务列表了。
标签: java工作流, 自定义工作流, web工作流, 工作流引擎, dotnet工作流引擎, .net工作流, .net工作流系统
二十七 .net工作流系统集成自定义表单
.net工作流系统集成自定义表单
工作流系统一般都包含工作流引擎,工作流引擎是对业务流程的抽象,是实现流程自动化的微内核,利用工作流引擎的基本元素能搭建出各种各样的流程,但仅限于流程,不涉及到业务实现。
流程的每个节点上可以挂接需要处理的业务模块,例如一个简单的报销流程,如下图:在填写报销单的流程节点上,就可以挂接上 填写报销单 这样一个业务模块;到审批的节点上,挂接 审批报销单模块。
工作流引擎是不负责这些具体业务模块的实现的,否则就不是对业务流程的抽象了。
这些具体业务模块的实现,可以是开发人员做好的一些业务模块,也可以是用一些表单工具做的自定义业务表单。
无论是定制的业务模块,还是利用表单工具做的自定义表单,都需要在这些模块中集成流程。
好的工作流引擎都应该是封装好的,对外仅提供调用的api函数。这样才能方便的将流程与业务模块集成在一起。
工作流引擎对外提供的api应该包含:
流程的初始化函数:给定一个具体的业务流程名称,启动流程,获得一个流程实例id.
流程的执行函数 :给定一个具体的流程实例id, 执行他的任务,使得流程递进,达到流程的流转。
获得与修改流程实例的状态:获得与修改一个具体流程实例的状态。指流程实例的 激活,挂起,与 完成 等状态。
获得流程定义任意节点的信息:获得指定流程指定节点的任务信息,包括流程定义的属性,自定义信息等等。
。。。。。。。
在业务模块中,嵌入流程引擎的api函数的调用,启动一个流程,或 通过给定的流程实例id,去执行它的当前任务,将当前任务提交,使得流程流转。当然,业务模块的业务数据提交和流程的流转应该保持在一个事务中,达到流程的长事务一致性。
下面以+为例,说明.net工作流系统与自定义表单系统的集成。
还是以报销流程为例,先将业务流程转换成eworkflow的流程。(流程图如上图中简单报销流程)
再设计好业务表,这里我们设计了两张表,报销主表和明细表。
从上面的流程中可以看出,需要有报销单填写模块,和审核模块。
用eform画好 报销单,如下:
注:eworkflow .net工作流系统中已经集成好了eform .net自定义表单系统了。表单属性中 选择 工作流工具栏
工作流工具栏也是用eform设计的一个页面,此页面中已经做好了和流程的集成。在表单提交到后台保存的之后,再执行流程的相应动作,达到流程的递进。
用eform画好 报销单的审核 如下:(同样在表单属性中,选择 工作流工具栏)
画好的页面保存在workflow\example_dj\目录中。
在流程设计器中,打开报销流程,在相应节点上挂接好 业务表单。
这样报销流程就设计好了,可以启动执行了。
有更细一些的控制,就在流程设计器中打开报销流程,修改流程节点的属性,或修改流程的流转。
在eform自定义表单系统的代码中已经有通用的模块集成了eworkflow .net工作流系统了,所以不需要再写代码调用流程api了。
二十八 工作流系统实例演练
工作流系统实例演练
有了工作流引擎,工作流设计器,工作流管理平台,自定义表单,然后业务流程确定之后,就可以快速的做好能运行的流程了。
首先业务要确定,包括业务细节部分。以一个 问题跟踪流程为例,实战演练一下,如何快速的搭建一个可以运行的业务流程。
业务需求:
用户在使用 我们公司的产品时,经常会遇到一些问题,有的是不会使用的问题,有的是误解,有的是bug,也有的是对产品的建议等等。
我们拟收集这些用户遇到的问题以及处理过程,所以设计如下流程:
流程如上面过程,具体的细节要求:
1、相关人员审核问题,通过则发送到技术人员解决问题,拒绝,则表示问题描述不够,打回原填写人继续填写。
2、原填写人收到打回的问题,可以继续完善,再次发送给审核,也可以直接作废问题,结束这次问题描述。
3、技术人员解决问题,有个锁定问题的过程,即谁先锁定了问题,就由谁解决。
4、解决的问题反馈给用户,用户查看处理结果,无异议则结束流程,也可以继续提出疑问,和技术人员继续沟通解决。
分析需求:
根据上面的需求描述,设计问题跟踪表如下:
根据业务过程和表,得出,至少需要设计三张表单:
用户提出问题表单
技术人员处理问题表单
反馈给用户时的,用户查看和继续提出疑问的表单
流程设计过程:
根据上面的业务流程:
用户提出问题《-》审核部门审核问题-》技术解决问题《-》反馈给用户-》结束
可以看出整个业务流程分为,4个环节,提出问题-》审核-》解决问题-》反馈
所以用eworkflow的流程设计器,新建一流程,流程属性页设置
业务标签页面填写 问题跟踪表名 和主键字段名...
然后画出,初始化动作。和4个步骤,每个步骤均带上动作。用连线连接好。流程的雏形就画好了,可以先保存一下。
再根据流程的细节要求,细化每个节点的属性,业务流程如下:
细化的过程:
节点名称的修改
拒绝后打回的动作结果连线,此连线为有条件结果,条件为业务表单中传来的通过还是拒绝的选项。因为表单还未制作,自定义条件中,可以先设置false,如这样设置<arg name="script">false</arg>
打回后的问题,可以直接作废的动作有条件结果连线,条件为业务表单中传来的 是否作废的 选择。表单未制作,自定义条件中,先设置成<arg name="script">false</arg>
设置任务信息:提出问题步骤,设置直接指派的任务;
审核步骤:设置直接指派任务,任务参与人为相关的审核部门人员。
解决问题步骤:设置竞争型任务,任务执行人为技术部门的人员。
问题反馈步骤:设置直接指派任务,任务执行人为问题的填写人。
注意:步骤动作设置完任务节点,再在步骤的动作中,选择相对应的动作条件。即:
直接指派型任务 --- 选择 判断直接指派任务的执行人
竞争型任务 --- 选择 判断竞争型任务的签收人
动态会签型任务 --- 选择 动态会签任务的可执行人判断条件
平均分配型任务 --- 选择 判断平均分配型任务的签收人
问题反馈步骤,继续提出问题,返回的有条件结果连线的设置,以及条件脚本的设置。先设置成false,待表单制作好后,再将条件填上。
审核步骤拒绝时,打回原填写人继续填写的设置,
问题反馈步骤,返回给问题的提出人查看处理结果。
业务流程设计完成。
业务表单的设计:
将业务表建立。新建业务表单,拉下数据集,拉下grid控件。在数据集中添加好业务字段。
拉下label控件,text控件,combox控件,将数据集中的字段,绑定到这些控件。
业务表单的属性页中,设置好表单名称,引入工作流工具条。
保存。则问题填写表单制作完成。
细节的设置,因为审核步骤用的表单,和填写 是同一张表单,所以,审核 是否通过等信息,需要设置控件权限,在填写步骤不可见;
审核的结果,作为条件送到流程中使用,则数据集中 审核结果字段,需要选择 流程用。
是否作废的结果,作为条件送到流程中使用,数据集上问题状态 字段,设置为 流程用。
问题处理表单的设计:
将表单挂接到流程节点上:
打开流程:在相应动作节点属性页上,设置业务表单。
再次设置条件结果,打开流程,在相应的动作有条件结果上修改条件。
保存。
整个流程设计完成,流程就可以运行了,当然之前的保存的业务流程也能运行,只是有些细节没有体现。
在工作流管理平台,登录,找到流程,启动流程,就可以跑这个完整的业务流程了。
启动一个流程实例,
做一个登记,
查看一下此流程运行的轨迹,运行到 审核步骤了。
换成 审核部门的人员登录,从我的待办任务中,找到任务连接,审核通过,则提交到技术部门。技术部门处理问题,反馈给用户,直到问题关闭,结束一个流程实例。
......
对流程设计器,eform表单熟悉的话,业务流程细节又很确定,最多2小时,就能完成这样一个能运行的业务流程了。
当然需求是不断变化的,我们利用eworkflow+eform的设计也可以是不断变化的。
在测试运行阶段,随时可以调整流程,随时可以调整业务表单;
在正式运行后,可以通过流程版本的控制,随时调整需求,随时调整流程,随时随地的调整业务表单。
二十九 详解工作流实例的一次流转
通常在利用流程设计器给业务流程建模之后,会生成一个流程描述的xml文件,业务流程的每个环节步骤,需要执行的操作,自动的,手动的等等信息,都 被描述在这个流程建模的xml文件中。xml文件的内容,是一些规则的预先定义的抽象的节点信息,流程引擎负责这些节点的定义,创建,解释,定位等等,业 务流程利用这些节点建模。建模完成的业务流程,挂接上业务表单后,就可以直接运行业务流程了。
业务流程的运行,从启动流程实例开始,启动一个流程实例即代表开始了一次业务流程处理。每例业务流程的处理过程,都包含从创建,到激活,到处理,到 结束(当然中间也可以人为的直接终止,或挂起,再恢复),这样一个过程。流程实例创建后,就按照流程建模的xml文件,按照定义的节点路由顺序一步一步的 流转,相应业务也在相应的步骤中处理。
流程实例按照节点路由顺序,每执行一次,代表一次流转。每次的流转包含流程节点的状态升迁和办理业务数据的提交,通过工作流的事务,控制这些状态升迁和业务数据达到同步和一致性。一旦这个流程实例结束了或意外终止了,都代表业务办理完成了,就再也不能再次发生流转了。
工作流实例的一次流转,会涉及到流程节点状态的升迁和办理业务数据的提交。
下面示意图,抽取流程一次流转的定义示意:从步骤A环节-》到达步骤B
当流程实例到达步骤A的时候,当前流程实例的状态=步骤A+步骤A的状态,当执行动作A的时候,通过 动作A的 结果导向 步骤B。当到达步骤B的时候,当前流程实例的状态=步骤B + 步骤B的状态。流程实例的状态通过执行动作A达到了升迁,当在动作A上面绑定了业务表单,业务数据也随着动作A的执行一起提交。业务数据的提交和流程状态 的升迁是在同一个事务中的,保证数据的一致性。
从上面的分析可以看出,流程的一次流转涉及到如下图中红色框中选中的部分。为什么步骤A和步骤B会分别是一半呢,下面我们来详细说明,流转过程中,每个流程基本元素的流转顺序。
在工作流系统的基本元素中,有一些前置后置函数,可以挂接到流程的节点上。当流程实例到达这个节点的时候,会触发前置函数,离开这个节点会 触发后置函数,就象事件一样。事件的内容是可以自己任意发挥的,就像一个button的点击函数一样,点击后做什么事情,有编写程序的人来编写代码。这里 的前置后置函数也是一样,当触发了前置后置函数后,内容可以是预置的一些系统函数,也可以是业务流程建模者自定义做的一些业务模块,体现流程的扩展性。
上图中只描述了动作的前置后置,步骤的前置后置,实际上动作的结果,也有前置后置函数,便于做扩展用。实际上可以引入业务模块的不仅是前置后置函 数,动作的可执行条件也可以引入业务规则的判断。例如一个请假的流程,在审核请假是否通过时,可以引入一个判断规则,将请假申请人的总年假-已经休的假 期=可休年假天数,再和当前申请的天数比较,如果大于则申请通过,否则不通过。
综合上面的描述,我们可以看出流程的一次流转的先后顺序为:
步骤的后置函数-》动作的前置函数-》完成本步骤的任务-》检查动作结果中的条件(不成立则无条件结果)-》动作结果的前置-》 创建新的当前步骤(执行新步骤的前置函数)-》 动作结果的后置-》 动作的后置函数
因为执行动作后,会离开本步骤,所以首先是从本步骤的后置函数开始的。
其中,创建新的当前步骤,关联到任务信息,所以也有个处理过程顺序:
本步骤标记完成,转到历史步骤-》下一步为当前步骤-》关闭当前步骤的所有未完成的任务-》到达新步骤,先生成新步骤的所有任务-》再执行新的当前步骤的前置函数。
业务流程在建模的时候,可以利用一些流程的上下文中的变量等做一些控制,也可以引入一些关键的业务数据做判断用。这涉及到流程的持久变量和临时变量。
例如,获取当前流程实例的创建者,作为一个变量,传递给接下来的第一个步骤作为第一个步骤任务的参与者。
这可以用一个流程的临时变量来处理:
在流程初始化动作(或动作结果)的前置函数中,将当前流程实例的创建者保存到变量caller中。然后在下一步骤的任务参与人中,就可以引入caller变量,获取他的值了。
因为caller变量是个临时变量,仅存在于流程的一次流转的中。当流程的这次流转结束了,这个变量就实效了。就像一个子函数一样,在子函数的开始,给变量caller赋值,在接下来的代码中就可以获取这个变量的值了。
所以在用流程的临时变量时候,通常都是在相应节点的前置函数中,给变量赋值,按照流程的流转顺序,在相应的后置节点中获取变量的值。
同样的方式还适用于mostRecentCaller,mostRecentOwner 这两个变量,获取指定步骤的执行者和获取指定步骤的所有者,这两个变量都属于发生了的历史步骤才能获取到。
流程的持久化变量,就与临时变量不一样了,只要流程的任意节点中保存了值,在后续的任意节点中都可以获取到值。这个不局限于流程的一次流转,流程多次流转都可以。只要在任意一次流转中保存了变量的值了,后续的任意流转中就都可以取值了。
例如一个报销流程中,报销申请是否通过,审核人将这个结果作为一个持久化的变量保存到流程中了。则在申请人查看审核结果的环节,就可以取出这个审核 结果了。审核的那次流转,和查看环节,这是流程的两个环节。不是流程的一次流转,但是审核的那次流转,必须先于查看环节,先将变量的值持久化进去,然后后 续的环节就能获取值了。
三十 流程的静态分支与动态分支
业务流程的流转过程中,经常会有需要并发处理的过程,即流程流转到下一步,同时产生多个 当前需要处理的过程,这些过程不分先后处理顺序,只要都处理完成了,最后汇聚到一起,再接着主流程运行,就可以了。例如:一份报销单,填写完成后,同时启 动财务部门审核和本部门的审核,这两部分的审核不分先后顺序,只要都完成后,再将结果返回给报销单填写人,继续下面的流转。这种的并行处理的过程,就需要 流程引擎支持分支和聚合。
分支又分为 静态的分支 和动态的分支。
静态的分支,即在业务流程建模之初,就能确定好有多少个分支,每个分支的具体流转,具体处理过程。
动态的分支,即在业务流程建模的时候,只能确定好一条分支的模版处理过程,在流程实例运行时,每流程实例根据自己的情况确定本次能产生多少个分支,然后依据分支模版的处理过程,复制出n个并发的分支线路,每分支线路的运行轨迹根据动态分支参数的设置而不尽相同。
聚合也分为 静态聚合 和 动态聚合
静态聚合,和静态分支匹配,当有静态的分支并发流转发生后,需要用静态聚合来汇聚并发的线路。
动态聚合,和动态分支匹配,当有动态的分支并发流转发生后,需要用动态聚合来汇聚并发的线路。
静态分支模式:
动态分支模式:
静态分支里面可以嵌套 静态分支:
动态分支里面也可以嵌套 动态分支:
静态分支里面可以嵌套 动态分支 (暂未做示例)
动态分支里面也可以嵌套 静态分支:
注意:静态分支,必须用静态聚合来汇聚, 动态分支必须用动态聚合来汇聚。
为了 方便 设置汇聚条件,分支嵌套的时候,避免 内层聚合--到--外层聚合 的 这种流程建模方式,如果业务流程中,确实是内层聚合--到--外层聚合 的流转,那就增加一个 自动步骤的 节点。即 内层聚合--自动步骤--外层聚合。此自动步骤,带有自动执行的方法,当流程流转到这里时,会自动完成此步骤。
静态分支后产生的并发流程,在流程建模时候,和普通的流程节点一样设计。
动态分支后产生的并发流程,有些参数需要在流程实例运行时设置,如动态分支的个数,每分支的步骤执行人等等。
动态分支节点,在流程建模时,先定义好需要那些参数,在分支模版节点中,引入这些参数。流程实例运行时,各流程实例根据实际情况给参数赋值,分支节点中遇到参数表达式,解释并得到参数值,参与到流程的流转中。
参见 web工作流管理系统开发之二十 动态创建流程多分支节点
展开阅读全文