我的微型工作流引擎-功能设计解析及使用示例

一、前言

上一篇我给大家介绍了我的工作流的模型和基本的设计,这篇我想详细说明下我这款工作流的功能及使用示例。这款工作流主要是面向开发者设计的,为了先让大家有个全局的认识,局部功能的设计实现就不细说了,后续有时间我会继续写文章向大家介绍。

二、功能详解及使用示例代码

1、配置流程引擎,一般在程序启动过程中调用(Global.asax.cs中)

//初始化流程引擎
BpmConfiguration
    .Instance()
    .Config(@"C:\Configration\BpmConfig.xml")
    .Start();

如果不指定配置文件,则默认从app.config或web.config中读取流程配置

//初始化流程引擎
BpmConfiguration
    .Instance()
    .Start();

当然还支持同时启动多个流程引擎,以提供SAAS程序的支持。

//A租户引擎配置
BpmConfiguration
    .Instance("TenantA")
    .Config(@"C:\BpmConfigA.xml") 
    .Start();

//B租户引擎配置
BpmConfiguration
    .Instance("TenantB")
    .Config(@"C:\BpmConfigB.xml")
    .Start();

XML中的配置包括:数据库连接、日志配置文件、任务计划启动延时、任务计划执行周期、用户关系结构的映射、流程中变量类型的拓展等。

2、取得工作流上下文,即工作流的入口,所有的功能都集中在这个入口上。

var bpm = new BpmContext()
    .UseTransaction(true)
    .SetActor("萧秦");

当前对于不同的引擎实例,其上下文是不同的

var bpm = new BpmContext("TenantA");
var bpm = new BpmContext("TenantB");

不传构造参数时,返回的是默认实例。
 
    3、事务支持,是否开启事务、提交、回滚。

bpm.UseTransaction(true);
bpm.Commit();
bpm.Rollback();

4、流程定义

//新增流程定义
bpm.NewProcessDefinition("请假流程")
    .SetXmlFile(@"C:\Definition\demo1.xml")
    .SetCategory("分类1")
    .SetEffectDate(DateTime.Now)
    .SetExpireDate(DateTime.Now.AddDays(180))
    .SetMemo("memo1")
    .Create()   //创建流程定义
    .Parse()    //解析xml

流程创建时,版本号是自动生成的,默认从1.0开始,当流程名称相同时,就会生成不同版本。
在xml中可定义不同的任务节点:开始节点、自动节点、人工节点、决策节点、发散节点、聚合节点、子流程节点、会签节点、等待节点、结束节点。

及连接任务节点的路由、人员分配情况、变量定义、事件动作等信息,可参照我上篇文章中的xml定义

//加载流程定义
var processDefinition = bpm.LoadProcessDefiniton("1");
processDefinition.Deploy();     //发布流程定义
processDefinition.Revoke();     //召回流程定义
processDefinition.Delete();     //删除流程定义

5、流程实例

//发起流程实例
var process = bpm.NewProcessIntance("请假流程","萧秦");
process.SetVariable("project_id", 1399); //保存流程变量
process.Start();   //启动
process.Suspend(); //挂起
process.Resume();  //恢复
process.Cancel();  //撤销
process.End();     //结束

这里NewProcessInstance这个方法实例上有三个参数,第一个是流程定义ID,第二个是启动的业务ID,第三个是子流程的返回栈点ID,非子流程可以忽略。

//启动流程
var startTask = process.Start();
startTask.SetRecord("SO20150903001");       //保存表单数据(关联)
startTask.SetAttach("01", "02");            //保存附件信息(关联),可多个
startTask.SetVariable("var1", "value1");    //保存任务变量
startTask.Signal();                         //转交下一步

task.SetRecord用于保存当前表单数据id,数据本身保存在业务表中
task.SetAttach用于保存当前节点的附件id,附件信息则保存在附件管理表中

task.Signal流程流转的关键方法,根据流程定义触发token令牌离开动作

//审批任务
var task = bpm.LoadTaskInstance("00");
task.SetOpinion(SignResult.Passed, "我同意");  //设置审批意见
task.SetReceiver("颜经理");                    //设置下一步的审批人
task.Signal();                                //转交下一步

这里提供了SetReceiver的方法设置下一步的审批人,正常情况下流程定义中已经定义好了,是不需要再进行设置的,但是考虑在实际应用中可能会有把任务给指定领导审批的情况,在通达OA中也是可以设置下一步审批人,故添加了此方法,需要时可以调用,注意应用此方法会覆盖定义中对工作项owner属性的设置。

//任务委派
var task1 = bpm.LoadTaskInstance("01");
task1.AssignCandidate("小郑,小胡");              //添加任务候选人
task1.AssignCandidate("saler", ActorType.Role); //添加任务候选人
task1.AssignTo("李四");                         //把任务分配给李四

我的工作流中,对于工作任务只能有一个所有者(owner),一个实际操作者(actor),但可以拥有多个候选人(candidate)。
候选人是当前工作可分配的一范围限制或人员列表,owner是任务的拥有者,actor是owner考虑复杂委办关系后计算出的操作者。

task.AssignCandidate这个方法用于添加任务候选人,第二个参数是对象类型,可以直接添加一个角色、机构、用户组等。

task.AssignTo即分配任务,任务的分配状态包括以下几个状态

public enum AssignStatus
{
    //未决
    Pending,

    //认领, 用户认领任务并接收任务输入数据
    Claim,

    //委办, 委派给另一个人(例如,经理)以代替他或她执行任务
    Depute,

    //到期, 没有在指定的时间段内处理批准任务
    Expire,

    //续订, 没有在给定的时间范围内处理此任务,则该任务将被续订,以便在另一时间段内执行
    Renew
}

如果流程卡到某个节点很久,我们可以发催办消息
如果一个流程节点的确需要很久才能完成,我设计了一个当前工作进度汇报接口

//工作催办
task.Urge("很急,请经理尽快处理,在线等!");

//汇报当前工作进度
task.Report(0.6, "预计这个星期就能完成");

task.Urge会向任务实际拥有者发送一条催办通知,并生成催办历史。
task.Report会向任务的订阅者(所有关注当前流程任务的人)发送一条进度报告。

//查询变量
var var0 = process.GetVariable("project_id");
var var1 = task1.GetVariable("var1");
var var2 = task1.GetVariable<DateTime>("var2");
var var3 = task1.GetVariableObject("var3");

变量分为三种:
流程变量 会持久化,存在于整个的流程周期内

任务变量 会持久化,存在在当前的任务中

临时变量 不会持久化到数据库中,只存在于当前执行上下文中(executionContext)。

设置变量SetVariable 获取变量GetVariable

支持任意数据类型

6、中国特色审批方式,主要包括会签、加签(前加签、后加签、并加签)、减签、自由流

会签:一个任务由多个人参与共同做决策

加签:这个任务我自己觉得没有把握,想加入一个人或多个人跟我共同决策(在前加签顺序在当前决策者之前,后加签顺序在当前决策者之后,并加签不分顺序并行处理)

减签:跟加签相反,取消某人参与决策的资格

自由流:流程定义中没有,临时添加的动态路由直接把当前工作发送到指定的节点审批。

转会签:由单人决策的普通审批节点转成多人共同决策的会签节点,支持递归会签,即会签子节点可以继续转会签节点 。

转审批:由多人共同决策的会签节点转成单人决策的普通审批节点

在我在工作流中,会签设计了以下几个参数:

a 运行模式,并行时如发散节点,进入会签节点时会同时激活所有参与人的工作任务,串行时则有先后顺序,所以才有了前加签和后加签

public enum RunMode
{
    //串行
    Serial,

    //并行
    Parallel
}

b 决策模式,根据子节点的结果如何去决策会签节点

public enum DecisionMode
{
    //主办人模式
    Sponsor, 

    //投票模式
    Vote, 

    //一票通过
    OnePass, 

    //一票否决
    OneVeto
}

主办人模式:需要设置一个主办人,结果以主办人的决策为准,其它人的决策只是提供参考
投票模式:即设置一个通过的比例,由大家投票决定。支持设置每个人的投票权重。

一票通过:其实可以看作是投票模式通过率设置大于0%的一种。

一票否决:可以看作投票模式通过率设置100%的一种。

当然这里只是我把常用的几种模式列出来了,还可以自己拓展决策模式,只需要继承实现我定义的抽象类Decision即可。

c 是否等待,即还有人未表决,但目前已表决的情况已经可以确定会签结果的情况下,需不需要等待其它人表决完成后才继续转交下一步。

会签分两种,一种是流程定义中定义好的会签,一种是普通审批节点临时转成会签的。实际上中国式审批其实就是要灵活,如果在流程定义中定义好的,其实可以不用会签节点,用多个普通节点也可以去实现。会签节点的设计主要是为了转会签这个场景:就是当前普通审批节点的审批人觉得自己没有把握或者不想担责任,可以加入上级领导或其它更多的人一起来决策或提供参考意见。

示例:普通审批转会签 运行模式设置为并行,决策模式是权重投票,需要等待所有人都投票,通过线为65%

//转会签
var task2 = bpm.LoadTaskInstance("02");
task2.ToCountersign(RunMode.Parallel, DecisionMode.Vote, true, 0.65M);
task2.CountersignAdd(new Countersigner() { actor_id = "张三", vote_weight = 1 });
task2.CountersignAdd(new Countersigner() { actor_id = "李四", vote_weight = 0.5 });
task2.CountersignAdd(new Countersigner() { actor_id = "小五", vote_weight = 2 });

并行模式即为并加签,前加签、后加签的前提是串行模式,假设task2为串行、主办人模式、原审批人为萧秦

//前加签
task2.CountersignAddBefore("萧秦", new Countersigner() { actor_id = "张三"});

//后加签
task2.CountersignAddAfter("萧秦", new Countersigner() { actor_id = "李四", is_sponsor = true});

减签则相对比较简单了

//减签
task2.CountersignRemove("王五");

会签节点转普通审批,直接让一个人决策

//转审批
 task2.ToSinglesign("隔壁老王");

自由流模式,创建临时路直接跳转到指定节点进行审批

//自由流
var task3 = bpm.LoadTaskInstance("03");
task3.SetFreeRedirect("总经理审批");
task3.Signal();

7、回退机制

流程回退到指定节点

//流程实例指定任意节点回退
var process2 = bpm.LoadProcessInstance("02");
process2.Rollback("填写请假单");

任务实例回退到上一步

//当前工作任务回退到上一个审批节点
var task4 = bpm.LoadTaskInstance("04");
task4.Rollback();

8、工作委办

张三把某个任务直接委托给李四办理,支持递归委办关系,即张三委托给李四,李四再委托给王五,王五在委托给赵六…

bpm.NewDeputeService("张三", "李四")
   .ForTaskInstance("任务实例ID")
   .Depute();

把整个流程实例委托给李四,即此流程实例下所有的张三的任务都会委托给李四

bpm.NewDeputeService("张三", "李四")
   .ForProcessInstance("流程实例ID")
   .Depute();

把某个流程定义中的一个任务节点委托给李四,即所有的这个节点创建的所有任务实例如果是张三的任务都会委托给李四

bpm.NewDeputeService("张三", "李四")
   .ForTaskDefinition("任务定义ID")
   .Depute();

把某个流程定义委托给李四,即这个流程中创建的所有的任务实例,如果是张三的任务,在设置的生效期间中都会委托给李四

bpm.NewDeputeService("张三", "李四")
   .ForProcessDefinition("流程定义ID")
   .SetDateRange(DateTime.Now, DateTime.Now.AddDays(30)) //生效期间
   .SetMemo("这个月出差,这个流程都委托给李四代办")            //委托说明
   .Depute();

收回委托关系,只要将Revoke替换Depute动作即可

//收回委办工作
bpm.NewDeputeService("张三", "李四")
   .ForProcessInstance("流程实例ID")
   .Revoke();

9、关注订阅

这个功能跟委托相似,订阅后会收到流程动态或任务动态消息提醒,如:流程已创建、启动、挂起…,任务已创建、分配给谁、进度汇报、任务完成等等

//关注订阅
bpm.NewSubscribeService("张三")
   .ForTaskInstance("任务实例ID")
   .Subscribe();

bpm.NewSubscribeService("张三")
   .ForProcessInstance("流程实例ID")
   .Subscribe();

bpm.NewSubscribeService("张三")
   .ForProcessDefinition("流程定义ID")
   .Subscribe();

bpm.NewSubscribeService("张三","李四","王五")
   .ForTaskDefinition("任务定义ID")
   .Subscribe();

取消订阅,一样只需要把Subscribe改为Unsubscribe即可

//取消订阅
bpm.NewSubscribeService("李四")
   .ForProcessDefinition("采购流程")
   .Unsubscribe();

10、数据查询

查询我没有提供接口,直接开放数据库查询比我提供的接口会更加灵活,比如:

a 查询已发布的流程定义

select * from bpm_definition_process where state = ‘Deploy‘

流程定义状态包括

public enum ProcessDefinitionState
{
    //创建
    Create,

    //解析
    Parse,

    //发布
    Deploy,

    //回收
    Revoke,

    //删除
    Delete
}

b 我的流程

select * from bpm_instance_process where state = ‘Run‘ and starter = ‘萧秦‘

流程状态包括

public enum ProcessState
{
    //创建
    Create,

    //运行
    Run,

    //挂起
    Pending,

    //终止
    Termination,

    //完成
    Complete,

    //取消
    Cancel
}

c 我的待办任务

select * from bpm_instance_task where state = ‘Run‘ and actor_id = ‘萧秦‘

待办任务包括了别人委托给你的任务,如果只想看属于自己的任务则可以

select * from bpm_instance_task where state = ‘Run‘ and owner_id = ‘萧秦‘

任务状态包括

public enum TaskState
{
    //创建, 任务已被创建
    Create,

    //阻塞, 到达线中有阻塞任务还未完成
    Blocking,

    //启动
    Run,

    //完成, 用户已经完成任务并提供了任务的输出数据
    Complete,

    //失败, 用户已经完成任务, 并且提供了错误消息
    Failure,

    //回退
    Rollback
}

d 查询任务的候选人信息

select * from bpm_instance_assignment where task_instance_id = ‘ID‘

e 查询我的消息

select * from bpm_application_notify where state=‘Unread‘ and reciever_id = ‘萧秦‘

其它查询就不再举例了

三、总结

之前我有说过我开发这个的引擎的目的是为了在做项目时,有一个体积轻巧,引入方便的单dll文件(发布后大小为1.1M)的工作流引擎,接口也简单易于二次开发,支持多数据库并且功能还算强大。从前年开始的简易版本设计开发到现在基本成形,测试也是花费了大量的时间,可能还有问题没有测到,不过现在基本稳定。接下来如果有时间我会慢慢跟大家介绍功能细节的设计和实现,如果还有什么功能我考虑不周全的大家可以留言给我提提意见。

时间: 2024-10-22 18:26:22

我的微型工作流引擎-功能设计解析及使用示例的相关文章

微型工作流引擎-功能设计

我的微型工作流引擎-功能设计解析及使用示例 一.前言 上一篇我给大家介绍了我的工作流的模型和基本的设计,这篇我想详细说明下我这款工作流的功能及使用示例.这款工作流主要是面向开发者设计的,为了先让大家有个全局的认识,局部功能的设计实现就不细说了,后续有时间我会继续写文章向大家介绍. 二.功能详解及使用示例代码 1.配置流程引擎,一般在程序启动过程中调用(Global.asax.cs中) //初始化流程引擎 BpmConfiguration .Instance() .Config(@"C:\Conf

微型工作流引擎设计

微型工作流引擎设计 一.前言 提到工作流很多人就会想到OA,的确OA就是典型的工作流的应用,但是工作流并不仅仅局限于OA,工作流应该算是基础框架软件,主要用于流程的重组和优化,它有广阔的应用领域.在java下有很多优秀的开源工作流可以选择比如activit5.jpbm4等,在.net下却几乎找不到令人满意的工作流引擎可用.当然不是说.net下没有开源的只是有些国产开源的但看了代码后就一点兴趣都没有了,且不说代码质量如何,还引入了一大堆的东西,想在项目中应用也是非常困难.鉴于此我还是决定自己开发一

我的微型工作流引擎设计

一.前言 提到工作流很多人就会想到OA,的确OA就是典型的工作流的应用,但是工作流并不仅仅局限于OA,工作流应该算是基础框架软件,主要用于流程的重组和优化,它有广阔的应用领域.在java下有很多优秀的开源工作流可以选择比如activit5.jpbm4等,在.net下却几乎找不到令人满意的工作流引擎可用.当然不是说.net下没有开源的只是有些国产开源的但看了代码后就一点兴趣都没有了,且不说代码质量如何,还引入了一大堆的东西,想在项目中应用也是非常困难.鉴于此我还是决定自己开发一款.NET微型工作流

Activiti6.0工作流引擎深度解析与实战|activiti6视频教程

Activiti6.0工作流引擎深度解析与实战网盘地址:https://pan.baidu.com/s/1aqGADN23lUKzcwkbTaV90g 密码: xmj5备用地址(腾讯微云):https://share.weiyun.com/5Z7sAqb 密码:8pwrkb 工作流引擎驱动业务正在互联网公司中盛行,越来越多的互联网公司开始采用工作流引擎的方式来适应业务的快速变化. 本课程将系统且深入源码讲解Activiti6.0工作流引擎的使用.配置.核心api以及BPMN2.0规范.数据库设计

我的微型工作流引擎-办公应用实战

一.前言 前面已经给大家介绍了我的工作流引擎的总体设计及的API设计,这篇是实战篇说说怎么实际应用了,这就得涉及到UI界面了.首先我们常用的工作流个人办公应用系统至少要包括发起流程.待办事项.已办事项等.我们设计了一个尽量简单的系统,能够满足个人办公的基本需求,只实现以下功能:     1.发起流程     2.待办事项     3.已办事项     4.我的流程     5.我的消息     6.我的委办 这些功能基本就是流程能正常的运行流转基础,其实只应用了我们引擎的一小部分功能,其它功能如

Activiti6.0工作流引擎深度解析与实战

第1章 课程介绍 本课程将系统且深入源码讲解Activiti6.0工作流引擎的使用.配置.核心api以及BPMN2.0规范.数据库设计及模型映射,Spring Boot2.0集成,工作流平台搭建.部署与运维等,通过本课程的学习,你将切实学会Activiti6.0工作流引擎开发,大大提升自己的业务建模能力,技术架构能力,开源库研究能力,流程梳理能力,从而进阶为Jav... 1-1 课程导学 第2章 工作流入门 本章首先介绍了工作流是什么,工作流技术选型,然后带大家快速体验activiti6.0,让

闲话js前端框架(5)——再看自己一年前设计的微型渲染引擎

闲话js前端框架 前端人员=美工+设计+代码+测试 --题记 专题文章: 一.从avalonjs的模板说起 二.庞大的angularjs 三.再也不想碰DOM 四.组件化?有没有后端的事? 五.再看自己一年前设计的微型渲染引擎 六.在浏览器标准上做文章 七.抛开浏览器,构建应用容器 八.为何Flash.银光和Java都在网页端一蹶不振 本文属 西风逍遥游 原创, 转载请注明出处: 西风世界 http://blog.csdn.net/xfxyy_sxfancy 五.再看自己一年前设计的微型渲染引擎

Slickflow.NET 开源工作流引擎基础介绍(二)

集成流程引擎的必要性 业务过程的变化是在BPM系统中常见的现象,企业管理层需要不断优化组织架构,改造业务流程,不可避免地带来了业务流程的变化,企业信息系统就会随之面临重构的可能性.一种直接的方式是改造业务代码,适应业务过程的变化,这将会面临不断改写代码的需求:还有一种方式是使用流程引擎控制业务过程的变化,将改写业务代码的操作交由流程引擎,通过流程引擎解析业务规则,驱动业务过程流转,从而将改写业务代码的可能性降到最低. 显而易见,流程引擎带来的好处是为了更好解决业务过程变化后带来的重构风险,信息系

高性能JavaScript模板引擎原理解析

随着 web 发展,前端应用变得越来越复杂,基于后端的 javascript(Node.js) 也开始崭露头角,此时 javascript 被寄予了更大的期望,与此同时 javascript MVC 思想也开始流行起来.javascript 模板引擎作为数据与界面分离工作中最重要一环,越来越受开发者关注,近一年来在开源社区中更是百花齐放,在 Twitter.淘宝网.新浪微博.腾讯QQ空间.腾讯微博等大型网站中均能看到它们的身影. 本文将用最简单的示例代码描述现有的 javascript 模板引擎