前言
最近公司让接收一个审批相关的项目,于是想到就用activiti工作流来处理,下面着重介绍一下activiti6.0整合springboot,以及一些常用的activiti java api的使用,比较实用,都是能够直接拷贝开干的方法。
首先,建议看一下actitivi官网上,有个基础的了解。
先说一下实现的效果,要做到能够通过官网提供的流程图demo设置修改流程,然后发布。然后后台通过各种操作去玩儿流程。
1.整合springboot
好了,开始整合springboot。
1.1pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ht</groupId>
<artifactId>activiti_springboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>activiti_springboot</name>
<description>activiti-springboot</description>
<properties>
<java.version>1.8</java.version>
<activiti.version>6.0.0</activiti.version>
<activiti-modeler.version>5.23.0</activiti-modeler.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.193</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
<!-- activiti begin -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.41</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-transcoder</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-codec</artifactId>
<version>1.9</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.9.RELEASE</version>
</plugin>
</plugins>
</build>
</project>
1.2前端画图工具整合
首先需要下载activiti-explorer.war(这个war包是官方给的demo)。这里后面我会给出源码,源码里面也有。
上图就是,我们在activiti-explorer.war包中需要的东西,stencilset.json是汉化包。
需要修改app-cfg.js,这里是为了让画图工具调用你自己的controller。
1.3基础方法支持
修改好后,需要重写一些基础的方法来支持流程图的编辑和保存,ModelEditorJsonRestResource类中的getEditorJson方法根据modelId来支持获取流程图的json串。
@RestController
@RequestMapping("service")
public class ModelEditorJsonRestResource implements ModelDataJsonConstants {
protected static final Logger LOGGER = LoggerFactory.getLogger(ModelEditorJsonRestResource.class);
@Resource
private RepositoryService repositoryService;
@Autowired
private ObjectMapper objectMapper;
@RequestMapping(value="/model/{modelId}/json", method = RequestMethod.GET, produces = "application/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(MODEL_NAME, model.getName());
}
modelNode.put(MODEL_ID, model.getId());
ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(
new String(repositoryService.getModelEditorSource(model.getId()), "utf-8"));
modelNode.put("model", editorJsonNode);
} catch (Exception e) {
LOGGER.error("Error creating model JSON", e);
throw new ActivitiException("Error creating model JSON", e);
}
}
return modelNode;
}
}
ModelSaveRestResource类中的save方法用于保存编辑流程图
@RestController
@RequestMapping("service")
public class ModelSaveRestResource implements ModelDataJsonConstants {
protected static final Logger LOGGER = LoggerFactory.getLogger(ModelSaveRestResource.class);
@Resource
private RepositoryService repositoryService;
@Autowired
private ObjectMapper objectMapper;
@RequestMapping(value = "/model/{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("utf-8"));
InputStream svgStream = new ByteArrayInputStream(svg_xml.getBytes("utf-8"));
TranscoderInput input = new TranscoderInput(svgStream);
PNGTranscoder transcoder = new PNGTranscoder();
// Setup output
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
TranscoderOutput output = new TranscoderOutput(outStream);
// Do the transformation
transcoder.transcode(input, output);
final byte[] result = outStream.toByteArray();
repositoryService.addModelEditorSourceExtra(model.getId(), result);
outStream.close();
} catch (Exception e) {
LOGGER.error("Error saving model", e);
throw new ActivitiException("Error saving model", e);
}
}
}
还需要一个StencilsetRestResource类的stencilset方法,这些方法都可以在集成好的画图工具页面f12看到,都是一些必须的方法。
@RestController
@RequestMapping("service")
public class StencilsetRestResource {
@RequestMapping(value = "/editor/stencilset", method = RequestMethod.GET, produces = "application/json;charset=utf-8")
@ResponseBody
public String getStencilset() {
InputStream stencilsetStream = this.getClass().getClassLoader().getResourceAsStream("stencilset.json");
try {
return IOUtils.toString(stencilsetStream, "utf-8");
} catch (Exception e) {
throw new ActivitiException("Error while loading stencil set", e);
}
}
}
1.4 yml文件
server:
port: 9999
spring:
application:
name: activiti-springboot
datasource:
url: xxx
username: xxx
password: xxx
driver-class-name: com.mysql.jdbc.Driver
activiti:
database-schema-update: true
# 自动部署验证设置:true-开启(默认)、false-关闭
check-process-definitions: false
thymeleaf:
mode: LEGACYHTML5
cache: false
logging:
level:
org.activiti.engine.impl.persistence.entity: debug
2.初始化流程
2.1 创建流程
通过单元测试创建一个流程,得到流程的modelId
@Test
public void createModel() throws UnsupportedEncodingException {
Model model = repositoryService.newModel();
//设置默认流程名称
String name = "TEST";
String description = "";
int revision = 1;
//设置key
String key = "TEST-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();
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);
repositoryService.addModelEditorSource(id, editorNode.toString().getBytes("utf-8"));
//得到modelid
System.out.println(id);
}
如果是第一次集成,运行项目之后,activiti对应的表会自动创建,很方便。流程创建成功后,可以看到对应的表与对应的记录已经生成,我这里modeId为1.
2.2 editor controller
建立一个editor controller用于访问画图工具的页面
@Controller
public class ModelerController {
@GetMapping("editor")
public String editor() {
return "/modeler";
}
}
2.3 启动项目访问页面
启动项目后访问页面http://localhost:9999/editor?modelId=1,这里modelId就是上面单元测试产生的modelId,可以如果可以看到画图的页面并且左侧事件以及顶部工具栏,那么就成功了。
初次访问该流程右边的为空白,这个流程图是我自己画的。
2.4 保存流程图
如果是第一次接触activiti的小伙伴们肯定看到左侧的一系列的事件列表等等可能比较懵。我第一次看也是完全处于懵逼状态,这里建议可以去看一下https://docs.awspaas.com/reference-guide/aws-paas-process-reference-guide/appendix/process_model_version_control.html这个网址,里面有对BPMN2的详细讲解,看完会有一个不错的理解。
好了,现在可以来画属于自己的流程图啦!一顿操作之后,点击左上角保存按钮,会弹出一个保存模型框,点击保存就可以了。刷新页面可以看到流程已经保存成功。
好了,写到这里,我项目目前也只搭建了这么一点,activiti与springboot的初步整合就已经完成了。
这只是第一步,后续我会再发一篇对activiti流程详细操作教程。都是工作上能够用到,自己摸索加上google的。也会基于上面我画的那个流程图对各种activiti的java api做个讲解,会涉及到基础的操作,以及退回等等稍微复杂一些的操作,基本上能够覆盖公司开发的需求。
详细的一些对于activiti的操作我写了另外一篇文章,也给出了源码,有兴趣的可以看看https://blog.csdn.net/a771664696/article/details/118358296