update 流程图处理

This commit is contained in:
lijiarao
2023-10-08 18:03:05 +08:00
parent 82bee649d6
commit b8d4116879
8 changed files with 652 additions and 233 deletions
@@ -2,7 +2,6 @@ package com.jero.modules.activiti.controller;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jero.common.api.vo.Result;
@@ -13,19 +12,15 @@ import com.jero.modules.activiti.entity.ProcessNodeOrigin;
import com.jero.modules.activiti.service.LawsProcessNodeOriginService;
import com.jero.modules.activiti.service.LawsProcessNodeService;
import com.jero.modules.activiti.service.ProcessService;
import com.jero.modules.activiti.vo.AddTaskVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
@@ -41,12 +36,8 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;
@@ -58,7 +49,7 @@ import java.util.*;
@RestController
@Api(tags = "流程控制")
@RequestMapping("/modeler")
public class AController {
public class ActivitiController {
@Autowired
private ProcessService processService;
@Resource
@@ -109,7 +100,6 @@ public class AController {
processDefinitionQuery.deploymentId(deployment.getId());
ProcessDefinition processDefinition = processDefinitionQuery.singleResult();
String processDefinitionId = processDefinition.getId();
processNodeOriginService.saveNodeList(processDefinitionId);
map.put("流程定义Id", processDefinitionId);
return Result.OK(map);
@@ -295,19 +285,6 @@ public class AController {
return Result.OK();
}
@PostMapping("/addTask")
@ApiOperation("新增节点")
public Object addTask(@RequestBody AddTaskVO addTaskVO, HttpServletResponse response) {
return processNodeOriginService.addTask(addTaskVO,response);
}
@ApiOperation("保存节点列表")
@GetMapping("/saveNodeList")
public Object saveNodeList(String processDefinitionId) {
processNodeOriginService.saveNodeList(processDefinitionId);
return null;
}
@GetMapping(value = "/readResource")
@ApiOperation(value = "获取实时流程图", notes = "获取实时流程图,输出跟踪流程信息")
@@ -320,13 +297,17 @@ public class AController {
}
}
@GetMapping(value = "/export/{modelId}")
@GetMapping(value = "/export")
@ApiOperation(value = "将流程模型导出为 bpmn文件", notes = "将流程模型导出为 bpmn文件")
public void export(@PathVariable("modelId") @ApiParam("流程模型Id") String modelId, HttpServletResponse
response) {
public void export(@RequestParam(value = "modelId", required = false) String modelId, HttpServletResponse response) {
try {
BpmnModel bpmnModel = repositoryService.getBpmnModel(modelId);
ObjectNode objectNode = null;
try {
objectNode = (ObjectNode) new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelId));
} catch (IOException e) {
e.printStackTrace();
}
BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(objectNode);
// 流程非空判断
if (!CollectionUtils.isEmpty(bpmnModel.getProcesses())) {
BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
@@ -1,11 +1,16 @@
package com.jero.modules.activiti.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jero.common.api.vo.Result;
import com.jero.modules.activiti.entity.ProcessModelNode;
import com.jero.modules.activiti.entity.ProcessNodeOrigin;
import com.jero.modules.activiti.service.LawsProcessNodeOriginService;
import com.jero.modules.activiti.service.ProcessModelNodeService;
import com.jero.modules.activiti.util.CreatedTools;
import com.jero.modules.activiti.vo.AddTaskVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
@@ -31,6 +36,7 @@ import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -44,7 +50,7 @@ import java.util.Map;
@RestController
@Api(tags = "工作流模板管理")
@RequestMapping("/activitiModel")
public class ActivitiModelerController {
public class ModelerController {
@Autowired
private RepositoryService repositoryService;
@@ -52,6 +58,8 @@ public class ActivitiModelerController {
private ObjectMapper objectMapper;
@Resource
private LawsProcessNodeOriginService processNodeOriginService;
@Resource
private ProcessModelNodeService processModelNodeService;
//@Autowired
//private IFormVariableService iFormVariableService;
//@Autowired
@@ -62,7 +70,7 @@ public class ActivitiModelerController {
@ApiImplicitParam(name = "name", value = "模型名称")
})
@PostMapping("/importModelFile")
public void importModelFile(@RequestPart(value = "file", required = false) MultipartFile file,
public Result<String> importModelFile(@RequestPart(value = "file", required = false) MultipartFile file,
@RequestParam(value = "name", required = false) String name) throws Exception {
InputStream fileInputStream = file.getInputStream();
XMLInputFactory xif = XMLInputFactory.newInstance();
@@ -79,8 +87,12 @@ public class ActivitiModelerController {
model.setKey(modelKey);
model.setMetaInfo(modelNode.toString());
repositoryService.saveModel(model);
String modelId = model.getId();
ObjectNode objectNode = new BpmnJsonConverter().convertToJson(bpmnModel);
repositoryService.addModelEditorSource(model.getId(), objectNode.toString().getBytes("utf-8"));
repositoryService.addModelEditorSource(modelId, objectNode.toString().getBytes(StandardCharsets.UTF_8));
//生成节点
processModelNodeService.generateNode(modelId);
return Result.OK(modelId);
}
@ApiOperation(value = "新建模板")
@@ -235,7 +247,7 @@ public class ActivitiModelerController {
Deployment deployment = repositoryService.createDeployment()
.name(modelData.getName())
.category(modelData.getCategory())
.addString(processName, new String(bpmnBytes, "UTF-8"))
.addString(processName, new String(bpmnBytes, StandardCharsets.UTF_8))
.deploy();
modelData.setDeploymentId(deployment.getId());
repositoryService.saveModel(modelData);
@@ -245,7 +257,7 @@ public class ActivitiModelerController {
processDefinitionQuery.deploymentId(deployment.getId());
ProcessDefinition processDefinition = processDefinitionQuery.singleResult();
String processDefinitionId = processDefinition.getId();
processNodeOriginService.saveNodeList(processDefinitionId);
processNodeOriginService.copyNodeFromModel(modelId,processDefinitionId);
// 4输出部署信息
Map<String, String> map = new HashMap<>();
map.put("流程部署id", deployment.getId());
@@ -255,4 +267,49 @@ public class ActivitiModelerController {
return Result.OK(map);
}
@GetMapping("/getNodeList")
@ApiImplicitParam(name = "modelId", value = "模型id")
@ApiOperation("获得节点列表")
public Result<Map<String,Object>> getNodeList(String modelId) {
//查询节点信息
LambdaQueryWrapper<ProcessModelNode> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(ProcessModelNode::getModelId,modelId);
//wrapper.eq(ProcessModelNode::getNodeType,"userTask");
wrapper.orderByAsc(ProcessModelNode::getSort);
List<ProcessModelNode> nodeOriginList = processModelNodeService.list(wrapper);
ArrayList<Map<String,Object>> nodes = new ArrayList<>();
ArrayList<Map<String,Object>> edges = new ArrayList<>();
for (ProcessModelNode modelNode : nodeOriginList) {
String nodeType = modelNode.getNodeType();
String nodeName = modelNode.getNodeName();
if ("sequenceFlow".equals(nodeType)){
if (!"驳回".equals(nodeName)){
Map<String,Object> edge = new HashMap<>();
edge.put("source",modelNode.getXmlSourceRef());
edge.put("target",modelNode.getXmlTargetRef());
edges.add(edge);
}
}else if (!"endEvent".equals(nodeType)&&!"startEvent".equals(nodeType)){
Map<String,Object> node = new HashMap<>();
node.put("id",modelNode.getXmlNodeId());
node.put("name",nodeName!=null?nodeName:"");
node.put("isApprovalNode",modelNode.getIsApprovalNode());
node.put("isCanDeleted",modelNode.getIsCanDeleted());
nodes.add(node);
}
}
Map<String,Object> result = new HashMap<>();
result.put("nodes",nodes);
result.put("edges",edges);
return Result.OK(result);
}
@PostMapping("/addTask")
@ApiOperation("新增节点")
public Object addTask(@RequestBody AddTaskVO addTaskVO, HttpServletResponse response) {
return processModelNodeService.addTask(addTaskVO,response);
}
}
@@ -0,0 +1,136 @@
package com.jero.modules.activiti.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
import lombok.Data;
/**
*
*@author liJiaRao
*@date 2023-10-08 18:01
*/
/**
* 流程节点加签表
*/
@ApiModel(description = "流程节点加签表")
@Data
@TableName(value = "process_model_node")
public class ProcessModelNode {
/**
* 主键id
*/
@TableId(value = "id", type = IdType.ASSIGN_ID)
@ApiModelProperty(value = "主键id")
private String id;
/**
* 模型id
*/
@TableField(value = "model_id")
@ApiModelProperty(value = "模型id")
private String modelId;
/**
* 节点名称
*/
@TableField(value = "node_name")
@ApiModelProperty(value = "节点名称")
private String nodeName;
/**
* 节点类型
*/
@TableField(value = "node_type")
@ApiModelProperty(value = "节点类型")
private String nodeType;
/**
* 子流程id
*/
@TableField(value = "xml_sub_node_id")
@ApiModelProperty(value = "子流程id")
private String xmlSubNodeId;
/**
* xml节点Id
*/
@TableField(value = "xml_node_id")
@ApiModelProperty(value = "xml节点Id")
private String xmlNodeId;
/**
* xml来源节点id
*/
@TableField(value = "xml_source_ref")
@ApiModelProperty(value = "xml来源节点id")
private String xmlSourceRef;
/**
* xml目标节点id
*/
@TableField(value = "xml_target_ref")
@ApiModelProperty(value = "xml目标节点id")
private String xmlTargetRef;
/**
* 是否审批节点
*/
@TableField(value = "is_approval_node")
@ApiModelProperty(value = "是否审批节点")
private Integer isApprovalNode;
/**
* 是否可删除
*/
@TableField(value = "is_can_deleted")
@ApiModelProperty(value = "是否可删除")
private Integer isCanDeleted;
/**
* 排序
*/
@TableField(value = "sort")
@ApiModelProperty(value = "排序")
private Integer sort;
/**
* 创建人
*/
@TableField(value = "create_by")
@ApiModelProperty(value = "创建人")
private String createBy;
/**
* 创建时间
*/
@TableField(value = "create_time")
@ApiModelProperty(value = "创建时间")
private Date createTime;
/**
* 更新人
*/
@TableField(value = "update_by")
@ApiModelProperty(value = "更新人")
private String updateBy;
/**
* 更新时间
*/
@TableField(value = "update_time")
@ApiModelProperty(value = "更新时间")
private Date updateTime;
/**
* 所属部门
*/
@TableField(value = "sys_code")
@ApiModelProperty(value = "所属部门")
private String sysCode;
}
@@ -0,0 +1,19 @@
package com.jero.modules.activiti.mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jero.modules.activiti.entity.ProcessModelNode;
/**
*
*@author liJiaRao
*@date 2023-10-08 14:08
*/
public interface ProcessModelNodeMapper extends BaseMapper<ProcessModelNode> {
int insertList(@Param("list")List<ProcessModelNode> list);
int deleteByModelId(@Param("modelId")String modelId);
}
@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jero.modules.activiti.mapper.ProcessModelNodeMapper">
<!--auto generated by MybatisCodeHelper on 2023-10-08-->
<sql id="Base_Column_List">
id,
model_id,
node_name,
node_type,
xml_node_id,
xml_source_ref,
xml_target_ref,
is_approval_node,
is_can_deleted,
sort,
create_by,
create_time,
update_by,
update_time,
sys_code
</sql>
<resultMap id="BaseResultMap" type="com.jero.modules.activiti.entity.ProcessModelNode">
<result column="id" property="id"/>
<result column="model_id" property="modelId"/>
<result column="node_name" property="nodeName"/>
<result column="node_type" property="nodeType"/>
<result column="xml_node_id" property="xmlNodeId"/>
<result column="xml_source_ref" property="xmlSourceRef"/>
<result column="xml_target_ref" property="xmlTargetRef"/>
<result column="is_approval_node" property="isApprovalNode"/>
<result column="is_can_deleted" property="isCanDeleted"/>
<result column="sort" property="sort"/>
<result column="create_by" property="createBy"/>
<result column="create_time" property="createTime"/>
<result column="update_by" property="updateBy"/>
<result column="update_time" property="updateTime"/>
<result column="sys_code" property="sysCode"/>
</resultMap>
<insert id="insertList">
INSERT INTO process_model_node(
id,
model_id,
node_name,
node_type,
xml_node_id,
xml_source_ref,
xml_target_ref,
is_approval_node,
is_can_deleted,
sort,
create_by,
create_time,
update_by,
update_time,
sys_code
)VALUES
<foreach collection="list" item="element" index="index" separator=",">
(
#{element.id,jdbcType=VARCHAR},
#{element.modelId,jdbcType=VARCHAR},
#{element.nodeName,jdbcType=VARCHAR},
#{element.nodeType},
#{element.xmlNodeId},
#{element.xmlSourceRef},
#{element.xmlTargetRef},
#{element.isApprovalNode,jdbcType=TINYINT},
#{element.isCanDeleted,jdbcType=TINYINT},
#{element.sort,jdbcType=TINYINT},
#{element.createBy,jdbcType=VARCHAR},
#{element.createTime,jdbcType=TIMESTAMP},
#{element.updateBy,jdbcType=VARCHAR},
#{element.updateTime,jdbcType=TIMESTAMP},
#{element.sysCode,jdbcType=VARCHAR}
)
</foreach>
</insert>
<!--auto generated by MybatisCodeHelper on 2023-10-08-->
<delete id="deleteByModelId">
delete from process_model_node
where model_id=#{modelId}
</delete>
</mapper>
@@ -1,24 +1,33 @@
package com.jero.modules.activiti.service;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jero.common.constant.enums.YesOrNoEnum;
import com.jero.common.exception.JeroBootException;
import com.jero.modules.activiti.entity.ProcessModelNode;
import com.jero.modules.activiti.mapper.ActGeBytearrayMapper;
import com.jero.modules.activiti.mapper.ProcessModelNodeMapper;
import com.jero.modules.activiti.vo.AddTaskVO;
import org.activiti.bpmn.BpmnAutoLayout;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.*;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -42,204 +51,22 @@ public class LawsProcessNodeOriginService extends ServiceImpl<LawsProcessNodeOri
private ActGeBytearrayMapper actGeBytearrayMapper;
@Resource
private LawsProcessNodeOriginMapper processNodeOriginMapper;
@Resource
private ProcessModelNodeMapper processModelNodeMapper;
public void copyNodeFromModel(String modelId, String processDefinitionId) {
LambdaQueryWrapper<ProcessModelNode> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(ProcessModelNode::getModelId,modelId);
List<ProcessModelNode> processModelNodes = processModelNodeMapper.selectList(wrapper);
public void saveNodeList(String processDefinitionId) {
final BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
Process process = bpmnModel.getMainProcess();
Collection<FlowElement> flowElements = process.getFlowElements();
List<ProcessNodeOrigin> processNodeOriginList = new ArrayList<>();
int sort = 1;
List<String> gatewayIdList = new ArrayList<>();
processNodeOriginList = handlerLawsProcessNodeOrigin(flowElements,sort,gatewayIdList,processDefinitionId);
List<String> approvalNodeIdList = processNodeOriginList.stream()
.filter(item -> gatewayIdList.contains(item.getXmlTargetRef()))
.map(ProcessNodeOrigin::getXmlSourceRef)
.collect(Collectors.toList());
for (ProcessNodeOrigin processNodeOrigin : processNodeOriginList) {
String xmlNodeId = processNodeOrigin.getXmlNodeId();
if (approvalNodeIdList.contains(xmlNodeId) ){
processNodeOrigin.setIsApprovalNode(YesOrNoEnum.YES.getInteger());
}
for (ProcessModelNode processModelNode : processModelNodes) {
ProcessNodeOrigin processNodeOrigin = new ProcessNodeOrigin();
BeanUtils.copyProperties(processModelNode,processNodeOrigin);
processNodeOrigin.setId(null);
processNodeOrigin.setProcessDefinitionId(processDefinitionId);
}
processNodeOriginMapper.insertList(processNodeOriginList);
}
public Object addTask(AddTaskVO addTaskVO, HttpServletResponse response) {
try {
String processDefinitionId = addTaskVO.getProcessDefinitionId();
String xmlNodeId = addTaskVO.getXmlNodeId();
String nodeName = addTaskVO.getNodeName();
//查找当前节点
LambdaQueryWrapper<ProcessNodeOrigin> processNodeOriginLambdaQueryWrapper = new LambdaQueryWrapper<>();
processNodeOriginLambdaQueryWrapper.eq(ProcessNodeOrigin::getXmlNodeId, xmlNodeId)
.eq(ProcessNodeOrigin::getProcessDefinitionId, processDefinitionId);
ProcessNodeOrigin processNodeOrigin = processNodeOriginMapper.selectOne(processNodeOriginLambdaQueryWrapper);
if (processNodeOrigin == null || !YesOrNoEnum.YES.getInteger().equals(processNodeOrigin.getIsApprovalNode())) {
throw new JeroBootException("只能在审批节点后新增");
}
processNodeOriginLambdaQueryWrapper.clear();
//查找节点的流出线
processNodeOriginLambdaQueryWrapper.eq(ProcessNodeOrigin::getXmlSourceRef, xmlNodeId)
.eq(ProcessNodeOrigin::getProcessDefinitionId, processDefinitionId);
ProcessNodeOrigin flowOrigin1 = processNodeOriginMapper.selectOne(processNodeOriginLambdaQueryWrapper);
processNodeOriginLambdaQueryWrapper.clear();
//查找流出线指向的网关
processNodeOriginLambdaQueryWrapper.eq(ProcessNodeOrigin::getXmlNodeId, flowOrigin1.getXmlTargetRef())
.eq(ProcessNodeOrigin::getProcessDefinitionId, processDefinitionId);
ProcessNodeOrigin gatewayOrigin = processNodeOriginMapper.selectOne(processNodeOriginLambdaQueryWrapper);
processNodeOriginLambdaQueryWrapper.clear();
//查找网关指向的线
processNodeOriginLambdaQueryWrapper.eq(ProcessNodeOrigin::getXmlSourceRef, gatewayOrigin.getXmlNodeId())
.eq(ProcessNodeOrigin::getNodeName, "通过")
.eq(ProcessNodeOrigin::getProcessDefinitionId, processDefinitionId);
ProcessNodeOrigin flowOrigin2 = processNodeOriginMapper.selectOne(processNodeOriginLambdaQueryWrapper);
BpmnModel bpmnModelOrigin = repositoryService.getBpmnModel(processDefinitionId);
BpmnXMLConverter converter = new BpmnXMLConverter();
byte[] bytesOrigin = converter.convertToXML(bpmnModelOrigin);
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytesOrigin);
XMLInputFactory factory = XMLInputFactory.newInstance();
BpmnModel bpmnModel = converter.convertToBpmnModel(factory.createXMLStreamReader(inputStream));
Process process = bpmnModel.getMainProcess();
SequenceFlow flowElement = (SequenceFlow) process.getFlowElement(flowOrigin2.getXmlNodeId());
process.removeFlowElement(flowOrigin2.getXmlNodeId());
UserTask userTask = createUserTask(nodeName, null);
String userTaskId = userTask.getId();
flowElement.setTargetRef(userTaskId);
process.addFlowElement(flowElement);
process.addFlowElement(userTask);
process.addFlowElement(createGateway(process, userTaskId, flowOrigin2.getXmlTargetRef(), processNodeOrigin.getXmlNodeId()));
//重新绘画图形
BpmnAutoLayout bpmnAutoLayout = new BpmnAutoLayout(bpmnModel);
bpmnAutoLayout.execute();
//把bpmnModel对象转换成字符
byte[] bytes = converter.convertToXML(bpmnModel);
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
String filename = bpmnModel.getMainProcess().getId() + ".bpmn";
response.setContentType("application/force-download");// 设置强制下载不打开
response.setHeader("Content-Disposition", "attachment; filename=" + filename);
IOUtils.copy(in, response.getOutputStream());
response.flushBuffer();
} catch (IOException e) {
e.printStackTrace();
} catch (XMLStreamException e) {
e.printStackTrace();
}
return null;
}
protected static UserTask createUserTask(String name, String assignee) {
String id = "Activity_" + UUID.randomUUID();
UserTask userTask = new UserTask();
userTask.setName(name);
userTask.setId(id);
userTask.setAssignee(assignee!=null?assignee:"${"+id.replace("-","")+"}");
return userTask;
}
protected static SequenceFlow createSequenceFlow(String from, String to) {
SequenceFlow flow = new SequenceFlow();
flow.setSourceRef(from);
flow.setTargetRef(to);
flow.setId("Flow_"+ UUID.randomUUID());
return flow;
}
protected static SequenceFlow createSequenceFlow(String from, String to,String name,String conditionExpression) {
SequenceFlow flow = new SequenceFlow();
flow.setSourceRef(from);
flow.setTargetRef(to);
flow.setName(name);
flow.setConditionExpression(conditionExpression);
flow.setId("Flow_"+ UUID.randomUUID());
return flow;
}
protected static ExclusiveGateway createGateway(Process process, String originId, String targetIdYes, String targetIdNo) {
ExclusiveGateway gateway = new ExclusiveGateway();
String id = "Gateway_" + UUID.randomUUID();
gateway.setId(id);
List<SequenceFlow> incomingFlows = new ArrayList<>();
SequenceFlow sequenceFlow = createSequenceFlow(originId, id);
process.addFlowElement(sequenceFlow);
incomingFlows.add(sequenceFlow);
gateway.setIncomingFlows(incomingFlows);
List<SequenceFlow> outgoingFlows = new ArrayList<>();
SequenceFlow sequenceFlow1 = createSequenceFlow(id, targetIdYes, "通过", "${pass}");
SequenceFlow sequenceFlow2 = createSequenceFlow(id, targetIdNo, "驳回", "${!pass}");
process.addFlowElement(sequenceFlow1);
process.addFlowElement(sequenceFlow2);
outgoingFlows.add(sequenceFlow1);
outgoingFlows.add(sequenceFlow2);
gateway.setOutgoingFlows(outgoingFlows);
return gateway;
}
private List<ProcessNodeOrigin> handlerLawsProcessNodeOrigin(
Collection<FlowElement> flowElements,
int sort,
List<String> gatewayIdList,
String processDefinitionId) {
List<ProcessNodeOrigin> processNodeOriginList = new ArrayList<>();
for (FlowElement flowElement : flowElements) {
ProcessNodeOrigin processNodeOrigin = new ProcessNodeOrigin();
String nodeName = processNodeOrigin.getNodeName();
String nodeType = processNodeOrigin.getNodeType();
String xmlNodeId = processNodeOrigin.getXmlNodeId();
String xmlSourceRef = processNodeOrigin.getXmlSourceRef();
String xmlTargetRef = processNodeOrigin.getXmlTargetRef();
if (flowElement instanceof UserTask) {
UserTask userTask = (UserTask) flowElement;
nodeType = "userTask";
nodeName = userTask.getName();
xmlNodeId = userTask.getId();
} else if (flowElement instanceof SequenceFlow) {
SequenceFlow sequenceFlow = (SequenceFlow) flowElement;
nodeType = "sequenceFlow";
nodeName = sequenceFlow.getName();
xmlNodeId = sequenceFlow.getId();
xmlSourceRef = sequenceFlow.getSourceRef();
xmlTargetRef = sequenceFlow.getTargetRef();
} else if (flowElement instanceof ExclusiveGateway) {
ExclusiveGateway gateway = (ExclusiveGateway) flowElement;
nodeType = "gateway";
nodeName = gateway.getName();
xmlNodeId = gateway.getId();
gatewayIdList.add(xmlNodeId);
} else if (flowElement instanceof SubProcess) {
SubProcess subProcess = (SubProcess) flowElement;
Collection<FlowElement> flowElements1 = subProcess.getFlowElements();
List<ProcessNodeOrigin> processNodeOrigins = handlerLawsProcessNodeOrigin(flowElements1, sort, gatewayIdList, processDefinitionId);
processNodeOriginList.addAll(processNodeOrigins);
nodeType = "subProcess";
nodeName = subProcess.getName();
xmlNodeId = subProcess.getId();
} else if (flowElement instanceof EndEvent) {
EndEvent endEvent = (EndEvent) flowElement;
nodeType = "endEvent";
nodeName = endEvent.getName();
xmlNodeId = endEvent.getId();
} else {
continue;
}
processNodeOrigin.setProcessDefinitionId(processDefinitionId);
processNodeOrigin.setNodeName(nodeName);
processNodeOrigin.setNodeType(nodeType);
processNodeOrigin.setXmlNodeId(xmlNodeId);
processNodeOrigin.setXmlSourceRef(xmlSourceRef);
processNodeOrigin.setXmlTargetRef(xmlTargetRef);
processNodeOrigin.setSort(sort++);
processNodeOrigin.setIsApprovalNode(YesOrNoEnum.NO.getInteger());
processNodeOrigin.setIsCanDeleted(YesOrNoEnum.NO.getInteger());
processNodeOriginList.add(processNodeOrigin);
}
return processNodeOriginList;
}
}
@@ -0,0 +1,316 @@
package com.jero.modules.activiti.service;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jero.common.constant.enums.YesOrNoEnum;
import com.jero.common.exception.JeroBootException;
import com.jero.modules.activiti.entity.ProcessModelNode;
import com.jero.modules.activiti.vo.AddTaskVO;
import org.activiti.bpmn.BpmnAutoLayout;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jero.modules.activiti.mapper.ProcessModelNodeMapper;
/**
*
*@author liJiaRao
*@date 2023-10-08 14:08
*/
@Service
public class ProcessModelNodeService extends ServiceImpl<ProcessModelNodeMapper, ProcessModelNode> {
@Resource
private RepositoryService repositoryService;
@Resource
private ProcessModelNodeMapper processModelNodeMapper;
public void generateNode(String modelId) {
ObjectNode objectNode = null;
try {
objectNode = (ObjectNode) new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelId));
} catch (IOException e) {
e.printStackTrace();
}
BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(objectNode);
Process process = bpmnModel.getMainProcess();
Collection<FlowElement> flowElements = process.getFlowElements();
List<ProcessModelNode> processModelNodeList = new ArrayList<>();
int sort = 1;
List<String> gatewayIdList = new ArrayList<>();
processModelNodeList = handlerLawsProcessModelNode(flowElements,sort,gatewayIdList,modelId, null);
List<String> approvalNodeIdList = processModelNodeList.stream()
.filter(item -> gatewayIdList.contains(item.getXmlTargetRef()))
.map(ProcessModelNode::getXmlSourceRef)
.collect(Collectors.toList());
for (ProcessModelNode processModelNode : processModelNodeList) {
String xmlNodeId = processModelNode.getXmlNodeId();
if (approvalNodeIdList.contains(xmlNodeId) ){
processModelNode.setIsApprovalNode(YesOrNoEnum.YES.getInteger());
}
}
processModelNodeMapper.insertList(processModelNodeList);
}
public Object addTask(AddTaskVO addTaskVO, HttpServletResponse response) {
try {
String modelId = addTaskVO.getModelId();
String xmlNodeId = addTaskVO.getXmlNodeId();
String nodeName = addTaskVO.getNodeName();
//查询模型
Model model = repositoryService.getModel(modelId);
String deploymentId = model.getDeploymentId();
//查找当前节点
LambdaQueryWrapper<ProcessModelNode> processModelNodeLambdaQueryWrapper = new LambdaQueryWrapper<>();
processModelNodeLambdaQueryWrapper.eq(ProcessModelNode::getXmlNodeId, xmlNodeId)
.eq(ProcessModelNode::getModelId, modelId);
ProcessModelNode processModelNode = processModelNodeMapper.selectOne(processModelNodeLambdaQueryWrapper);
if (processModelNode == null || !YesOrNoEnum.YES.getInteger().equals(processModelNode.getIsApprovalNode())) {
throw new JeroBootException("只能在审批节点后新增");
}
processModelNodeLambdaQueryWrapper.clear();
//查找节点的流出线
processModelNodeLambdaQueryWrapper.eq(ProcessModelNode::getXmlSourceRef, xmlNodeId)
.eq(ProcessModelNode::getModelId, modelId);
ProcessModelNode flowOrigin1 = processModelNodeMapper.selectOne(processModelNodeLambdaQueryWrapper);
processModelNodeLambdaQueryWrapper.clear();
//查找流出线指向的网关
processModelNodeLambdaQueryWrapper.eq(ProcessModelNode::getXmlNodeId, flowOrigin1.getXmlTargetRef())
.eq(ProcessModelNode::getModelId, modelId);
ProcessModelNode gatewayOrigin = processModelNodeMapper.selectOne(processModelNodeLambdaQueryWrapper);
processModelNodeLambdaQueryWrapper.clear();
//查找网关指向的线
processModelNodeLambdaQueryWrapper.eq(ProcessModelNode::getXmlSourceRef, gatewayOrigin.getXmlNodeId())
.eq(ProcessModelNode::getNodeName, "通过")
.eq(ProcessModelNode::getModelId, modelId);
ProcessModelNode flowOrigin2 = processModelNodeMapper.selectOne(processModelNodeLambdaQueryWrapper);
byte[] modelEditorSource = repositoryService.getModelEditorSource(modelId);
ObjectNode objectNode = (ObjectNode) new ObjectMapper().readTree(modelEditorSource);
BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(objectNode);
Process process = bpmnModel.getMainProcess();
SequenceFlow flowElement = (SequenceFlow) process.getFlowElement(flowOrigin2.getXmlNodeId());
process.removeFlowElement(flowOrigin2.getXmlNodeId());
//新增节点
UserTask userTask = createUserTask(nodeName);
String userTaskId = userTask.getId();
flowElement.setTargetRef(userTaskId);
process.addFlowElement(flowElement);
process.addFlowElement(userTask);
ExclusiveGateway gateway = createGateway(process, userTaskId, flowOrigin2.getXmlTargetRef(), processModelNode.getXmlNodeId());
process.addFlowElement(gateway);
List<SequenceFlow> incomingFlows1 = gateway.getIncomingFlows();
userTask.setOutgoingFlows(incomingFlows1);
//重新绘画图形
BpmnAutoLayout bpmnAutoLayout = new BpmnAutoLayout(bpmnModel);
bpmnAutoLayout.execute();
//更新model
ObjectNode objectNode1 = new BpmnJsonConverter().convertToJson(bpmnModel);
String json = objectNode1.toString();
byte[] bytes1 = json.getBytes(StandardCharsets.UTF_8);
repositoryService.addModelEditorSource(model.getId(), bytes1);
//把新增的节点同步到数据库
LambdaUpdateWrapper<ProcessModelNode> updateFlow = new LambdaUpdateWrapper<>();
updateFlow.eq(ProcessModelNode::getXmlNodeId,flowOrigin2.getXmlNodeId());
updateFlow.set(ProcessModelNode::getXmlTargetRef,userTaskId);
processModelNodeMapper.update(null,updateFlow);
insertUserTask(modelId, userTask);
List<SequenceFlow> incomingFlows = gateway.getIncomingFlows();
for (SequenceFlow incomingFlow : incomingFlows) {
insertFlow(modelId, incomingFlow);
}
insertGateway(modelId, gateway);
List<SequenceFlow> outgoingFlows = gateway.getOutgoingFlows();
for (SequenceFlow outgoingFlow : outgoingFlows) {
insertFlow(modelId, outgoingFlow);
}
//把bpmnModel对象转换成字符
BpmnXMLConverter converter = new BpmnXMLConverter();
byte[] bytes = converter.convertToXML(bpmnModel);
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
String filename = bpmnModel.getMainProcess().getId() + ".bpmn";
response.setContentType("application/force-download");// 设置强制下载不打开
response.setHeader("Content-Disposition", "attachment; filename=" + filename);
IOUtils.copy(in, response.getOutputStream());
response.flushBuffer();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private void insertGateway(String modelId, ExclusiveGateway gateway) {
ProcessModelNode gatewayNode = new ProcessModelNode();
gatewayNode.setModelId(modelId);
gatewayNode.setNodeName(gateway.getName());
gatewayNode.setNodeType("gateway");
gatewayNode.setXmlNodeId(gateway.getId());
gatewayNode.setIsApprovalNode(0);
gatewayNode.setIsCanDeleted(0);
processModelNodeMapper.insert(gatewayNode);
}
private void insertUserTask(String modelId, UserTask userTask) {
ProcessModelNode userTaskNode = new ProcessModelNode();
userTaskNode.setModelId(modelId);
userTaskNode.setNodeName(userTask.getName());
userTaskNode.setNodeType("userTask");
userTaskNode.setXmlNodeId(userTask.getId());
userTaskNode.setIsApprovalNode(1);
userTaskNode.setIsCanDeleted(1);
processModelNodeMapper.insert(userTaskNode);
}
private void insertFlow(String modelId, SequenceFlow incomingFlow) {
ProcessModelNode flowNode = new ProcessModelNode();
flowNode.setModelId(modelId);
flowNode.setNodeName(incomingFlow.getName());
flowNode.setNodeType("sequenceFlow");
flowNode.setXmlNodeId(incomingFlow.getId());
flowNode.setIsApprovalNode(0);
flowNode.setIsCanDeleted(0);
flowNode.setXmlSourceRef(incomingFlow.getSourceRef());
flowNode.setXmlTargetRef(incomingFlow.getTargetRef());
processModelNodeMapper.insert(flowNode);
}
protected static UserTask createUserTask(String name) {
String id = "Activity_" + RandomUtil.randomString(8);
UserTask userTask = new UserTask();
userTask.setName(name);
userTask.setId(id);
userTask.setAssignee("${"+id.replace("-","")+"}");
return userTask;
}
protected static SequenceFlow createSequenceFlow(String from, String to) {
SequenceFlow flow = new SequenceFlow();
flow.setSourceRef(from);
flow.setTargetRef(to);
flow.setId("Flow_"+ RandomUtil.randomString(8));
return flow;
}
protected static SequenceFlow createSequenceFlow(String from, String to,String name,String conditionExpression) {
SequenceFlow flow = new SequenceFlow();
flow.setSourceRef(from);
flow.setTargetRef(to);
flow.setName(name);
flow.setConditionExpression(conditionExpression);
flow.setId("Flow_"+ RandomUtil.randomString(8));
return flow;
}
protected static ExclusiveGateway createGateway(Process process, String originId, String targetIdYes, String targetIdNo) {
ExclusiveGateway gateway = new ExclusiveGateway();
String id = "Gateway_" + RandomUtil.randomString(8);
gateway.setId(id);
List<SequenceFlow> incomingFlows = new ArrayList<>();
SequenceFlow sequenceFlow = createSequenceFlow(originId, id);
process.addFlowElement(sequenceFlow);
incomingFlows.add(sequenceFlow);
gateway.setIncomingFlows(incomingFlows);
List<SequenceFlow> outgoingFlows = new ArrayList<>();
SequenceFlow sequenceFlow1 = createSequenceFlow(id, targetIdYes, "通过", "${pass}");
SequenceFlow sequenceFlow2 = createSequenceFlow(id, targetIdNo, "驳回", "${!pass}");
process.addFlowElement(sequenceFlow1);
process.addFlowElement(sequenceFlow2);
outgoingFlows.add(sequenceFlow1);
outgoingFlows.add(sequenceFlow2);
gateway.setOutgoingFlows(outgoingFlows);
return gateway;
}
private List<ProcessModelNode> handlerLawsProcessModelNode(
Collection<FlowElement> flowElements,
int sort,
List<String> gatewayIdList,
String modelId, String subNodeId) {
List<ProcessModelNode> processModelNodeList = new ArrayList<>();
for (FlowElement flowElement : flowElements) {
ProcessModelNode processModelNode = new ProcessModelNode();
String nodeName = processModelNode.getNodeName();
String nodeType = processModelNode.getNodeType();
String xmlNodeId = processModelNode.getXmlNodeId();
String xmlSourceRef = processModelNode.getXmlSourceRef();
String xmlTargetRef = processModelNode.getXmlTargetRef();
if (flowElement instanceof UserTask) {
UserTask userTask = (UserTask) flowElement;
nodeType = "userTask";
nodeName = userTask.getName();
xmlNodeId = userTask.getId();
} else if (flowElement instanceof SequenceFlow) {
SequenceFlow sequenceFlow = (SequenceFlow) flowElement;
nodeType = "sequenceFlow";
nodeName = sequenceFlow.getName();
xmlNodeId = sequenceFlow.getId();
xmlSourceRef = sequenceFlow.getSourceRef();
xmlTargetRef = sequenceFlow.getTargetRef();
} else if (flowElement instanceof ExclusiveGateway) {
ExclusiveGateway gateway = (ExclusiveGateway) flowElement;
nodeType = "gateway";
nodeName = gateway.getName();
xmlNodeId = gateway.getId();
gatewayIdList.add(xmlNodeId);
} else if (flowElement instanceof SubProcess) {
SubProcess subProcess = (SubProcess) flowElement;
Collection<FlowElement> flowElements1 = subProcess.getFlowElements();
xmlNodeId = subProcess.getId();
List<ProcessModelNode> processModelNodes = handlerLawsProcessModelNode(flowElements1, sort, gatewayIdList, modelId, xmlNodeId);
processModelNodeList.addAll(processModelNodes);
nodeType = "subProcess";
nodeName = subProcess.getName();
} else if (flowElement instanceof StartEvent) {
StartEvent startEvent = (StartEvent) flowElement;
nodeType = "startEvent";
nodeName = startEvent.getName();
xmlNodeId = startEvent.getId();
}else if (flowElement instanceof EndEvent) {
EndEvent endEvent = (EndEvent) flowElement;
nodeType = "endEvent";
nodeName = endEvent.getName();
xmlNodeId = endEvent.getId();
} else {
continue;
}
processModelNode.setModelId(modelId);
processModelNode.setNodeName(nodeName);
processModelNode.setNodeType(nodeType);
processModelNode.setXmlSubNodeId(subNodeId);
processModelNode.setXmlNodeId(xmlNodeId);
processModelNode.setXmlSourceRef(xmlSourceRef);
processModelNode.setXmlTargetRef(xmlTargetRef);
processModelNode.setSort(sort++);
processModelNode.setIsApprovalNode(YesOrNoEnum.NO.getInteger());
processModelNode.setIsCanDeleted(YesOrNoEnum.NO.getInteger());
processModelNodeList.add(processModelNode);
}
return processModelNodeList;
}
}
@@ -11,10 +11,10 @@ import lombok.Data;
@Data
public class AddTaskVO {
/**
* 流程定义id
* 模型id
*/
@ApiModelProperty(value = "流程定义id")
private String processDefinitionId;
@ApiModelProperty(value = "模型id")
private String modelId;
/**
* xml节点Id
*/