背景

流程审批系统是一个很常见的系统,包括我们在日常权限申请,订单状态流转等很多场景都会接触。其核心的点有两个:1.状态流转 2.流程驱动

我们以我们常见的流程审批为例,比如我想向上街申请一台新电脑,解释整个流程。
状态流转:也就是我们从发起审批流程到上级审批再到最终通过或者驳回。
流程驱动:流程驱动既是我们点了申请之后,后续操作我们只需等着就好,一条审批会按照既定的过程完成审批,对于接入的开发理解就是调用了api之后我就可以等着回调了。

1. 流程审批分析

具体的审批API在每个公司内部都有提供,这里抽象处理。

流程审批的过程是申请人填写审批人向一个通用的审批API发起审批流程,审批API向负责人发送审批申请,负责人对申请进行处理,审批API根据审批结果进行回调,如图:

上述例子是单人审批,多人审批将重复上述流程,直到最终拿到审批结果。

流程审批可以抽象为pipeline,审批人是其中的节点(node),在普通的链式审批模式中,审批节点从头开始构成一条链表,而复杂的审批流程中,可以加入线段(line),将链表拓展成为有向图,其中node定义审批人信息,line控制审批流向,pipeline驱动流程。
链式模型图:

有向图模型图:

其本质可以抽象成pipeline,通过myoa事件进行驱动,最后根据事件结果结束pipeline。

2. 实现思路

整个流程审批系统分为三个部分:

  1. 核心模块-提供核心的流程控制以及单据流转。
  2. 持久化模块-提供单据持久化功能。
  3. 调度模块-失败重试,定时调度等任务。

2.1 核心模块

其中核心模块定义:

Flow:一条审批流程

Node:审批节点,审批节点可能是静态或者是动态的,静态节点是指申请时输入审批人,而动态节点则是拉取申请人上级或是上级审批人上级,不同的申请人审批人可能不同。同时一个审批节点可能包含多个审批人,因此需要设置审批通过阈值。

NodeHandler:审批节点的处理器,每一种类型Node都将省成不同的NodeHandler,NodeHandler负责处理当前Node的流转以及结果判断。

NodeResult:NodeHandler处理结果,分为:Continue,Abort,End,Aysnc,Ignore五类。其中Aysnc需要将更新后的FlowInstance和Node持久化。

FlowInstance:一条审批流程对应的框架实例,整个框架中驱动的是FlowInstance,FlowInstance中包含了完整的原始申请单据,以及每次审批意见。对开发者使用。

FlowEngine:流程驱动器,负责驱动所有的FlowInstance,每个FlowInstance中Node流转都在FlowEngine中处理。

关于pipeline的设计参考了Netty的ChannelPipeline,为每一条pipeline设置一条双向Node链表,其中head和tail是初始化时生成的。链表中的Node对应于Netty的ChannelHandlerContext,而NodeHandler则对应ChannelHandler。FlowEngine则对应于DefaultChannelPipeline。

核心流程代码:

public void process(FlowInstance instance) {FlowNode node = instance.getCurNode();while (node != null) {NodeHandler handler = map.get(node.getClass());if (null != handler) {instance.setCurNode(node);NodeResult r = handler.handle(instance);if (r==NodeResult.Aysnc){this.save(instance);return;}if (r == NodeResult.Abort || r == NodeResult.End) {instance.setResult(r);return;}if (r == NodeResult.Continue) {node = node.next;}}}instance.setResult(NodeResult.End);
}

核心流程反序列化代码:

public void resume(String flowInstance, MyOACallbackItem callbackItem) {FlowInstance instance = load(flowInstance);instance.setMyOACallbackItem(callbackItem);FlowNode node = instance.getCurNode();NodeResult r;if (node instanceof SimpleMyOANode) {r = ((SimpleMyOANode) node).judge(callbackItem);DBHelper.storeFlowNode((SimpleMyOANode)node);save(instance);if (r == NodeResult.Abort || r == NodeResult.End) {logger.info("flow end :" + flowInstance);instance.setResult(r);return;}if (r == NodeResult.Ignore) {}if (r == NodeResult.Continue) {instance.setCurNode(node.next);process(instance);}}
}

2.2 持久化模块

持久化分为两个部分:

  1. 流程中实例的持久化。
  2. 用户定义数据的持久化。

为什么需要持久化模块,因为上述任何一个类型都是内存中的一个实例,机器重启将会被销毁,因此需要将每个实例在变化之后立即持久化。持久化的选择可以多种多样,结合管理后台的使用场景,DB是非常合适的。head节点的任务就是将Node和FlowInstance持久化,并驱动流程至用户定义节点。

相比于框架层面的持久化,用户层面的持久化是指用户在创建流程时传入的回调类。回调类的持久化比较简单,但是从DB中如何反序列化是一个问题,newInstance对框架是一个黑盒,用户的回调类可能注入了很多bean,因此需要借助spring等容器来实现。

2.3调度模块

调度模块主要负责对状态异常的节点进行定时修复。对于回调请求丢失或者是提交单据失败的情况进行定时恢复。

3 具体实例

myoa是腾讯内部提供的一个流程审批http接口,在审批人审批结束后会通过预先设定的http回调,并且可以支持回调原参数。但是其只能支持单人审批,无法实现复杂的审批模型。即其职能完成单个节点的任务。

代码demo

1.提交审核

通过代码的方式主要是构造SubmitItem,其原理与通过页面配置相似

SubmitItem item = new SubmitItem("listViewTitle","listViewDetail","detailViewTitle","detailViewDetail", BusCategory.TEST,handlers,callbackData,"title",rtx);
//函数定义如下
public static String submit(SubmitItem item, Class<? extends FlowInstanceResultListener> callbackClass)

SubmitItem提供了两个构造函数,分别用户处理两种场景。

  1. 单人审批节点,及A->B->C依次审核,依次通过即可完成最后的审核,中途拒绝将终止流程。
  2. 多人审批节点,A、B->C、D->E、F,多人审核,需要超过一个阈值才能进入下一步,例如A、B两人审核,只需其中一人通过即可。

单人审批节点构造器:

public SubmitItem(String listViewTitle, String listViewDetail,String detailViewTitle, String detailViewDetail,BusCategory category, List<String> handlers,Map<String,List<String>> callbackData,String title, String application)

具体参数含义请阅读myoa参数定义,参数名称与json字段一一对应。handlers是一个队列,对应着A,B,C。会先向A发起审核,A通过后向B发起,B拒接则审核关闭,不会再向C发送。

多人审批节点构造器:

public SubmitItem(String listViewTitle, String listViewDetail,String detailViewTitle, String detailViewDetail,List<List<String>> handlerList, BusCategory category,List<Integer> handlerValve, Map<String,List<String>> callbackData,String title,String application)

handlerList是一个二维数组,其中每个一维数组定义着一次审核的人数,如A、B,handlerValve定义着需要通过的阈值,如二人只需通过一个即可valve则为1。A、B节点审核结束后会向C、D发送审核。

2.接收回调函数

审核结束应该回调发起者,然后对审核结果进行判断。审核结果的数据封装在FlowInstance中的MyOACallbackItem,具体字段内容与myoa回调单据一致。

@Controller
public class MyoaDemoController extends MyoaBaseController{...@Overridepublic void onResult(FlowInstance ins) {try {List<MyOACallbackItem> list = ins.getMyOACallbackItem();MyOACallbackItem item = list.get(0);//回调数据,回调数据由提交时传递Map<String, List<String>> callbackData = item.getData();//审批结果NodeResult result = ins.getResult();} catch (Exception e) {logger.error("MyoaDemoController onresult err {}",e);}}
}

回调json示例,MyOACallbackItem将存储了整个回调json数据,字段名称一一对应。

{"id": "5b1f49880c64f159a4c39612","business_key": "633C74A559724244A185EA88749C6B97:admin_oa_process:4b3cc81a-0fc7-410c-9929-a4c281f5fb43","handler": "zoehzhang","category": "633C74A559724244A185EA88749C6B97","process_name": "admin_oa_process","process_inst_id": "4b3cc81a-0fc7-410c-9929-a4c281f5fb43","activity": "approve","submit_source": "PC","submit_action": "2","submit_action_name": "驳回","submit_opinion": " 【通过PC快速审批】","submit_form": {},"data": [{"key": "id","value": ["2001"]}],"create_time": "2018-06-12T12:18:16.479+08:00","submit_time": "2018-06-12T12:19:06.047199031+08:00"
}

代码demo地址:https://github.com/wsrspirit/pipeline_demo

更复杂的可以参考阿里巴巴的开源项目 https://github.com/alibaba/bulbasaur

流程审批系统设计思路及实现方法相关推荐

  1. 电商秒杀系统设计思路和实现方法

    1 秒杀业务分析 正常电子商务流程 (1)查询商品:(2)创建订单:(3)扣减库存:(4)更新订单:(5)付款:(6)卖家发货 秒杀业务的特性 (1)低廉价格:(2)大幅推广:(3)瞬时售空:(4)一 ...

  2. java+SpringBoot+HTML+Mysq行政审批系统设计与实现

     详细功能设计:请点击下面链接查看 java+SpringBoot+HTML+Mysq行政审批系统设计与实现_哔哩哔哩_bilibili 源码+论文获取: 源码+论文获取请私信获取 目 录 摘 要 A ...

  3. java毕业设计——基于java+Java Applet+access的OA流程可视化系统设计与实现(毕业论文+程序源码)——OA流程可视化系统

    基于java+Java Applet+access的OA流程可视化系统设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于java+Java Applet+access的OA流程可视化系统设计 ...

  4. Springboot企业报销审批系统设计与实现 计算机毕设源码44362

    摘  要 企业报销系审批统是将企业财务报销和计算机技术结合起来的一种新型的办公方式,是信息化社会的产物.通过网络,组织机构内部的人员可跨越时间.空间进行操作.通过企业报销审批系统所实施的交换式网络应用 ...

  5. 高校调课代课审批系统设计研究

    一.基本信息 标题:高校调课代课审批系统设计研究 时间:2017 出版源:通讯世界 领域分类:调课代课 二.研究背景 问题定义:代课调课的审批 难点:找到相应的方法来替代传统的C/S模式 相关工作:利 ...

  6. srs流媒体服务器windows_基于SRS构建的直播平台的监控系统的搭建思路与实现方法...

    市面直播平台百家争鸣,直播监控系统是判断一个直播平台是否完善的必要条件.文章简要介绍了笔者搭建的一套基于SRS的直播平台,并从设计思路.实现方法与实现过程等方面重点介绍了针对此直播平台建设的监控系统, ...

  7. 财务报销网上预审单html,网上财务报销审批系统设计与开发.pdf

    网上财务报销审批系统设计与开发 基于.NET的网上财务报销审批系统设计与实现 目录 目 录 摘要 ------------------------------1 ABSTRACT----------- ...

  8. flowable-ui(v6.7.2)简单的请假流程审批操作(一)

    网上的Flowable流程审批教程很多,但新版本的UI界面操作实例不全面或者不详细,因此在这里分享下几天来的入坑经历,希望有需要了解,看完我的文章后能有所启发,文章有不足之处还请指正,若有相关问题请留 ...

  9. C#毕业设计——基于C#+asp.net+sqlserver的工作计划流程管理系统设计与实现(毕业论文+程序源码)——流程管理系统

    基于C#+asp.net+sqlserver的工作计划流程管理系统设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于C#+asp.net+sqlserver的工作计划流程管理系统设计与实现, ...

最新文章

  1. 每日一皮:实习生将他的代码交给高级开发人员,高级开发反手一个...
  2. 精通python爬虫框架-精通Python爬虫框架Scrapy.pdf
  3. 加拿大皇后大学朱晓丹教授课题组招收NLP方向博士和硕士研究生
  4. Office365----Project Online SKUs Change
  5. C#详解值类型和引用类型区别
  6. (Deep learning)深度卷积网络实战——第四部分
  7. mysql启动和常用语法实战回顾
  8. 解决Android Studio 新建导入项目时死掉
  9. 安卓微信打开的文档存放在哪里
  10. vscode 使用beautify插件格式化.vue文件
  11. Google App Engine + JDO + Spring MVC,CRUD示例
  12. dayday60-120
  13. 计算机网络的 89 个核心概念【转自微信公众号Linux爱好者】
  14. C语言小程序实现输出国际象棋棋盘
  15. Mac快捷键大全及cheatsheet插件
  16. 一个男孩子写的超级情书!!!
  17. 企业级日志平台新秀!比 ELK 更轻量、高效
  18. 民办大学计算机专业教师,普通本科院校计算机专业教师胜任力模型构建及应用...
  19. 小满OKKICRM与金蝶云星空对接集成客户档案
  20. 新形势下,互联网公益应该怎么做?

热门文章

  1. 搭建Win7调试ACPI的环境
  2. android 打开其它app,Android 在一个APP里打开另一个APP
  3. Nacos更改配置导致AnnotationConfigApplicationContext has been closed
  4. 计算化学系列教程-第四章-一维谐振子
  5. 网狐、6878、名字修改图片文字路径【第四次更新】
  6. 14.4 设计新闻发布系统
  7. MacOS好用的系统清理工具CleanMyMac有哪些特点功能?
  8. 字符串分割(比如按逗号,分号)
  9. c语言将1元5角兑换成,编写c语言程序 假定有 5 角、 1 角、 5 分、 2 分和 1 分共 5 种硬币,在 给顾客找硬币时,一般都会尽可能...
  10. ANSI与UTF-8区别