1. 引言

1.1. 应用背景

随时企业的IT系统建设越来越多,往往一个企业中形成各种独立的系统,各系统相对独立,缺乏流程支掌,为达到通过构建流程服务中心向各处应用系统提供流程服务,同时将各个独立的系统以流程中心为扭带链接起来。

流程中心仅是作为后台管理,对于用户来说并不需要登录此平台上做相关的业务操作管理。流程中心作为应用系统的服务端,应用系统作为客户端。流程中心相对前端的客户来说是一个黑盒模式。

F2BPM流程服务中心(简称:F2流程中心),是指将F2-BPM做为流程平台独立部署成流程中心的方式,其它应用系统调用F2流程服务中心进行流程流转的使用场景。

由于每个企业自身的IT系统应用环境千差万别,本文档给出F2流程中心应用到企业中作为流程中心的常见应用解决方案。

目前越来越多的企业架构解决方案更加趋向于基于http协议“微服务”架构,即通过RESTfull方式进行交互,更加轻量整合调用更上方便。F2流程中心应用方案也是建议采用轻量级的RESTfull方案。

1应用方案模式

由于企业的IT建设的环境不心相同,构建流程中心的方案也会有所不同,由于独立部署面临的一个最大问题就:用户组织架构问题、登录授权身份问题。所以会有不同的企业IT环境会有不同的应用方案模式。

  • 方案模式一:流程中心和应用系统共同相同数据库,程序独立部署方式
  • 方案模式二:流程中心和应用系统的数据库和程序都是独立部署方式
  • 方案模式三:有统一人事系统用户认证服务器,流程中心和应用系统的数据库和程序都是独立部署

2. 共用数据库模式

共用数据库模式是指流程中心与应用系统使用相同的数据,将流程中心的所有表建包括流程中心平台用户组织表都创建在应用系统所在的数据库中。

此时流程中心的用户组织架构管理仅是作为流程中心平台管理员使用的用户组织,用于登录维护管理流程中心相关的事务。流程中心的用户组织与应用系统的用户组织无关。而当调用流程中心执行流程流转时用户组织是通过引擎的用户组织架构接入的配置读取应用系统的用户组织,依然使用的是应用系统自身的用户组织架构。流程引擎使用的是应用系统自身的用户组织架构,用户组织架构的维护管理依然是由应用系统自身来管理。

RESTfull的数据交互机制详细见Oauth2.0接口交互授权。

3. 独立程序和数据库部署模式

数据库和程序都是独立部署模式是指流程中心与应用系统使用各自的数据库。

此时流程中心自身数据库中的用户组织架构管理仅是作为流程中心平台管理员使用的用户组织,用于登录维护管理流程中心相关的事务。流程中心的用户组织与应用系统的用户组织无关。

而当调用流程中心执行流程流转时用户组织是通过重写F2用户组织架构接口的实现读取应用系统的用户组织架构,依然使用的是应用系统自身的用户组织架构。流程引擎使用的是重写实现组织接口的应用系统自身的用户组织架构,用户组织架构的维护管理依然是由应用系统自身来管理。

4. 使用统一人事系统用户服务器模式

使用统一人事用户系统模式是最复杂但也是整体企业信息化环境比较好的方式,一般应用于比较大的集团企业,他们的特点是数据库和程序都是独立部署,流程中心与应用系统使用各自的数据库,同时各应用系统都是统一使用HR系统的用户组织架构。

此时流程中心自身数据库中的用户组织架构管理仅是作为流程中心平台管理员使用的用户组织,用于登录维护管理流程中心相关的事务。流程中心的用户组织与应用系统的用户组织无关。

而当调用流程中心执行流程流转时用户组织是通过重写F2用户组织架构接口的实现读取应用系统的用户组织架构,依然使用的是应用系统自身的用户组织架构。流程引擎使用的是重写实现组织接口的应用系统自身的用户组织架构,用户组织架构的维护管理依然是由应用系统自身来管理。

因企业信息化环境差异大,此方案需要各方一同共同实施才能达到比较好的效果。我们可以合作实施。

5. RESTfull接口的OAuth2.0身份授权

5.1. 什么是OAuth2.0

OAuth2.0是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版。本文是对OAuth 2.0的设计思路和运行原理应用到F2BPM平台中,目标是为了防止接口被不安全使用,接口的调用必须有安全的身份认证机制。

5.2. OAuth2.0与F2-BPM平台

因为要将F2-BPM平台做为流程服务中心,那么F2-BPM平台就会与多个应用系统打交道,多个应该系统通过调用RESTfull接口来驱动流程或者获取流程相关数据时需要安全验证后才可以进行接口影响返回正确的数据结果。

F2-BPM流程中心构建了OAuth2.0的身份认证机制,此身份的认证是应该系统级别的,目的验证是否来自合法注册的应该系统调用了流程中心的RESTfull接口。(数据关联的用户是应用系统开发调用流程中心接口时决定)。

本流程中心的OAuthor并非用于用户的第三方登录认证,当然也能扩展出来,但由于F2-BPM并非人事系统的统一用户管理中心。

5.3. F2-BPM流程中心OAUTH2.0身份验证时序图

每个接口必须传递的数据:{token:,corpId:,timeStamp:,nonce:,signature:,loginAccount:}

参数名

值示例

说明

token

oa_token

系统令牌,在流程中心配置的固定值

corpId

app255e7feb2645dd23

应用系统的ID,在流程中心增加应用接入时生成的ID

timeStamp

1706261844

时间戳,传递时由客户端生成,格式:yymmddHHmm,客户端时间与F2-PBM流程中心系统时间误差充许在10分钟以内

nonce

6723

随时数,由客户端生成一个至少4位的随时数

signature

ZDlUMYZeJKXrAZ3ofbZQnXgSPqjHw9xw2lZhj0hPwF5VUG0yMhknJ-8Ql8zK8tXK

签名加密字符串,由客户端将timeStamp和nonce进行加密得到此签名加密字符串

loginAccount

zs

当前登录者的账号,用于作为调用RESTfull接口流程引擎将以此账号作为流程引擎运行中的当前登录人身份

客户端与流程中心接口交互参数说明:

authorJson:主要是接口身份的认证相关参数,校验访问者的来源合法性

parmJson:请求业务数据的参数,比如分页参数,查询参数等

所有RESTfull都统一只有这两个Json参数
一般情况

get只适合参数相对简单的请求,如果参数过长或参数字符复杂,则使用Post 来传参请求。

F2BPM接口强大的特点:服务端可以利用F2BPM非常丰富的流程引擎WAPI进行发布成RESTfull服务接口供应用端系统调用。而且接口可以是无状态的请求

客户端Get请求

/**
* get请求 get只适合参数相对简单的请求,如果参数过长或参数字符复杂,则使用Post 来传参请求
*/
public void getTodoList() {
String urlString = webApiUrl + "/workflowBusiness/getTodoList/?";
StringBuilder queryString = new StringBuilder();
queryString.append(StringUtil.format("authorJson={loginAccount:\"{0}\"}", "admin"));
queryString.append(StringUtil.format("&parmJson={pageIndex:{0},pageSize:{1},sort:\"{2}\",order:\"{3}\"}", 1, 2, "CreatedTime", "desc"));
String param = HttpClientUtil.urlEncode(queryString.toString()); // 特殊字符进行转义
urlString = urlString + param;
String jsonRes = HttpClientUtil.get(urlString);
System.out.println(jsonRes);
} 

对应的流程中心服务端

// 获取待办列表
@RequestMapping(value = "getTodoList", method = RequestMethod.GET)
public void getTodoList(String authorJson, String parmJson, HttpServletRequest request, HttpServletResponse response) throws Exception {
JSONObject jsonJSONObject = JSONObject.fromObject(parmJson);
PageParams pageParams = JsonHelper.jsonToObject(parmJson, PageParams.class);
AuthorEntity authorEntity = JsonHelper.jsonToObject(authorJson, AuthorEntity.class);
String loginAccount = authorEntity.getLoginAccount();
MyInteger recordCount = new MyInteger(0);
MyInteger pageCount = new MyInteger(0);
String whereStr = JsonHelper.getString(jsonJSONObject, "whereStr");
IUser user = userService.getUserByAccount(loginAccount);
List<TaskInstanceInfo> list = WorkflowAPI.getWorkTaskManager().getTodoList(user.getUserId(), whereStr.toString(), pageParams.getOrderBy(), pageParams.getPageIndex(), pageParams.getPageSize(), pageCount, recordCount, true);
String jsonString = JsonHelper.listToJSON(list);
String jsonResult = JsonHelper.convertToEasyUIJsonResult(jsonString, pageParams.getPageSize(), pageParams.getPageIndex(), recordCount.getValue(), pageCount.getValue());
JsonHelper.write(response, jsonResult);
}

Post请求来获取已办列表

	/**
* post请求,参数复杂的建议使用Post来请求
*/
public void getDoneList() {
String urlString = webApiUrl + "/workflowBusiness/getDoneList/";
Map<String, String> params = new HashMap<String, String>();
StringBuilder queryString = new StringBuilder();
params.put("authorJson", StringUtil.format("{loginAccount:\"{0}\"}", "admin"));
// isHistory:0 进行中的已办,isHistory:1流程已结束并归档的已办
params.put("parmJson", StringUtil.format("{isHistory:0,pageIndex:{0},pageSize:{1},sort:\"{2}\",order:\"{3}\",whereStr:\"{4}\",}", 1, 2, "CreatedTime", "desc", ""));
String jsonRes = HttpClientUtil.post(urlString, params);
System.out.println(jsonRes);
}
// 流程中心服务-已办列表
@RequestMapping(value = "getDoneList", method = RequestMethod.POST)
public void getDoneList(String authorJson, String parmJson, HttpServletRequest request, HttpServletResponse response) throws Exception {
JSONObject jsonJSONObject = JSONObject.fromObject(parmJson);
PageParams pageParams = JsonHelper.jsonToObject(parmJson, PageParams.class);
AuthorEntity authorEntity = JsonHelper.jsonToObject(authorJson, AuthorEntity.class);
String loginAccount = authorEntity.getLoginAccount();
MyInteger recordCount = new MyInteger(0);
MyInteger pageCount = new MyInteger(0);
String whereStr = JsonHelper.getString(jsonJSONObject, "whereStr");
int isHistory = JsonHelper.getInt(jsonJSONObject, "isHistory");
IUser user = userService.getUserByAccount(loginAccount);
List<TaskInstanceInfo> list =null;
if(isHistory==1){
//归档中的列表
list = WorkflowAPI.getHistoryDataManager().getHistoryDoneList(user.getUserId(), whereStr.toString(), pageParams.getOrderBy(), pageParams.getPageIndex(), pageParams.getPageSize(), pageCount, recordCount, true);
}else {
//进行中的已办
list = WorkflowAPI.getWorkTaskManager().getDoneList(user.getUserId(), whereStr.toString(), pageParams.getOrderBy(), pageParams.getPageIndex(), pageParams.getPageSize(), pageCount, recordCount, true);
} String jsonString = JsonHelper.listToJSON(list);
String jsonResult = JsonHelper.convertToEasyUIJsonResult(jsonString, pageParams.getPageSize(), pageParams.getPageIndex(), recordCount.getValue(), pageCount.getValue());
JsonHelper.write(response, jsonResult);
}

输出响应结果到客户端

{"success":true,"msg":"","total":4,"pageCount":2,"pageSize":2,"pageIndex":1, "rows":[{"isDelegateDone":false,"workflowTitle":"[系统管理员费用报销申请","directBackAct":"","expectFinishedTime":
{"time":0,"minutes":0,"seconds":0,"hours":8,"month":0,"year":70,"timezoneOffset":-480,"day":4,"date":1},"businessKey":"","delegatorUserId":"","respondType":"","delegatorRealName":"",
"wiState":0,"taskExpireTime":null,"mainActivityInstanceId":"","urgency":1,"activityId":"","extStr":"","formId":"bdd11478-97ab-4612-beb9-575a3b3d9e83","description":"","userId":"3c1df0b3-a4d9-4731-b143-02e81bce17ce",
"delegatorName":"","userName":"","opinion":"","taskDealHours":0,"appType":"表单规则2.0","isCirculated":false,"isContainDelegator":false,"currentActors":"","fromCreatorID":"","taskCreateType":"","currentActivityName":"",
"openBizDate":"","isReferred":false,"delegatorMobile":"","importance":1,"workflowInstanceState":2,"activityShowName":"","userMobile":"","creatorRealName":"系统管理员","userDpId":"","taskState":0,"isValid":false,"userDpName":"",
"appId":"AI","formType":"","workflowInstanceId":"5e2cfc5b-3fcb-4ae5-ae1d-fbdb27b4980e","creatorDepartId":"ZhiBoRuanJian","fromTaskId":"","activityInstanceId":"","taskSeq":"","creator":"admin","realTime":null,
"isCompleter":false,"completedType":"","delegatorDpName":"","finishedTime":null,"isMobileApproval":true,"stepId":0,"delegatorDpId":"","isMobileStart":true,"taskId":"","requirement":"",
"createdTime":{"time":1499268876000,"minutes":34,"seconds":36,"hours":23,"month":6,"year":117,"timezoneOffset":-480,"day":3,"date":5},"logs":"","creatorId":"3c1df0b3-a4d9-4731-b143-02e81bce17ce",
"taskRemark":"","secrecy":0,"commentCount":0,"mainWorkflowInstanceId":"","appName":"费用报销申请","sheetId":"AI20170705233435818","completedTime":null,"isDelegatorCompleted":false,"workflowId":"3944ea6b-0c56-4c74-8b0e-af82d128f772",
"urgeTimes":0,"creatorDpName":"致博软件","fromCreator":"","realName":"","activityName":"","startedTime":{"time":1499268876000,"minutes":34,"seconds":36,"hours":23,"month":6,"year":117,
"timezoneOffset":-480,"day":3,"date":5}},{"isDelegateDone":false,"workflowTitle":"系统管理员请假申请","directBackAct":"","expectFinishedTime":{"time":0,"minutes":0,"seconds":0,"hours":8,"month":0,"year":70,"timezoneOffset":-480,"day":4,"date":1},"businessKey":"","delegatorUserId":"","respondType":"","delegatorRealName":"",
"wiState":0,"taskExpireTime":null,"mainActivityInstanceId":"","urgency":1,"activityId":"","extStr":"","formId":"26eaad7d-ccfb-4b6a-96c0-4efc796f5d47","description":"","userId":"3c1df0b3-a4d9-4731-b143-02e81bce17ce","delegatorName":"","userName":"","opinion":"","taskDealHours":0,"appType":"表单规则2.0","isCirculated":false,"isContainDelegator":false,"currentActors":"","fromCreatorID":"","taskCreateType":"","currentActivityName":"","openBizDate":"","isReferred":false,"delegatorMobile":"","importance":1,"workflowInstanceState":2,"activityShowName":"","userMobile":"",
"creatorRealName":"系统管理员","userDpId":"","taskState":0,"isValid":false,"userDpName":"",
"appId":"AB","formType":"","workflowInstanceId":"a4d02561-7dc0-4a01-9368-687363081395","creatorDepartId":"ZhiBoRuanJian","fromTaskId":"",
"activityInstanceId":"","taskSeq":"","creator":"admin","realTime":null,"isCompleter":false,"completedType":"","delegatorDpName":"","finishedTime":null,"isMobileApproval":true,"stepId":0,"delegatorDpId":"","isMobileStart":true,"taskId":"","requirement":"","createdTime":{"time":1499268669000,"minutes":31,"seconds":9,"hours":23,"month":6,"year":117,"timezoneOffset":-480,"day":3,"date":5},"logs":"","creatorId":"3c1df0b3-a4d9-4731-b143-02e81bce17ce","taskRemark":"","secrecy":0,"commentCount":0,"mainWorkflowInstanceId":"",
"appName":"请假申请","sheetId":"AB20170705233109293","completedTime":null,"isDelegatorCompleted":false,
"workflowId":"4ae848a4-70f7-4e76-bd35-8f33f5bbac1e","urgeTimes":0,"creatorDpName":"致博软件","fromCreator":"","realName":"","activityName":"",
"startedTime":{"time":1499268669000,"minutes":31,"seconds":9,"hours":23,"month":6,"year":117,"timezoneOffset":-480,"day":3,"date":5}}]}

发起流程示例:

客户端

/**
* post请求
*/
public void startWorkflow() {
String urlString = webApiUrl + "/workflowBusiness/startWorkflow/";
Map<String, String> params = new HashMap<String, String>();
StringBuilder queryString = new StringBuilder();
String onlineFormData = StringUtil.format("[{\"mainTable\":\"csb\",\"data\":[{\"name\":\"csb.nl\",\"value\":\"22\"},{\"name\":\"csb.MyId\",\"value\":\"\"},{\"name\":\"csb.zz\",\"value\":\"RestFull测试\"},{\"name\":\"csb.xm\",\"value\":\"RestFull姓名\"}],\"subTables\":[]}]");
params.put("authorJson", StringUtil.format("{loginAccount:\"{0}\"}", "admin"));
params.put("parmJson", StringUtil.format("{appId:\"{0}\",wiid:\"{1}\",businessKey:\"{2}\",title:\"{3}\",opinion:\"{4}\",jsonFormData:{5}}", "ZX", Guid.getGuid(), Guid.getGuid(), "应用端RestFull请求测试", "同意", onlineFormData));
// String param = HttpClientUtil.urlEncode(queryString.toString());
// //特殊字符进行转义
String jsonRes = HttpClientUtil.post(urlString, params);
System.out.println(jsonRes);
}

流程中心处理发起请求

    //响应发起流程
@RequestMapping(value = "startWorkflow", method = RequestMethod.POST)
public void startWorkflow(String authorJson, String parmJson, HttpServletRequest request, HttpServletResponse response) throws IOException {
JSONObject jsonJSONObject = JSONObject.fromObject(parmJson);
AuthorEntity authorEntity = JsonHelper.jsonToObject(authorJson, AuthorEntity.class);
String loginAccount = authorEntity.getLoginAccount();
// IUser user = userService.getUserByAccount(loginAccount);
String appId = JsonHelper.getString(jsonJSONObject, "appId");
String wiid = JsonHelper.getString(jsonJSONObject, "wiid");
String businessKey = JsonHelper.getString(jsonJSONObject, "businessKey");
String title = JsonHelper.getString(jsonJSONObject, "title");
String opinion = JsonHelper.getString(jsonJSONObject, "opinion");
String jsonFormData = JsonHelper.getString(jsonJSONObject, "jsonFormData");
StringBuilder message = new StringBuilder();
boolean success = WorkflowAPI.getWorkflowEnactmentManager().startWorkflow(appId, wiid, businessKey, title, opinion, loginAccount, null, message, jsonFormData, null, 0, 0);
String jsonResult = JsonHelper.outResult(success, message.toString());
JsonHelper.write(response, jsonResult);
}

  

  

  

F2BPM流程中心RESTfull解决方案及示例的更多相关文章

  1. BPM流程中心解决方案分享

    一.需求分析 在过去办公自动化的浪潮中,很多企业已经实施了OA流程,但随着客户的发展和对流程管理的越来越重视, 客户对流程应用需求越来越深 入,您可能面临以下需求: 1.流程功能不能满足需求,包括流程 ...

  2. H3C数据中心虚拟化解决方案技术白皮书

    缩略语清单: 缩略语 英文全名 中文解释 IDC Internet Data Center 互联网数据中心 VRF Virtual Router Forwarding 虚拟路由器转发 SMP Symm ...

  3. SpringCloud微服务小白入门之Eureka注册中心和服务中心搭建示例

    一.注册中心配置文件 代码复制区域: spring: application: name: spring-cloud-server server: port: 7000 eureka: instanc ...

  4. OpenNebula Restfull 接口请求示例

    Fri Jun 20 07:28:20 2014 [I]: 10.0.2.2 - - [20/Jun/2014 07:28:20] "POST /vmtemplate HTTP/1.1&qu ...

  5. WebRTC VideoEngine综合应用示例(一)——视频通话的基本流程(转)

    本系列目前共三篇文章,后续还会更新 WebRTC VideoEngine综合应用示例(一)——视频通话的基本流程 WebRTC VideoEngine综合应用示例(二)——集成OPENH264编解码器 ...

  6. Fixflow引擎解析(一)(介绍) - Fixflow开源流程引擎介绍

    Fixflow引擎解析(四)(模型) - 通过EMF扩展BPMN2.0元素 Fixflow引擎解析(三)(模型) - 创建EMF模型来读写XML文件 Fixflow引擎解析(二)(模型) - BPMN ...

  7. .NET Core部署到linux(CentOS)最全解决方案,高阶篇(Docker+Nginx 或 Jexus)

    在前两篇: .NET Core部署到linux(CentOS)最全解决方案,常规篇 .NET Core部署到linux(CentOS)最全解决方案,进阶篇(Supervisor+Nginx) 我们对. ...

  8. SDN与NFV技术在云数据中心的规模应用探讨

    Neo 2016-1-29 | 发表评论 编者按:以云数据中心为切入点,首先对SDN领域中的叠加网络.SDN控制器.VxLAN 3种重要技术特点进行了研究,接下来对NFV领域中的通用服务器性能.服务链 ...

  9. 微信小程序 教程及示例

    作者:初雪链接:https://www.zhihu.com/question/50907897/answer/128494332来源:知乎著作权归作者所有,转载请联系作者获得授权.微信小程序正式公测, ...

随机推荐

  1. php排序函数测试

    1.sort,asort,arsort函数 十万个数的数组排序,用了0.17秒 $starttime=explode(' ',microtime());;for ($i=0; $i <10000 ...

  2. Java转大数据开发全套视频资料

    大数据在近两年可算是特别火,有很多人都想去学大数据,有java转大数据的,零基础学习大数据的.但是大数据真的好学吗. 我们先来了解一下什么是大数据. 大数据是指无法在一定时间内用常规软件工具对其内容进 ...

  3. Codeforces 903G 巧妙的线段树

    思路: 巧妙的线段树 想方法将网络流往数据结构方向转化 http://www.cnblogs.com/yyf0309/p/8724558.html //By SiriusRen #include &l ...

  4. Objective-C——Runtime理解

    动态语言 OC是一门不折不扣的动态语言,所以它的很多机制都是动态运行时决定的.这点和C语言不一样,C语言是静态绑定,也就是编译后所有的一切都已经决定了.这一点和C语言的函数指针有些类似,很多时候函数指 ...

  5. SQL基本操作——DROP撤销索引、表以及数据库

    DROP撤销索引.表以及数据库 --DROP INDEX 命令删除表格中的索引 DROP INDEX table_name.index_name --DROP TABLE 语句删除表(表的结构.属性以 ...

  6. 用nginx实现分布式限流

    1.前言 一般对外暴露的系统,在促销或者黑客攻击时会涌来大量的请求,为了保护系统不被瞬间到来的高并发流量给打垮, 就需要限流 . 本文主要阐述如何用nginx 来实现限流. 听说 Hystrix 也可 ...

  7. 详解HashMap数据结构实现

    HashMap的设计是由数组加链表的符合数据结构,在这里用自己的语言以及结合源码去总结一下,如果有不对的地方希望评论指正,先拱手谢谢. HashMap是日常中非常常用的一种数据结构,我们要想深入了解学 ...

  8. 11-c++虚拟函数

    虚拟函数 #include "stdio.h" class A{ public: void print() { printf("%s","this i ...

  9. sublime之markdown快捷键

    目录 sublime 快捷键 markdown技能 sublime 快捷键 ctrl + shift + p 进入命令面板 package install 进入下载仓库 ctrl + alt + O ...

  10. hdu 2084 数塔(简单dp)

    题目 简单dp //简单的dp #include<stdio.h> #include<string.h> #include<algorithm> using nam ...