说明
在上一章节中,介绍了如何基于 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