• 工作流系统中的语法标记系统


    以微软的WF为基础,为达到ERP中的批核与通知目的,参考现有系统中的技术,在此分享其中的技巧。

    先来看最终的结果,也就是下图中的工作流宿主。

    image

    在上面的工作流定义中,除工作流宿主(rehost)技术外,还需要解决规则表达式的解析难题。

    .NET WF提供的规则编辑器是基于代码的,但对于一个无代码的开发环境,需要找到一种表达式的设计,解析规范。

    比如,在运行时,我们需要根据当前的运行参数解析出以上表达式的分支,最终流向哪个批核结点。

    经过摸索,我提供现有系统中已经应用的三种方案,供读者参考。

    1 查询表达式

    比如一个费用报销流程,当报销金额小于1000元时,可由部门主管直接批核。用SQL语句表达如下:

    SELECT AMOUNT  FROM dbo.ICMOVH WHERE AMOUNT <1000  
    
    AND REF_NO='<%InventoryMovementEntity.RefNo%>‘
     
    <% 标记表示当前正在运行的业务对象,<%InventoryMovementEntity.RefNo%> 这一句可取到当前业务对象的标识值。再与金额条件Amount(小于等于1000)组合,当存在这样的单据时,即为满足分支条件,由部门主管批核。
     

    2 查询语句

    查询语句的作用是为了发送消息通知,将SQL命令通过参数化的方式封装,达到运行时获取数据的目的。
    比如一个安全库存报警,当物料安全库存变动时,物料的库存余额小于当前物料设定的安全库存。
    image 
    为了查询数据,设计出一种新语法标记,例子如下:
    <%RepeatEachRecord_Begin.SqlQuery1%> 
    
    Job No: <%SqlQuery1.job_no%>
    
    <%RepeatEachRecord_End.SqlQuery1%>

    通过上图的界面设计中可看出,一个消息通知可包含很多个SQL命名查询,每个SQL命名查询可返回一个或多个数据行,我们在消息文本中用特定的语法,解析出命名查询中字段,即可达到获取数据的目的。

    3 常量

    工作流中的活动可理解为一个封装的独立的代码片段,为了与外界通信,必须向活动传递参数。有时候参数是固定的值,比如当前的报销单据,在前面我们用到过<%InventoryMovementEntity.RefNo%>表示报销单据编号。

    若是要取到当前登录系统的用户,可用<%SessionEntity.UserId%>来获取。

    比如给仓库单据增加一个验证,取出当前用户创建的引用(Reference)为空的参考编号。可通过下面的SQL语句实现:

    SELECT RefNo  FROM dbo.ICMOVH WHERE REFERENCE IS NULL 
    
    AND CREATED_BY='<%SessionEntity.UserId%>‘
     

    4 调用程序代码

    在一套业务工作流系统中调用代码实在是无奈之举。如果发生的业务很有规律,可考虑封装为活动以方便重用。

    代码活动的表达方式如下:

    image

    我用了三行标记为的是表示一个.NET方法:
    assembly=Microsoft.Workflow
    
    class=Microsoft.Workflow.Extension
    
    method=Microsoft.Workflow.Extension.VoucherPost
    如果你熟悉.NET反射,很快能写出调用这个方法的代码。
    Assembly assembly = null;
    
    Type type = null;
    
    string method = string.Empty;
    
    List<string> format = new List<string>() { "assembly", "class", "method" };
    
    string[] codes = Regex.Split(this.Code, ";");
    
    foreach (string code in codes)
    
    {
    
       if (string.IsNullOrWhiteSpace(code))
    
                        continue;
    
       string[] segments = Regex.Split(code, "=");
    
       if (Microsoft.Common.Shared.StringCompare(segments[0].ToUpper(), "assembly".ToUpper()) == 0)
    
             assembly = Assembly.Load(segments[1]);
    
       if (Microsoft.Common.Shared.StringCompare(segments[0].ToUpper(), "class".ToUpper()) == 0)
    
             type = assembly.GetType(segments[1]);
    
       if (Microsoft.Common.Shared.StringCompare(segments[0].ToUpper(), "method".ToUpper()) == 0)
    
            method = segments[1];
    
    }
    
    type.GetMethod(method, BindingFlags.Public | BindingFlags.Static).Invoke(null, null);
    从最后一段代码中可以看出,上面标记的方法必须是静态(static,非实例)方法。
     
    最后,我将前三种情况附加到程序中,以帮助对话框的形式提供给工作流开发人员。
    image 
     
    我这里所提到的工作流是以微软的WF为基础开发的一套工作流系统,如果你需要自定义一套工作流设计,业务开发,表达式解析等功能,文中的标记技术可供您参考。
     
  • 相关阅读:
    java中的位运算符
    Servlet中的初始化参数、上下文参数、以及@Resource资源注入
    Servlet中文件上传的几种方式
    marquee标签的使用
    SpringBoot热部署的两种方式
    eclipse中安装lombok插件
    关于Servlet中的转发和重定项
    Cormen — The Best Friend Of a Man CodeForces 732B
    牛客小白月赛9之签到题
    Codeforces アンバランス / Unbalanced
  • 原文地址:https://www.cnblogs.com/JamesLi2015/p/5476030.html
Copyright © 2020-2023  润新知