【弄nèng - Activiti6】Springboot搭建Activiti整合流程设计器
文章目录
开发工具使用IDE,基于Springboot项目搭建
Activiti整合流程设计器是5.22版本包内的工具,6.0以上没有。不过使用无异,直接用它就行了。它可以是我们快速构建Activiti流程图,方便使用,便于管理。
本文不止整合Activiti流程设计器,也包含Springboot整合Activiti
1. 引入依赖
pom.xml
这里只列出核心pom,像数据库,springboot等其他依赖自己添加
<!-- activiti -->
<properties>
<activiti.version>6.0.0</activiti.version>
</properties>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>${activiti.version}</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>${activiti.version}</version>
</dependency>
2. Activiti配置
# activiti配置
activiti:
# true 代表没有表就自动创建
database-schema-update: true
# 记录级别,默认audit
history-level: full
# (可选)自动部署验证设置:true-开启(默认)、false-关闭
check-process-definitions: false
# (可选)默认流程定义文件存放目录
process-definition-location-prefix: classpath:/processes/
3. 整合流程设计器
3.1下载流程设计器
activiti-5.22.0下载地址
链接:https://pan.baidu.com/s/1FEznQtYvTx-qiAB7_MUoJQ
提取码:a56t
下载官方activiti-5.22.0的包,解压wars下面的activiti-explorer.war,把diagram-viewer、editor-app、modeler.html复制到Springboot项目的static目录下,这个是activiti的在线设计器,modeler.html是主界面。
3.2 汉化
stencilset.json下载地址
链接:https://pan.baidu.com/s/15koYuOoV42PIHQeB4RsHbw
提取码:qnxd
下载stencilset.json,放在Springboot项目的static目录下
3.3 修改配置
在editor-app/app-cfg.js中contextRoot是编辑器的后台服务的url,去掉activiti-explorer
改成
4.流程设计器后端服务
- StencilsetRestResource 获取编辑器组件及配置项信息。
- ModelEditorJsonRestResource 根据modelId获取model的节点信息,编辑器根据返回的json进行绘图。
- ModelSaveRestResource 编辑器制图之后,将节点信息以json的形式提交给这个Controller,然后由其进行持久化操作。
将以下ActManageController.java类复制你的项目
@RequestMapping("/service") 是跟editor-app/app-cfg.js中contextRoot对应的
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.it.cloud.common.xss.XssHttpServletRequestWrapper;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
* @author 司马缸砸缸了
* @date 2019/8/23 15:40
* @description activiti editor管理类
*/
@RestController
@RequestMapping("/service")
public class ActManageController {
@Autowired
ObjectMapper objectMapper;
@Autowired
private RepositoryService repositoryService;
/**
* stencilset:获取编辑器组件及配置项信息
*
* @return stencilset.json
*/
@RequestMapping("/editor/stencilset")
public String getStencilset() {
InputStream stencilsetStream = this.getClass().getResourceAsStream("/static/stencilset.json");
try {
return IOUtils.toString(stencilsetStream, "utf-8");
} catch (Exception e) {
throw new ActivitiException("Error while loading stencil set", e);
}
}
/**
* 模型详情
*
* @param modelId
* @return
*/
@RequestMapping("/model/{modelId}/json")
public ObjectNode getEditorJson(@PathVariable String modelId) {
ObjectNode modelNode = null;
Model model = repositoryService.getModel(modelId);
if (model != null) {
try {
if (StringUtils.isNotEmpty(model.getMetaInfo())) {
modelNode = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
} else {
modelNode = objectMapper.createObjectNode();
modelNode.put("name", model.getName());
}
modelNode.put("modelId", model.getId());
ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(
new String(repositoryService.getModelEditorSource(model.getId()), "utf-8"));
modelNode.set("model", editorJsonNode);
} catch (Exception e) {
throw new ActivitiException("Error creating model JSON", e);
}
}
return modelNode;
}
/**
* 保存
*
* @param modelId
* @param name
* @param jsonXml
* @param svgXml
* @param description
*/
@RequestMapping("/model/{modelId}/save")
@RequiresPermissions("act:manage:save")
public void saveModel(@PathVariable String modelId, @RequestParam("name") String name,
@RequestParam("json_xml") String jsonXml, @RequestParam("svg_xml") String svgXml,
@RequestParam("description") String description, HttpServletRequest request) {
HttpServletRequest orgRequest = XssHttpServletRequestWrapper.getOrgRequest(request);
try {
// 因为添加了html过滤,直接通过参数得不到html符号(XssFilter)
svgXml = orgRequest.getParameterMap().get("svg_xml")[0];
Model model = repositoryService.getModel(modelId);
ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
modelJson.put("name", name);
modelJson.put("description", description);
model.setMetaInfo(modelJson.toString());
model.setName(name);
repositoryService.saveModel(model);
repositoryService.addModelEditorSource(model.getId(), jsonXml.getBytes(StandardCharsets.UTF_8));
InputStream svgStream = new ByteArrayInputStream(svgXml.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);
}
}
}
5. Activiti乱码配置
ActivitiConfig.java
import org.activiti.engine.*;
import org.activiti.spring.SpringProcessEngineConfiguration;
import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.io.IOException;
/**
* 工作流配置
*
* @author 司马缸砸缸了
*/
@Component
public class ActivitiConfig implements ProcessEngineConfigurationConfigurer {
/**
* 解決工作流生成图片乱码问题
*
* @param processEngineConfiguration processEngineConfiguration
*/
@Override
public void configure(SpringProcessEngineConfiguration processEngineConfiguration) {
processEngineConfiguration.setActivityFontName("宋体");
processEngineConfiguration.setAnnotationFontName("宋体");
processEngineConfiguration.setLabelFontName("宋体");
}
}
6.启动类
排除SecurityAutoConfiguration,不然启动会报错
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
7.测试
需要数据库中已经存在model记录,才可以看到效果,只要替换modelId就可以了。
访问 http:localhost:8080/modeler.html?modelId=25001
以上代码我已经整合到IT-CLOUD项目中
代码地址
IT-CLOUD :IT服务管理平台,集成基础服务,中间件服务,监控告警服务等
开源项目,持续更新中,喜欢请 Star~