带工作流的管理系统开发实战
前言
近几年SOA与微服务的发展使得Java后端开发人员能力越来越集中于后端接口与微服务架构中。对传统的企业应用提供商,带有工作流的管理系统大都已经成熟,成为企业的基本框架。对于需要从零开始架构带工作流的管理系统的需求,市场上缺乏相应的资料,而一些企业提供的收费方案质量也参差不齐。如果企业没有一个已经成熟的现有底层框架,开发一个类似OA一样的系统并没有想象中的那般简单,国情式的审批流程更是让国外开源的工作流框架“水土不服”。本文将简单描述建立一个带工作流的管理系统核心要点。
1、管理系统概述
无论传统企业级还是互联网应用,管理系统通常是不可缺少的,一般来说它的用户是企业内部员工、合作公司员工等。狭义上的管理系统通常是业务或核心系统的配套支撑系统。广义上的管理系统还包括CMS、CRM、ERP、OA等通用系统。
与微服务、大数据等技术的日新月异相比,管理系统的技术较多集中在J2EE技术体系,显得较陈旧。当然诸如前后端分离、微服务等技术也可以应用在管理系统建设中,但这得结合公司技术人员组织架构实施。通常来说由于管理系统的用户是内部人员,对于UI交互要求并不太高,多数情况下是由后端开发人员承担所有开发任务,这就要求开发人员需要懂得基础的html、css、javascript、jsp等技术基础。
2、工作流概述
在计算机尚未普及时,许多工作流程采用手工传递纸张表单的方式,一级一级审批签字, 工作效率非常低下,对于数据统计以及生成报表的功能,需要经过大量的手工操作才能实现。 随着电脑的普及,这些工作的参与者只需要在电脑的系统中填入工作内容,系统就会按照定义好的流程自动执行,各级审批者可以得到工作的信息并作出相应的审批和管理操作,数据统计和报表的生成均由系统代为完成,这样大大提高了工作效率,在这种背景下,各种工作流应用以及中间件应运而生。
工作流(Workflow),是对工作流程及其各操作步骤之间业务规则的抽象、概括、描述。 工作流建模,即将工作流程中的工作如何前后组织在一起的逻辑和规则在计算机中以恰当的 模型进行表示并对其实施计算。工作流要解决的主要问题是:为实现某个业务目标,在多个参与者之间,利用计算机,按某种预定规则自动传递文档、信息或者任务。
工作流适用于制造业,电信服务业,银证保险等金融服务业,物流服务业,物业服务业,物业管理,大中型进出口贸易公司,政府事业机构,研究院所及教育服务业等,大型企业集团。(PS:21世纪初工作流曾是当时IT行业最热门的概念之一,就像今天的区块链。)
BPMN 规范 1.0 版本由 BPMI 组织于 2004 年发布,全称是 Business Process Modeling Notation,BPMN 规范的发布是为了让业务流程的全部参与人员对流程可以进行可视化管理,提供一套让所有参与人员都易于理解的语言和标记,为业务流程的设计人员(非技术人员)和流程的实现人员(技术人员)建立起一座桥梁。BPMN2.0 规范于 2011 年 1 月正式发布,并且全称改为 Business Process Model And Notation(业务流程模型和 符号)。BPMN 2.0 流程定义模型不仅仅可以在任何兼容 BPMN 2.0 的引擎中执行,而且也可以在图形编辑器间交换。作为一个标准,BPMN 2.0 统一了工作流社区。
工作流引擎的选择:
1、最原始的“工作流实现”,拼接处理页面,通过数据库表当前处理人的变更实现流转。
优点:简单。
缺点:硬编码,强耦合。
2、自研实现工作流,如多数国内的OA系统。
优点:定制化程度高。
缺点:研发资源投入较高,对核心研发人员技术要求较高。
3、国内收费工作流引擎。
优点:多数是在开源引擎上做了二次封装。
缺点:质量参差不齐,通常是一站式解决方案,较难单独剥离出工作流部分。
4、开源工作流实现( jBPM、OSWorkflow、Activiti)。
优点:通用灵活。
缺点:为适合国情需做二次封装。
开源方案中以Activiti最为活跃,本文也是通过扩展Activiti的方式实现工作流框架。
3、组织机构与用户
每个公司都有其组织机构,到目前为止再扁平的组织也仍然逃不过树状结构,只不过树的层级大大降低了而已。传统的单个组织架构已经不能完全支持业务的发展,比如某公司成立了架构部,人是从各个业务开发部门抽调形成,这些人既跟进架构部的事情,又跟进原业务部门的工作。一个简单的方案是使用虚拟组织架构,每个人只属于主组织架构的某个节点,不能重复,但可以属于多个虚拟组织架构。Activiti只支持简单的用户及用户组,在一般公司的组织架构下,通常是不够的,需要加以扩展。扩展的方向有以下几方面:
1、使用管理系统角色对应Activiti的用户组,用户与角色之间要支持n:n关系,对于这类用于工作流中的角色,必须要跟普通角色加以区分,如:某部门经理用户,他对应两个角色:部门经理、工作流-部门经理。
2、对于简单场景,assignee可以指定到人,注意这里要使用有意义的惟一id,如用户名:moext,不要使用自增id等,一来可读性差,二来以后数据迁移可能带来问题。
3、对于简单场景,assignee可以指定到角色,这里可以通过监听器的方式稍加扩展,当某角色只存在1个人时,直接将任务指派给该人,当用户角色大于1个人时,先签收,再处理。
4、找到发起人的上级,甚至是上级的上级,这种场景是普遍的需求。一种做法是工作流在启动前就把需要的参与人查询出来,作为变量传给工作流,这其实是一种硬编码的方式。
5、在多公司或多部门的情况下,角色名通常是有重复的,比如A部门有部门总监,B部门也有部门总监。部门或公司不多的情况下,一种简单的方案是给A和B部门各自建立不同的角色如:A部门总监、B部门总监。
6、其它一些有特色需求的情况,需要硬编码的方式实现。
7、基于4、5、6的情形能不能建立一套通用可扩展的方案呢?答案是能。通过扩展assignee,assignee配置成json的方式。工作流运行时通过监听器实时解析json,再指派给实际处理人。
4、菜单角色与权限
权限实现从弱到强,依次分为:
1、没有权限,没权限的人只是看不到该菜单,手工输入URL的方式即可绕过;
2、菜单级别权限;
3、按钮级别权限。
权限检查的实现,对于简单权限校验可以通过拦截器的方式实现。复杂权限可使用shiro等权限框架,核心是每个权限资源(或按钮等)都对应某个惟一的token,在相应的Controller中使用注解的方式实现权限检查。
5、代码生成器
一般的管理系统,页面模式多为:列表页,内容页。java层代码多为Controller、Service、DAO。提供代码生成器生成CRUD代码在一定程度上提高工作效率。代码生成器的原理多为使用Freemarker等模板技术生成指定Pattern的源码。
6、通用标签
权限判断、字典选择与翻译、组织架构选择与翻译、用户选择与翻译,这些都可以通过扩展tag的方式实现。
7、通用页面
用户选择、组织架构树选择、文件上传、提示框、进度框等,都可以实现成通用页面。
8、统计报表
统计报表数据由小到大的常见实现方案有:
1、直接连主库查询业务表;
2、查询备库查询业务表;
3、调用相关服务查询;
4、根据业务库生成报表库。
9、通用文件服务
为了实现管理后台的伸缩性,文件必然不能直接放在应用服务器的文件系统中,然后将相关path存到数据库表。而应该单独抽取出通用文件服务,该服务是无状态的。
10、在线Office处理
Office控件用得较普遍的有金格和PageOffice。
金格是通过ActiveX的方式实现的,所以浏览器必须是IE内核。
PageOffice是通过修改注册表,监听某扩展名的文件实现的,所以操作系统必须是Windows。
11、在线流程设计
流程设计可以使用Eclipse插件Activity designer,也可以在应用中集成Modeler。如果考虑到支撑后期非开发人员线上配流程并热发布的需求,那必须优先使用Modeler。
12、流程发布
代码或SQL脚本可以使用Git或SVN等版本管理工具进行版本管理。流程在act_ge_bytearray表中是以二进制流的方式存储,所以使用导SQL(字符)的方式是无法发布的。那一个流程如何从Test环境部署到Prod呢?在模型管理中开发一键导出功能,将整个Model使用Java序列化,在导入功能中反序列化。
13、流程待办已办及办结
Activiti工作流中查询历史Task是面向任务的,而已办办结对中国式的工作流来说是面向流程的,比如说某个请假流程:发起人申请->人事审批->发起人返回销假->结束,对Activiti而言,对发起人而言,这个流程(请假事项)有两个Task,一个是发起申请,另一个是返回销假,但中国式的流程往往会要求对这个流程只展示一次,另外 还要考虑到已办和办结分页需求,就不能先查出Task再去重了。一个解决思路是先分页查出已办、办结的process_instance_id,再根据process_instance_id列表查询出相关的Task,最后再去重。
14、流程与组织架构相结合
流程与组织架构相结合,除了将管理系统的用户对应Activiti的用户,角色对应Activiti的用户组之外,还需要扩展Activiti,以支持复杂的业务需求。
15、流程与表单相结合
不同的流程节点,显示的表单是不同的,有以下几种实现方式
1、简单表单,使用form properties属性,简单方便, 排版单一、表单里每个字段都会存储到变量表,数据量大,适合极简单业务;
2、扩展表单,排版比1灵活,适合业务简单,排版有一定要求场景;
3、硬编码实现,多数情况下我们用这种方式。
4、动态表单,需要做大量的开发工作,包括表单设计、表单映射定义等。
16、流程干预
流程干预是管理员对流程进行临时性的操作,如删除、指派、跳转到指定节点。对一个成熟的系统而言,流程干预是必不可少的功能。
17、流程抄送
在中国式的审批流中,经常需要将自己的流程抄送给相关的人(包括已办结的),因为Activiti中一个流程结束后,这个流程就归档了,不能再产生任何新的处理节点。所以一个可行的思路是,基于流程的流程实现。
18、流程审批
在中国式的审批流中,一般审批操作有:同意、不同意、退回(可选择退回节点)、会签、加签发起人等。其中退回操作是原Activiti API不支持的,需要扩展实现,需要注意的是退回节点时需要排除会签节点以及时序正确性处理,避免来回修改后退回节点出现前节点可以退回后节点的情况出现。