集成Activiti-Modeler流程设计器
集成Activiti-Modeler流程设计器
Activiti Modeler 是 Activiti 官方提供的一款在线流程设计的前端插件,可以方便流程设计与开发人员绘制流程图,保存流程模型,部署至流程定义等等。
1、材料准备
 首先我们需要获取activiti-explorer.zip,这个是activiti-5.22.0才有的。
链接:https://pan.baidu.com/s/1zZ8vcjR63_hgzcLl6soiDw
提取码:1e8a
2、集成
 2.1 集成静态资源

 其中的editor-app就是编辑器,modeler.html是编辑器的入口页面。
 diagram-viewer是流程跟踪插件,虽然这次用不着,但之后会用到。
还有一个界面组件文件,在resource下,名称叫stencilset.json。本身是英文的,可以通过替换它来达到汉化的效果。但现在还是先把它放到项目中去。
 
 在editor-app/app-cfg.js中配置一下项目url。这个url是编辑器相关的后台服务的url。
ACTIVITI.CONFIG = {'contextRoot' : '/service',
};
我去掉了项目名。
3.后端部分
 先引入两个activiti的模块,因为编辑器会用到这两个模块。
  <dependency><groupId>org.activiti</groupId><artifactId>activiti-modeler</artifactId><version>${activiti.version}</version></dependency><dependency><groupId>org.activiti</groupId><artifactId>activiti-diagram-rest</artifactId><version>${activiti.version}</version></dependency>
其中需要将modeler模块的源代码放到src中,因为需要在其中做部分修改,主要是url的映射。
源码:
 https://github.com/Activiti/Activiti/tree/master/modules/activiti-modeler
其中有3个类,都是Controller:
StencilsetRestResource #获取编辑器组件及配置项信息。
ModelEditorJsonRestResource #根据modelId获取model的节点信息,编辑器根据返回的json进行绘图。
ModelSaveRestResource #编辑器制图之后,将节点信息以json的形式提交给这个Controller,然后由其进行持久化操作。
需要修改的地方就三个,在每个Controller类上加上@RequestMapping注解,并指定值为"service"(对应前台app-cfg.js中配置的url)。
···
@RequestMapping("service")
public class StencilsetRestResource {
···
···
@RequestMapping("service")
public class ModelEditorJsonRestResource implements ModelDataJsonConstants {
···
···
@RequestMapping("service")
public class ModelSaveRestResource implements ModelDataJsonConstants {
···
最后别忘了添加包扫描,扫描activiti提供的这些controller。
@SpringBootApplication
@ComponentScan({"org.activiti","com.jerryl"})
public class SpringBootWithActivitiApplication {
···
这样整合部分就基本结束了,此时编辑器已经可以使用了。
至于界面的汉化,界面上各个组件,各个标签上的文字都是在resource下的stencilset.json文件中设置的,可以在网上找一个汉化后的stencilset.json文件替换掉,就能看到中文界面了。
modeler相关方法的封装
 主要需要封装4个方法:1.新建一个空的模型;2.所有模型列表;3.发布模型;4.删除模型;(activiti已提供了保存和获取模型节点信息的方法,就是上面的那3个类)
 由于这里涉及前后端交互,实现方式随意,主要是activiti的api的调用。
参考代码:
/*** Created by liuruijie on 2017/2/21.* 模型管理*/
@RestController
@RequestMapping("models")
public class ModelerController {@AutowiredProcessEngine processEngine;@AutowiredObjectMapper objectMapper;/*** 新建一个空模型* @return* @throws UnsupportedEncodingException*/@PostMappingpublic Object newModel() throws UnsupportedEncodingException {RepositoryService repositoryService = processEngine.getRepositoryService();//初始化一个空模型Model model = repositoryService.newModel();//设置一些默认信息String name = "new-process";String description = "";int revision = 1;String key = "process";ObjectNode modelNode = objectMapper.createObjectNode();modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);model.setName(name);model.setKey(key);model.setMetaInfo(modelNode.toString());repositoryService.saveModel(model);String id = model.getId();//完善ModelEditorSourceObjectNode editorNode = objectMapper.createObjectNode();editorNode.put("id", "canvas");editorNode.put("resourceId", "canvas");ObjectNode stencilSetNode = objectMapper.createObjectNode();stencilSetNode.put("namespace","http://b3mn.org/stencilset/bpmn2.0#");editorNode.put("stencilset", stencilSetNode);repositoryService.addModelEditorSource(id,editorNode.toString().getBytes("utf-8"));return ToWeb.buildResult().redirectUrl("/modeler.html?modelId="+id);}/*** 获取所有模型* @return*/@GetMappingpublic Object modelList(){RepositoryService repositoryService = processEngine.getRepositoryService();List<Model> models = repositoryService.createModelQuery().list();return ToWeb.buildResult().putData("models", models);}/*** 删除模型* @param id* @return*/@DeleteMapping("{id}")public Object deleteModel(@PathVariable("id")String id){RepositoryService repositoryService = processEngine.getRepositoryService();repositoryService.deleteModel(id);return ToWeb.buildResult().refresh();}/*** 发布模型为流程定义* @param id* @return* @throws Exception*/@PostMapping("{id}/deployment")public Object deploy(@PathVariable("id")String id) throws Exception {//获取模型RepositoryService repositoryService = processEngine.getRepositoryService();Model modelData = repositoryService.getModel(id);byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());if (bytes == null) {return ToWeb.buildResult().status(Config.FAIL).msg("模型数据为空,请先设计流程并成功保存,再进行发布。");}JsonNode modelNode = new ObjectMapper().readTree(bytes);BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);if(model.getProcesses().size()==0){return ToWeb.buildResult().status(Config.FAIL).msg("数据模型不符要求,请至少设计一条主线流程。");}byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model);//发布流程String processName = modelData.getName() + ".bpmn20.xml";Deployment deployment = repositoryService.createDeployment().name(modelData.getName()).addString(processName, new String(bpmnBytes, "UTF-8")).deploy();modelData.setDeploymentId(deployment.getId());repositoryService.saveModel(modelData);return ToWeb.buildResult().refresh();}
}
springboot静态文件处理
@Configuration
public  class WebConfig implements WebMvcConfigurer {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry){registry.addResourceHandler("/html/**").addResourceLocations("classpath:/html/");registry.addResourceHandler("/diagram-viewer/**").addResourceLocations("classpath:/html/");registry.addResourceHandler("/editor-app/**").addResourceLocations("classpath:/html/");registry.addResourceHandler("/js/**").addResourceLocations("classpath:/js/");registry.addResourceHandler("/css/**").addResourceLocations("classpath:/css/");}
}获取json数据的请求
@RestController
public class Test01Controller {@RequestMapping("/editor/stencilset")public String test01(){InputStream stream=this.getClass().getClassLoader().getResourceAsStream("stencilset.json");try{return IOUtils.toString(stream,"utf-8");}catch (Exception e){}return null;}
}在线设计流程新建model
@Controller
@RequestMapping("model")
public class ModelTest {@RequestMapping("create")public void createModel(HttpServletRequest request, HttpServletResponse response){try{String modelName = "modelName6";String modelKey = "modelKey66";String description = "modelKey666";ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();RepositoryService repositoryService = processEngine.getRepositoryService();ObjectMapper objectMapper = new ObjectMapper();ObjectNode editorNode = objectMapper.createObjectNode();editorNode.put("id", "canvas");editorNode.put("resourceId", "canvas");ObjectNode stencilSetNode = objectMapper.createObjectNode();stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");editorNode.put("stencilset", stencilSetNode);Model modelData = repositoryService.newModel();ObjectNode modelObjectNode = objectMapper.createObjectNode();modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, modelName);modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);modelData.setMetaInfo(modelObjectNode.toString());modelData.setName(modelName);modelData.setKey(modelKey);//保存模型repositoryService.saveModel(modelData);repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8"));response.sendRedirect(request.getContextPath() + "/html/modeler.html?modelId=" + modelData.getId());}catch (Exception e){}}}画流程图保存请求
@RequestMapping("/model/{modelId}/save")@ResponseStatus(HttpStatus.OK)public void saveModel(@PathVariable String modelId, HttpServletRequest req, HttpServletResponse resp) {try {Model model = this.repositoryService.getModel(modelId);ObjectNode modelJson = (ObjectNode)this.objectMapper.readTree(model.getMetaInfo());modelJson.put("name", req.getParameter("name"));modelJson.put("description",req.getParameter("description"));model.setMetaInfo(modelJson.toString());model.setName(req.getParameter("name"));this.repositoryService.saveModel(model);this.repositoryService.addModelEditorSource(model.getId(), (req.getParameter("json_xml")).getBytes("utf-8"));InputStream svgStream = new ByteArrayInputStream((req.getParameter("svg_xml")).getBytes("utf-8"));TranscoderInput input = new TranscoderInput(svgStream);PNGTranscoder transcoder = new PNGTranscoder();ByteArrayOutputStream outStream = new ByteArrayOutputStream();TranscoderOutput output = new TranscoderOutput(outStream);transcoder.transcode(input, output);byte[] result = outStream.toByteArray();System.out.println(new String(result,"utf-8"));this.repositoryService.addModelEditorSourceExtra(model.getId(), result);outStream.close();} catch (Exception var11) {LOGGER.error("Error saving model", var11);throw new ActivitiException("Error saving model", var11);}}流程图查看的请求
@RequestMapping(value = {"/model/{modelId}/json"},method = {RequestMethod.GET},produces = {"application/json"})public ObjectNode getEditorJson(@PathVariable String modelId) {ObjectNode modelNode = null;Model model = this.repositoryService.getModel(modelId);if (model != null) {try {if (StringUtils.isNotEmpty(model.getMetaInfo())) {modelNode = (ObjectNode)this.objectMapper.readTree(model.getMetaInfo());} else {modelNode = this.objectMapper.createObjectNode();modelNode.put("name", model.getName());}modelNode.put("modelId", model.getId());ObjectNode editorJsonNode = (ObjectNode)this.objectMapper.readTree(new String(this.repositoryService.getModelEditorSource(model.getId()), "utf-8"));modelNode.put("model", editorJsonNode);} catch (Exception var5) {LOGGER.error("Error creating model JSON", var5);throw new ActivitiException("Error creating model JSON", var5);}}return modelNode;}
流程图保存成功以后ACT_RE_MODEL这张表会有数据

程图部署以后ACT_GE_BYTEARRAY会出现bomn结尾的文件
 
部署流程的请求,根据modelId
@RequestMapping("/model/test02")public void test02(Object obj) throws Exception {Model modelData = repositoryService.getModel("40001");ObjectNode modelNode = (ObjectNode) new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));byte[] bpmnBytes = null;BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);bpmnBytes = new BpmnXMLConverter().convertToXML(model);String processName = modelData.getName() + ".bpmn";Deployment deployment = repositoryService.createDeployment().name(modelData.getName()).addString(processName, new String(bpmnBytes,"UTF-8")).deploy();}根据这个表的key进行流程启动,指定审批人
 
相关文章:
 
集成Activiti-Modeler流程设计器
集成Activiti-Modeler流程设计器 Activiti Modeler 是 Activiti 官方提供的一款在线流程设计的前端插件,可以方便流程设计与开发人员绘制流程图,保存流程模型,部署至流程定义等等。 1、材料准备 首先我们需要获取activiti-explorer.zip&…...
 
【深度学习】 Python 和 NumPy 系列教程(十一):NumPy详解:3、数组数学(元素、数组、矩阵级别的各种运算)
目录 一、前言 二、实验环境 三、NumPy 0、多维数组对象(ndarray) 多维数组的属性 1、创建数组 2、数组操作 3、数组数学 1. 元素级别 a. 直接运算 b. 加法:np.add()函数 c. 减法:np.subtract()函数 d. 乘法…...
 
python难题切片处理
边距折叠 Html经常出现的一个外边距折叠,可能有人的不太理解,或者说不知道怎么解决、我们来着重来看下: 当两个div盒子模型连续出现的时候并且同时应用了一个margin外边距,会出现边距重叠的现象: .Div {width:150px; #定义公共的盒子样式 Height:150px; Margin:20p…...
 
《研发效能(DevOps)工程师(中级)认证》证书查询方式和路径丨IDCF
由国家工业和信息化部教育与考试中心颁发的职业技术证书,也是国内首个《研发效能(DevOps)工程师国家职业技术认证》,IDCF社区作为官方指定培训中心,邀请了多位业界知名专家讲师(部分专家讲师名单:王立杰、杜伟忠、陈老…...
 
NVR添加rtsp流模拟GB28181视频通道
一、海康、大华监控摄像头和硬盘录像机接入GB28181平台配置 1、海康设备接入配置 通过web登录NVR管理系统,进入网络,高级配置界面,填入GB28181相关参数。 将对应项按刚才获取的配置信息填入即可,下面的视频通道的编码ID可以保持…...
 
浅谈C++|文件篇
引子: 程序运行时产生的数据都属于临时数据,程序一旦运行结束都会被释放通过文件可以将数据持久化。C中对文件操作需要包含头文件< fstream > 。 C提供了丰富的文件操作功能,你可以使用标准库中的fstream库来进行文件的读取、写入和定位…...
 
C++ QT qml 学习之 做个登录界面
最近在学习QT,也初探到qml 做ui 的灵活性与强大,于是手痒痒,做个demo 记录下学习成果 主要内容是如何自己编写一个按钮以及qml多窗口。 参考WX桌面版,做一个登录界面,这里面按钮是写的一个组合控件,有 按…...
LLM 06-大模型架构
LLM 06-大模型架构 6.1 大模型之模型概括 语言模型的一开始就可以被看做是一个黑箱,当前大规模语言模型的能力在于给定一个基于自身需求的prompt就可以生成符合需求的结果。形式可以表达为: p r o m p t ⇝ c o m p l e t i o n prompt \leadsto compl…...
 
openGauss学习笔记-71 openGauss 数据库管理-创建和管理普通表-删除表中数据
文章目录 openGauss学习笔记-71 openGauss 数据库管理-创建和管理普通表-删除表中数据 openGauss学习笔记-71 openGauss 数据库管理-创建和管理普通表-删除表中数据 在使用表的过程中,可能会需要删除已过期的数据,删除数据必须从表中整行的删除。 SQL不…...
【k8s】kube-proxy 工作模式
文章目录 Userspace模式:iptables模式:负载均衡(Load Balancing) LB轮询(Round Robin):SessionAffinity:最少连接(Least Connection):IP哈希&…...
 
Linux:Centos9 《下载-安装》
下载 Download (centos.org)https://www.centos.org/download/ 安装 选择第一个安装centos 根据自己需要的语言环境选择即可 这里选择要安装的磁盘,然后点击完成 这里选择第一个就行带有图形化 然后我们去对这两个进行设置就行 这两个地方自己进行设置就行 耐心等…...
 
数字化管理平台建设实践
在勘察设计行业,各企业加速推进数字化转型。通过管理要素数字化,不断优化内部组织运营效率;通过生产手段数字化、技术产品数字化,提升服务质量,改善客户体验;通过数字化营销,精准对接市场需求&a…...
Linux命令(80)之sort
linux命令之sort 1.sort介绍 linux命令sort用于将文本文件内容以行为单位加以排序;sort命令默认按每行的第一个字符排序,根据首字母的ASCII码值进行升序(从小到大排列)。 sort的默认分隔符是空白(空格和tab),多少空白都算一个分隔符。 2.…...
[k8s] kubectl port-forward 和kubectl expose的区别
kubectl port-forward 和 kubectl expose 是 Kubernetes 命令行工具 kubectl 提供的两种不同方式来公开服务。 kubectl port-forward kubectl port-forward 命令用于在本地主机和集群内部的 Pod 之间建立一个临时的端口转发通道。 该命令将本地机器上的一个端口绑定到集群内部…...
 
vscode如何设置文件折叠
随着项目的不断迭代开发,复杂度越来越高,配置文件越来越多,导致vscode左侧文件列表展示非常不直观,幸好可以通过文件折叠来简化展示效果,把同类相关的文件折叠在一块展示,方便查看配置文件。配置好后的效果…...
 
Linux centos7 bash编程训练
训练编写一段代码,打印输出100之内的明7暗7,同时要求每5个数字打印在一行。 此项训练主要是考察for循环的使用,及条件判断表达式的设置和不同写法的应用。 常用的for循环有四种写法(如打印1-100的整数): …...
k8s集群换ip
1.把/etc/kubernetes/*.conf中所有的旧ip换成新ip cd /etc/kubernetes/ find . -type f | xargs sed -i "s/$oldip/$newip/"2.替换$HOME/.kube/config文件中的旧ip为新ip(注意sudo的话需要改root下的) cd $HOME/.kube/ find . -type f | xargs sed -i "s/$old…...
选择HAL库还是标准库
选择HAL库还是标准库呢?HAL库是趋势,标准库不再升级了,转HAL库是大势所趋。HAL库有优点,也有自身的不足,建议初学者还是从标准库入手。 标准库是单片机开发的基本库,它把“用寄存器实现的功能”写成一个函…...
 
计算机竞赛 机器视觉的试卷批改系统 - opencv python 视觉识别
文章目录 0 简介1 项目背景2 项目目的3 系统设计3.1 目标对象3.2 系统架构3.3 软件设计方案 4 图像预处理4.1 灰度二值化4.2 形态学处理4.3 算式提取4.4 倾斜校正4.5 字符分割 5 字符识别5.1 支持向量机原理5.2 基于SVM的字符识别5.3 SVM算法实现 6 算法测试7 系统实现8 最后 0…...
 
Mapbox gl HTML经纬度点渲染,动态轨迹播放,自定义图形以及轨迹上显示箭头方向
Mapbox gl HTML经纬度点渲染,动态轨迹播放,自定义图形以及轨迹上显示箭头方向 1. 效果图2. 源码2.1 line.html2.2line_arrow.html 参考 今天要排查个问题,需要显示多个经纬度点连接成线段的方向,于是尝试下展示。 1. mapbox渲染经…...
 
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
 
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
 
第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
 
九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...
学习一下用鸿蒙DevEco Studio HarmonyOS5实现百度地图
在鸿蒙(HarmonyOS5)中集成百度地图,可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API,可以构建跨设备的定位、导航和地图展示功能。 1. 鸿蒙环境准备 开发工具:下载安装 De…...
