写这个的业务场景是需要呈现流程实例的 流程图同时要在环节节点呈现对应的处理日志以及表单信息。(应用于flowable远程服务,非嵌入式开发,其主要思路也只是把官方服务的相关数据进行二次封装)

目前还是个小白。如果有不对的地方请大家多多指教

先看下最终封装后的流程图对象,只封装了节点,不包含流线。若需要可根据后续介绍自行封装

 [{"id": "startEvent1","name": "派单","current": false,"completed": true,"incomingElements": [],"outgoingElements": [{"id": "point001","tips": null}],"realgoingElements": [],"type": "StartEvent"},{"id": "point001","name": "受理","current": false,"completed": true,"incomingElements": ["startEvent1"],"outgoingElements": [{"id": "sid-74327205-DEFC-4D60-B15D-606A65EF5B0D","tips": null}],"realgoingElements": [],"type": "UserTask"},{"id": "sid-74327205-DEFC-4D60-B15D-606A65EF5B0D","name": null,"current": false,"completed": true,"incomingElements": ["point001"],"outgoingElements": [{"id": "point002","tips": "通过"},{"id": "sid-38583216-0EB6-4E99-BFB9-F94A40738148","tips": "驳回"}],"realgoingElements": ["sid-38583216-0EB6-4E99-BFB9-F94A40738148"],"type": "ExclusiveGateway"},{"id": "point002","name": "确认","current": false,"completed": true,"incomingElements": ["sid-74327205-DEFC-4D60-B15D-606A65EF5B0D"],"outgoingElements": [{"id": "sid-38583216-0EB6-4E99-BFB9-F94A40738148","tips": null}],"realgoingElements": [],"type": "UserTask"},{"id": "sid-38583216-0EB6-4E99-BFB9-F94A40738148","name": "归档","current": false,"completed": true,"incomingElements": ["point002","sid-74327205-DEFC-4D60-B15D-606A65EF5B0D"],"outgoingElements": [],"realgoingElements": [],"type": "EndEvent"}]

1、首先流程比较简单,如果不会画流程图和部署可度娘上边应该有很多资源。

流程分配人也是写死的:

流程需要注意的地方:
启动节点默认未定义ID。因为官方回默认配置其ID为
startEvent1。其主要目的是为了最后前端解析后台数据(无序)画流程图,知道第一个节点数据是什么。其实也可通过节点类型 因为启动节点的类型为StartEvent

这里我随便启动了一个测试流程实例test_001,首先官方提供的flow-rest服务走流程,然后在flow-admin服务查看流程实例实际运行状态,当前测试流程我已经归档了。

2、同时来看下官方服务对流程实例画的流程图:



同时这个我们可以看到官方服务其实调了自身封装好流程图数据的接口(这个接口服务是封装我们实际流程对象的关键数据之一):


官方的请求地址为 : http://127.0.0.1:8087/flowable-admin/app/rest/admin/process-instances/0cbeb6f1-ccba-11ea-ac6a-8ee4c8e29e52/history-model-json?processDefinitionId=test_element:1:e2ff27d5-ccb9-11ea-852f-8ee4c8e29e52&nocaching=1595561437641
同时header中要带当前登录账户的 cookie

{"elements":[{"completed":true,"id":"startEvent1","name":"派单","incomingFlows":[],"x":165,"y":150,"width":30,"height":30,"type":"StartEvent"},{"completed":true,"id":"point001","name":"受理","incomingFlows":["sid-AF892F55-DC8E-4459-AC05-F3257EA819BF"],"x":240,"y":125,"width":100,"height":80,"type":"UserTask","properties":[{"name":"Assignee","value":"管理员"}]},{"completed":true,"id":"sid-74327205-DEFC-4D60-B15D-606A65EF5B0D","name":null,"incomingFlows":["sid-E2F0CF0A-6350-4613-84F2-F3C182B1FA29"],"x":390,"y":145,"width":40,"height":40,"type":"ExclusiveGateway"},{"completed":true,"id":"point002","name":"确认","incomingFlows":["sid-44C6C3AD-B759-4BCB-916F-CCD06E818E7C"],"x":495,"y":125,"width":100,"height":80,"type":"UserTask","properties":[{"name":"Assignee","value":"班组人员"},{"name":"Form key","value":"commonForm"}]},{"completed":true,"id":"sid-38583216-0EB6-4E99-BFB9-F94A40738148","name":"归档","incomingFlows":["sid-CF99371B-C4BE-4443-A7AA-5DE2828278E7","sid-0FEBE0D2-DF46-4CAC-898F-DD8778DC94BC"],"x":675,"y":151,"width":28,"height":28,"type":"EndEvent"}],"flows":[{"completed":false,"id":"sid-AF892F55-DC8E-4459-AC05-F3257EA819BF","type":"sequenceFlow","sourceRef":"startEvent1","targetRef":"point001","waypoints":[{"x":194,"y":165},{"x":240,"y":165}]},{"completed":false,"id":"sid-CF99371B-C4BE-4443-A7AA-5DE2828278E7","type":"sequenceFlow","sourceRef":"point002","targetRef":"sid-38583216-0EB6-4E99-BFB9-F94A40738148","waypoints":[{"x":594,"y":165},{"x":675,"y":165}]},{"completed":false,"id":"sid-44C6C3AD-B759-4BCB-916F-CCD06E818E7C","type":"sequenceFlow","sourceRef":"sid-74327205-DEFC-4D60-B15D-606A65EF5B0D","targetRef":"point002","waypoints":[{"x":429,"y":165},{"x":494,"y":165}]},{"completed":true,"id":"sid-0FEBE0D2-DF46-4CAC-898F-DD8778DC94BC","type":"sequenceFlow","sourceRef":"sid-74327205-DEFC-4D60-B15D-606A65EF5B0D","targetRef":"sid-38583216-0EB6-4E99-BFB9-F94A40738148","waypoints":[{"x":410,"y":145},{"x":410,"y":89},{"x":689,"y":89},{"x":689,"y":151}]},{"completed":false,"id":"sid-E2F0CF0A-6350-4613-84F2-F3C182B1FA29","type":"sequenceFlow","sourceRef":"point001","targetRef":"sid-74327205-DEFC-4D60-B15D-606A65EF5B0D","waypoints":[{"x":339,"y":165},{"x":390,"y":165}]}],"collapsed":[],"diagramBeginX":180,"diagramBeginY":89,"diagramWidth":703,"diagramHeight":205,"completedActivities":["point001","startEvent1","point002","sid-74327205-DEFC-4D60-B15D-606A65EF5B0D","sid-38583216-0EB6-4E99-BFB9-F94A40738148"],"completedSequenceFlows":["sid-0FEBE0D2-DF46-4CAC-898F-DD8778DC94BC"]
}

官方服务封装好的流程图对象 elements:节点信息 flows:流线信息 completedActivities:已完成节点信息 completedSequenceFlows:已完成流线信息。这个数据说明了,节点与节点之间是通过线连接的。

@Data
@Builder
public class Element {private String id;              //节点Idprivate String type;            //节点类型   枚举:ExclusiveGateway 网关    UserTask 用户任务private String name;            //节点名称private boolean current;        //是否当前节点private boolean completed;      //是否完成private int x;                  //横坐标private int y;                  //纵坐标private int width;              //宽度private int height;             //高度private List<String> incomingFlows;    //入口节点private List<Properties> properties;   //配置变量@Toleratepublic Element() {}}@Data
public class Flows {private String targetRef;       //目标节点private boolean current;        //是否当前private boolean completed;      //是否完成private String id;              //流线IDprivate String type;            //类型private String sourceRef;       //来源节点private List<Waypoints> waypoints;  //流线坐标@Datapublic static class Waypoints {private double x;private double y;}
}

调用flow-admin登录接口进行认证获取cookie:

public static final String bpmApiIdmAuthPath = "flowable-idm/app/authentication";public static final String bpmApiIdmUser = "admin";public static final String bpmApiIdmPassword = "test";public static final String bpmApiProcessPath = "flowable-admin/app/rest/admin/process-instances";/*** flowable-admin登录认证** @return cookie* @throws IOException*/public static String getAuthenticationSession() {// http协议头+服务器ip+端口 + flowable-idm/app/authentication(admin的登陆请求)String baseUrl = FlowableRestClient.baseUrl;String authenticationUrl = baseUrl.replace("flowable-rest", "") + bpmApiIdmAuthPath;URL url = null;String responseCookie= "";try {url = new URL(authenticationUrl);HttpURLConnection connection = (HttpURLConnection) url.openConnection();// 允许连接提交信息connection.setDoOutput(true);connection.setRequestMethod("POST");// 请求参数String content = "j_username=" + bpmApiIdmUser + "&j_password=" + bpmApiIdmPassword + "&_spring_security_remember_me=true&submit=Login";// 提交请求数据OutputStream os = connection.getOutputStream();os.write(content.getBytes("utf8"));os.close();// 取到所用的Cookie, 认证responseCookie = connection.getHeaderField("Set-Cookie");} catch (MalformedURLException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (ProtocolException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return responseCookie;}

根据 流程业务标识 businessKey,获取流程实例ID 和 流程定义ID,调用查询接口获取业务工单运行的流程图数据

public static String getDiagramHistory(String businessKey) {String modelpath = "model-json";String instanceInfo = queryHistoryInstanceByBusinessKey(businessKey);JSONArray instanceInfoJson = JSONObject.parseObject(instanceInfo).getJSONArray("data");Assert.isTrue(instanceInfoJson.size() > 0, "流程实例为空!");if (instanceInfoJson.getJSONObject(0).getDate("endTime") != null) {modelpath = "history-model-json";}URL url = null;try {// 获取响应的cookie 值String responseCookie = getAuthenticationSession();HttpURLConnection conn = null;// 请求路径根路径String baseUrl = FlowableRestClient.baseUrl;// http://服务器ip:端口/flowable-admin/app/rest/admin/process-instances/流程实例id/model-json?processDefinitionId=流程定义idString modelUrl = baseUrl.replace("flowable-rest", "") + bpmApiProcessPath + "/";String processInstanceId = instanceInfoJson.getJSONObject(0).getString("id");String processDefinitionId = instanceInfoJson.getJSONObject(0).getString("processDefinitionId");url = new URL(modelUrl + processInstanceId + "/" + modelpath + "?processDefinitionId=" + processDefinitionId);conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setRequestProperty("Accept", "application/json");// 设置为之前登录获取的cookieconn.setRequestProperty("Cookie", responseCookie);conn.connect();StringBuilder builder = new StringBuilder();// 将数据读入StringBuilder;int successCode = 200;if (conn.getResponseCode() == successCode) {InputStream inputStream = conn.getInputStream();byte[] data = new byte[1024];StringBuffer sb1 = new StringBuffer();int length = 0;while ((length = inputStream.read(data)) != -1) {String s = new String(data, 0, length);sb1.append(s);}builder.append(sb1.toString());inputStream.close();}return builder.toString();} catch (IOException e) {e.printStackTrace();log.error(e.getMessage());return null;}}

3、官方服务提供了一个接口查询部署的流程图数据



其返回的数据其实就是画流程图时官方生成的数据,不关联流程实际运行实例。具体的数据结构是干嘛就不详细介绍,无碍乎是关于流程图相关的。我们重点关心 process 中的 flowElements 对应的是定义流程图的数据

/*** uri: GET /repository/process-definitions/{processDefinitionId}/model* @param businessKey* @return*/public static List<FlowElement> getProcModel(String businessKey) {List<FlowElement> list = Lists.newArrayList();Map<String, String> params = new HashMap<>();params.put("processBusinessKey", businessKey);JSONObject hisProcInst = JSON.parseObject(FlowableHisQueryClient.queryHisProcInst(JSONObject.toJSONString(params)));JSONArray jsonArray = hisProcInst.getJSONArray("data");if (jsonArray.isEmpty()) {throw new RuntimeException("根据业务ID " + businessKey + " 未查到流程信息!");}String processDefinitionId = jsonArray.getJSONObject(0).getString("processDefinitionId");//调用的flowable-rest中二次开发的功能String uri = RestUrls.createRelativeResourceUrl(RestUrls.URL_PROCESS_DEFINITION_MODEL, processDefinitionId);ResponseEntity<String> respones = FlowableRestClient.callFlowRestApi(service.concat(uri), HttpMethod.GET, null, null);if (respones.getStatusCode() != HttpStatus.OK) {throw new RuntimeException("获取流程定义数据失败:" + respones.getBody());}if (respones.getStatusCode() == HttpStatus.OK) {String res = respones.getBody();JSONObject obj = JSON.parseObject(res);JSONObject process = obj.getJSONArray("processes").getJSONObject(0);JSONArray flowElements = process.getJSONArray("flowElements");System.out.println("完整流程图数据: " + flowElements);list = JSONObject.parseArray(flowElements.toJSONString(), FlowElement.class);}return list;}
@Data
public class FlowElement {private boolean interrupting;private List<String> eventDefinitions;private ExtensionElements extensionElements;private List<IncomingFlows> incomingFlows;private List<OutgoingFlows> outgoingFlows;private int xmlColumnNumber;private List<String> executionListeners;private boolean notExclusive;private boolean asynchronous;private boolean exclusive;private Attributes attributes;private String id;private int xmlRowNumber;private List<String> formProperties;
}

最终将两个数据对象进行解析,封装想要的数据。其中心思想就是节点与节点之间是线。flowaable-admin 获取了流程实例运行的节点和线各自的状态。rest接口获取了流程定义的完整节点和线的流向。 所以 节点的出口是线,线的出口是节点。最后还发现官方有一个bug,两个节点的 completed 为true 但中间的线 为false,但还好不影响最终想要的流程图数据

/*** 获取动态流程图数据  只包含节点 不包含线** @param businessKey* @return*/public static List<RunElement> getRunElements(String businessKey) {String builder = getDiagramHistory(businessKey);JSONObject processData = JSONObject.parseObject(builder);if (processData == null) {throw new RuntimeException("工单运行流程图实例获取异常");}JSONArray elements = (JSONArray) processData.get("elements");JSONArray flows = (JSONArray) processData.get("flows");//System.out.println("运行节点数据: " + elements.toJSONString());//System.out.println("运行线数据: " + flows.toJSONString());List<Flows> flowList = JSONObject.parseArray(flows.toJSONString(), Flows.class);List<Element> elementList = JSONObject.parseArray(elements.toJSONString(), Element.class);List<FlowElement> procElementList = FlowableProcDefClient.getProcModel(businessKey);List<RunElement> runElementList = Lists.newArrayList();if (elementList != null && !elementList.isEmpty()) {elementList.forEach((element) -> {String nodeId = element.getId();String nodeName = element.getName();boolean current = element.isCurrent();boolean completed = element.isCompleted();String type = element.getType();List<String> incomingElements = Lists.newArrayList();List<OutgoingElement> outgoingElements = Lists.newArrayList();List<String> realgoingElements = Lists.newArrayList();RunElement runElement = RunElement.builder().id(nodeId).name(nodeName).current(current).completed(completed).type(type).incomingElements(incomingElements).build();//流程出口节点, 不包含线if (procElementList != null && !procElementList.isEmpty()) {for (FlowElement flowElement : procElementList) {if (flowElement.getId().equals(nodeId)) {List<OutgoingFlows> outgoingFlowsList = flowElement.getOutgoingFlows();List<IncomingFlows> incomingFlowsList = flowElement.getIncomingFlows();if (outgoingFlowsList != null && !outgoingFlowsList.isEmpty()) {for (OutgoingFlows goingFlows : outgoingFlowsList) {OutgoingElement outgoingElement = OutgoingElement.builder().id(goingFlows.getTargetRef()).tips(goingFlows.getName()).build();outgoingElements.add(outgoingElement);}runElement.setOutgoingElements(outgoingElements);}if (incomingFlowsList != null && !incomingFlowsList.isEmpty()) {for (IncomingFlows incomingFlows : incomingFlowsList) {incomingElements.add(incomingFlows.getSourceRef());}runElement.setOutgoingElements(outgoingElements);}break;}}}//运行出口节点if (flowList != null && !flowList.isEmpty()) {for (Flows flow : flowList) {if (flow.getSourceRef().equals(nodeId) && flow.isCompleted()) {realgoingElements.add(flow.getTargetRef());}}runElement.setRealgoingElements(realgoingElements);}runElementList.add(runElement);});}//System.out.println("查询的流程图数据:" + JSON.toJSON(runElementList));return runElementList;}
/*** 动态流程图数据  只包含节点 不包含线** @param businessKey* @return*/
@Data
@Builder
public class RunElement {private String id;          //节点IDprivate String name;        //节点名称private boolean current;    //是否当前节点private boolean completed;  //是否完成private List<String> incomingElements;          //入口节点private List<OutgoingElement> outgoingElements; //出口节点private List<String> realgoingElements;         //实际出口节点private String type;    //类型 枚举:ExclusiveGateway网关         UserTask用户任务  StartEvent开始节点@Toleratepublic RunElement() {}
}

Flowable流程图数据封装相关推荐

  1. Vue中加 flowable 流程图

    目录 简介 实现方案 使用案例 简介 我就在想前端有没有现成的库,可以直接用来绘制 Flowable 流程图的?找来找去,找到了两个,这两个的相似度还蛮高的,不过这两个都有一个问题,那就是都是基于 V ...

  2. flowable流程图有效性检验,可自定义规则

    文章目录 前言 一.主要方法 二.自定义规则校验器 总结 前言 对设计好的流程图xml进行有效性校验,可自定义规则 一.主要方法 package com.lc.workflow.common.util ...

  3. Flowable工作流入门

    Flowable工作流入门 本文链接:https://blog.csdn.net/qq_37059838/article/details/83576097 原作者:吕小小布 下载地址:Flowable ...

  4. 从入门到实战—————Flowable(工作流)

    目录 前言 相关概念 Flowable 流程图 流程id 任务id SpringBoot项目集成Flowable 1.pom.xml文件添加依赖 添加flowable依赖(查找依赖有很多方式,这里用i ...

  5. Springboot +Flowable,通过代码绘制流程图并设置高亮

    一.简介 通过代码绘制一张流程图,并设置成高亮. 首先先来看一下绘制出来的效果图,截图如下: 已经执行的节点和连线用红色标记出来,大致上就是这么一个效果. 二.怎么实现 将一个流程图绘制成图片,相关的 ...

  6. Flowable定时器与实时流程图

    1. 定时器 1.1. 流程定义定时激活 在之前松哥给小伙伴们介绍流程定义的时候,流程都是定义好之后立马就激活了,其实在流程定义的这个过程中,我们还可以设置一个激活时间,也就是流程定义好之后,并不会立 ...

  7. flowable+tomcat部署flowable项目,在线画流程图

    前置条件:jdk8,tomcat8(注意:jdk7可能会报错) flowable下载地址 https://github.com/flowable/flowable-engine/releases/do ...

  8. Flowable工作流之Flowable UI画工作流程图

    目录 1. `Flowable` 简介 2. 绘制工作流程图 2.1. `Flowable UI` 的安装部署 2.2. 启动服务 2.3. 用户管理 2.4. 工作流程效果图 2.5. 绘制工作流程 ...

  9. Flowable UI制作流程图

    使用Flowable UI创建流程 Flowable UI提供了几个web应用,用于演示及介绍Flowable项目提供的功能: Flowable IDM: 身份管理应用.为所有Flowable UI应 ...

最新文章

  1. 前序,中序,后序遍历
  2. 002_SpringIOC
  3. python编程--通过单纯形法和scipy库实现线性规划以及通过拉格朗日来求解非线性
  4. img src SVG使用CSS更改样式
  5. 【分布式】Zookeeper序列化及通信协议
  6. MATLAB和C语言的区别
  7. vue中使用保利威视频播放器
  8. 安卓一键新机_新机速递:vivo S7,如7而至;更有Nokia携手一键直达登场
  9. CSI Report中关于codebook/PMI的理解(2)
  10. php初级程序员的自我评价,程序员的自我评价【程序员的简历自我评价】
  11. 《统计学》笔记:第2章 数据的搜集
  12. Windows系统下的mklink指令
  13. OCCT示例学习笔记3--Modeling项目
  14. 这样设计积分兑换系统,让你的用户“活”起来
  15. 个人阅读作业+个人总结
  16. spring boot静态资源文件的访问以及自定义
  17. 【时间函数】gettimeofday
  18. day 和datepart 日期函数
  19. 微信图片服务器逻辑,微信小程序[第八篇] -- 实现完整的相册列表逻辑(小程序端服务器端)...
  20. 【R统计】主成分分析2——主成分回归

热门文章

  1. python中txt转成csv_python 快速把超大txt文件转存为csv的实例
  2. 虚构建筑·未来城~GANism艺术家会被人工智能取代吗?
  3. 嵌入式GUI LVGL『Tile View拼接视图控件』介绍
  4. PHP生成二维码(学习)
  5. 小韦老师@神犇营-my0008-请输出一首唐诗
  6. 课堂演讲之《遵纪守法》
  7. 2017年淘宝直通车“开车”技能汇总
  8. php 邮件发送检测,php发邮件测试
  9. Struts2 国际化
  10. WPF ListView 数据绑定后,ListViewItem如何拥有ContextMenu