一、环境springboot2.6.4 activiti6.0.0 vue2.x
二、后台
- pom.xml
-
<!– activiti工作流引擎 –>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-model</artifactId>
<version>7.1.0.M6</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>7.1.0.M6</version>
</dependency><!– 配合activiti流工具 –>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-codec</artifactId>
<version>1.14</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-css</artifactId>
<version>1.14</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-svg-dom</artifactId>
<version>1.14</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-svggen</artifactId>
<version>1.14</version>
</dependency><!– IO 工具类 –>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons.io.version}</version>
</dependency> -
- 配置文件
-
activiti:
# 1.false:默认值。activiti在启动时,对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常
# 2.true: activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建
# 3.create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)
# 4.drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)
database-schema-update: true
# 启动是否检查流程图
check-process-definitions: false
# 默认
historyLevel: audit
# 记录历史等级 可配置的历史级别有none, activity, audit, full
# none:不保存任何的历史数据,因此,在流程执行过程中,这是最高效的。
# activity:级别高于none,保存流程实例与流程行为,其他数据不保存。
# audit:除activity级别会保存的数据外,还会保存全部的流程任务及其属性。audit为history的默认值。
# full:保存历史数据的最高级别,除了会保存audit级别的数据外,还会保存其他全部流程相关的细节数据,包括一些流程参数等。
# historyLevel: full
# 默认关闭的,不生成历史记录
db-history-used: true
- controller
-
/**
* 流程工具列表
*
* @return {@link String}
*/
@ResponseBody
@GetMapping(value = “stencilset”, produces = “application/json;charset=utf-8”)
public String stencilset() {
InputStream stream = this.getClass().getClassLoader().getResourceAsStream(“static/stencilset.json”);
try {
return IOUtils.toString(stream, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new ActivitiException(“Error while loading stencil set”, e);
}
}/**
* 根据 modelId 获取流程模型
*
* @param modelId 模型ID
* @return {@link ObjectNode}
*/
@RequestMapping(value = “/{modelId}/json”, method = RequestMethod.GET, produces = “application/json”)
@ResponseBody
public Object getEditorJson(@PathVariable String modelId) {
ObjectNode modelNode = null;
Model model = repositoryService.getModel(modelId);
if (model != null) {
try {
if (org.apache.commons.lang3.StringUtils.isNotEmpty(model.getMetaInfo())) {
modelNode = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
} else {
modelNode = objectMapper.createObjectNode();
modelNode.put(MODEL_NAME, model.getName());
}
modelNode.put(MODEL_ID, model.getId());
ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(
new String(repositoryService.getModelEditorSource(model.getId()), StandardCharsets.UTF_8));
modelNode.replace(“model”, editorJsonNode);
} catch (Exception e) {
throw new ActivitiException(“Error creating model JSON”, e);
}
}
return JSONObject.parse(modelNode.toString());
}/**
* 保存流程模型
*
* @param modelId 模型ID
* @param name 流程模型名称
* @param description 流程描述
* @param json_xml 流程文件
* @param svg_xml 流程图片
*/
@RequestMapping(value = “/{modelId}/save”, method = RequestMethod.PUT)
@ResponseStatus(value = HttpStatus.OK)
public void saveModel(@PathVariable String modelId, String name, String description, String json_xml, String svg_xml) {
try {
Model model = repositoryService.getModel(modelId);
ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
modelJson.put(MODEL_NAME, name);
modelJson.put(MODEL_DESCRIPTION, description);
model.setMetaInfo(modelJson.toString());
model.setName(name);
repositoryService.saveModel(model);
repositoryService.addModelEditorSource(model.getId(), json_xml.getBytes(StandardCharsets.UTF_8));InputStream svgStream = new ByteArrayInputStream(svg_xml.getBytes(StandardCharsets.UTF_8));
TranscoderInput input = new TranscoderInput(svgStream);
PNGTranscoder transcoder = new PNGTranscoder();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
TranscoderOutput output = new TranscoderOutput(outStream);transcoder.transcode(input, output);
final byte[] result = outStream.toByteArray();
repositoryService.addModelEditorSourceExtra(model.getId(), result);
outStream.close();
} catch (Exception e) {
throw new ActivitiException(“Error saving model”, e);
}
} -
三、前端图形化设计器
- 需准备内容
- 官网下载内容(有的可能带图标,有的最外层的html可能不叫这个名字,都一样,只要其
- 中是引入了一大堆js的那个就是):
及汉化包:
前端设计器文件放入public/static下:
汉化包放入后台静态资源位置
-
- 准备新的vue页面
-
<template>
<div>
<iframe :src=”src” frameborder=”0″></iframe>
</div>
</template>
<script>
import Vue from ‘vue’
import { ACCESS_TOKEN } from ‘@/store/mutation-types’
export default {
data () {
return {
modelId: ”,
iframeUrl: ”
}
},
computed: {
src () {
// 设计器最外部主入口html
return ‘./static/editor.html?modelId=’ + this.modelId
},
apiUrl () {
// 后台部署的api服务
return process.env.VUE_APP_API_BASE_URL + ‘/pc/process’
},
token () {
// token
return Vue.ls.get(ACCESS_TOKEN)
}
},
mounted () {
window.getMyVue = this // 全局存入当前vue实例,供activiti调用
this.modelId = this.$route.params.processModelCode
}
}
</script>
<style lang=”less” scoped>
iframe {
width: 100%;
min-height: calc(100vh – 80px);
}
</style> -
- 设计器主入口editor.html文件加入如下代码
-
<script>
(
function(open){
XMLHttpRequest.prototype.open = function(method,url,async,user,pass){
// this指XMLHttpRequest
open.call(this,method,url,async,user,pass);
// mounted时传入的token
this.setRequestHeader(“token”,window.parent.getMyVue.token);
}
}
)(XMLHttpRequest.prototype.open)
</script> -
- 设计器文件/editor-app/app-cfg.js修改为(主要修改调用后台方法的地址)
-
var ACTIVITI = ACTIVITI || {}
ACTIVITI.CONFIG = {
contextRoot: (function () {
return window.parent.getMyVue.apiUrl// 上一步将vue实例传入的父窗口
})()
} -
完成前后台的基本集成
四、踩坑问题
- namespace问题
发生TypeError: Cannot read properties of undefined (reading ‘namespace’)问题加入后台getEditorJson方法调整输出类型为JSON,如下
/**
* 根据 modelId 获取流程模型
*
* @param modelId 模型ID
* @return {@link ObjectNode}
*/
@RequestMapping(value = “/{modelId}/json”, method = RequestMethod.GET, produces = “application/json”)
@ResponseBody
public Object getEditorJson(@PathVariable String modelId) {
ObjectNode modelNode = null;
Model model = repositoryService.getModel(modelId);
if (model != null) {
try {
if (org.apache.commons.lang3.StringUtils.isNotEmpty(model.getMetaInfo())) {
modelNode = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
} else {
modelNode = objectMapper.createObjectNode();
modelNode.put(MODEL_NAME, model.getName());
}
modelNode.put(MODEL_ID, model.getId());
ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(
new String(repositoryService.getModelEditorSource(model.getId()), StandardCharsets.UTF_8));
modelNode.replace(“model”, editorJsonNode);
} catch (Exception e) {
throw new ActivitiException(“Error creating model JSON”, e);
}
}
return JSON.parse(modelNode.toString());
}split问题
由于上面调整了JSON输出,所以转码时出现问题,如下解决
转载:发生TypeError: Cannot read property ‘split’ of undefined问题解决方案(这个博主的activiti版本为5.x,可能跟6.x的行数不一样,不过文件里搜一下就可以了).
Refused to get unsafe header “X-JSON”不影响开发五、js
- 访问后台接口文件
editor-app/configuration/url-config.js
结果图
-
转自:https://blog.csdn.net/qq_36268025/article/details/123651903
- 需准备内容