From f7be7b64dab3e0a092a08821af646c5924f8af00 Mon Sep 17 00:00:00 2001 From: lvshaohua Date: Tue, 6 Jun 2023 18:38:36 +0800 Subject: [PATCH] =?UTF-8?q?json=E8=BD=ACbpmn=E5=8D=8F=E8=AE=AE=E5=BC=80?= =?UTF-8?q?=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapper/BpmProcessInstanceExtMapper.java | 14 + .../dto/process/BpmProcessInstanceExtDO.java | 98 ++++++ .../service/impl/BpmProcessServiceImpl.java | 4 + .../server/service/util/BpmTransformUtil.java | 327 +++++++++++++++++- 4 files changed, 440 insertions(+), 3 deletions(-) create mode 100644 workflow-engine-server/src/main/java/cn/axzo/server/repository/mapper/BpmProcessInstanceExtMapper.java create mode 100644 workflow-engine-server/src/main/java/cn/axzo/server/service/dto/process/BpmProcessInstanceExtDO.java create mode 100644 workflow-engine-server/src/main/java/cn/axzo/server/service/impl/BpmProcessServiceImpl.java diff --git a/workflow-engine-server/src/main/java/cn/axzo/server/repository/mapper/BpmProcessInstanceExtMapper.java b/workflow-engine-server/src/main/java/cn/axzo/server/repository/mapper/BpmProcessInstanceExtMapper.java new file mode 100644 index 000000000..897616f5b --- /dev/null +++ b/workflow-engine-server/src/main/java/cn/axzo/server/repository/mapper/BpmProcessInstanceExtMapper.java @@ -0,0 +1,14 @@ +package cn.axzo.server.repository.mapper; + +import cn.axzo.server.service.dto.process.BpmProcessInstanceExtDO; +import cn.axzo.server.service.dto.response.PageResult; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.util.StringUtils; + +@Mapper +public interface BpmProcessInstanceExtMapper extends BaseMapper { + +} diff --git a/workflow-engine-server/src/main/java/cn/axzo/server/service/dto/process/BpmProcessInstanceExtDO.java b/workflow-engine-server/src/main/java/cn/axzo/server/service/dto/process/BpmProcessInstanceExtDO.java new file mode 100644 index 000000000..47261a319 --- /dev/null +++ b/workflow-engine-server/src/main/java/cn/axzo/server/service/dto/process/BpmProcessInstanceExtDO.java @@ -0,0 +1,98 @@ +package cn.axzo.server.service.dto.process; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.Date; +import java.util.Map; + +@TableName(value = "bpm_process_instance_ext", autoResultMap = true) +@Data +@ToString(callSuper = true) +public class BpmProcessInstanceExtDO { + /** + * 编号,自增 + */ + @TableId + private Long id; + /** + * 流程实例的名字 + *

+ * 冗余 ProcessInstance 的 name 属性,用于筛选 + */ + private String name; + + /** + * 自定义的流程实例的编号 + */ + private String customProInstId; + /** + * 流程实例的编号 + *

+ * 关联 ProcessInstance 的 id 属性 + */ + private String processInstanceId; + /** + * 流程定义的编号 + *

+ * 关联 ProcessDefinition 的 id 属性 + */ + private String processDefinitionId; + /** + * 流程分类 + *

+ * 冗余 ProcessDefinition 的 category 属性 数据字典 bpm_model_category + */ + private String category; + /** + * 流程实例的状态 + *

+ * 枚举 {@link BpmProcessInstanceStatusEnum} + */ + private Integer status; + /** + * 流程实例的结果 + *

+ * 枚举 {@link BpmProcessInstanceResultEnum} + */ + private Integer result; + /** + * 结束时间 + *

+ * 冗余 HistoricProcessInstance 的 endTime 属性 + */ + private Date endTime; + + /** + * 提交的表单值 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map formVariables; + + /** + * 发起人所在的工作台ID(企业/项目) + *

+ * 使用租户字段隔离 + */ + private String tenantId; + + /** + * 发起人所在的项目工作台中的具体单位ID + */ + private Long startCompanyId; + + /** + * 发起人的身份ID + */ + private Long startIdentityId; + + /** + * 发起人的姓名 + */ + private String startUserName; +} diff --git a/workflow-engine-server/src/main/java/cn/axzo/server/service/impl/BpmProcessServiceImpl.java b/workflow-engine-server/src/main/java/cn/axzo/server/service/impl/BpmProcessServiceImpl.java new file mode 100644 index 000000000..b4179b2c5 --- /dev/null +++ b/workflow-engine-server/src/main/java/cn/axzo/server/service/impl/BpmProcessServiceImpl.java @@ -0,0 +1,4 @@ +package cn.axzo.server.service.impl; + +public class BpmProcessServiceImpl { +} diff --git a/workflow-engine-server/src/main/java/cn/axzo/server/service/util/BpmTransformUtil.java b/workflow-engine-server/src/main/java/cn/axzo/server/service/util/BpmTransformUtil.java index 8a9477ba6..73cfc61d7 100644 --- a/workflow-engine-server/src/main/java/cn/axzo/server/service/util/BpmTransformUtil.java +++ b/workflow-engine-server/src/main/java/cn/axzo/server/service/util/BpmTransformUtil.java @@ -20,11 +20,84 @@ import static org.flowable.bpmn.model.ImplementationType.IMPLEMENTATION_TYPE_DEL public class BpmTransformUtil { + public String transformBpmnJsonToXml(DDBpmModelSaveReqVO updateReqVO) { + + JSONObject bpmnJson = (JSONObject) updateReqVO.getBpmnJson(); + + BpmnModel bpmnModel =new BpmnModel(); + Process process=new Process(); + bpmnModel.addProcess(process); + List sequenceFlows = Lists.newArrayList(); + process.setId(updateReqVO.getKey()); + StartEvent startEvent = DDBpmnModelUtils.createStartEvent(); + process.addFlowElement(startEvent); + process.setName(updateReqVO.getName()); + + ExtensionAttribute extensionAttribute=new ExtensionAttribute(); + extensionAttribute.setName("TestName"); + extensionAttribute.setNamespace("http://flowable.org/bpmn"); + extensionAttribute.setValue(bpmnJson.toJSONString()); +// process.addAttribute(extensionAttribute); + JSONObject processNodes = bpmnJson.getJSONObject("nodeConfig"); + String lastNode = null; + try { + lastNode = create(startEvent.getId(), processNodes,bpmnModel,process,sequenceFlows); + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException(1245, "协议解析出错"); + } + EndEvent endEvent = createEndEvent(); + process.addFlowElement(endEvent); + process.addFlowElement(connect(lastNode, endEvent.getId(),sequenceFlows)); + + new BpmnAutoLayout(bpmnModel).execute(); + String xmlResult = new String(new BpmnXMLConverter().convertToXML(bpmnModel)); + System.err.println(xmlResult); + return xmlResult; + } + +// @PostMapping("/jsonToBpmn") +// public Object saveForm(@RequestBody com.alibaba.fastjson.JSONObject jsonObject) throws InvocationTargetException, IllegalAccessException { +// System.err.println(jsonObject.toJSONString()); +// BpmnModel bpmnModel =new BpmnModel(); +// Process process=new Process(); +// bpmnModel.addProcess(process); +// List sequenceFlows = Lists.newArrayList(); +// process.setId("flowableV2_"+idWorker.nextId()); +// StartEvent startEvent = BpmnModelUtils.createStartEvent(); +// process.addFlowElement(startEvent); +// com.alibaba.fastjson.JSONObject workFlowObj = jsonObject.getJSONObject("_value"); +// String name = workFlowObj.getJSONObject("workFlowDef").getString("name"); +// process.setName(name); +// +// ExtensionAttribute extensionAttribute=new ExtensionAttribute(); +// extensionAttribute.setName("DingDing"); +// extensionAttribute.setNamespace("http://flowable.org/bpmn"); +// extensionAttribute.setValue(jsonObject.toJSONString()); +// process.addAttribute(extensionAttribute); +// com.alibaba.fastjson.JSONObject processNodes = workFlowObj.getJSONObject("nodeConfig"); +// String lastNode = create(startEvent.getId(), processNodes,bpmnModel,process,sequenceFlows); +// EndEvent endEvent = createEndEvent(); +// process.addFlowElement(endEvent); +// process.addFlowElement(connect(lastNode, endEvent.getId(),sequenceFlows)); +// +// new BpmnAutoLayout(bpmnModel).execute(); +// System.err.println(new String(new BpmnXMLConverter().convertToXML(bpmnModel))); +// return R.ok("保存成功"); +// } + private static String create(String fromId, com.alibaba.fastjson.JSONObject flowNode, BpmnModel model, Process process, List sequenceFlows) throws InvocationTargetException, IllegalAccessException { String nodeType = flowNode.getString("type"); - - if ("userTask".equals(nodeType)) { + if (DDFlowNodeType.NODE_PARALLEL.name().equals(nodeType)) { + return createParallelGatewayBuilder(fromId, flowNode,model,process,sequenceFlows); + } + else if (DDFlowNodeType.NODE_ROUTER.name().equals(nodeType)) { + return createExclusiveGatewayBuilder(fromId, flowNode,model,process,sequenceFlows); + } + else if (DDFlowNodeType.NODE_STARTER.name().equals(nodeType)) { +// flowNode.put("incoming", Collections.singletonList(fromId)); String id = fromId; + // 如果当前任务还有后续任务,则遍历创建后续任务 com.alibaba.fastjson.JSONObject nextNode = flowNode.getJSONObject("childNode"); if (Objects.nonNull(nextNode)) { @@ -34,7 +107,20 @@ public class BpmTransformUtil { return id; } } - else if ("condition".equals(nodeType)) { + else if (DDFlowNodeType.NODE_COPY.name().equals(nodeType)) { + flowNode.put("incoming", Collections.singletonList(fromId)); + String id = createServiceTask(flowNode,process,sequenceFlows); + + // 如果当前任务还有后续任务,则遍历创建后续任务 + com.alibaba.fastjson.JSONObject nextNode = flowNode.getJSONObject("childNode"); + if (Objects.nonNull(nextNode)) { + FlowElement flowElement = model.getFlowElement(id); + return create(id, nextNode,model,process,sequenceFlows); + } else { + return id; + } + } + else if (DDFlowNodeType.NODE_TASK.name().equals(nodeType)) { flowNode.put("incoming", Collections.singletonList(fromId)); String id = createTask(flowNode,process,sequenceFlows); @@ -52,6 +138,229 @@ public class BpmTransformUtil { } } + private static String createExclusiveGatewayBuilder(String formId, com.alibaba.fastjson.JSONObject flowNode, BpmnModel model, Process process, List sequenceFlows) throws InvocationTargetException, IllegalAccessException { + String name = flowNode.getString("nodeName"); + String exclusiveGatewayId = id("exclusiveGateway"); + ExclusiveGateway exclusiveGateway = new ExclusiveGateway(); + exclusiveGateway.setId(exclusiveGatewayId); + exclusiveGateway.setName(name); + process.addFlowElement(exclusiveGateway); + process.addFlowElement(connect(formId, exclusiveGatewayId,sequenceFlows)); + + if (Objects.isNull(flowNode.getJSONArray("conditionNodes")) && Objects.isNull(flowNode.getJSONObject("childNode"))) { + return exclusiveGatewayId; + } + List flowNodes = Optional.ofNullable(flowNode.getJSONArray("conditionNodes")).map(e -> e.toJavaList(com.alibaba.fastjson.JSONObject.class)).orElse(Collections.emptyList()); + List incoming = Lists.newArrayListWithCapacity(flowNodes.size()); + + List conditions = Lists.newCopyOnWriteArrayList(); + for (com.alibaba.fastjson.JSONObject element : flowNodes) { + com.alibaba.fastjson.JSONObject childNode = element.getJSONObject("childNode"); + + String nodeName = element.getString("nodeName"); + String expression = element.getString("conditionExpression"); + + if (Objects.isNull(childNode)) { + incoming.add(exclusiveGatewayId); + com.alibaba.fastjson.JSONObject condition = new com.alibaba.fastjson.JSONObject(); + condition.fluentPut("nodeName", nodeName) + .fluentPut("expression", expression); + conditions.add(condition); + continue; + } + // 只生成一个任务,同时设置当前任务的条件 + childNode.put("incoming", Collections.singletonList(exclusiveGatewayId)); + String identifier = create(exclusiveGatewayId, childNode,model,process,sequenceFlows); + List flows = sequenceFlows.stream().filter(flow -> StringUtils.equals(exclusiveGatewayId, flow.getSourceRef())) + .collect(Collectors.toList()); + flows.stream().forEach( + e -> { + if (StringUtils.isBlank(e.getName()) && StringUtils.isNotBlank(nodeName)) { + e.setName(nodeName); + } + // 设置条件表达式 + if (Objects.isNull(e.getConditionExpression()) && StringUtils.isNotBlank(expression)) { + e.setConditionExpression(expression); + } + } + ); + if (Objects.nonNull(identifier)) { + incoming.add(identifier); + } + } + + + com.alibaba.fastjson.JSONObject childNode = flowNode.getJSONObject("childNode"); + + if (Objects.nonNull(childNode)) { + if (incoming == null || incoming.isEmpty()) { + return create(exclusiveGatewayId, childNode,model,process,sequenceFlows); + } + else { + // 所有 service task 连接 end exclusive gateway + childNode.put("incoming", incoming); + FlowElement flowElement = model.getFlowElement(incoming.get(0)); + // 1.0 先进行边连接, 暂存 nextNode + com.alibaba.fastjson.JSONObject nextNode = childNode.getJSONObject("childNode"); + String endExId=id("exclusiveGateway")+"end"; + process.addFlowElement(DDBpmnModelUtils.createExclusiveGateWayEnd(endExId)); + childNode.put("childNode", null); + String identifier =endExId;/*create(flowElement.getId(), childNode,model,process,sequenceFlows);*/ + for (int i = 0; i < incoming.size(); i++) { + process.addFlowElement(connect(incoming.get(i), endExId,sequenceFlows)); + } + + // 针对 gateway 空任务分支 添加条件表达式 + if (!conditions.isEmpty()) { + FlowElement flowElement1 = model.getFlowElement(identifier); + // 获取从 gateway 到目标节点 未设置条件表达式的节点 + List flows = sequenceFlows.stream().filter(flow -> StringUtils.equals(flowElement1.getId(), flow.getTargetRef())) + .filter(flow -> StringUtils.equals(flow.getSourceRef(), exclusiveGatewayId)) + .collect(Collectors.toList()); + flows.stream().forEach(sequenceFlow -> { + if (!conditions.isEmpty()) { + com.alibaba.fastjson.JSONObject condition = conditions.get(0); + String nodeName = condition.getString("nodeName"); + String expression = condition.getString("expression"); + + if (StringUtils.isBlank(sequenceFlow.getName()) && StringUtils.isNotBlank(nodeName)) { + sequenceFlow.setName(nodeName); + } + // 设置条件表达式 + if (Objects.isNull(sequenceFlow.getConditionExpression()) && StringUtils.isNotBlank(expression)) { + sequenceFlow.setConditionExpression(expression); + } + + conditions.remove(0); + } + }); + + } + + // 1.1 边连接完成后,在进行 nextNode 创建 + if (Objects.nonNull(childNode)) { + return create(endExId, childNode,model,process,sequenceFlows); + } else { + return endExId; + } + } + } + else{ + // 所有 service task 连接 end exclusive gateway + // 1.0 先进行边连接, 暂存 nextNode + String endExId=id("exclusiveGateway")+"end"; + process.addFlowElement(DDBpmnModelUtils.createExclusiveGateWayEnd(endExId)); + String identifier =endExId;/*create(flowElement.getId(), childNode,model,process,sequenceFlows);*/ + for (int i = 0; i < incoming.size(); i++) { + process.addFlowElement(connect(incoming.get(i), endExId,sequenceFlows)); + } + + // 针对 gateway 空任务分支 添加条件表达式 + if (!conditions.isEmpty()) { + FlowElement flowElement1 = model.getFlowElement(identifier); + // 获取从 gateway 到目标节点 未设置条件表达式的节点 + List flows = sequenceFlows.stream().filter(flow -> StringUtils.equals(flowElement1.getId(), flow.getTargetRef())) + .filter(flow -> StringUtils.equals(flow.getSourceRef(), exclusiveGatewayId)) + .collect(Collectors.toList()); + flows.stream().forEach(sequenceFlow -> { + if (!conditions.isEmpty()) { + com.alibaba.fastjson.JSONObject condition = conditions.get(0); + String nodeName = condition.getString("nodeName"); + String expression = condition.getString("expression"); + + if (StringUtils.isBlank(sequenceFlow.getName()) && StringUtils.isNotBlank(nodeName)) { + sequenceFlow.setName(nodeName); + } + // 设置条件表达式 + if (Objects.isNull(sequenceFlow.getConditionExpression()) && StringUtils.isNotBlank(expression)) { + sequenceFlow.setConditionExpression(expression); + } + + conditions.remove(0); + } + }); + + } + return endExId; + } +// return exclusiveGatewayId; + } + + private static String createParallelGatewayBuilder(String formId, com.alibaba.fastjson.JSONObject flowNode, BpmnModel model, Process process, List sequenceFlows) throws InvocationTargetException, IllegalAccessException { + String name = flowNode.getString("nodeName"); + ParallelGateway parallelGateway = new ParallelGateway(); + String parallelGatewayId = id("parallelGateway"); + parallelGateway.setId(parallelGatewayId); + parallelGateway.setName(name); + process.addFlowElement(parallelGateway); + process.addFlowElement(connect(formId, parallelGatewayId,sequenceFlows)); + + if (Objects.isNull(flowNode.getJSONArray("conditionNodes")) + && Objects.isNull(flowNode.getJSONObject("childNode"))) { + return parallelGatewayId; + } + + List flowNodes = Optional.ofNullable(flowNode.getJSONArray("conditionNodes")).map(e -> e.toJavaList(com.alibaba.fastjson.JSONObject.class)).orElse(Collections.emptyList()); + List incoming = Lists.newArrayListWithCapacity(flowNodes.size()); + for (com.alibaba.fastjson.JSONObject element : flowNodes) { + com.alibaba.fastjson.JSONObject childNode = element.getJSONObject("childNode"); + if (Objects.isNull(childNode)) { + incoming.add(parallelGatewayId); + continue; + } + String identifier = create(parallelGatewayId, childNode,model,process,sequenceFlows); + if (Objects.nonNull(identifier)) { + incoming.add(identifier); + } + } + + com.alibaba.fastjson.JSONObject childNode = flowNode.getJSONObject("childNode"); + if (Objects.nonNull(childNode)) { + // 普通结束网关 + if (CollectionUtils.isEmpty(incoming)) { + return create(parallelGatewayId, childNode,model,process,sequenceFlows); + } else { + // 所有 service task 连接 end parallel gateway + childNode.put("incoming", incoming); + FlowElement flowElement = model.getFlowElement(incoming.get(0)); + // 1.0 先进行边连接, 暂存 nextNode + com.alibaba.fastjson.JSONObject nextNode = childNode.getJSONObject("childNode"); + childNode.put("childNode", null); + String identifier = create(incoming.get(0), childNode,model,process,sequenceFlows); + for (int i = 1; i < incoming.size(); i++) { + FlowElement flowElement1 = model.getFlowElement(incoming.get(i)); + process.addFlowElement(connect(flowElement1.getId(), identifier,sequenceFlows)); + } + // 1.1 边连接完成后,在进行 nextNode 创建 + if (Objects.nonNull(nextNode)) { + return create(identifier, nextNode,model,process,sequenceFlows); + } else { + return identifier; + } + } + } + return parallelGatewayId; + } + + private static String createServiceTask(com.alibaba.fastjson.JSONObject flowNode, Process process, List sequenceFlows) { + List incoming = flowNode.getJSONArray("incoming").toJavaList(String.class); + // 自动生成id + String id = id("serviceTask"); + if (incoming != null && !incoming.isEmpty()) { + ServiceTask serviceTask = new ServiceTask(); + serviceTask.setName(flowNode.getString("nodeName")); + serviceTask.setId(id); + + // todo lvshaohua + serviceTask.setImplementationType("class"); + serviceTask.setImplementation("com.dingding.mid.listener.Vue3Listener"); + + process.addFlowElement(serviceTask); + process.addFlowElement(connect(incoming.get(0), id,sequenceFlows)); + } + return id; + } + private static String createTask(com.alibaba.fastjson.JSONObject flowNode, Process process, List sequenceFlows) { List incoming = flowNode.getJSONArray("incoming").toJavaList(String.class); @@ -144,4 +453,16 @@ public class BpmTransformUtil { sequenceFlows.add(flow); return flow; } + + protected static StartEvent createStartEvent() { + StartEvent startEvent = new StartEvent(); + startEvent.setId(id("start")); + return startEvent; + } + + protected static EndEvent createEndEvent() { + EndEvent endEvent = new EndEvent(); + endEvent.setId(id("end")); + return endEvent; + } }