乐趣区

SpringBoot-Activiti6系列教程四流程部署

说明

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

部署的时候指定部署的 namekey,方便后续对部署进行进一步操作。

声明 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

退出移动版