Flowable租户相关
2022-02-26
租户问题
问题描述:
由于目前项目采用多租户方式和指定 流程编号 方式组合启动流程,但是发现 flowable 未提供对应方式,那么该如何解决呢?
源代码截图
解决方案
仔细查看 runtimeService 发现提供了 构造器启动方式,因此可以采用该方法 启动流程
启动方式可以改成如下:
Authentication.setAuthenticatedUserId(String.valueOf(applyAddReqDTO.getStartUserId()));
/* 以Builder 方式启动流程,解决 无 租户 和 Id 的启动方式 使用租户的前提时,部署时 也需要设置 租户编号! */
ProcessInstance processInstance = runtimeService.createProcessInstanceBuilder()
.tenantId(applyAddReqDTO.getTenantId())
.processDefinitionId(processInfo.getDefinitionId())
.variables(businessDataMap)
.start();
/* 防止多线程的时候出问题 */
Authentication.setAuthenticatedUserId(null);
123456789
查看结果
聪明的你是否以为 使用构造器启动,并设置租户编号即可呢?
注意这里有个BUG,必须部署时 也设置 租户编号 才能发起流程时 也设置租户编号!
以下为手动部署的代码:
1234
Deployment deployment = null;
try {
deployment = repositoryService.createDeployment()
.name(processDTO.getProcessName())
.key(processPublishDTO.getProcessKey())
.tenantId(processPublishDTO.getTenantId())
.addBytes(processPublishDTO.getProcessKey() + ".bpmn20.xml", processPublishDTO.getProcessXml().getBytes("UTF-8"))
.deploy();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return Result.responseError(new EntityError(EntityError.SYSTEM_ERROR.getCode(), e.getMessage()));
}
1234567891011121314
dataObject多租户
在 Flowable 流程图的绘制过程中,我们可以编写一个名为 dataObject 的元素,这个元素可以指定变量的 id、名称以及数据类型等各种属性,并且在流程实例启动的时候,会自动将 dataObject 元素的信息转换为流程实例变量.
1. 添加 dataObject
首先我们来看下,在流程绘制的过程中,如何去添加 dataObject 对象。
IDEA 上的 Flowable 流程图绘制插件中还不能添加 dataObject 属性,这个需要我们去 flowable-ui 中去添加。
我们来随便绘制一个如下这样简单的流程图:
现在就想给这个流程图,添加 dataObject 属性,方式如下:
首先打开流程图,不要选择任何节点,在下方可以找到数据对象属性,如下图:
点击之后,就可以添加 dataObject 了,如下:
配置完成之后,点击保存按钮。然后我们下载这个流程图,下载之后,打开,我们会发现这次的 XMl 节点比之前的 XML 节点多出来了如下一些内容:
<dataObject id="name" name="流程绘制人" itemSubjectRef="xsd:string">
<extensionElements>
<flowable:value>javaboy</flowable:value>
</extensionElements>
</dataObject>
<dataObject id="site" name="流程作者网站" itemSubjectRef="xsd:string">
<extensionElements>
<flowable:value>www.javaboy.org</flowable:value>
</extensionElements>
</dataObject>
<dataObject id="date" name="流程绘制时间" itemSubjectRef="xsd:datetime">
<extensionElements>
<flowable:value>2022-09-23T00:00:00</flowable:value>
</extensionElements>
</dataObject>
2. 查询 dataObject
接下来,按照之前文章介绍的方式,我们先来部署并启动这个流程图。
当流程部署成功之后,我们可以在 ACT_RU_VARIABLE
表中查看到 dataObject 中的数据,如下图:
可以看到,dataObject 的数据是和执行实例 ID 以及流程实例 ID 相关的。
接下来,我们可以通过如下方式来查询 ACT_RU_VARIABLE
表中的数据:
@Test
void test08() {
List<Execution> list = runtimeService.createExecutionQuery().list();
for (Execution execution : list) {
DataObject data = runtimeService.getDataObject(execution.getId(), "流程绘制人");
logger.info("key:{},name:{},value:{}",data.getDataObjectDefinitionKey(),data.getName(),data.getValue());
}
}
这里打印出来的信息就是我们刚刚在定义的时候配置的所有流程信息了。
我们来看看这里查询的表:
可以看到,这里先去 ACT_RU_EXECUTION
表中查询执行实例 ID,然后再根据拿到的执行实例 ID 去 ACT_RU_VARIABLE
表中查询 dataObject 信息。
这就是 dataObject 的使用,其实非常 Easy!dataObject 平时主要可以用来定义一些全局的属性。
3. 租户
说到这里,就顺便再来和小伙伴们聊一聊 Flowable 中的租户。
租户这个其实好理解,举个栗子:
假设我们现在有 A、B、C、D 四个子系统,四个子系统都要部署同一个名为 leave 的流程,如何区分四个不同子系统的的流程呢?通过租户可以解决这个问题。
Flowable 中的租户其实很好理解,其实就是在流程中,多一个一个 TenantID 加以区分每一个流程属于哪个租户。
我举个简单的例子,假设我现在想要根据不同的子系统来部署流程,那么我可以按照如下方式来设计接口:
@RestController
public class ProcessDeployController {
@Autowired
RepositoryService repositoryService;
@PostMapping("/deploy")
public RespBean deploy(MultipartFile file,String tenantId) throws IOException {
DeploymentBuilder deploymentBuilder = repositoryService.createDeployment()
.category("javaboy的工作流分类")
.name("javaboy的工作流名称")
.addInputStream("fff.bpmn", file.getInputStream())
.tenantId(tenantId)
.key("javaboy的工作流key666");
Deployment deployment = deploymentBuilder
.deploy();
return RespBean.ok("部署成功",deployment.getId());
}
}
接下来我们通过 POSTMAN 来发送一个 POST 请求,提交流程图和租户 ID 这两个参数,如下图:
小伙伴们注意,我这里提交了两个参数,一个是流程图本身,还有一个是租户 ID。
当这个流程图部署成功之后,我们在流程定义表 ACT_RE_PROCDEF
中可以看到刚刚设置的租户 ID:
接下来我们需要启动流程实例的时候,就不能单纯拿着流程部署的 ID 去启动了,还得拿上流程的租户 ID。如果只拿流程本身的信息去启动,会抛出如下异常:
正确的启动方式如下:
@Test
void test09() {
identityService.setAuthenticatedUserId("wangwu");
ProcessInstance pi = runtimeService.startProcessInstanceByKeyAndTenantId("leave","A");
logger.info("id:{},activityId:{}", pi.getId(), pi.getActivityId());
}
在后续的 Task 查询中,我们也可以根据具体的租户 ID 来查询,这个就看具体情况了。