flowable已发起流程管理 1.新增节点、2.修改流程节点路径、3.移动某个节点(自由跳转,当前节点自动完成)

flowable已发起流程变更节点、修改节点路径、移动节点

1.引入包:为了后面自适应排版

implementation "org.flowable:flowable-bpmn-layout:6.4.1"

2.模版类:UserTaskDTO

@Data
public class UserTaskDTO {
    /**
     * type:0新增节点;1:修改流程节点路径
     */
    @NotNull(message = "type不能为空")
    private Integer type;
    /**
     * taskId:节点ID
     */
    private String taskId;
    /**
     * processInstanceId:流程ID
     */
    @NotBlank(message = "processInstanceId不能为空")
    private String processInstanceId;
    /**
     * 自定义ID或者是传入ID(为空是自动生成)
     */
    private String id;
    /**
     * 名称
     */
    private String name;
    /**
     * 人员变量
     */
    private String assignee;
    /**
     * 表单标识
     */
    private String formKey;
    /**
     * 多实例问题
     */
    private MultiInstanceLoopCharacteristicsDTO multiInstanceLoopCharacteristicsDTO;
    /**
     * 任务监听器列表
     */
    private List<TaskListenerDTO> taskListenerList;
    /**
     * 执行监听器列表
     */
    private List<ExecutionListenerDTO> executionListenerList;
    /**
     * 出线规律(不配置默认拿到当前节点的出线规则)
     */
    private List<SequenceFlowDTO> sequenceFlowList;
}

3.模版类:MultiInstanceLoopCharacteristicsDTO

 @Data
public class MultiInstanceLoopCharacteristicsDTO {

    /**完成条件
     1.${nrOfInstances == nrOfCompletedInstances}:表示所有人都需要完成任务会签才结束;
     2.${nrOfCompletedInstances == 1}:表示一个人完成任务,会签结束
     3.可自定义
    **/
    private String completionCondition;

    /**
     * 多实例类型(是否是顺序的)
     */
    private Boolean sequential;
    /**
     * //集合
     */
    private  String inputDataItem;

    /**
     * 元素变量
     */
    private  String elementVariable;

}

4.模版类:TaskListenerDTO

@Data
public class TaskListenerDTO {
    /**
     * 事件
     */
    private String event;
    /**
     * 类型 :class
     */
    private String implementationType ="class";
    /**
     * 类名称
     */
    private String implementation;
}

5.模版类:ExecutionListenerDTO

@Data
public class ExecutionListenerDTO {

    /**
     * 事件
     */
    private String event;
    /**
     * 类型 :class
     */
    private String implementationType ="class";
    /**
     * 类名称
     */
    private String implementation;
}

6.模版类:SequenceFlowDTO

@Data
public class SequenceFlowDTO {
    /**
     * 名称
     */
    private String name;
    /**
     * 描述
     */
    private String documentation;
    /**
     * 表达式
     */
    private String conditionExpression;
    /**
     * 进入的node节点id
     */
    private String sourceRef;
    /**
     * 转换的node节点id
     */
    private String targetRef;
    /**
     * 跳过表达式
     */
    private String skipExpression;

}

7.实现方法

@Slf4j
public class CustomInjectUserTaskInProcessInstanceCmd extends AbstractDynamicInjectionCmd implements Command<Void> {

    protected UserTaskDTO userTaskDTO;
    protected DynamicUserTaskBuilder dynamicUserTaskBuilder;

    private final FlowElement currentFlowElemet;

    public CustomInjectUserTaskInProcessInstanceCmd(UserTaskDTO userTaskDTO, DynamicUserTaskBuilder dynamicUserTaskBuilder, FlowElement currentFlowElemet) {
        this.userTaskDTO = userTaskDTO;
        this.dynamicUserTaskBuilder = dynamicUserTaskBuilder;
        this.currentFlowElemet = currentFlowElemet;
    }

    @Override
    public Void execute(CommandContext commandContext) {
        createDerivedProcessDefinitionForProcessInstance(commandContext, userTaskDTO.getProcessInstanceId());
        return null;
    }

    @Override
    protected void updateBpmnProcess(CommandContext commandContext, Process process,
                                     BpmnModel bpmnModel, ProcessDefinitionEntity originalProcessDefinitionEntity, DeploymentEntity newDeploymentEntity){

        //type:0新增节点;1:修改流程节点路径
        if(userTaskDTO.getType().equals(0)){
            List<StartEvent> startEvents = process.findFlowElementsOfType(StartEvent.class);
            StartEvent initialStartEvent = null;
            for (StartEvent startEvent : startEvents) {
                if (startEvent.getEventDefinitions().isEmpty()) {
                    initialStartEvent = startEvent;
                    break;
                } else if (initialStartEvent == null) {
                    initialStartEvent = startEvent;
                }
            }
            
                UserTask userTask = new UserTask();
                userTask.setId(userTaskDTO.getId());
                userTask.setName(userTaskDTO.getName());
                userTask.setAssignee(userTaskDTO.getAssignee());

                // 设置任务监听器
                if(CollectionUtil.isNotEmpty(userTaskDTO.getTaskListenerList())){
                    List<FlowableListener>flowableListenerList=new ArrayList<>();
                    userTaskDTO.getTaskListenerList().forEach(task->{
                        FlowableListener flowableListener=new FlowableListener();
                        flowableListener.setEvent(task.getEvent());
                        flowableListener.setImplementationType(task.getImplementationType());
                        flowableListener.setImplementation(task.getImplementation());
                        flowableListenerList.add(flowableListener);
                    });
                    userTask.setTaskListeners(flowableListenerList);
                }
                // 设置执行监听器
                if(CollectionUtil.isNotEmpty(userTaskDTO.getExecutionListenerList())){
                    List<FlowableListener>flowableListenerList=new ArrayList<>();
                    userTaskDTO.getExecutionListenerList().forEach(execution->{
                        FlowableListener flowableListener=new FlowableListener();
                        flowableListener.setEvent(execution.getEvent());
                        flowableListener.setImplementationType(execution.getImplementationType());
                        flowableListener.setImplementation(execution.getImplementation());
                        flowableListenerList.add(flowableListener);
                    });
                    userTask.setExecutionListeners(flowableListenerList);
                }

                //formKey
                if(StrUtil.isNotBlank(userTaskDTO.getFormKey())){
                    userTask.setFormKey(userTaskDTO.getFormKey());
                }


                //多实例问题
                MultiInstanceLoopCharacteristicsDTO multiInstanceLoopCharacteristicsDtos = userTaskDTO.getMultiInstanceLoopCharacteristicsDTO();
                if(multiInstanceLoopCharacteristicsDtos!=null){
                    MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics=new MultiInstanceLoopCharacteristics();
                    multiInstanceLoopCharacteristics.setCompletionCondition(multiInstanceLoopCharacteristicsDtos.getCompletionCondition());
                    multiInstanceLoopCharacteristics.setSequential(multiInstanceLoopCharacteristicsDtos.getSequential());
                    multiInstanceLoopCharacteristics.setInputDataItem(multiInstanceLoopCharacteristicsDtos.getInputDataItem());
                    multiInstanceLoopCharacteristics.setElementVariable(multiInstanceLoopCharacteristicsDtos.getElementVariable());
                    userTask.setLoopCharacteristics(multiInstanceLoopCharacteristics);
                }

                UserTask currentFlowElemet = (UserTask) this.currentFlowElemet;
                SequenceFlow sequenceFlow;

                List<SequenceFlow> outgoingFlows = new ArrayList<>();
                if(CollectionUtil.isNotEmpty(userTaskDTO.getSequenceFlowList())){
                    for (SequenceFlow sequenceFlow1 : currentFlowElemet.getOutgoingFlows()) {
                        //删除原先节点的出线
                        process.removeFlowElement(sequenceFlow1.getId());
                    }
                    //增加新的线段
                    for (SequenceFlowDTO sequenceFlowNew :userTaskDTO.getSequenceFlowList()){
                        sequenceFlow = new SequenceFlow(StrUtil.isBlank(sequenceFlowNew.getSourceRef())?userTask.getId():sequenceFlowNew.getSourceRef(),sequenceFlowNew.getTargetRef());
                        sequenceFlow.setSkipExpression(sequenceFlowNew.getSkipExpression());
                        sequenceFlow.setConditionExpression(sequenceFlowNew.getConditionExpression());
                        sequenceFlow.setName(sequenceFlowNew.getName());
                        sequenceFlow.setId("seq_"+ UUID.randomUUID().toString().replaceAll("-","" ));
                        outgoingFlows.add(sequenceFlow);
                        process.addFlowElement(sequenceFlow);
                    }

                }else{
                    for (SequenceFlow sequenceFlow1 : currentFlowElemet.getOutgoingFlows()) {
                        sequenceFlow = new SequenceFlow(userTask.getId(),sequenceFlow1.getTargetRef());
                        sequenceFlow.setSkipExpression(sequenceFlow1.getSkipExpression());
                        sequenceFlow.setConditionExpression(sequenceFlow1.getConditionExpression());
                        sequenceFlow.setExtensionElements(sequenceFlow1.getExtensionElements());
                        sequenceFlow.setExecutionListeners(sequenceFlow1.getExecutionListeners());
                        sequenceFlow.setName(sequenceFlow1.getName());
                        sequenceFlow.setId("seq_"+ UUID.randomUUID().toString().replaceAll("-","" ));
                        outgoingFlows.add(sequenceFlow);
                        //删除原先节点的出线
                        process.removeFlowElement(sequenceFlow1.getId());
                        process.addFlowElement(sequenceFlow);
                    }
                }


                List<SequenceFlow> incomingFlows = new ArrayList<>();
                SequenceFlow incomingFlow = new  SequenceFlow(currentFlowElemet.getId(),userTask.getId());
                // 可以设置唯一编号,这里通过雪花算法设置
                incomingFlow.setId("seq_"+ UUID.randomUUID().toString().replaceAll("-","" ));
                incomingFlows.add(incomingFlow);

                process.addFlowElement(incomingFlow);
                userTask.setOutgoingFlows(outgoingFlows);
                userTask.setIncomingFlows(incomingFlows);
                process.addFlowElement(userTask);

                //新增坐标 点
                GraphicInfo elementGraphicInfo = bpmnModel.getGraphicInfo(currentFlowElemet.getId());
                if (elementGraphicInfo != null) {
                    double yDiff = 0;
                    double xDiff = 80;
                    if (elementGraphicInfo.getY() < 173) {
                        yDiff = 173 - elementGraphicInfo.getY();
                        elementGraphicInfo.setY(173);
                    }

                    Map<String, GraphicInfo> locationMap = bpmnModel.getLocationMap();
                    for (String locationId : locationMap.keySet()) {
                        if (initialStartEvent != null && initialStartEvent.getId().equals(locationId)) {
                            continue;
                        }
                        GraphicInfo locationGraphicInfo = locationMap.get(locationId);
                        locationGraphicInfo.setX(locationGraphicInfo.getX() + xDiff);
                        locationGraphicInfo.setY(locationGraphicInfo.getY() + yDiff);
                    }

                    Map<String, List<GraphicInfo>> flowLocationMap = bpmnModel.getFlowLocationMap();
                    for (String flowId : flowLocationMap.keySet()) {
                        List<GraphicInfo> flowGraphicInfoList = flowLocationMap.get(flowId);
                        for (GraphicInfo flowGraphicInfo : flowGraphicInfoList) {
                            flowGraphicInfo.setX(flowGraphicInfo.getX() + xDiff);
                            flowGraphicInfo.setY(flowGraphicInfo.getY() + yDiff);
                        }
                    }
                    new BpmnAutoLayout(bpmnModel).execute();
                }
            }

        }else if(userTaskDTO.getType().equals(1)){
            UserTask currentFlowElemet = (UserTask) this.currentFlowElemet;
            SequenceFlow sequenceFlow;
            List<SequenceFlow> outgoingFlows = new ArrayList<>();

            if(CollectionUtil.isNotEmpty(userTaskDTO.getSequenceFlowList())){
                process.removeFlowElement(currentFlowElemet.getId());
                for (SequenceFlow sequenceFlow1 : currentFlowElemet.getOutgoingFlows()) {
                    //删除原先节点的出线
                    process.removeFlowElement(sequenceFlow1.getId());
                }
                //增加新的线段
                for (SequenceFlowDTO sequenceFlowNew :userTaskDTO.getSequenceFlowList()){
                    sequenceFlow = new SequenceFlow(currentFlowElemet.getId(),sequenceFlowNew.getTargetRef());
                    sequenceFlow.setSkipExpression(sequenceFlowNew.getSkipExpression());
                    sequenceFlow.setConditionExpression(sequenceFlowNew.getConditionExpression());
                    sequenceFlow.setName(sequenceFlowNew.getName());
                    sequenceFlow.setId("seq_"+ UUID.randomUUID().toString().replaceAll("-","" ));
                    outgoingFlows.add(sequenceFlow);
                    process.addFlowElement(sequenceFlow);
                }

            }
            currentFlowElemet.setOutgoingFlows(outgoingFlows);
            process.addFlowElement(currentFlowElemet);
            GraphicInfo elementGraphicInfo = bpmnModel.getGraphicInfo(currentFlowElemet.getId());
            if (elementGraphicInfo != null) {
                new BpmnAutoLayout(bpmnModel).execute();
            }
        }

        BaseDynamicSubProcessInjectUtil.processFlowElements(commandContext, process, bpmnModel, originalProcessDefinitionEntity, newDeploymentEntity);
    }
    
    @Override
    protected void updateExecutions(CommandContext commandContext, ProcessDefinitionEntity processDefinitionEntity,
                                    ExecutionEntity processInstance, List<ExecutionEntity> childExecutions) {
        BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinitionEntity.getId());
        try {
            BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
            byte[] bpmnBytes = bpmnXMLConverter.convertToXML(bpmnModel);
            String bpmnXml = new String(bpmnBytes, StandardCharsets.UTF_8);
            // 打印XML
            System.out.println(bpmnXml);
        }catch (Exception e){
            log.error(e.getMessage());
        }
    }

8.调用方法

@Component
@RequiredArgsConstructor
@Slf4j
public class UpdateBpmnUtil {

    private final ProcessEngine processEngine;

    public void updateBpmn(UserTaskDTO userTaskDTO) {
        if(userTaskDTO.getType().equals(1)){
            if (StrUtil.isBlank(userTaskDTO.getId())){
                throw new CustomException("9999", "移动节点NodeID不存在!");
            }
        }

        if (CollectionUtil.isNotEmpty(userTaskDTO.getExecutionListenerList())) {
            userTaskDTO.getExecutionListenerList().forEach(execution -> {
                if (!execution.getEvent().equals("start") && !execution.getEvent().equals("end") && !execution.getEvent().equals("task")) {
                    throw new CustomException("9999", "执行监听器不存在此类型!");
                }
                if (classIsExist(execution.getImplementation())) {
                    throw new CustomException("9999", "此类:" + execution.getImplementation() + "不存在");
                }
            });
        }

        if (CollectionUtil.isNotEmpty(userTaskDTO.getTaskListenerList())) {
            userTaskDTO.getTaskListenerList().forEach(task -> {
                if (!task.getEvent().equals("create") && !task.getEvent().equals("assignment") && !task.getEvent().equals("complete") && !task.getEvent().equals("delete")) {
                    throw new CustomException("9999", "任务监听器不存在");
                }
                if (classIsExist(task.getImplementation())) {
                    throw new CustomException("9999", "此类:" + task.getImplementation() + "不存在");
                }
            });
        }

        if (CollectionUtil.isNotEmpty(userTaskDTO.getSequenceFlowList())) {
            Set<String> sequenceKey=new HashSet<>();
            userTaskDTO.getSequenceFlowList().forEach(sequence -> {
               if(!sequenceKey.contains(sequence.getConditionExpression())){
                   sequenceKey.add(sequence.getConditionExpression());
               }else{
                   throw new CustomException("9999", "此:" +sequence.getConditionExpression()  + "表达式重复!");
               }
            });
        }

        DynamicUserTaskBuilder dynamicUserTaskBuilder = new DynamicUserTaskBuilder();
        if (StrUtil.isBlank(userTaskDTO.getId())) {
            userTaskDTO.setId("sid-" + UUID.randomUUID());
        } else {
            userTaskDTO.setId("sid-" + userTaskDTO.getId());
        }
        List<Task> list = processEngine.getTaskService().createTaskQuery().active().taskId(userTaskDTO.getTaskId()).list();
        if (CollectionUtil.isEmpty(list)) {
            list = processEngine.getTaskService().createTaskQuery().active().processInstanceId(userTaskDTO.getProcessInstanceId()).list();
        }
        if (CollectionUtil.isNotEmpty(list)) {
            Task task = list.get(0);
            BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(task.getProcessDefinitionId());
            dynamicUserTaskBuilder.setId(userTaskDTO.getId());
            dynamicUserTaskBuilder.setAssignee(userTaskDTO.getAssignee());
            dynamicUserTaskBuilder.setName(userTaskDTO.getName());

            Process process = bpmnModel.getProcesses().get(0);
            try {
                processEngine.getManagementService().executeCommand(new CustomInjectUserTaskInProcessInstanceCmd(userTaskDTO, dynamicUserTaskBuilder, process.getFlowElement(task.getTaskDefinitionKey())));
            } catch (Exception e) {
                throw new CustomException("999999", e.getMessage());
            }
        }
    }

    /**
     * 检验类是否存在
     *
     * @param className className路径
     * @return boolean
     */
    public boolean classIsExist(String className) {
        try {
            String path = ResourceUtils.getURL("classpath:").getPath();
            File file = new File(path + className.replace(".", "/") + ".class");
            return !file.exists();
        } catch (Exception e) {
            // 类不存在
            return true;
        }
    }

    /**
     * 移动某个节点(自由跳转,当前节点自动完成)
     *
     * @param moveNodeDTO moveNodeDTO
     */
    public void moveNode(MoveNodeDTO moveNodeDTO) {
        processEngine.getRuntimeService().createChangeActivityStateBuilder()
                .processInstanceId(moveNodeDTO.getProcessInstanceId())
                .moveActivityIdTo(moveNodeDTO.getNodeId(), moveNodeDTO.getToNodeId())
                .changeState();
    }

    /**
     * 查看流程引擎xml文件
     *
     * @param bpmnGetMyTaskDTO bpmnGetMyTaskDTO
     */
    public String lookXmlForFlowable(BpmnGetMyTaskDTO bpmnGetMyTaskDTO) {
        String bpmnXml = "";
        List<HistoricTaskInstance> list = processEngine.getHistoryService().createHistoricTaskInstanceQuery().processInstanceId(bpmnGetMyTaskDTO.getProcessInstanceId()).list();
        if (CollectionUtil.isNotEmpty(list)) {
            BpmnModel bpmnModel =  processEngine.getRepositoryService().getBpmnModel(list.get(0).getProcessDefinitionId());
            BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
            byte[] bpmnBytes = bpmnXMLConverter.convertToXML(bpmnModel);
            bpmnXml = new String(bpmnBytes, StandardCharsets.UTF_8);
            System.out.println(bpmnXml);
        }

        return bpmnXml;
    }

9.入参JSON

  1. 新增节点 (所有的操作仅在流程流转到当前节点。配置下一节点有效)
{
	"type":0,
	"processInstanceId": "??????",
	"taskId": "??????",
	"id": "??????",
	"formKey": "",
	"name": "新增节点40",
	"assignee": "${user}",
	"multiInstanceLoopCharacteristicsDTO": {
		"completionCondition": "??????",
		"sequential": false,
		"inputDataItem": "${UserList}",
		"elementVariable": "user"
	},
	"taskListenerList": [
		{
			"event": "create",
			"implementationType": "class",
			"implementation": "*.listener.TestTaskListener"
		},
		{
			"event": "complete",
			"implementationType": "class",
			"implementation": "*.listener.TestTaskListener"
		}
	],
	"executionListenerList": [
		{
			"event": "start",
			"implementationType": "class",
			"implementation": "*.listener.TestListener"
		},
		{
			"event": "end",
			"implementationType": "class",
			"implementation": "*.listener.TestListener"
		}
	]
	,
	"sequenceFlowList": [
		 {
		 	"name": "3333",
		 	"documentation": "55555555",
			"conditionExpression": "${ok == 0}",
		 	"sourceRef": "",
		 	"targetRef": "??????",
		 	"skipExpression": ""
		 }
		, {
			"name": "44444",
		 	"documentation": "66666",
		 	"conditionExpression": "${ok == 1}",
		 	"sourceRef": "",
		 	"targetRef": "??????",
		 	"skipExpression": ""
		 },
		 {
		 	"name": "77777",
		 	"documentation": "88888",
		 	"conditionExpression": "${ok == 2}",
		 	"sourceRef": "",
		 	"targetRef": "??????",
		 	"skipExpression": ""
		 }
	]
}
  1. 查看流程引擎xml文件
{
	"processInstanceId": "??????"
}
  1. 修改流程节点路径 (所有的操作仅在流程流转到当前节点。配置下一节点有效)
{
	"type": 1,
	"processInstanceId": "??????",
	"taskId": "??????",
	"id":"??????",
	"sequenceFlowList": [
		{
			"name": "3333",
			"documentation": "55555555",
			"conditionExpression": "${ok == 1}",
			"targetRef": "??????",
			"skipExpression": ""
		}
		, {
			"name": "44444",
			"documentation": "66666",
			"conditionExpression": "${ok == 0}",
			"sourceRef": "",
			"targetRef": "??????",
			"skipExpression": ""
		}
	]
}
  • 15
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值