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); }
相关推荐
Spring Restful解决方案是一种基于Java和Spring框架构建RESTful Web服务的方法。REST(Representational State Transfer)是一种网络应用程序的设计风格和开发方式,它基于HTTP协议,强调简洁和标准化的接口,使得...
它通过一个配置文件pom.xml来管理项目依赖关系,自动化构建流程,使得开发者能够更专注于代码编写而非构建过程。 以下是针对这些文件内容的详细知识点讲解: 1. **RESTful API设计最佳实践**: - 资源的唯一标识...
Qt http同步请求测试(restfull中常用的get/post/put/delete、文件上传/下载) 示例源码 https://blog.csdn.net/aggs1990/article/details/124104548 CSDN审核可能较慢,如无法下载,可以过段时间再回来看下
This specification defines a set of Java APIs for the development of Web services built according to the Representational State Transfer[1] (REST) architectural style. Readers are assumed to be ...
6. **安全控制(Security)**:Spring Security 提供了强大的安全解决方案,可以为 RESTful API 添加认证和授权功能。 7. **错误处理(Error Handling)**:使用 `@ControllerAdvice` 和 `@ExceptionHandler` 注解...
在本项目中,“HelloWorld Restfull”意味着我们将构建一个基础的示例应用,它不仅会展示如何设置和运行 SpringMVC 项目,还会涉及到 RESTful 风格的 API 设计。 1. **SpringMVC 概述** - MVC 模式:将应用程序...
**WCF RESTful服务详解** WCF(Windows Communication Foundation)是微软.NET框架中的一种全面的服务模型,用于构建可互操作的、面向服务的应用程序。它支持多种通信协议,包括SOAP消息传递以及RESTful架构。...
项目需要要和别人对接,对方用的是RestFul接口,Java平台的,我们是.NET平台的,需要编写RestFul调用客户端,为了测试也要相应的服务端,虽然我也会Java语言,但是不熟啊,搞个环境都要一两天。...
压缩包中包含:jersey RESTfull最新版全部jar和官方demo
Retrofit的工作流程大致如下: 1. 定义接口:创建一个接口,使用注解标注HTTP方法和URL。 2. 创建实例:通过Retrofit.Builder构建Retrofit对象,并指定基础URL和其他配置。 3. 服务绑定:使用Retrofit对象创建接口的...
在Gradle中,我们可以创建构建脚本来定义项目依赖、任务以及构建流程。对于一个基于Java的Restful服务,可能需要添加如Spring Boot和Spring Web的依赖,这两个库可以帮助我们轻松地构建REST端点。在`build.gradle`...
在本示例中,我们将深入探讨 UnoNet 服务器和 Java 客户端之间的通信流程,以及如何构建和调用 REST API。 首先,了解 REST 基本概念很重要。RESTful API 通过 HTTP 协议工作,使用标准方法(GET、POST、PUT、...
Spring Boot的核心特性包括自动配置、内嵌Web服务器(如Tomcat或Jetty)以及“起步依赖”(Starter POMs),这些都极大地加速了开发流程。 在Spring REST中,我们利用Spring MVC的@Controller和@RequestMapping注解...
项目适合对struts2,spring,ibatis 和 restfull以及jquery有所了解的人员用来学习研究执行原理之用,亦可以作为项目对功能进行延伸。底层已经写好的基类。只要在此基础上拓展自己需要的功能接口就可以了,另外项目中...
CodeIgniter RestFull Automatic 您是否认为 repetivo 必须为所有表创建所有标准方法才能进行 Restfull 映射? 欢迎这是 CodeIgniter Restfull Automatic。 看下面它的优点: 一个完整的实现 Restfull GET、PUT、...
restfull-api 由 NodeJS 提供支持的 Restfull API 我们需要安装 Mongo DB - - 安装 下载所需版本的 MongoDB 的二进制文件。 从下载二进制文件。 例如,要通过 shell 下载最新版本,请发出以下命令: curl -O ...
在现代Web开发中,RESTful API设计已经成为构建可扩展、可维护的网络服务的主流方式。REST(Representational State Transfer,表述性状态转移)是一种架构风格,用于设计分布式系统,特别是互联网应用。...
管理Restfull Api响应的项目 Rest Response是一个简单且经过优化的小型库,可以在Api的RestFull上管理HTTP响应 Rest Responseéuma pequena bibliotecafácile otimizada para gerenciar suas respostas ...
Spring启动培训计划 文件夹1)-> MicroServices Things。 文件夹2)-> Spring Boot(静态)中的RestFull Api。 文件夹3)-> Spring Boot中的RestFull Api(数据库)
Flask-Restfull-API 步骤1在Ubuntu Server上安装Python3和pip3 sudo apt update sudo apt install python3-pip pip3 --version pip3 install flask pip3 install flask_restful 步骤2安装Docker sudo apt-get ...