最近公司让接收一个审批相关的项目,于是想到就用activiti工作流来处理,下面着重介绍一下activiti6.0整合springboot,以及一些常用的activiti java api的使用,比较实用,都是能够直接拷贝开干的方法。
首先,建议看一下actitivi官网上,有个基础的了解。
先说一下实现的效果,要做到能够通过官网提供的流程图demo设置修改流程,然后发布。然后后台通过各种操作去玩儿流程。
好了,开始整合springboot。
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.3.9.RELEASE
com.ht
activiti_springboot
0.0.1-SNAPSHOT
activiti_springboot
activiti-springboot
1.8
6.0.0
5.23.0
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.slf4j
slf4j-api
1.7.21
org.slf4j
slf4j-log4j12
1.7.21
com.h2database
h2
1.4.193
org.springframework.boot
spring-boot-starter-thymeleaf
org.projectlombok
lombok
1.18.20
provided
org.activiti
activiti-spring-boot-starter-basic
${activiti.version}
org.activiti
activiti-json-converter
${activiti.version}
mysql
mysql-connector-java
5.1.41
commons-io
commons-io
2.10.0
org.apache.xmlgraphics
batik-transcoder
1.10
org.apache.xmlgraphics
batik-codec
1.9
org.springframework.boot
spring-boot-maven-plugin
2.3.9.RELEASE
首先需要下载activiti-explorer.war(这个war包是官方给的demo)。这里后面我会给出源码,源码里面也有。
上图就是,我们在activiti-explorer.war包中需要的东西,stencilset.json是汉化包。
需要修改app-cfg.js,这里是为了让画图工具调用你自己的controller。
修改好后,需要重写一些基础的方法来支持流程图的编辑和保存,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);
}
}
}
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
通过单元测试创建一个流程,得到流程的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.
建立一个editor controller用于访问画图工具的页面
@Controller
public class ModelerController {
@GetMapping("editor")
public String editor() {
return "/modeler";
}
}
启动项目后访问页面http://localhost:9999/editor?modelId=1,这里modelId就是上面单元测试产生的modelId,可以如果可以看到画图的页面并且左侧事件以及顶部工具栏,那么就成功了。
初次访问该流程右边的为空白,这个流程图是我自己画的。
如果是第一次接触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