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.rhkb.cn/news/250729.html

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

相关文章

如何在Windows部署GoLand并通过SSH远程连接Linux服务器

文章目录 1. 安装配置GoLand2. 服务器开启SSH服务3. GoLand本地服务器远程连接测试4. 安装cpolar内网穿透远程访问服务器端4.1 服务器端安装cpolar4.2 创建远程连接公网地址 5. 使用固定TCP地址远程开发 本文主要介绍使用GoLand通过SSH远程连接服务器&#xff0c;并结合cpolar内…

二叉树(1)

1 树概念及结构 1.1树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。 把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 有一个特殊的结点&a…

c++设计模式之适配器模式

作用 适配器模式的作用是可以让不兼容的接口在一起工作 案例 假如现在有一台电脑和一台投影仪&#xff0c;现在需要把电脑和投影仪进行连接 在此基础上我们再假设&#xff0c;电脑只能连接VGA接口&#xff0c;而投影仪的种类繁多&#xff0c;有VGA接口、HAMI接口等多种种类…

初探分布式链路追踪

本篇文章&#xff0c;主要介绍应用如何正确使用日志系统&#xff0c;帮助用户从依赖、输出、清理、问题排查、报警等各方面全面掌握。 可观测性 可观察性不单是一套理论框架&#xff0c;而且并不强制具体的技术规格。其核心在于鼓励团队内化可观察性的理念&#xff0c;并确保由…

低版本MATLAB打开高版本Simulink文件的方法

打开simulink&#xff0c;依次点击“建模”、“环境”、“simulink预设项”&#xff0c;如图所示&#xff1a; 然后在弹出的窗口中&#xff0c;点击“模型文件”&#xff0c;并取消勾选“不要加载用更新版本的simulink创建的模型”&#xff0c;接着点击“应用”即可。如图所示&…

跟着cherno手搓游戏引擎【19】抽象纹理

引入&#xff1a; 导入stb_image: GitHub - nothings/stb: stb single-file public domain libraries for C/C 下载复制stb_image.h的内容&#xff08;8000多行&#xff09;&#xff0c;然后粘到如图位置 stb_image.cpp: #include"ytpch.h" #define STB_IMAGE_IM…

Revit中使用依赖注入

依赖注入的技术已经很成熟&#xff0c;本文主要是说明一下Revit中的适用版本与介绍相关的开源项目。 版本问题 版本 目前的依赖注入包无法支持Revit 2020 以下的版本&#xff0c;原因是因为包中的依赖项与Revit本身的依赖项不一致导致的&#xff0c;所以说如果使用Revit DI…

题目:有1,2,3,4共四个数字,能组成多少个不相同而且无重复数字的三位数有多少个,都是多少?lua

这是作者的思路&#xff0c; 创建三个表&#xff0c; 第一个数是从四个数遍历&#xff0c; 第二个是数剔除第一个数进行遍历 第三个是剔除第一第二个数遍历 脚本如下 local a{1,2, 3, 4} local b{} local c{} local d{} local function copy(tbl) local ctbl{} for k,v in…

机器学习复习(4)——CNN算法

目录 数据增强方法 CNN图像分类数据集构建 导入数据集 定义trainer 超参数设置 数据增强 构建CNN网络 开始训练 模型测试 数据增强方法 # 一般情况下&#xff0c;我们不会在验证集和测试集上做数据扩增 # 我们只需要将图片裁剪成同样的大小并装换成Tensor就行 test_t…

nginx初学者指南

一、启动、停止和重新加载配置 前提&#xff1a;先要启动nginx 在Windows上启动nginx的步骤如下&#xff1a; 1. 下载并安装nginx。可以从nginx官网下载适合自己操作系统的版本&#xff0c;一般是zip压缩包&#xff0c;解压到指定目录中。 2. 进入nginx的安装目录&#xff…

LeetCode:138. 随机链表的复制之如何有效copy

自己复制的话&#xff0c;很容易写出来一个时间复杂度O&#xff08;n ^ 2&#xff09; 空O&#xff08;n&#xff09;的做法 我们可以参考基因的复制&#xff0c; 目录 题目&#xff1a; 实现思路&#xff08;基因复制式的copy&#xff09;&#xff1a; 官方快慢指针解法&…

基于Python的招聘网站爬虫及可视化的设计与实现

摘要&#xff1a;现在&#xff0c;随着互联网网络的飞速发展&#xff0c;人们获取信息的最重要来源也由报纸、电视转变为了互联网。互联网的广泛应用使网络的数据量呈指数增长&#xff0c;让人们得到了更新、更完整的海量信息的同时&#xff0c;也使得人们在提取自己最想要的信…

山东淄博刑侦大队利用无人机抓获盗窃团伙

山东淄博刑侦大队利用无人机抓获盗窃团伙 近期&#xff0c;山东淄博临淄区发生多起盗窃案件。通过视频追踪和调查访问&#xff0c;推断临淄区某村可能为嫌疑人藏匿地点。刑侦大队无人机应急小组迅速到达现场&#xff0c;经无人机高空侦查&#xff0c;发现并锁定了嫌疑人的藏匿…

【开源】SpringBoot框架开发城市桥梁道路管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 查询城市桥梁4.2 新增城市桥梁4.3 编辑城市桥梁4.4 删除城市桥梁4.5 查询单个城市桥梁 五、免责说明 一、摘要 1.1 项目介绍 基于VueSpringBootMySQL的城市桥梁道路管理系统&#xff0c;支持…

灵伴科技(Rokid)借助 Knative 实现 AI 应用云原生 Serverless 化

作者&#xff1a;朱炜栋、元毅、子白 公司介绍 Rokid 创立于 2014 年&#xff0c;是一家专注于人机交互技术的产品平台公司&#xff0c;2018 年即被评为国家高新技术企业。Rokid 作为行业的探索者、领跑者&#xff0c;目前致力于 AR 眼镜等软硬件产品的研发及以 YodaOS 操作系…

B3626 跳跃机器人——洛谷(疑问)

题目描述 地上有一排格子&#xff0c;共 &#xfffd;n 个位置。机器猫站在第一个格子上&#xff0c;需要取第 &#xfffd;n 个格子里的东西。 机器猫当然不愿意自己跑过去&#xff0c;所以机器猫从口袋里掏出了一个机器人&#xff01;这个机器人的行动遵循下面的规则&#…

百分点科技:《数据科学技术: 文本分析和知识图谱》

科技进步带来的便利已经渗透到工作生活的方方面面&#xff0c;ChatGPT的出现更是掀起了新一波的智能化浪潮&#xff0c;推动更多智能应用的涌现。这背后离不开一个朴素的逻辑&#xff0c;即对数据的收集、治理、建模、分析和应用&#xff0c;这便是数据科学所重点研究的对象——…

格式化内存卡后,如何找回丢失的监控视频?

随着摄像头的应用越来越广泛&#xff0c;很多监控摄像头采用了内存卡作为存储介质&#xff0c;方便用户存储和查看摄像头拍摄的视频文件。然而&#xff0c;由于各种原因&#xff0c;监控摄像头的内存卡有时会被意外格式化导致重要数据的丢失&#xff0c;给用户带来诸多困扰。 那…

无人机激光雷达标定板

机载激光雷达标定板是用于校准和验证机载激光雷达系统的设备。由于机载激光雷达系统在测量地形、建筑物和植被等方面具有广泛的应用&#xff0c;因此标定板的使用对于确保测量结果的准确性和可靠性至关重要。 标定板通常由高反射率的材料制成&#xff0c;如镀金的玻璃或陶瓷&am…

flv视频格式批量截取封面图(不占内存版)--其他视频格式也通用

flv视频格式批量截取封面图&#xff08;不占内存版&#xff09;--其他视频格式也通用 需求&#xff08;实现的效果&#xff09;功能实现htmlcssjs 需求&#xff08;实现的效果&#xff09; 批量显示视频&#xff0c;后端若返回有imgUrl,则直接显示图1&#xff0c; 若无&#xf…