95. 基于Notes/Domino的文档工作流系统(七)

本文继续剖析基于Notes/Domino的文档工作流系统的设计和代码,以方便用户能应用和创建自己的工作流。(CSDN的下载资源一旦上传就不能修改,很不方便,现已将下载地址改到GitHub,若发现下载有问题,请与我联系。)

在前文对工作流建模时,我们抽象出以下几类对象:

工作流:每个工作流实例都存放工作流名称、当前节点等信息,并负责处理流程各节点的操作。

采用工作流的业务对象:在这里也就是采购单。

工作流的配置对象:不同工作流实例以及各个节点的操作的实际差异都是从配置数据中读取的。

最后一类对象体现为工作流、节点和操作三种配置文档,在上文已经介绍。前两类对象在我们的Notes工作流里保存于同一个文档,即流程文档主文档合一。现在我们就来看看与这个文档对应的表单设计和代码类。

流程子表单

流程文档的字段都包含在FlowControls子表单内,主文档对应的则是主表单,这样只要将该子表单嵌入主表单,主文档就具备了运行工作流的数据。

应用它创建你的工作流时需注意以下几点:

1. 能进行工作流的操作的用户有三类,一是流程在当前节点的处理人,保存在FlowControls子表单的PersonInCharge字段里。二是能进行像取消Cancel这样的操作的特殊用户,保存在FlowHandlers字段里。三是特权用户角色,像本演示流程用的[IT]角色,能进行上述两类操作。这个[IT]不宜配置,所以在Actions按钮的隐藏公式和代码里都直接用的。所以须将它换成你的系统里代表特权用户的角色。

2. 流程名称保存在FlowName字段里。因为位于通用的子表单内,无法直接写入特定的流程名称,所以在创建主文档时,要将应用的流程名称写入该字段。例如:

    Dim doc As NotesDocument
    ‘CreateDoc is a function in LS library lsNotes
    Set doc=CreateDoc("fmPurchasing")
    doc.FlowName="Purchasing"

    Dim ws As New NotesUIWorkspace
    Call ws.EditDocument(True, doc)

3.当前状态保存在Status字段里。在表单上要显示当前状态的地方可以创建一个计算文本或显示时计算字段引用Status字段的值。

4.ActionOptions和Action用于用户点击流程操作时容纳操作选项和用户的选择。PersonInCharge和FlowHandlers分别保存流程的当前处理人和能进行特殊操作的用户。FlowEnds保证流程是否结束的标志,初始值为0,结束时为1。CreatedBy记录文档的创建者。FlowReaders保存文档的读者,FlowWriters保存除流程处理人之外的其他可能的编辑者。FlowComments用于临时容纳用户进行流程操作时写的意见。

5.当用户点击子表单上的流程操作Actions…时,系统需要从流程操作配置文档读取数据并计算出该用户可见的操作选项。完成此功能的代码类FlowActions保存在lsSimpleFlow脚本库中。

工作流类

本流程系统在客户端和XPages环境下运行使用的语言分别是LotusScript和Java。下面先讨论LotusScript下的实现。处理流程各节点操作的通用代码组成了三个类,都在lsSimpleFlow脚本库里。之所以用三个类,是为了在普通应用之外满足测试的需要。作为核心的后端代码都在AbstractFlow类中。一般流程操作都使用它的子类SimpleFlow,作用是从NotesUIDocument获取主文档,处理字段校验等涉及界面交互的任务。BatchFlow类在构造函数内传入主文档,没使用到任何前端类,可用于测试或批量审批。为了方便不妨将这些类称为流程引擎。

如前文所述,这些类能完成以下流程的通用功能:

  • 校验必填字段。
  • 修改流程文档的权限,包括有关的读者域、作者域、存取控制区段。
  • 添加操作记录。
  • 修改配置的业务字段。
  • 发送邮件通知相关处理人。

实际工作流往往会有特殊的需求,这就要求能以某种方式扩展流程类,基本上可概括为在流程提交前后执行一定的逻辑,不妨分别称为QuerySubmit和PostSubmit的业务逻辑。在Lotus Notes中理论上有很多种方式可考虑。

1. 将特定流程的代码写在配置文档里。

因为LotusScript是一种解释型的脚本语言,流程引擎可以像读取其他配置数据一样以文本的形式读取这些代码,再解释执行。

缺点是这些代码不在Designer内编写,没有语法校验、颜色标记、格式化等帮助,运行时若出错很难调试,以及没有经过预处理速度也会稍慢。

2. 在流程类的代码中添加运行特定流程逻辑的函数。

例如在流程类的Submit方法中调用QuerySubmit和PostSubmit函数,它们或与流程引擎同位于一脚本库lsSimpleFlow,或在lsSimpleFlow引用的另一脚本库中。

缺点是通用的流程类对特定的流程逻辑产生了依赖。lsSimpleFlow脚本库无法单独部署到某个应用程序里。如果QuerySubmit之类的函数保存在lsSimpleFlow脚本库里,一旦流程引擎的代码需要更正或升级,就不能简单刷新该脚本库。如果这些特定的逻辑存于lsSimpleFlow脚本库引用的另一个脚本库内,则该库的名称须写死,并且逻辑上让通用代码引用特定代码的设计奇怪不易理解。

3. 采用事件机制在流程引擎中调用特定流程的代码。

要实现流程引擎与特定流程代码之间的分离,在许多程序语言中都会采用所谓事件的机制。LotusScript也支持事件,但仅限于NotesUIDocument等对象预定义的事件。为了让自定义类能够支持事件机制,我们需要自己编写代码。在33. 面向对象的LotusScript(六)之为自定义对象模拟事件Java、LotusScript和JavaScript中的自定义事件编程等几篇文章里我讨论了在LotusScript实现事件机制的两种途径。以两者中较优的类似Java中自定义事件的实现方式为例,要在流程引擎的Submit方法前模拟QuerySubmit事件,需要编写一个包含QuerySubmit方法的FlowEventHandler类,然后调用流程引擎的AddEventHandler方法传入该类的一个实例,最后在Submit方法中调用该实例的QuerySubmit方法。

4. 在通用流程类的子类中写入特定流程的代码

在AbstractFlow类的Submit方法中调用空的QuerySubmit和PostSubmit函数。在SimpleFlow的子类内,如我们演示的采购工作流的PurchaseFlow,再此两函数中写入实际的代码。这类似于Java中的实现接口。

与采取事件机制相比,此方法也要求为某个特定的流程写一个类。另一个好处是有需要时在子类中可以覆盖通用流程类的其他方法,例如流程操作配置文档难以满足某一操作选择下一节点的复杂要求时,可以覆盖GetNextNode方法,在其中写入所需的逻辑。

5. 在一个引用流程引擎的脚本库中以函数而不是类的方式编写特定流程的代码

上述两种方式中的类代码都是在某个引用lsSimpleFlow库的脚本库里编写的,那么是否一定要以面向对象的形式呢,直接以一组函数的方式编写特定流程的代码,在主函数中按次序调用通用流程类和其它函数如何?

与方法4相比,此途径只有几个细微的劣处:

因为PostSubmit的逻辑从在SimpleFlow类的Submit方法内调用变为从主函数中调用Submit方法后运行,原本在Submit方法内完成的前端文档NotesUIDocument的一系列Reload、Refresh、AutoRefresh操作也宜移至PostSubmit函数内。再加上QuerySubmit和PostSubmit函数里必然会用到主文档等其他对象,必须写代码获得,而不能如在子类中那样直接引用。

通常QuerySubmit的逻辑是在Submit方法内的表单校验通过后再运行,以函数的方法顺序调用QuerySubmit和SimpleFlow对象时就无法做到这一点。

综合以上讨论,我们选择方法4——在通用流程类的子类中写入特定流程的代码。特定流程类的代码容纳于lsLocalFlow脚本库中,此脚本库名不得不固定下来,因为在调用它的FlowControls子表单需要确定地引用它的名称。子表单的Actions操作最终调用的是这个脚本库里的SubmitFlow函数:

Function SubmitFlow(flow As String, curNode As String, action As String)
    If Not IsDebuggingLS() Then
        On Error Goto ErrorHandler
    End If
    ‘Dim objFlow As New SimpleFlow(flow,curNode,action)
    Dim objFlow As New PurchaseFlow(flow, curNode, action)
    Call objFlow.Submit
    Exit Function
ErrorHandler:
    Call objFlow.RollBack()
    MessageBox Error & " occured when flow submitted at line " & CStr(Erl),64,"Error " & CStr(Err)
    Exit Function
End Function

从上面的代码可见,如果当前流程没有特殊的业务逻辑,可以使用通用的流程类SimpleFlow,否则便要用一个写好的SimpleFlow的子类,即此处的PurchaseFlow。最后谈谈这里被包含在If语句中的错误处理。

错误处理和模拟事务

上面的代码如果应用普通的错误处理,普通用户看到的错误信息会稍微友好一些。但因为骨干代码都包含在Submit方法里,捕捉到的错误发生的行几乎注定就是这一行,而这对确定真正出错的代码帮助不大。并且因为错误被捕捉了,打开Notes客户端的调试LotusScript工具也没用。如此看来,似乎不应该添加错误处理代码。但此处有一个微妙的问题。流程类的Submit方法执行时如果发生错误,很有可能已经修改了当前主文档,甚至已经修改了文档的状态和存取控制字段的值,在这样的数据“破损”状态下,用户关闭文档时如果保存,则将产生一个无法解释其数据和进行后续操作的异常文档,例如流程已处于下一节点,但文档权限并未改变。通用的流程引擎类尚可以精心编写反复测试,尽量减少出错的可能。但是特定于某流程的代码,同样可能造成上述问题,它们的质量却取决于各自的作者。

在使用其他编程语言和关系型数据库时,保证数据不会处于此种不一致状态的解决方法是事务(transaction)。一个事务内的一系列状态改变,或者成功,或者失败时回滚至原位。LotusScript和Notes数据库不支持此功能。我们能做到的只是尽量模拟,所以AbstractFlow类中有一个RollBack方法,可以将主文档的所有域值恢复到保存在一个临时备份文档中的初始状态。SubmitFlow函数里添加错误处理代码的目的就是利用RollBack方法防止错误发生时主文档的数据处于不确定状态。剩下的问题便是出错时如何调试,最好有一个便捷的途径在不修改代码的情况下使错误处理代码失效。这就是IsDebuggingLS和一个工具代理Tools\Toggle LS Error Handler的由来。它们通过设置和检查一个特殊的Notes环境变量“DEBUG_LS”来控制错误处理代码是否生效。后者将环境变量“DEBUG_LS”的值在0和1之间切换,前者检查该值是否为1。这样在SubmitFlow函数里,如果检查到处于“调试”状态,就不进行错误处理,此时便能用调试器跟踪错误。

时间: 2024-10-24 06:22:00

95. 基于Notes/Domino的文档工作流系统(七)的相关文章

94. 基于Notes/Domino的文档工作流系统(六)

(流程样例应用程序终于整理上传好可供下载了http://download.csdn.net/download/starrow/8422299) 上文分析了我们的流程配置使用三类对象,分别对应三类文档:工作流配置文档.节点配置文档和操作配置文档.本文介绍三类配置文档的内容,也可以看作本流程系统的设置教程. 这些配置文档的共同点包括: 处于编辑状态时,必填字段的右边会显示红色星号(这实际也是整个系统的共同设计),保存文档时会对这些字段进行校验. 许多字段既能输入静态值,也可输入公式以计算动态值.输入

89. 基于Notes/Domino的文档工作流系统(一)

介绍 Notes/Domino作为一个数据库系统和开发平台,具有许多与众不同的特点.这些特点使得它适于开发某些类型的应用系统(同时就不是开发其他一些类型系统的适宜平台),这其中就包括工作流.这里指的并不是如工作流管理联盟(Workflow Management Coalition, WfMC)制定的工作流标准(Workflow Reference Model)那样通用的工作流,而是一类以文档为中心的主要活动为用户审批的工作流.Notes的文档型数据库.客户端与服务器架构.自带的用户目录和登录校验

93. 基于Notes/Domino的文档工作流系统(五)

确定了流程引擎包含以下功能: 校验必填字段. 修改流程文档的权限,包括有关的读者域.作者域.存取控制区段. 添加操作记录. 修改配置的业务字段. 发送邮件通知相关处理人. 随后就要为其建模.此过程在用不同范式的语言开发时有不同的形式和术语.在C之类的过程式语言里,包括设计数据结构和自上而下的函数层次.用面向对象的方法时,就是要设计出类图.在我们的Notes环境里,基本上奉行的是"面向界面"的开发,确定了需要几种表单和视图,设计出来后,再写入必要的事件处理代码,一个应用程序就初具雏形了.

90. 基于Notes/Domino的文档工作流系统(二)

XPages下的工作流演示 网页外观的可能性在技术上超过Notes客户端里的表单,Web应用程序在页面设计上花费的精力和取得的效果也远远超过基本保持传统客户端应用程序界面风格的Notes.我是程序员,不是设计师.在下面的演示里,页面都以展现功能为主,基本采用XPages的默认输出. 按状态分类显示采购单的视图: 采购单页面: 单击Flow actions-按钮弹出的对话框: 流程设置 先来看看这个采购系统的流程图. 在客户端里选择导航中的FlowSettings,看到的是配置文档的全景. 双击视

92. 基于Notes/Domino的文档工作流系统(四)

现在我们以演示的采购工作流来研究工作流系统的设计.本文将讨论一个通用的工作流"引擎"包含哪些功能.通过需求分析和梳理,我们已经获得如下的流程图.由此可知该流程由一组状态.与状态对应的一组用户和流程处于某种状态时当前用户所能进行的若干操作组成. 接下来逐个分析这些操作.首先看IT部门的起草人填完采购单后提交.此时流程系统须做以下工作: 校验必填字段. 生成采购单号. 修改采购单状态为Waiting For IT Approval. 将流程的当前处理人由起草人改为负责审批的IT Leade

基于Noootes/Dooomino的文档工作流系统(转)

(流程样例应用程序终于整理上传好可供下载了http://download.csdn.net/download/starrow/8422299) 上文分析了我们的流程配置使用三类对象,分别对应三类文档:工作流配置文档.节点配置文档和操作配置文档.本文介绍三类配置文档的内容,也可以看作本流程系统的设置教程. 这些配置文档的共同点包括: 处于编辑状态时,必填字段的右边会显示红色星号(这实际也是整个系统的共同设计),保存文档时会对这些字段进行校验. 许多字段既能输入静态值,也可输入公式以计算动态值.输入

基于T4模板的文档生成

看了好几个代码自动生成的工具,用起来很方便,但有些方面还是不够自由:这些日子里忙里偷闲摸索了一番,个人觉的基于T4模板的代码生成方案还是不错的. 下面就看看这个T4到底是什么东东-- T4 = Text Template Transformation Toolkit 不知道电脑前的你是否接触过Asp或jsp之类的动态网页编程语言,个人感觉就和那些动态网页的的编写思路差不多只不过那些编译前是*.asp.*.aspx,或*.jsp,这个T4编译前是的扩展名是tt(*.tt) 先看一个简单的tt文件

“在线Excel文档编辑系统”新手开发训练营开营啦,完全免费,欲报从速!

疫情当前,远程办公风口正盛,腾讯文档.飞书.石墨文档等在线协同办公软件供应商迅速崛起.抓住风口,你也能造就下一个BAT. 本期训练营,将引导您快速开发一款基于Vue框架,简单.能迅速投入使用的在线Excel文档编辑软件. 新手开发训练营,助您找回丢失的时间! 面向所有前端开发者, 推出3 天学会:在 Vue 框架下搭建“在线Excel”文档编辑系统 旨在给您更棒的学习体验! 最重要的是,本期活动全程免费!不限报名人数! √    小群交流,零基础也能轻松学会 √     直播互动,授课 & 答疑

springmvc+mybatis+lucene4文档搜索系统(支持分页)

原文:springmvc+mybatis+lucene4文档搜索系统(支持分页) 源代码下载地址:http://www.zuidaima.com/share/1550463731436544.htm springmvc+mybatis+lucene4文档搜索系统(支持分页) 说明在readme.txt中 链接:http://pan.baidu.com/share/link?shareid=1973707360&uk=402880896 密码:01r6