flowable 设置自定义属性教程

概述

        由于工作需要给flowable工作流设计器添加自定义属性,以满足功能实现。所以这篇文章介绍下用flowable 开源的的flowable-ui 前端添加自定义属性,后端解析属性值的例子。

技术栈

序号技术点名称版本
1Flowable6.8.0

使用的是flowable6.8.0 版的代码

GitHub - flowable/flowable-engine at flowable-release-6.8.0icon-default.png?t=N7T8https://github.com/flowable/flowable-engine/tree/flowable-release-6.8.0然后依照下面链接启动flowable-ui项目

手把手教大家编译 flowable 源码-腾讯云开发者社区-腾讯云松哥最近正在录制 TienChin 项目视频~采用 Spring Boot+Vue3 技术栈,里边会涉及到各种好玩的技术,小伙伴们来和松哥一起做一个完成率超 90% 的项目,戳戳戳这里-->TienChin 项目配套视频来啦。----要说这个编译源码其实没什么技术含量,但是由于国内的网络问题,Spring 等各种常...icon-default.png?t=N7T8https://cloud.tencent.com/developer/article/2108059

添加flowable-ui前端属性

添加boolean 属性

找到flowable-engine-flowable-6.8.0\modules\flowable-ui\flowable-ui-modeler-logic\src\main\resources\stencilset_bpmn.json 路径文件 这个json 就是设计器的所有内容,

\flowable-engine-flowable-6.8.0\modules\flowable-ui\flowable-ui-modeler-frontend\src\main\resources\static\modeler\i18n\zh-CN.json 文件是汉化文件

下面是stencilset_bpmn.json 的文件格式:

{"title": "BPMN 2.0标准工具","namespace": "http://b3mn.org/stencilset/bpmn2.0#","description": "BPMN process editor","propertyPackages": [{"name": "overrideidpackage","properties": [{"id": "overrideid","type": "String","title": "Id","value": "","description": "元素的唯一标识.","popular": true}]}, {"name": "namepackage","properties": [{"id": "name","type": "String","title": "名称","value": "","description": "BPMN元素的描述名称.","popular": true,"refToView": "text_name"}]}],"stencils": [{"type": "node","id": "UserTask","title": "用户活动","description": "分配给特定人的任务 ","view": "此处代码已省略,请查看本书配套资源内容","groups": ["活动列表"],"propertyPackages": ["overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "executionlistenerspackage", "multiinstance_typepackage", "multiinstance_cardinalitypackage", "multiinstance_collectionpackage", "multiinstance_variablepackage", "multiinstance_conditionpackage", "isforcompensationpackage", "usertaskassignmentpackage", "formkeydefinitionpackage", "formreferencepackage", "duedatedefinitionpackage", "prioritydefinitionpackage", "formpropertiespackage", "tasklistenerspackage"],"hiddenPropertyPackages": [],"roles": ["Activity", "sequence_start", "sequence_end", "ActivitiesMorph", "all"]}]
}

从以上配置文件内容中可以看出,最顶层有五个元素:title,namespace,description,

propertyPackages和stencils,分别代表标题,命名空间,描述,属性集合,节点属性,其中

propertyPackages表示的是设计器下栏的各个属性。通过propertyPackages 可以设置属性的名称,样式,字段类型。

 

type 对应的是当前属性的类型,和flowable-engine-flowable-6.8.0\modules\flowable-ui\flowable-ui-modeler-frontend\src\main\resources\static\modeler\editor-app\configuration\properties.js

里面的内容一一对应

stencils.propertyPackages 的值可以表示哪些活动使用哪些属性。

第一步:添加允许催办属性

第二步:将允许催办属性添加到用户属性下

第三步:重启服务

就可以看到用户任务下有允许催办属性了。

添加下拉框样式属性

上面我们完成了通过设置type 为boolean,添加允许催办属性,那么string,text属性大家也都可以在properties.js 文件中看到,按需添加即可。

如果是添加下拉框属性,我们可以仿照多实例的下拉框属性实现。

第一步:在stencilset_bpmn.json 文件的propertyPackages 下添加下拉属性的内容

,{"name" : "usertaskovertimehandlertypepackage","properties" : [{"id" :"overtimehandlertype","type" : "fd-overtimehandlertype","title" : "逾期处理方式","value" : "0","description" : "逾期处理方式","popular" : true}]}

注意id 和type ,我们去properties.js 文件下添加该类

第二步:在properties.js 文件下添加类型

注意1:properties.js 文件下的自定义名称为: oryx-上面的id-上面的type

注意2:不要用驼峰格式命名。

第三步:定义html

这些步骤我都是抄多实例怎么实现的。

下面是html 的下拉框格式,ng-controller 是用的angular.js 语言 下面红框里的内容我们自己定义

第四步:定义js 文件 

在 flowable-engine-flowable-6.8.0\modules\flowable-ui\flowable-ui-modeler-frontend\src\main\resources\static\modeler\index.html 文件下设置自定义的js路径

下面图片是js的内容,注意除默认值外其他两个字段需要和第二步html 里的值保持一致。

第五步:重启服务

重启服务就可以看到flowable-ui 界面上出现下拉框的属性了。如果是其他样式的属性,可以借鉴flowable-ui  中相同的样式是如何实现的。

后端添加自定义属性解析处理类

第一步:定义UserTaskJsonConverter实现类

package org.flowable.ui.application.converter;import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.flowable.bpmn.constants.BpmnXMLConstants;
import org.flowable.bpmn.model.*;
import org.flowable.editor.language.json.converter.BaseBpmnJsonConverter;
import org.flowable.editor.language.json.converter.BpmnJsonConverterContext;
import org.flowable.editor.language.json.converter.UserTaskJsonConverter;import java.util.List;
import java.util.Map;/*** @author admin*/
public class CustomUserTaskJsonConverter extends UserTaskJsonConverter {/***  用户任务类型*/public static final String ACTIVE_TYPE = "activetype";/***  允许撤回*/public static final String ALLOW_RECALL = "allowrecall";/***  允许终止*/public static final String ALLOW_STOP = "allowstop";/***  允许跳过*/public static final String ALLOW_SKIP = "allowskip";/***  允许修改下一个节点参与者*/public static final String ALLOW_UPDATE_NEXT_ONE = "allowupdatenextone";/***  允许修改后续节点参与者*/public static final String ALLOW_UPDATE_NEXT_ALL = "allowupdatenextall";/***  允许上传附件*/public static final String ALLOW_UPLOAD = "allowupload";/***  工作期限(单位:天)*/public static final String LIMIT_TIME = "limittime";/***  逾期处理方式*/public static final String OVER_TIME_HANDLER_TYPE = "overtimehandlertype";/***  预警提醒(逾期前天数)*/public static final String OVER_TIME_WARN_TIME = "overtimewarntime";/***  预警提醒(逾期前天数)*/public static final String CIRCULATION_WARN_TIME = "circulationwarntime";@Overrideprotected void convertElementToJson(ObjectNode propertiesNode, BaseElement baseElement, BpmnJsonConverterContext converterContext) {super.convertElementToJson(propertiesNode, baseElement, converterContext);UserTask userTask = (UserTask) baseElement;//解析Map<String, List<ExtensionElement>> extensionElements = userTask.getExtensionElements();if(extensionElements != null && extensionElements.containsKey(ACTIVE_TYPE)){ExtensionElement e = extensionElements.get(ACTIVE_TYPE).get(0);setPropertyValue(ACTIVE_TYPE, e.getElementText(), propertiesNode);}if(extensionElements != null && extensionElements.containsKey(ALLOW_RECALL)){ExtensionElement e = extensionElements.get(ALLOW_RECALL).get(0);setPropertyValue(ALLOW_RECALL, e.getElementText(), propertiesNode);}if(extensionElements != null && extensionElements.containsKey(ALLOW_STOP)){ExtensionElement e = extensionElements.get(ALLOW_STOP).get(0);setPropertyValue(ALLOW_STOP, e.getElementText(), propertiesNode);}if(extensionElements != null && extensionElements.containsKey(ALLOW_SKIP)){ExtensionElement e = extensionElements.get(ALLOW_SKIP).get(0);setPropertyValue(ALLOW_SKIP, e.getElementText(), propertiesNode);}if(extensionElements != null && extensionElements.containsKey(ALLOW_UPDATE_NEXT_ONE)){ExtensionElement e = extensionElements.get(ALLOW_UPDATE_NEXT_ONE).get(0);setPropertyValue(ALLOW_UPDATE_NEXT_ONE, e.getElementText(), propertiesNode);}if(extensionElements != null && extensionElements.containsKey(ALLOW_UPDATE_NEXT_ALL)){ExtensionElement e = extensionElements.get(ALLOW_UPDATE_NEXT_ALL).get(0);setPropertyValue(ALLOW_UPDATE_NEXT_ALL, e.getElementText(), propertiesNode);}if(extensionElements != null && extensionElements.containsKey(ALLOW_UPLOAD)){ExtensionElement e = extensionElements.get(ALLOW_UPLOAD).get(0);setPropertyValue(ALLOW_UPLOAD, e.getElementText(), propertiesNode);}if(extensionElements != null && extensionElements.containsKey(LIMIT_TIME)){ExtensionElement e = extensionElements.get(LIMIT_TIME).get(0);setPropertyValue(LIMIT_TIME, e.getElementText(), propertiesNode);}if(extensionElements != null && extensionElements.containsKey(OVER_TIME_HANDLER_TYPE)){ExtensionElement e = extensionElements.get(OVER_TIME_HANDLER_TYPE).get(0);setPropertyValue(OVER_TIME_HANDLER_TYPE, e.getElementText(), propertiesNode);}if(extensionElements != null && extensionElements.containsKey(OVER_TIME_WARN_TIME)){ExtensionElement e = extensionElements.get(OVER_TIME_WARN_TIME).get(0);setPropertyValue(OVER_TIME_WARN_TIME, e.getElementText(), propertiesNode);}if(extensionElements != null && extensionElements.containsKey(CIRCULATION_WARN_TIME)){ExtensionElement e = extensionElements.get(CIRCULATION_WARN_TIME).get(0);setPropertyValue(CIRCULATION_WARN_TIME, e.getElementText(), propertiesNode);}}@Overrideprotected FlowElement convertJsonToElement(JsonNode elementNode, JsonNode modelNode, Map<String, JsonNode> shapeMap, BpmnJsonConverterContext converterContext) {FlowElement flowElement = super.convertJsonToElement(elementNode, modelNode, shapeMap, converterContext);UserTask userTask = (UserTask) flowElement;//解析自定义扩展属性this.addExtansionPropertiesElement(userTask,elementNode,ACTIVE_TYPE);this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_RECALL);this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_STOP);this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_SKIP);this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_UPDATE_NEXT_ONE);this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_UPDATE_NEXT_ALL);this.addExtansionPropertiesElement(userTask,elementNode,ALLOW_UPLOAD);this.addExtansionPropertiesElement(userTask,elementNode,LIMIT_TIME);this.addExtansionPropertiesElement(userTask,elementNode,OVER_TIME_HANDLER_TYPE);this.addExtansionPropertiesElement(userTask,elementNode,OVER_TIME_WARN_TIME);this.addExtansionPropertiesElement(userTask,elementNode,CIRCULATION_WARN_TIME);return userTask;}private void addExtansionPropertiesElement(UserTask userTask,  JsonNode elementNode, String name) {ExtensionElement extensionElement = new ExtensionElement();extensionElement.setName(name);//BpmnXMLConstants.FLOWABLE_EXTENSIONS_PREFIXextensionElement.setNamespacePrefix("model");extensionElement.setNamespace(BpmnXMLConstants.FLOWABLE_EXTENSIONS_NAMESPACE);String customProperties = getPropertyValueAsString(name, elementNode);extensionElement.setElementText(customProperties);userTask.addExtensionElement(extensionElement);}public static void fillTypes(Map<String, Class<? extends BaseBpmnJsonConverter>>convertersToBpmnMap, Map<Class<? extends BaseElement>, Class<? extendsBaseBpmnJsonConverter>> convertersToJsonMap) {fillJsonTypes(convertersToBpmnMap);fillBpmnTypes(convertersToJsonMap);}public static void fillJsonTypes(Map<String, Class<? extends BaseBpmnJsonConverter>>convertersToBpmnMap) {convertersToBpmnMap.put(STENCIL_TASK_USER, CustomUserTaskJsonConverter.class);}public static void fillBpmnTypes(Map<Class<? extends BaseElement>, Class<? extendsBaseBpmnJsonConverter>> convertersToJsonMap) {convertersToJsonMap.put(UserTask.class, CustomUserTaskJsonConverter.class);}}

第二步:定义BpmnJsonConverter实现类

package org.flowable.ui.application.converter;import org.flowable.editor.language.json.converter.BpmnJsonConverter;/*** @author admin*/public class CustomBpmnJsonConverter extends BpmnJsonConverter {static {//这里可以加入所有自定义的属性内容convertersToBpmnMap.put(STENCIL_TASK_USER, CustomUserTaskJsonConverter.class);}}

第三步:解析json 转成Bpmn

package org.flowable.ui.application;import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.ExtensionElement;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.UserTask;
import org.flowable.editor.language.json.converter.BpmnJsonConverter;
import org.flowable.editor.language.json.converter.util.CollectionUtils;
import org.flowable.ui.application.converter.CustomBpmnJsonConverter;
import org.junit.jupiter.api.Test;import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;@Slf4j
public class RunCustomJsonConverterDemo {@Testpublic void runCustomJsonConverterDemo() throws Exception {//读取Flowable Modeler保存的JsonInputStream processModelJsonInputStream =getClass().getClassLoader().getResourceAsStream("model-json/model.json");ObjectMapper mapper = new ObjectMapper();JsonNode processJsonNode = mapper.readTree(processModelJsonInputStream);//获取流程模型的Json//使用自定义转换类由Json转换为BpmnModel对象BpmnJsonConverter bpmnJsonConverter = new CustomBpmnJsonConverter();BpmnModel bpmnModel = bpmnJsonConverter.convertToBpmnModel(processJsonNode);Process mainProcess = bpmnModel.getMainProcess();UserTask userTask = (UserTask) mainProcess.getFlowElement("sid-DA2AB9F9-3CB2-40C5-945B-95B6DADFA1E1");//查询用户任务对象并打印属性Map<String, List<ExtensionElement>> extensionElements = userTask.getExtensionElements();List<ExtensionElement> allowurgingExtension = extensionElements.get("allowrecall");if (CollectionUtils.isNotEmpty(allowurgingExtension)) {log.info("扩展属性activetype值为:{}", allowurgingExtension.get(0).getElementText());}byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(bpmnModel);// 转xmllog.info("bpmnBytes:"+new String(bpmnBytes));}
}

其中model.json 是flowable-ui点击保存传过来的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/663435.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

画质和场景双需求下,海信电视U8KL的变与不变

又到一年春节&#xff0c;最近几年大家过年的方式越来越丰富&#xff0c;但是跟家人在一起看春晚依然是主流&#xff0c;电视也是过年不可或缺的家庭成员。 当然&#xff0c;随着大家对生活品质的要求更高&#xff0c;对电视的要求也变得更高了。比如&#xff0c;现在春晚直播…

爬虫笔记(三):实战qq登录

咳咳&#xff0c;再这样下去会进橘子叭hhhhhh 以及&#xff0c;这个我觉得大概率是成功的&#xff0c;因为测试了太多次&#xff0c;登录并且验证之后&#xff0c;qq提醒我要我修改密码才可以登录捏QAQ 1. selenium 有关selenium具体是啥&#xff0c;这里就不再赘述了&#x…

leetcode c++ 超出内存限制

给两个主要原因&#xff0c;这两个原因&#xff0c;如果在递归或者循环里就很容易导致内存超出限制 首先就是误用 如果只是变量的变化实现的话&#xff0c;或者-就可以了&#xff0c;不需要写成AAx的形式&#xff0c;那样会重新开辟一块内存 其次就是值传递 值传递也是会开辟…

在Linux中对Nginx进行安全加固

准备工作 在IP为x.x.x.x的服务器上安装nginx&#xff0c;确保Linux系统为nginx环境。 检查nginx是否配置nginx账号锁定策略 配置nginx账号锁定策略&#xff0c;降低被攻击概率。 第一步&#xff0c;查看nginx的锁定状态。 命令&#xff1a;passwd -S nginx 若结果出现“P…

【gcc】webrtc发送侧计算 丢包率

大神的分析 : 提到: 每当收到cc-feedback或者收到RR-report的时候就能统计出丢包率,在cc-controller中就会调用SendSideBandwidthEstimation::UpdatePacketsLost()去更新丢包率,同时进行码率预估 G:\CDN\rtcCli\m98\src\modules\congestion_controller\goog_cc\send_side_b…

今日arXiv最热NLP大模型论文:像人一样浏览网页执行任务,腾讯AI lab发布多模态端到端Agent

Agent的发展成为了LLM发展的一个热点。只需通过简单指令&#xff0c;Agent帮你完成从输入内容、浏览网页、选择事项、点击、返回等一系列需要执行多步&#xff0c;才能完成的与网页交互的复杂任务。 比如给定任务&#xff1a;“搜索Apple商店&#xff0c;了解iPad智能保护壳Sm…

Qt中的绝对位置与相对位置

在Qt的开发中&#xff0c;有时候需要获取鼠标点击的位置的坐标。在Qt中坐标分为相对坐标和绝对坐标&#xff1b;相对坐标是以控件的左上角为&#xff08;0&#xff0c;0&#xff09;点的坐标系的坐标&#xff0c;绝对坐标是以显示器屏幕的左上角为&#xff08;0&#xff0c;0&a…

蓝桥杯-常用STL(二)

常用STL &#x1f388;1.集合&#x1f388;2.set的基础使用&#x1f52d;2.1引入库&#x1f52d;2.2插入元素&#x1f52d;2.3删除元素&#x1f52d;2.4判断元素是否存在&#x1f52d;2.5遍历元素&#x1f52d;2.6清空 &#x1f388;3.set与结构体 &#x1f388;1.集合 &#x…

【Algorithms 4】算法(第4版)学习笔记 04 - 2.1 初级排序算法

文章目录 前言参考目录学习笔记1&#xff1a;前置说明1.1&#xff1a;全序关系1.2&#xff1a;Comparable API 实现 demo1.3&#xff1a;排序算法模板2&#xff1a;选择排序2.1&#xff1a;内循环实现过程拆解2.2&#xff1a;代码实现2.3&#xff1a;特点3&#xff1a;插入排序…

【kubernetes】集群网络(二):Flannel的VxLan、Host-GW模式

文章目录 1 Pod的IP地址的分配2 CNI3 Flannel3.1 Flannel的安装3.2 VxLan3.3 Host-GW 4 总结 1 Pod的IP地址的分配 当节点上只安装了docker&#xff0c;则会用veth pairdocker0实现单个节点上容器之间的通信&#xff0c;并且这些容器都在同一个IP段&#xff0c;如果不修改&…

(2024,SaFaRI,双三上采样和 DFT,空间特征和频率特征)基于扩散模型的图像空间和频率感知恢复方法

Spatial-and-Frequency-aware Restoration method for Images based on Diffusion Models 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 3. 方法 3.1 修改数据保真度 3.2 …

JMeter GUI:测试计划和工作台

什么是测试计划&#xff1f; 测试计划是您添加 JMeter 测试所需元素的地方。 它存储运行所需测试所需的所有元素&#xff08;如线程组、计时器等&#xff09;及其相应的设置。 下图显示了测试计划的示例 测试计划是您添加 JMeter 测试所需元素的地方。 它存储运行所需测试…

Modbus协议学习第六篇之基于libmodbus库的示例程序(可以联合Modbus模拟仿真软件进行调试)

前置工作 学了这么多Modbus的知识&#xff0c;如果不进行实际的操作&#xff0c;总感觉懂的不透彻。基于此&#xff0c; 本篇博文就带各位读者来了解下如何通过编写程序来模拟与Modbus Slave仿真软件的通讯。当然了&#xff0c;这里有两个前提&#xff0c;如下&#xff1a; 1.请…

【深度强化学习】Python:OpenAI Gym-CarRacing 自动驾驶 | 提供项目完整代码 | 车道检测功能 | 路径训练功能 | 车辆控制功能

💭 写在前面:本篇是关于 OpenAI Gym-CarRacing 自动驾驶项目的博客,面向掌握 Python 并有一定的深度强化学习基础的读者。GYM-Box2D CarRacing 是一种在 OpenAI Gym 平台上开发和比较强化学习算法的模拟环境。它是流行的 Box2D 物理引擎的一个版本,经过修改以支持模拟汽车…

一键部署幻兽帕鲁服务器免费一年方案

一、背景介绍 简单讲一下历程&#xff0c;幻兽帕鲁从在1月19日上线&#xff0c;24小时内在线人数峰值便突破200万&#xff0c;作为2024年第一款现象级游戏&#xff0c;《幻兽帕鲁》上线后&#xff0c;由于人数太多&#xff0c;频现服务器过载导致游戏卡顿掉线的情况。为了能够…

【GitHub项目推荐--大语言模型课程】【转载】

Large Language Model Course Large Language Model Course&#xff08;大型语言模型课程&#xff09;是一个开源项目&#xff0c;该课程分为三个部分&#xff1a; LLM 基础&#xff1a;涵盖了数学、Python 和神经网络的基础知识。 LLM 科学家&#xff1a;专注于学习如何使用…

【机器学习】基于K-近邻的车牌号识别

实验四: 基于K-近邻的车牌号识别 1 案例简介 ​ 图像的智能处理一直是人工智能领域广受关注的一类技术&#xff0c;代表性的如人脸识别与 CT 肿瘤识别&#xff0c;在人工智能落地的进程中发挥着重要作用。其中车牌号识别作为一个早期应用场景&#xff0c;已经融入日常生活中&…

LVGL部件7

一.图片部件 1.知识概览 2.函数接口 1.lv_img_set_pivot 在LVGL&#xff08;LittlevGL&#xff09;中&#xff0c;要设置图像对象的旋转中心点&#xff0c;可以使用 lv_img_set_pivot 函数。该函数的原型如下&#xff1a; void lv_img_set_pivot(lv_obj_t * img, lv_coord_…

Flask框架开发学习笔记《5》简易服务器代码

Flask框架开发学习笔记《5》 Flask是使用python的后端&#xff0c;由于小程序需要后端开发&#xff0c;遂学习一下后端开发。 简易服务器代码 接口解析那一块很关键&#xff0c;学后端服务器这一块&#xff0c;感觉主要就是学习相应地址的接口怎么处理。 然后写清楚每个地址…

在centos 7 中安装配置Jdk、Tomcat、及Tomcat自启动

目录 一、安装配置Jdk 1.创建目录并上传文件 2.解压JDK压缩包 3.配置JDK环境变量 4.设置环境变量生效 二、安装配置Tomcat 1.上传Tomcat并解压 2.启停Tomcat 3.修改tomcat-user.xml配置 4.配置远程访问Tomcat 5.远程项目发布 三.Tomcat自启动配置 1.配置Tomcat自启…