1、二十一 巧用流程轨迹表主键ID 在工作流系统中,业务流程按流程引擎定义的模型规则,定义成流程的一个一个节点。当流程实例运行时,流转到流程的各个节点,通过执行动作之类的操作提交 关联的业务表单,导向流程的下一个节点,同时修改流程实例的状态,达到流程的流转。流程实例每流转一次,都会将当前节点的信息写入一个历史轨迹表,同时将 下一节点的信息写入当前步骤表。当流程实例流转多次后,根据历史轨迹表的记录,就能追踪到此流程实例的实际运行轨迹。 工作流系统的数据主要分为流程数据和业务数据,流程的历史轨迹表仅仅记录的是流程的数据,与业务数据业务表单无关,甚至是流程的上下文数据也记录不了。 当流程实例在追踪历史轨
2、迹的时候,作为监控使用,或者是历史步骤的再现,经常需要将此轨迹节点上关联的业务表单重新装入,查看监控当时的流程状态和业务状 态。但流程的轨迹表仅记录的是流程的节点步骤信息。业务表的信息是不记录的,业务表记录的再现,只能通过流程数据和业务数据的关联去查找。查找出的业务记 录只有一个最后的状态,如果流程的多个节点对此业务数据做过修改,那么就很难在各个轨迹节点中还原出当时的状态。可能可以通过类似同一张单据在流程的多节 点中流转的方式来达到,但如果多节点写了同一个字段的信息,就根本区别不出是流程的那个节点做的修改了,因为业务表没有记录轨迹。 总结一下,实际上流程系统中的历史轨迹表,只记录的是流程实例运
3、行的各节点的轨迹,没有记录业务数据的轨迹。当 流程监控的时候要求对业务表的记录也做出精确的监控,那肯定需要建立业务表的轨迹表(或叫日志表),此业务轨迹表当属于业务系统的表,不属于工作流系统 表。并且在业务轨迹表中增加一个 流程轨迹id字段 ,用于和流程的轨迹相关联。当流程流转时,产生流程的历史轨迹,同时也产生业务轨迹表的记录,并将流程的历史轨迹表记录id写入业务轨迹表中。当流程监控 时,显示流程历史轨迹的同时,也可以通过轨迹表的id字段 关联出业务轨迹表中的业务记录,再现出当时的业务数据状态。此为流程轨迹表主键ID的一种用法。流程轨迹表的主键 id,是流程实例运行轨迹的一个唯一标志,与流程节点
4、的id不一样,流程节点的id是流程定义节点中的唯一标识,流程实例运行时,同一个节点,通过回退, 循环,主动取回等可能会多次运行。但轨迹表的主键id则肯定是唯一的,流程实例的每次流转都会生成轨迹表的新记录。当流程运行到节点上,关联的业务表单填 写的是多条业务记录时,如主从表的录入,从表在流程的不同节点上多次填写。当流程监控时,需要再现出每个节点关联的从表业务记录时,就定位不了业务记录。 如果在业务从表中增加一个 流程轨迹主键id 字段,在流程节点提交的时候,将此轨迹id写入 业务从表中,就能将流程的轨迹和业务从表记录关联起来了。此处如果写入业务从表的是流程节点id是不行的,流程回退,取回,一个节
5、点重复执行时,就标识不 了了。 此为流程轨迹主键id的另一种用法。 流程轨迹主键id 还有一种更为巧妙的用法,作为流程主动取回后,再次发送,流程下一节点是否可执行的判断标志。流程实例的每次执行操作之前将流程轨迹id传递到前台,等待 用户执行操作。提交操作时,取道页面传递回来的轨迹主键id,和流程轨迹表中当前步骤的轨迹id相比较,如果一致,则可以继续操作,如果不同,则表示流程 轨迹已经发生了变化,需要再次打开链接重新执行此节点的操作。二十二 dotnet版工作流引擎工作流管理系统为实现流程的自动化,必须包含一个工作流引擎,工作流引擎负责流程的定义,解释和运转。流程引擎是对业务流程的一个抽象,因此
6、工作流引擎的设计模型是决定流程功能的重中之重,将直接影像流程的各个环节。一套工作流管理系统还包含很多个必须要实现的部分,如:事件处理,任务处理,组织机构的适配,自定义表单等等。以及很多中国式的“动态会签,回退, 自由流”等等变态需求。但抛开这些,只关注每个流程的最基本的部分,即解决一个过程运转的问题,从一个环节到另一个环节,使得流程能够运转起来。这应该就 是流程引擎要实现要关注的基本问题,即流程引擎的抽象。工作流引擎模型有很多种,FSM、PetriNet、EPC、Activity Diagram等等,不论采用那种流程引擎模型,最终都需要能将业务流程用流程引擎的符号或元素表述出来。我们公司的ew
7、orkflow自定义工作流系统dotnet版,流程引擎采用C#语言实现了FSM有限状态机的流程引擎模型。有限状态机是一种数学模型,广泛应用于流程引擎,rpg游戏等领域。是表示有限个状态以及通过执行动作使得状态发生转移的数学模型。状态转换图:工作流引擎的模型正是利用这种定义的有限个状态和动作,动作的结果导向另外一个状态来达到流程的流转。工作流引擎的每一个状态 一个业务环节 业务环节的状态业务环节:即为一个虚拟的业务操作场所业务环节的状态:即为一个具体的流程运转到此业务环节的实际状态。流程引擎对流程的描述通常是采用xml格式的文档来描述,xml文档中的每个节点都赋予了一定意义,各节点作为流程定义的
8、基本元素,流程引擎能够定义、解释和应用它们来描述尽可能多的业务流程。一个简单的流程描述xml文件:上图xml流程的图解状态过程如下:开始节点-初始化动作-步骤节点动作节点-结束xml文件中基本元素即工作流引擎的基本元素:步骤(step) 一个step描述的是工作流所处的位置。可能从一个step transtion到另外一个step,或者也可以在同一个step内流转(因为step可以通Status来细分,形成多个state)。一个流程里面可以有多个step。状态(status) 状态status 是用来描述工作流程中具体step(步骤)状态的字符串。eWorkFlow中预置了三种步骤的状态 Un
9、derway(进行中)、Queued(等候处理中)、Finished(完成),用户可以任意扩展自己的状态。而工作流的状态state则是由 step(步骤)status(步骤的状态)组成的。工作流状态state的升迁来达到工作流实例的推进。流转(transtion) 一个工作流实例状态state到另一个状态state的转移。动作(action) action 触发了发生在 step 内或 step 间的流转,或者说是基于 state 的流转。一个 step 里面可以有多个action。action 和step 之间的关系是,step 说明“在哪里”,action 说明“去哪里”。 一个 acti
10、on 典型地由两部分组成:可以执行此action(动作)的condition(条件),以及执行此动作后的 result(结果)。 任务(task) 任务是当工作流状态发生转移的时候,产生的任务。任务可以指定为一个具体的角色,人,或者群组。任务具体,待办,已办,竞争办理,代理待办等多种功能。条件(condition)类似于逻辑判断,可包含“AND”和“OR”逻辑。比如一个请假流程中的“本部门审批阶段”,该阶段利用“AND”逻辑,判断流程状态是否为等候处理中,以及审批者是否为本部门主管。结果(result)Result 代表执行action(动作)后的结果,指向新的 step 及其 step st
11、atus,也可能进入 split 或者 join。result 分为两种, contidional-result (有条件结果),只有条件为真时才使用该结果,和 unconditional-result(无条件结果),当条件不满足或没有条件时使用该结果。分支/合并(split/join)流程的分支和合并。分支是指流程下一步可以同时分发给多个步骤,分支split 提供多个unconditional-result(无条件结果);join 则判断多个current step 的状态提供一个 result(结果)。子流程(subflow)子流程,动作的结果可以指向一个子流程,子流程是一个独立的流程,可
12、以单独启动也可以嵌套在另外的流程中启动,和主流程有同步或异步衔接的属性。工作流程引擎利用这些基本的元素,能够实现各种类型的路由。1、串行:就是一个步骤流向下一个步骤的基本路由方式。2、并行:一个步骤下可以执行多个动作,动作的结果可以流向不同的步骤,这是并行路由的一种方式。3、条件:步骤的动作结果可以设置条件,满足条件的则流向条件结果。4、分支:动作结果可以流向一个分支,分支可以同时流向多个不同的结果步骤,这也是并行路由的一种方式。5、合并:多个结果流向一个合并节点,合并节点满足一定条件后,就可以流向下一步骤。6、循环:动作的结果指向本步骤或上一步骤,形成循环路由。7、子流程嵌套:在工作流中嵌套
13、执行另一工作流,叫子流程嵌套路由,子流程可以是同步执行和异步执行两种属性,主子流程可设置输入输出参数来达到信息的传递。8、自由跳转:流程实例运行当中,正常的流程是按照流程定义的节点往下执行,自由跳转就是可以跳转到任意的步骤,执行过和未执行过的步骤。9、回退:回退是指当流程实例运行过程中,由于某些原因回退到已经执行过的某个步骤,并辅助执行业务补偿,使得业务数据也回退到已经执行过的步骤状态。要了解一个工作流系统,必须要先理解流程引擎的模型,理解了流程引擎的原理,模型,就如同掌握这套工作流系统的灵魂,然后再去理解它的全部。否则,一套工作流系统对你来说,可能只是一些复杂的结构,丰富多彩的示例,眼花缭乱
14、的功能 等等。二十三 图解工作流的基本路由方式上一篇主要说明 dotnet工作流引擎的基本原理和引擎的基本元素。这篇主要以图解的方式说明工作流引擎的运转模型,路由方式。一个业务流程包含一序列的处理过程,以及他们的相互顺序关系,还包括过程的启动条件,过程循环,同时还会辅助一些相关的事件消息处理等。工 作流引擎负责创建,定义,解释和运行业务流程,首先需要将业务流程的处理过程转化为流程的基本元素、基本节点,然后将业务处理过程之间的顺序关系用流程引 擎支持的路由方式表达出来,再设置好一些相关的事件消息处理等,业务流程就创建完成。然后再运行流程,启动流程实例,运行业务流程,流程引擎负责解释流程 的各节点
15、以及按路由方式运转业务流程。因此流程的运转模型,支持的路由方式也是工作流引擎的核心内容。常见的运转模型,基本路由方式:串行路由:最简单,也是最容易理解模型,一个步骤接着一个步骤的 基本路由方式。eWorkflow中的图例:并行路由:一个步骤接下来分出多个同时可以执行的步骤,通常会由分支节点分出。eWorkflow中的图例:条件路由:满足条件后导向一个步骤,不满足条件的导向另外一个步骤,就如同代码中的 if (条件1)步骤1else if(条件2) 步骤2else if (条件n) 步骤n.else 步骤n+1eWorkflow中的图例:分支路由:分支路由平行分支出多条线路,多条线路之间是并行的
16、关系。eworkflow中的图例:合并路由:并行的多路分支集结到一个点的路由方式。eworkflow中的图例:循环路由:下一步返回到原来的任意一个步骤,这之间形成的回路就是一个循环路由。可以由多个步骤构成一个循环路由,也可以自己返回到自己,这样的自循环路由。eworkflow中的图例: 子流程嵌套:在工作流中嵌入另外一个独立的流程,主流程的下一步为启动另外一个流程,这样的结构为嵌套自流程。子流程可以是同步执行和异步执行两种属性,主子流程可设置输入输出参数来达到信息的传递。eworkflow中的图例:自由跳转:这种是很特殊的路由方式,在流程实际运行时跳出原来定义的线路,自由跳转到任意的步骤。ew
17、orkflow中的图例:回退:和自由跳转类似,在流程实际运行时跳出物理的回退方式,可以任意的回退到曾经运行过的步骤。eworkflow中的图例:动态多路分支路由:在流程定义的时候只定义一条分支后的运行线路,在流程实际运行时根据实际情况动态创建出n条分支线路。eworkflow中的图例:标签: 自定义工作流, 工作流, 工作流引擎, dotnet工作流引擎二十四 如何构建支持多数据库的.net工作流系统主流数据库有,sqlserver,oralce,db2,mysql。产品级的.net工作流系统必须要能支持这多种数据库,同时还需要能方便的扩展支持新的数据库。在做数据库操作方面,java和.net
18、的各不一样,java是利用jdbc的一套类库来做数据库的读写。但.net的就比较多了,微软提供的就有oledb,sqlclent,oracleClient,odbc等,还有一些第三方提供的访问类。所以在做多数据库支持方面,.net工作流系统,就需要考虑这些方式都支持,并且能很容易的切换。 C#数据库多种访问方式类框图首先按上面的类框图,设计好类接口关系。DbProvider:为数据库类实现方式的接口,提供有打开数据库,关闭,启事务,事务回滚,事务提交等方法。OleDbProvider:为oledb方式的连接数据库的实现类,实现DbProvider接口;OracleDbProvider: 为or
19、alceClient方式的连接数据库的实现类,实现DbProvider接口。SqlDbProvider: 为SqlClient方式的连接数据库的实现类,实现DbProvider接口。DbProviderFactory:负责创建具体的实现类,根据传入的参数来创建具体的数据库操作实现类。Environment: 为需要获取数据库连接的类。具体的数据库连接参数,在binfcconfig.xml文件中,fcconfig.xml文件如下:第一个ds子节点为工作流系统的默认连接 (注:fcconfig.xml文件.net工作流系统和java工作流系统一致,只是具体的属性值设置不一样。)type属性sqlc
20、lient 则为使用SqlDbProvider类创建的DbProvider。type属性oracleclient则为使用OracleDbProvider类创建的DbProvider.type属性oledb则为使用OleDbProvider类创建的DbProvider.在对外的操作中屏蔽了sqlClient,OracleClient,oleDb等的差异。一个简单的使用实例如下:Environment env = new Environment(Session);DbProvider db = env.getDbProvider();env.beginTransaction();string sq
21、l=;sql = insert into wf_user(user_id,user_code,user_name,user_password,user_status) ;sql += values(1,xx,xx,1,1);db.ExecuteNonQuery(sql);sql =select user_code,user_name from wf_user where user_id=1 ;System.Data.IDataReader ds = db.ExecuteSqlReader(sql);if (ds.Read()string usercode =(string)dsuser_cod
22、e;string username1 =(string)dsuser_name;ds.Close();sql =delete from wf_user where user_id=1 ;db.ExecuteNonQuery(sql);mitConnection();env.closeConnection();当如果没有写数据库操作时,则不需要env.beginTransaction();和mitConnection();直接使用db就可以了。二十五 .net工作流系统开发体会.net工作流系统开发体会公司的eworkflow自定义工作流系统,最初是开发了java版的。待java版的功能稳定后,
23、就开始开发.net版的。java版的eworkflow工作流系统,我们没有依赖于任何框架,如struts,spring等,也没有用hibernate,ibatis 等orm映射工具。在支持web方面也有一套自己的mvc框架,都是纯java的代码。因为工作流系统,比较注重的是工作流引擎核心的实现,其他的表现形 式,人机交互等都相对不是工作流系统的重要部分,并且业务模块的自定义表单采用的是eform自定义表单,所以在mvc的框架中,我们只需要注重M部分的 流程引擎的开发。在用.net实现工作流系统的时候,只需要将java版的后台纯java的代码,用.net的c#来实现。java和c#就象孪生兄弟,
24、长的太象 了。都是纯面向对象的,有类,接口,继承,多态等。只是关键字的写法不一样。我们只需一点一点的将java实现的流程引擎代码用c#翻译过来即可,保留所 有的java设计思路,设计模式,包名类路径等。为实现同样的功能,c#的语法有的更简单、方便一些。因为java版的eworkflow 没有依赖于任何开源的框架,所以在实现上少了这些开源框架代码的移植。工作流系统框架图:用c#实现eworkflow工作流系统主要需要修改如下方面的代码。java版:基本的语法,类定义,包名等c#版:改用c#的语法,关键字等。c#的命名空间比java的package更灵活。java版:数组,集合等方面的实现c#版:
25、翻译成对等的 数组,集合等。java版:xml的实现采用jdk1.4自带的包c# :xml的实现采用System.xml在所有涉及xml节点部分的代码全部转换过来。java版:数据库操作采用jdbcc#:数据库的实现比较麻烦。有oledb,sqlclient,oracleclient。这 部分的实现与java版的不同,但仅限于实现方面不同,.net工作流系统的数据库实现采用了工厂模式封装了 oledb,sqlclient,oracleClient的不同,对外表现形式和java工作流系统一样,在所有涉及数据库操作的部分代码逻辑还是一 样。(.net工作流系统的数据库实现见上一篇文章:如何构建支持多数据库的.net工作流系统 java版:反射部分有反射包c#:翻译成c#的反射实现。java版:流程定义时自定义脚本,采用了beanshell。c#:.net方面没有类似的软件,自己开发了一个支持自定义脚本功能,脚本语法是c#(和java版的一样,java版的beanshell脚本语法是java),实现动态编译和加载。还有很多细节方面的修改,散布在各处。总之,java版的eworkflow工作流系统和.net工作流系统也象孪生兄弟一样,功能是一样的,只是实现方式不同。标签: java工作流, 自定义工作流, 工作流引擎, dotnet工作流引擎, .net工作流, .net工作流系统