博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
企业级工作流解决方案(十七)--工作流--工作流插件模型
阅读量:6247 次
发布时间:2019-06-22

本文共 4510 字,大约阅读时间需要 15 分钟。

  我们搭建框架,一方面是需要满足业务的需求、易于后期扩展,另一方面,需要减少开发人员的工作量,让他们不需要整体理解框架的情况下,照样能接入团队进行业务开发。

  WWF工作流开发平台对于很多开发人员都比较陌生,如果让每一个开发人员都充分的理解WWF的定义时和运行时的机制,再接入工作流开发,不管是时间还是成本都是不能接受的。

  我们需要搭建一套工作流开发框架,把WWF的定义时和运行时的逻辑都高度的抽象出来进行封装,让不同的开发者只需要关注业务部分的实现即可。

  工作流插件模型设计图:

  一个WWF工作流,必然有一个唯一的根活动,一般都为组合活动FlowChart,一个组合活动可以包含任何数量的组合活动或者单个活动,活动与活动之间可以通过连线建立关联,工作流运行时,从起点根据连线往下面执行活动逻辑。

  WWF允许我们自定义活动,需要实现活动基娄NativeActivity,自定义活动包括自定义活动设计器以及自定义活动本身,在活动设计器中,我们可以定义双击活动设计器行为,比如双击活动设计器打开活动配置窗体,活动设计器与活动之间的关联是通过ModelItem关联起来的,即在活动的ModelItem里面可以存取活动配置信息。

我们可以在自定义活动增加一个属性,ConfigData,存储活动的配置信息,流程定义时,通过活动配置窗体配置信息,然后把配置信息序列化为字符串,保存到流程定义模版中,设计时和运行时都可以取出ConfigData信息。

  流程运行时,可以把运行时信息持久化到外部存储介质,可以是数据库或者Xml,持久化时,需要指定恢复的书签值,下次运行时,传递书签值到流程引擎,就可以恢复到指定的活动。

一个活动可以定义一个插件与之对应,活动只做一些简单的配置以及对插件的封装,基本不处理具体业务,真正的业务执行交由插件来完成。业务插件也不需要关心活动是什么,以及怎么封装的,只需要执行业务逻辑,需要实现以下几部分内容:

插件需要定义插件配置窗体,双击活动时动态创建窗体,弹出配置窗体,把活动定义时上下文信息传递到配置窗体中,在配置窗体中就可以读取和写入配置信息,由框架负责存储配置信息。插件的Execute方法为运行时活动执行的方法,需要把流程的配置信息取出来做为参数传递给插件的Execute方法。CallbackExecute为恢复书签时执行的方法,工作流恢复时调用此方法。

插件执行定义时活动运行时是不知道工作流的信息的,但是有些时候,需要读取流程的信息,比如运行时工作流的参数集合,定义时流程实例的一些信息,那么这些信息都从IPluginContext插件上下文中获取。

  关于ConfigData,插件框架定义的是string,插件可以定义自己的业务配置接口,定义时序列化为字符串,运行是反序列化为业务配置接口,方便业务处理。

流程发起时会创建流程实例,流程结束时,会更新流程实例状态,流程执行到每一个活动,会创建流程审批项以及流程跟踪信息,流程审批项可以定义TaskId(Guid)做为书签值,某一个用户打开任务时,执行审批,根据TaskId恢复流程运行。

  自定义活动基类:

public abstract class BaseActivity : NativeActivity    {        private object wfworkflowContext;        #region Property        ///         /// 活动对应的插件        ///         [Browsable(false)]        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]        public IPlugin Plugin { get; set; }        ///         /// 活动Id        ///         [Browsable(true)]        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]        public string ActivityId {            get            {                return this.Id;            }        }        ///         /// 工作流配置信息        ///         [Browsable(false)]        public string ConfigData { get; set; }        [Browsable(false)]        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]        public abstract string ActivityIcon { get; }        #endregion        protected BaseActivity()        {            Plugin = GetPlugin();        }        protected abstract IPlugin GetPlugin();        protected abstract override void Execute(NativeActivityContext context);        protected void SetTryRunParams(PluginContext pluginContext, WFWorkflowContext wfworkflowContext)        {            var unitOfWorkManager = IocManager.Instance.Resolve
(); UnitOfWorkOptions unitOfWorkOptions = new UnitOfWorkOptions(); using (var uow = unitOfWorkManager.Begin(unitOfWorkOptions)) { var wf_WF_FlowItemRepository = IocManager.Instance.Resolve
>(); var wf_WF_FlowTrackItemRepository = IocManager.Instance.Resolve
>(); WF_FlowItem flowItem = wf_WF_FlowItemRepository.Get(wfworkflowContext.WFActivityRunData.FlowItemId); WF_FlowTrack flowTrack = wf_WF_FlowTrackItemRepository.GetAll() .Where(r => (r.WF_FlowInstance_Id == flowItem.WF_FlowInstance_Id) && (r.ActivityId == Id)).OrderByDescending(r => r.TrackTime).FirstOrDefault(); if (flowTrack != null && !string.IsNullOrEmpty(flowTrack.ActivityParam)) { pluginContext.RuntimeService.SetArgValue(flowTrack.ActivityParam, flowTrack.RouteValue); } uow.Complete(); } } }

  插件基类:

public interface IPlugin    {        ///         /// Plugin上下文        ///         IPluginContext PluginContext { get; set; }        ///         /// 工作流运行时调用的方法        ///         /// ConfigData        /// 
调用反回值
bool Execute(IConfigData configData); /// /// 返回工作流设计时,活动弹出的窗体 /// /// ConfigData /// 工作流设计时上下文 /// 事实库类型 ///
活动弹出窗体
IConfigForm GetConfigForm(IConfigData configData, WorkflowDesignService workflowDesignService, List
factModel, Guid flowDefineId); ///
/// 恢复书签调用的回调方法 /// ///
ConfigData ///
工作流运行时数据 ///
调用反回值
bool CallbackExecute(IConfigData configData, IWFActivityRunData wfactivityRunData); }

 

转载于:https://www.cnblogs.com/spritekuang/p/10852812.html

你可能感兴趣的文章
log springboot 日志
查看>>
语音压缩编码——脉冲编码调制
查看>>
月薪80k阿里架构师:给迷茫的JAVA一些中肯建议(附学习路线图)
查看>>
近几年,出现的技术热点有哪些?
查看>>
求人不如求己,MySql常见问题解析
查看>>
批处理-映射磁盘驱动
查看>>
理解 QEMU/KVM 和 Ceph(1):QEMU-KVM 和 Ceph RBD 的 缓存机制总结
查看>>
理解 OpenStack 高可用(HA)(5):RabbitMQ HA
查看>>
获取应用的IP,端口等
查看>>
Java平均拆分list
查看>>
UFT开发实例:一个完整的测试框架源码
查看>>
java的元组封装:JTuple
查看>>
我的友情链接
查看>>
Python Virtualenv
查看>>
zimbra mail.TRY_AGAIN
查看>>
域名解析服务(DNS)之bind
查看>>
mybatis xml使用不存在的类
查看>>
服务器机柜和网络机柜的区别
查看>>
我的友情链接
查看>>
saltstack安装配置
查看>>