说明
在上一章节中,介绍了如何基于bpmn2.0的xml文件发起流程和获取待办,其中流程文件和代码打包在一起,但实际项目中很少会把流程文件和代码一起打包部署,这样的话,每次流程更新或者发布新流程都需要重新部署应用,因此我们制定了以下部署方案:
- 提供流程部署接口,可以通过上传流程文件对流程进行部署。
- 如果流程文件没有发生变化,不做新的部署,防止因为重新部署导致版本号上升。
资源部署
activit部署资源文件需要通过RepositoryService
创建一个deployment
,通过该deployment进行资源的部署,不单单是bpmn流程文件,activiti可以部署任何文件。
上传资源到activiti
@Service
public class DeploymentService {
@Autowired
private RepositoryService repositoryService;
/**
* deploy resource
*
* @param name resource name
* @param fin resource inputstream
* @return
*/
public String deploy(String name, InputStream fin) {
String deploymentId = repositoryService.createDeployment()
.addInputStream(name, fin)
.name(name)
.key(name)
.deploy()
.getId();
return deploymentId;
}
}
部署的时候指定部署的name
和key
,方便后续对部署进行进一步操作。
声明restController
@RestController
public class DeploymentController {
@Autowired
private DeploymentService service;
@PostMapping(value = "/deploy")
public String deploy(@RequestParam("file") MultipartFile file) {
try {
return service.deploy(file.getOriginalFilename(), file.getInputStream());
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("upload failed");
}
}
}
这里以文件名作为部署的名称,可以根据实际情况指定名称。
测试(可以通过postman进行测试,这里使用curl工具进行上传测试)
curl -X POST -F 'file=@WechatIMG1.jpeg' http://localhost:8080/deploy
25001
返回的25001就是部署id。
当执行deploy
操作时,activiti后台做了以下事
- 在表
ACT_RE_DEPLOYMENT
创建一条记录 - 将资源存储至表
ACT_GE_BYTEARRAY
,字段BYTES_
存储文件内容
流程部署
流程部署和资源部署一样,但有一点需要注意,部署流程时,资源的名称必须以bpmn20.xml
或者bpmn
结尾,否则activiti会当作普通资源上传,你可以在controller上加个判断避免用户上错错误文件。
@PostMapping(value = "/deployBpmn")
public String deployBpmn(@RequestParam("file") MultipartFile file) {
try {
String name = file.getOriginalFilename();
if (!name.endsWith(".bpmn20.xm") && !name.endsWith(".bpmn")) {
name = name + ".bpmn";
}
return service.deploy(name, file.getInputStream());
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("upload failed");
}
}
当部署流程后,activit后台除了执行部署资源的动作外,还额外执行以下动作
- 在表
ACT_RE_PROCDEF
上创建一条记录,引用deployment_id
。
流程部署优化
以上我们实现了流程的部署,但每次部署都会导致流程版本递增,我们的方案是如果文件不发生变化则不执行部署操作,保持流程版本好不变,不至于让版本号升的太快,也节省系统资源。那么我们需要完成以下两个逻辑
- 根据key查询到最新的一次部署
- 获取最新的一次流程源文件
- 因为xml是文本文件,我们可以进行文本比对,如果内容一致就认为版本不变
代码如下:
/**
* deploy resource
*
* @param name resource name
* @param fin resource inputstream
* @return
*/
public String noChangeNoDeploy(String name, InputStream fin) {
//获取最新的一次部署
Deployment latestDeployment = repositoryService.createDeploymentQuery()
.deploymentName(name)
.deploymentKey(name)
.latest()
.singleResult();
String sbpmn = ActivitiUtil.text(fin);
if (latestDeployment != null) {
//检测是否内容发生变化,只重新部署有修改的流程
InputStream input = repositoryService.getResourceAsStream(latestDeployment.getId(), name);
String dbpmn = ActivitiUtil.text(input);
if (sbpmn.length() == dbpmn.length() && sbpmn.equals(dbpmn)) {
return latestDeployment.getId();
}
}
String deploymentId = repositoryService.createDeployment()
.addString(name, sbpmn)
.name(name)
.key(name)
.deploy()
.getId();
return deploymentId;
}
测试:
curl -X POST -F 'file=@ComplexDemo.bpmn20.xml' http://localhost:8080/deployBpmn
27501 curl -X POST -F 'file=@ComplexDemo.bpmn20.xml' http://localhost:8080/deployBpmn
27501
可以看到,如果两次内容一样deployid不会改变
其他
除了通过addInputStream
增加资源文件外,RepositoryService
还提供了其他api进行资源的添加。如下
DeploymentBuilder addInputStream(String resourceName, InputStream inputStream);
DeploymentBuilder addClasspathResource(String resource);
DeploymentBuilder addString(String resourceName, String text);
DeploymentBuilder addBytes(String resourceName, byte[] bytes);
DeploymentBuilder addZipInputStream(ZipInputStream zipInputStream);
DeploymentBuilder addBpmnModel(String resourceName, BpmnModel bpmnModel);
本文所有代码已经上传至github,仓库地址为
https://github.com/wls1036/springboot-activiti6-tutorial欢迎star