本文正在参与「金石计划 . 瓜分6万现金大奖」
前语
最近项目有用到Activiti工作流,可是需求有点特别,需求经过参数去生成BPMN图,查阅了资料后,能完成简略的工作流生成,那接下来看看如何经过代码动态生成工作流的吧。
一.规划思路
1.以一般的请假流程为例 (1)生成开端节点加第1个使命和调整请求使命(回绝或者退回操作)以及其排他网关
(2)循环批阅列表,生成第2至第N-1个使命,并每个使命后都有1个排他网关,用于连接调整请求使命
(3)最后1个节点,后面无排他使命,故需求独自处理
二.详细完成代码
List<String> roles=new ArrayList<>();
roles.add("1508574");
roles.add("13765234");
roles.add("18834222");
listMap.put("province",roles);
for (String auditRole : processParamsDto.getAuditRoles()) {
if (auditRole.equals(processParamsDto.getAuditRoles().get(0))) {
//开端连线
process.addFlowElement(createUserTask("task".concat("_").concat(auditRole), "批阅".concat(auditRole), auditRole));
process.addFlowElement(createSequenceFlow("start", "task".concat("_").concat(auditRole), null));
//正常的 第一个网关 process.addFlowElement(createExclusiveGateway("exclusiveGateWay".concat("_").concat(auditRole), "exclusiveGateWay".concat("_").concat(auditRole)));
//第一个排他网关连线 使命->排他网关
process.addFlowElement(createSequenceFlow("task".concat("_").concat(auditRole), "exclusiveGateWay".concat("_").concat(auditRole), null));
//从头请求分支 创立从头请求使命
process.addFlowElement(createUserTask("task".concat("_").concat("从头请求"), "指定人".concat("批阅"), "${startBy}"));
//请求网关->请求使命
process.addFlowElement(createSequenceFlow("exclusiveGateWay".concat("_").concat(auditRole), "task".concat("_").concat("从头请求"), "${flag==false}"));
//请求网关
process.addFlowElement(createExclusiveGateway("exclusiveGateWay".concat("_").concat("从头请求"), "exclusiveGateWay".concat("_").concat("从头请求")));
//请求使命->请求网关
process.addFlowElement(createSequenceFlow("task".concat("_").concat("从头请求"),"exclusiveGateWay".concat("_").concat("从头请求"), null));
} else if (!auditRole.equals(processParamsDto.getAuditRoles().get(processParamsDto.getAuditRoles().size() - 1))) {
//创立排他网关 每个使命后都有一个排他网关
//第二个使命至第size-1个使命
process.addFlowElement(createUserTask("task".concat("_").concat(auditRole), "批阅".concat(auditRole), auditRole));
//第一个网关->第二个使命 使命之前的节点 网关->第二个使命....第N个使命 true
process.addFlowElement(createSequenceFlow("exclusiveGateWay".concat("_").concat(getPreAuditRole(auditRole,processParamsDto.getAuditRoles())), "task".concat("_").concat(auditRole), "${flag==true}"));
//网关->请求使命 false
process.addFlowElement(createExclusiveGateway("exclusiveGateWay".concat("_").concat(auditRole), "exclusiveGateWay(当前)".concat("_").concat(auditRole)));
process.addFlowElement(createSequenceFlow("task".concat("_").concat(auditRole), "exclusiveGateWay".concat("_").concat(auditRole), null));
//排他网关—>从头请求使命
process.addFlowElement(createSequenceFlow("exclusiveGateWay".concat("_").concat(auditRole), "task".concat("_").concat("从头请求"),"#{flag==false}"));
} else if (auditRole.equals(processParamsDto.getAuditRoles().get(processParamsDto.getAuditRoles().size() - 1))) {
String lastNode=processParamsDto.getAuditRoles().get(processParamsDto.getAuditRoles().size() - 1);
System.out.println("当前节点"+lastNode);
process.addFlowElement(createUserTask("task".concat(lastNode), "批阅".concat(auditRole), auditRole));
process.addFlowElement(createSequenceFlow("exclusiveGateWay".concat("_").concat(getPreAuditRole(auditRole,processParamsDto.getAuditRoles())),"task".concat(lastNode),"#{flag==true}"));
process.addFlowElement(createEndEvent());
process.addFlowElement(createSequenceFlow("task".concat(processParamsDto.getAuditRoles().get(processParamsDto.getAuditRoles().size() - 1)), "end", "${flag==true}")); process.addFlowElement(createSequenceFlow("exclusiveGateWay".concat("_").concat("从头请求"), "end", "${flag==false}"));
process.addFlowElement(createSequenceFlow("exclusiveGateWay".concat("_").concat("从头请求"), "task".concat("_").concat(processParamsDto.getAuditRoles().get(0)), "${flag==true}"));
}
}
new BpmnAutoLayout(model).execute();
//界说并设置流程变量
Map<String, Object> variables = new HashMap<>();
variables.put("flag", 1 == 2);
//deploy
Deployment deployment = repositoryService.createDeployment().addBpmnModel("process/dynamic-model.bpmn", model).name("Dynamic process deployment").key("test_bpmn").deploy();
processEngine.getRuntimeService().startProcessInstanceByKey(processDefinition.getKey(), variables);
InputStream inputStreamXml = processEngine.getRepositoryService().getResourceAsStream(deployment.getId(), "process/dynamic-model.bpmn");
//保存到本地,便利查看生成后的文件
FileUtils.copyInputStreamToFile(inputStreamXml, new File("D:\bpmn_data\process.bpmn.xml"));
三.注意事项
1.activiti-bpmn-layout.jar
//BPMN图布局主动调整需求增加
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-layout</artifactId>
<version>7.1.0.M4</version>
</dependency>
2.mxgraph-all.jar
//需求手动增加,其自带的mxgraph找不到办法,原因待承认,有时间去提个issue问问
<dependency>
<groupId>com.mxgraph</groupId>
<artifactId>mxgraph-all</artifactId>
<version>4.2.2</version>
<scope>system</scope>
</dependency>
3.运用了layout和不运用的生成的图对比
四.总结
经过代码生成的BPMN图其实很乱,即便加了BpmnAutoLayout办法去调整布局,可是不影响流程正常运用。还有就是看了一遍源码,没有找到子流程(SubProcess的子使命)的生成办法,暂时不支持生成子流程,待我再多研究研究。
后话
简略流程经过代码生成没问题,复杂流程还是主张用东西绘图,经过代码生成有时候容易出问题。究竟有一些节点不能连线,并且复杂流程对于一些退回操作不是很友爱,完成起来很麻烦。