静态解析activiti文本,不入库操作流程
说明:
activiti本身状态存库,导致效率太低,把中间状态封装成一个载荷类,返回给上游,下次请求时给带着载荷类即可。
1.pom依赖
<dependency><groupId>net.sf.json-lib</groupId><artifactId>json-lib</artifactId><version>${json-lib.version}</version><classifier>jdk15</classifier></dependency><dependency><groupId>org.activiti</groupId><artifactId>activiti-engine</artifactId><version>5.22.0</version></dependency><dependency><groupId>org.activiti</groupId><artifactId>activiti-bpmn-converter</artifactId><version>5.22.0</version></dependency><dependency><groupId>org.activiti</groupId><artifactId>activiti-bpmn-model</artifactId><version>5.22.0</version></dependency>
2.关键类
2.1解析类-BPMNService
package cn.com.agree.activiti10;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.CallActivity;
import org.activiti.bpmn.model.EndEvent;
import org.activiti.bpmn.model.ExclusiveGateway;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.InclusiveGateway;
import org.activiti.bpmn.model.ParallelGateway;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.StartEvent;
import org.activiti.bpmn.model.SubProcess;
import org.activiti.engine.impl.util.io.InputStreamSource;
import org.mvel2.MVEL;import log.cn.com.agree.ab.a5.runtime.InvokeLog;import java.io.FileInputStream;
import java.io.InputStream;
import java.util.*;
/*** 静态解析bpmn文件 -返回payLoad* payLoad:包含相关信息,替代数据库中 存储的信息。比如当前交易名,对象组名,整体链路节点等* 每次请求时带着payLoad* @author fanjinliang@agree.com.cn**/
public class BPMNService {private Map<String, BpmnModel> bpmnModelMap = new HashMap<>();private Map<String, Process> processMap = new HashMap<>();// 初始化方法,在服务启动时调用public void init(List<String> bpmnFilePaths) throws Exception {for (String filePath : bpmnFilePaths) {loadBpmnModel(filePath);}}// 加载单个 BPMN 文件private void loadBpmnModel(String bpmnFilePath) throws Exception {InputStream bpmnStream = new FileInputStream(bpmnFilePath);BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();InputStreamSource inputStreamSource = new InputStreamSource(bpmnStream);BpmnModel bpmnModel = bpmnXMLConverter.convertToBpmnModel(inputStreamSource, false, false);bpmnStream.close();for (Process process : bpmnModel.getProcesses()) {String definitionKey = process.getId();bpmnModelMap.put(definitionKey, bpmnModel);processMap.put(definitionKey, process);}}// 根据 definitionKey 获取 Processpublic Process getProcessByDefinitionKey(String definitionKey) {return processMap.get(definitionKey);}// 根据当前节点的 ID 获取下一个节点(包括处理网关和嵌套流程)public FlowElement getNextFlowElement(String definitionKey, String currentElementId, Map<String, Object> variables) throws ActivitiException{Process process = getProcessByDefinitionKey(definitionKey);if (process == null||process.getFlowElement(currentElementId)==null) {return null;}FlowElement currentElement = process.getFlowElement(currentElementId);FlowElement flowElement =null;if (currentElement instanceof FlowNode) {List<SequenceFlow> outgoingFlows = ((FlowNode) currentElement).getOutgoingFlows();if (outgoingFlows.isEmpty()) {return null;}Class<?> currentElementType = currentElement.getClass();switch (currentElementType.getSimpleName()) {case "ExclusiveGateway":// 处理排他网关for (SequenceFlow outgoingFlow : outgoingFlows) {if (evaluateCondition(outgoingFlow.getConditionExpression(), variables)) {return process.getFlowElement(outgoingFlow.getTargetRef());}}
// InvokeLog.error("网关不匹配");throw new ActivitiException(ActivitiServiceResults.BIZ002_网关未匹配);
// break;case "ParallelGateway":case "InclusiveGateway":// 处理并行网关或包容网关,假设返回第一个符合条件的目标节点for (SequenceFlow outgoingFlow : outgoingFlows) {return process.getFlowElement(outgoingFlow.getTargetRef());}break;case "CallActivity":// 处理 CallActivityString calledElement = ((CallActivity) currentElement).getCalledElement();Process calledProcess = getProcessByDefinitionKey(calledElement);if (calledProcess != null) {// 假设子流程的开始事件是唯一的for (FlowElement element : calledProcess.getFlowElements()) {if (element instanceof StartEvent) {return element;}}}break;case "SubProcess":// 处理 SubProcessflowElement = process.getFlowElement(outgoingFlows.get(0).getTargetRef());break;default:// 默认处理,返回第一个目标节点flowElement = process.getFlowElement(outgoingFlows.get(0).getTargetRef());break;}// if (currentElement instanceof ExclusiveGateway) {// // 处理排他网关// for (SequenceFlow outgoingFlow : outgoingFlows) {// if (evaluateCondition(outgoingFlow.getConditionExpression(), variables)) {// return process.getFlowElement(outgoingFlow.getTargetRef());// }else {// throw new RuntimeException("网关不匹配");// }// }// } else if (currentElement instanceof ParallelGateway || currentElement instanceof InclusiveGateway) {// // 处理并行网关或包容网关,假设返回第一个符合条件的目标节点// for (SequenceFlow outgoingFlow : outgoingFlows) {// return process.getFlowElement(outgoingFlow.getTargetRef());// }// } else if (currentElement instanceof CallActivity) {// // 处理 callActivity// String calledElement = ((CallActivity) currentElement).getCalledElement();// Process calledProcess = getProcessByDefinitionKey(calledElement);// if (calledProcess != null) {// // 假设子流程的开始事件是唯一的// for (FlowElement element : calledProcess.getFlowElements()) {// if (element instanceof StartEvent) {// return element;// }// }// }// } else if (currentElement instanceof SubProcess) {// // 处理 SubProcess// flowElement =process.getFlowElement(outgoingFlows.get(0).getTargetRef());// } // else {// flowElement = process.getFlowElement(outgoingFlows.get(0).getTargetRef());// // 默认处理,返回第一个目标节点// }}//判断flowElement的类型if (flowElement!=null) {//对象组后的汇总网关放过就行if (currentElement instanceof SubProcess&&flowElement instanceof ParallelGateway) {flowElement=getNextFlowElement(process, flowElement.getId(), variables);}}return flowElement;}private boolean evaluateCondition(String conditionExpression, Map<String, Object> variables) {if (conditionExpression == null || conditionExpression.trim().isEmpty()) {return true; // 无条件表达式时默认返回 true}return MVEL.evalToBoolean(conditionExpression.replaceAll("\\$|\\{|\\}", ""), variables);}public ProcessPayload startProcess(String definitionKey, Map<String, Object> var) throws ActivitiException {// TODO Auto-generated method stubProcess process = processMap.get(definitionKey);if (process==null) {throw new ActivitiException(ActivitiServiceResults.BIZ001_流程定义不存在);}Collection<FlowElement> flowElements = process.getFlowElements();String startId="";for (FlowElement e : flowElements) {if (e instanceof StartEvent) {startId = e.getId();break;}}FlowElement nextFlowElement = getNextFlowElement(definitionKey, startId, var);ProcessPayload processPayload=new ProcessPayload(definitionKey, process.getName());refreshProcessPayload(processPayload,nextFlowElement);return processPayload;}private void refreshProcessPayload(ProcessPayload processPayload, FlowElement nextFlowElement) {// TODO Auto-generated method stubif (nextFlowElement==null) {processPayload.setEnd(true);return;}String id=nextFlowElement.getId();String name=nextFlowElement.getName();String type = nextFlowElement.getClass().getSimpleName();SimpleFlowElement simpleFlowElement = new SimpleFlowElement(id, name, type);Set<String> objIds=new HashSet<String>();if ("SubProcess".equalsIgnoreCase(type)) {//对象组simpleFlowElement.setSubProcess(true);SubProcess sub=(SubProcess)nextFlowElement;List<SimpleFlowElement> subSimpleFlowElement=getSubProcessSimpleFlowElement(sub);//更新当前对象组的对象列表simpleFlowElement.setSubSimpleFlowElement(subSimpleFlowElement);for (SimpleFlowElement e : subSimpleFlowElement) {objIds.add(e.getId());}//更新当前对象组的对象id列表}else if ("ExclusiveGateway".equalsIgnoreCase(type)) {simpleFlowElement.setExclusiveGateway(true);objIds.add(simpleFlowElement.getId());}else if ("ParallelGateway".equalsIgnoreCase(type)) {simpleFlowElement.setParallelGateway(true);objIds.add(simpleFlowElement.getId());}else {objIds.add(simpleFlowElement.getId());}processPayload.setCurrentObjtIdSet(objIds);processPayload.setCurrentFlowElement(simpleFlowElement);}/*** 获取对象组内的对象节点信息* @param process* @return*/private List<SimpleFlowElement> getSubProcessSimpleFlowElement(SubProcess process) {// TODO Auto-generated method stubList<SimpleFlowElement> list=new ArrayList<SimpleFlowElement>();Collection<FlowElement> flowElements = process.getFlowElements();for (FlowElement e : flowElements) {if (!(e instanceof StartEvent || e instanceof EndEvent || e instanceof SequenceFlow)) {String id=e.getId();String name=e.getName();String type = e.getClass().getSimpleName();SimpleFlowElement simpleFlowElement = new SimpleFlowElement(id, name, type);list.add(simpleFlowElement);}}return list;}private FlowElement getNextFlowElement(Process process, String currentElementId, Map<String, Object> var) {if (process == null) {return null;}FlowElement currentElement = process.getFlowElement(currentElementId);if (currentElement == null) {return null;}if (currentElement instanceof FlowNode) {List<SequenceFlow> outgoingFlows = ((FlowNode) currentElement).getOutgoingFlows();if (outgoingFlows.isEmpty()) {return null;}if (currentElement instanceof ExclusiveGateway) {// 处理排他网关for (SequenceFlow outgoingFlow : outgoingFlows) {if (evaluateCondition(outgoingFlow.getConditionExpression(), var)) {return process.getFlowElement(outgoingFlow.getTargetRef());}}} else if (currentElement instanceof ParallelGateway || currentElement instanceof InclusiveGateway) {// 处理并行网关或包容网关,假设返回第一个符合条件的目标节点for (SequenceFlow outgoingFlow : outgoingFlows) {return process.getFlowElement(outgoingFlow.getTargetRef());}} else if (currentElement instanceof CallActivity) {// 处理 callActivityString calledElement = ((CallActivity) currentElement).getCalledElement();Process calledProcess = getProcessByDefinitionKey(calledElement);if (calledProcess != null) {// 假设子流程的开始事件是唯一的for (FlowElement element : calledProcess.getFlowElements()) {if (element instanceof StartEvent) {return element;}}}} else {// 默认处理,返回第一个目标节点return process.getFlowElement(outgoingFlows.get(0).getTargetRef());}}return null;}public ProcessPayload commitProcess(ProcessPayload processPayload, Set<String> commitObjIdSet, Map<String, Object> var) {try {SimpleFlowElement currentFlowElement = processPayload.getCurrentFlowElement();if (currentFlowElement.isSubProcess()) {//处理对象组List<SimpleFlowElement> subSimpleFlowElement = currentFlowElement.getSubSimpleFlowElement();for (String string : commitObjIdSet) {for (SimpleFlowElement e : subSimpleFlowElement) {if (e.getId().equalsIgnoreCase(string)) {e.setCommit(true);processPayload.getCurrentObjtIdSet().remove(string);currentFlowElement.getFlowElementNum().addAndGet(1);}}}// if (currentFlowElement.getFlowElementNum().get()==subSimpleFlowElement.size()) {// //当前对象组提交完毕// // }if (processPayload.getCurrentObjtIdSet().size()==0) {//当前对象组提交完毕//1.更新当前节点状态currentFlowElement.setCommit(true);//2.更新历史节点processPayload.addHistoryFlowElement(currentFlowElement);//3.获取下一节点并且封装对象FlowElement nextFlowElement = getNextFlowElement(processPayload.getId(), currentFlowElement.getId(), var);refreshProcessPayload(processPayload, nextFlowElement);
// return processPayload;}else {//仍然返回当前节点
// return processPayload;}}else {//非对象组currentFlowElement.setCommit(true);//2.更新历史节点processPayload.addHistoryFlowElement(currentFlowElement);//3.获取下一节点并且封装对象FlowElement nextFlowElement = getNextFlowElement(processPayload.getId(), currentFlowElement.getId(), var);refreshProcessPayload(processPayload, nextFlowElement);}} catch (Exception e) {e.printStackTrace();if (e instanceof ActivitiException) {ActivitiException ae=(ActivitiException) e;processPayload.setErrorInfo(ae);}}return processPayload;}}
2.2 自定义节点类-SimpleFlowElement
package cn.com.agree.activiti10;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;public class SimpleFlowElement {private String id;private String name;private String type; // Task, Event, Gateway, etc./* 标识对象是否提交 */private boolean isCommit=false;/* 当前节点是否是对象组 */private boolean isSubProcess;/* 当前节点是否是排他网关 */private boolean isExclusiveGateway;/* 当前节点是否是并行网关 */private boolean isParallelGateway;/* 如果是对象组,保留组内对象 */List<SimpleFlowElement> subSimpleFlowElement=new ArrayList<SimpleFlowElement>();private AtomicInteger flowElementNum=new AtomicInteger(0);public SimpleFlowElement(String id, String name, String type) {this.id = id;this.name = name;this.type = type;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getType() {return type;}public void setType(String type) {this.type = type;}public boolean isCommit() {return isCommit;}public void setCommit(boolean isCommit) {this.isCommit = isCommit;}public boolean isSubProcess() {return isSubProcess;}public void setSubProcess(boolean isSubProcess) {this.isSubProcess = isSubProcess;}public List<SimpleFlowElement> getSubSimpleFlowElement() {return subSimpleFlowElement;}public void setSubSimpleFlowElement(List<SimpleFlowElement> subSimpleFlowElement) {this.subSimpleFlowElement = subSimpleFlowElement;}public boolean isExclusiveGateway() {return isExclusiveGateway;}public void setExclusiveGateway(boolean isExclusiveGateway) {this.isExclusiveGateway = isExclusiveGateway;}public boolean isParallelGateway() {return isParallelGateway;}public void setParallelGateway(boolean isParallelGateway) {this.isParallelGateway = isParallelGateway;}public AtomicInteger getFlowElementNum() {return flowElementNum;}public void setFlowElementNum(AtomicInteger flowElementNum) {this.flowElementNum = flowElementNum;}}
2.3 自定义载荷类
package cn.com.agree.activiti10;import java.util.ArrayList;
import java.util.List;
import java.util.Set;public class ProcessPayload {/* 活动ID */private String id;/* 活动name */private String name;/* 当前节点 */private SimpleFlowElement currentFlowElement;/* 历史节点 */private List<SimpleFlowElement> historyFlowElement=new ArrayList<SimpleFlowElement>();// /* 一级流程下的节点ID ---合并到currentFlowElement*/
// private String currentObjtId;/* 提交上来的taskId */
// private Set<String> commitObjtId;// /* 当前节点是否是对象组 ---合并到currentFlowElement */
// private boolean isSubProcess;// /* 当前待做的taskId,如果是对象组,那就是多个 ---合并到currentFlowElement*/private Set<String> currentObjtIdSet;private boolean end=false;//TODO 接收到json串的时候,记得把上次可能存在的错误信息给重置下private String code="200";private String message;public ProcessPayload() {}public ProcessPayload(String id, String name) {this.id = id;this.name = name;}public ProcessPayload errorProcessPayload(String msg) {this.setCode("400");this.setMessage(msg);return this;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public SimpleFlowElement getCurrentFlowElement() {return currentFlowElement;}public void setCurrentFlowElement(SimpleFlowElement currentFlowElement) {this.currentFlowElement = currentFlowElement;}// public Set<String> getCommitObjtId() {
// return commitObjtId;
// }
//
//
//
// public void setCommitObjtId(Set<String> commitObjtId) {
// this.commitObjtId = commitObjtId;
// }public boolean isEnd() {return end;}public void setEnd(boolean end) {this.end = end;}public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public List<SimpleFlowElement> getHistoryFlowElement() {return historyFlowElement;}public void setHistoryFlowElement(List<SimpleFlowElement> historyFlowElement) {this.historyFlowElement = historyFlowElement;}public Set<String> getCurrentObjtIdSet() {return currentObjtIdSet;}public void setCurrentObjtIdSet(Set<String> currentObjtIdSet) {this.currentObjtIdSet = currentObjtIdSet;}public void addHistoryFlowElement(SimpleFlowElement historyFlowElement) {getHistoryFlowElement().add(historyFlowElement);}public void setErrorInfo(ActivitiException ae) {this.setCode(ae.getCode());this.setMessage(ae.getMessage());}}
2.4 测试类
package cn.com.agree.activiti10;import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;import org.activiti.bpmn.model.FlowElement;import com.alibaba.fastjson.JSON;public class Test {public static void main(String[] args) {try {BPMNService bpmnService = new BPMNService();// bpmnService.init(Arrays.asList("bpmn\\index.flow.bpmn"));// String definitionKey = "trade/test";// String startNodeId = "task2";bpmnService.init(Arrays.asList("bpmn\\index.activity.bpmn"));String definitionKey = "publicAc";Map<String,Object>var=new HashMap<String,Object>();var.put("a", "2");ProcessPayload processPayload=bpmnService.startProcess(definitionKey,var);String jsonString = JSON.toJSONString(processPayload);System.out.println(jsonString);while (!processPayload.isEnd()) {SimpleFlowElement currentFlowElement = processPayload.getCurrentFlowElement();System.out.println("currentFlowElement ID: " + currentFlowElement.getId());System.out.println("currentFlowElement Name: " + currentFlowElement.getName());System.out.println("currentObjIds : " + processPayload.getCurrentObjtIdSet());System.out.println("=========================================================");Set<String> currentObjtIdSet = processPayload.getCurrentObjtIdSet();Set<String>commitObjIdSet=new HashSet<String>();commitObjIdSet.addAll(currentObjtIdSet);processPayload=bpmnService.commitProcess(processPayload,commitObjIdSet,var);if (!"200".equalsIgnoreCase(processPayload.getCode())) {System.out.println(processPayload.getCode()+"--"+processPayload.getMessage());break;}
// jsonString = JSON.toJSONString(processPayload);
// System.out.println("processPayload"+jsonString);}} catch (Exception e) {e.printStackTrace();}}
}
2.5 其他类
package cn.com.agree.activiti10;public class ActivitiException extends Exception{/*** */private static final long serialVersionUID = 1L;private String code;private String detail;public ActivitiException(ActivitiServiceResults callResult){super(callResult.getMessage());this.code = callResult.getCode();}public ActivitiException(ActivitiServiceResults callResult, String detail){this(callResult);this.detail = detail;}public ActivitiException() {}public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getDetail() {return detail;}public void setDetail(String detail) {this.detail = detail;}}
package cn.com.agree.activiti10;
public enum ActivitiServiceResults
{BIZ001_流程定义不存在("BIZ001", "流程定义不存在"),BIZ002_网关未匹配("BIZ002", "网关未匹配");private String code;private String message;ActivitiServiceResults(String code, String message){this.code = code;this.message = message;}/*** @return the code*/public String getCode(){return code;}/*** @return the message*/public String getMessage(){return message;}/*** @param code* the code to set*/public void setCode(String code){this.code = code;}/*** @param message* the message to set*/public void setMessage(String message){this.message = message;}
}
2.6 bpmn文件
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test"><process isExecutable="true" id="publicAc" name="通用活动"><startEvent id="startEvent1" name="startEvent" /><endEvent id="endEvent1" name="endEvent" /><userTask id="pubObj_subObject1" name="账务提交处理" objectEntryConditions=""><extensionElements><activiti:formProperty id="CPCP条件" default="" /><activiti:formProperty id="pojoPath" default="BankCModule/scene/activity/publicAc/pubObj/pubObj" /></extensionElements></userTask><parallelGateway id="parallelGateway_subProcess1" name="parallelGateway_风控对象组" /><sequenceFlow id="sequenceFlow_subProcess1" name="" sourceRef="subProcess1" targetRef="parallelGateway_subProcess1" /><subProcess id="subProcess1" name="风控对象组"><startEvent id="subProcess1_start" name="startEvent" /><endEvent id="subProcess_end_authCheck_subObject2" name="endEvent" /><sequenceFlow id="sequenceFlow_start_authCheck_subObject2" name="" sourceRef="subProcess1_start" targetRef="authCheck_subObject2" /><sequenceFlow id="sequenceFlow_end_authCheck_subObject2" name="" sourceRef="authCheck_subObject2" targetRef="subProcess_end_authCheck_subObject2" /><userTask id="authCheck_subObject2" name="授权对象处理" objectEntryConditions=""><documentation>{"id":"subProcess1","name":"风控对象组"}</documentation><extensionElements><activiti:formProperty id="CPCP条件" default="" /><activiti:formProperty id="pojoPath" default="BankCModule/processes/authCheck/authCheck" /></extensionElements></userTask><endEvent id="subProcess_end_reviewCheck_subObject3" name="endEvent" /><sequenceFlow id="sequenceFlow_start_reviewCheck_subObject3" name="" sourceRef="subProcess1_start" targetRef="reviewCheck_subObject3" /><sequenceFlow id="sequenceFlow_end_reviewCheck_subObject3" name="" sourceRef="reviewCheck_subObject3" targetRef="subProcess_end_reviewCheck_subObject3" /><userTask id="reviewCheck_subObject3" name="复核对象处理" objectEntryConditions=""><documentation>{"id":"subProcess1","name":"风控对象组"}</documentation><extensionElements><activiti:formProperty id="CPCP条件" default="" /><activiti:formProperty id="pojoPath" default="BankCModule/processes/reviewCheck/reviewCheck" /></extensionElements></userTask></subProcess><sequenceFlow id="sequenceFlow5" name="" sourceRef="parallelGateway_subProcess1" targetRef="pubObj_subObject1" /><sequenceFlow id="sequenceFlow6" name="" sourceRef="startEvent1" targetRef="subProcess1" /><exclusiveGateway id="exclusiveGateway1" name="网关" /><userTask id="subObject4" name="网关1" objectEntryConditions="" /><sequenceFlow id="sequenceFlow7" name="条件" sourceRef="exclusiveGateway1" targetRef="subObject4"><conditionExpression xsi:type="tFormalExpression">${a=='1'}</conditionExpression></sequenceFlow><userTask id="subObject5" name="网关2" objectEntryConditions="" /><sequenceFlow id="sequenceFlow8" name="条件" sourceRef="exclusiveGateway1" targetRef="subObject5"><conditionExpression xsi:type="tFormalExpression">${a=='2'}</conditionExpression></sequenceFlow><sequenceFlow id="sequenceFlow9" name="" sourceRef="pubObj_subObject1" targetRef="exclusiveGateway1" /><userTask id="subObject6" name="对象" objectEntryConditions="" /><sequenceFlow id="sequenceFlow10" name="" sourceRef="subObject4" targetRef="subObject6" /><sequenceFlow id="sequenceFlow12" name="" sourceRef="subObject6" targetRef="endEvent1" /><sequenceFlow id="sequenceFlow13" name="" sourceRef="subObject5" targetRef="endEvent1" /></process><bpmndi:BPMNDiagram id="BPMNDiagram_通用活动" xmlns="http://www.omg.org/spec/BPMN/20100524/DI"><bpmndi:BPMNPlane bpmnElement="通用活动" id="BPMNPlane_通用活动"><bpmndi:BPMNShape id="BPMNShape_startEvent1" bpmnElement="startEvent1"><omgdc:Bounds x="65" y="85" height="50" width="50" /></bpmndi:BPMNShape><bpmndi:BPMNShape id="BPMNShape_endEvent1" bpmnElement="endEvent1"><omgdc:Bounds x="950" y="185" height="50" width="50" /></bpmndi:BPMNShape><bpmndi:BPMNShape id="BPMNShape_pubObj_subObject1" bpmnElement="pubObj_subObject1"><omgdc:Bounds x="530" y="85" height="50" width="90" /></bpmndi:BPMNShape><bpmndi:BPMNShape id="BPMNShape_authCheck_subObject2" bpmnElement="authCheck_subObject2"><omgdc:Bounds x="40" y="33" height="50" width="90" /></bpmndi:BPMNShape><bpmndi:BPMNShape id="BPMNShape_reviewCheck_subObject3" bpmnElement="reviewCheck_subObject3"><omgdc:Bounds x="160" y="35" height="50" width="90" /></bpmndi:BPMNShape><bpmndi:BPMNShape id="BPMNShape_subProcess1" bpmnElement="subProcess1"><omgdc:Bounds x="230" y="52" height="115" width="265" /></bpmndi:BPMNShape><bpmndi:BPMNEdge id="BPMNEdge_sequenceFlow5" bpmnElement="sequenceFlow5"><omgdi:waypoint x="495" y="109.5" /><omgdi:waypoint x="530" y="110" /></bpmndi:BPMNEdge><bpmndi:BPMNEdge id="BPMNEdge_sequenceFlow6" bpmnElement="sequenceFlow6"><omgdi:waypoint x="115" y="110" /><omgdi:waypoint x="230" y="109.5" /></bpmndi:BPMNEdge><bpmndi:BPMNShape id="BPMNShape_exclusiveGateway1" bpmnElement="exclusiveGateway1"><omgdc:Bounds x="535" y="235" height="30" width="30" /></bpmndi:BPMNShape><bpmndi:BPMNShape id="BPMNShape_subObject4" bpmnElement="subObject4"><omgdc:Bounds x="620" y="145" height="50" width="90" /></bpmndi:BPMNShape><bpmndi:BPMNEdge id="BPMNEdge_sequenceFlow7" bpmnElement="sequenceFlow7"><omgdi:waypoint x="565" y="250" /><omgdi:waypoint x="620" y="170" /></bpmndi:BPMNEdge><bpmndi:BPMNShape id="BPMNShape_subObject5" bpmnElement="subObject5"><omgdc:Bounds x="615" y="285" height="50" width="90" /></bpmndi:BPMNShape><bpmndi:BPMNEdge id="BPMNEdge_sequenceFlow8" bpmnElement="sequenceFlow8"><omgdi:waypoint x="565" y="250" /><omgdi:waypoint x="615" y="310" /></bpmndi:BPMNEdge><bpmndi:BPMNEdge id="BPMNEdge_sequenceFlow9" bpmnElement="sequenceFlow9"><omgdi:waypoint x="620" y="110" /><omgdi:waypoint x="535" y="250" /></bpmndi:BPMNEdge><bpmndi:BPMNShape id="BPMNShape_subObject6" bpmnElement="subObject6"><omgdc:Bounds x="810" y="185" height="50" width="90" /></bpmndi:BPMNShape><bpmndi:BPMNEdge id="BPMNEdge_sequenceFlow10" bpmnElement="sequenceFlow10"><omgdi:waypoint x="710" y="170" /><omgdi:waypoint x="810" y="210" /></bpmndi:BPMNEdge><bpmndi:BPMNEdge id="BPMNEdge_sequenceFlow12" bpmnElement="sequenceFlow12"><omgdi:waypoint x="900" y="210" /><omgdi:waypoint x="950" y="210" /></bpmndi:BPMNEdge><bpmndi:BPMNEdge id="BPMNEdge_sequenceFlow13" bpmnElement="sequenceFlow13"><omgdi:waypoint x="705" y="310" /><omgdi:waypoint x="950" y="210" /></bpmndi:BPMNEdge></bpmndi:BPMNPlane></bpmndi:BPMNDiagram>
</definitions>
相关文章:
静态解析activiti文本,不入库操作流程
说明: activiti本身状态存库,导致效率太低,把中间状态封装成一个载荷类,返回给上游,下次请求时给带着载荷类即可。 1.pom依赖 <dependency><groupId>net.sf.json-lib</groupId><artifactId>js…...
100个python的基本语法知识【上】
0. 变量和赋值: x 5 name “John” 1. 数据类型: 整数(int) 浮点数(float) 字符串(str) 布尔值(bool) 2. 注释: # 这是单行注释 ""…...

Python从0到100(四十四):读取数据库数据
前言: 零基础学Python:Python从0到100最新最全教程。 想做这件事情很久了,这次我更新了自己所写过的所有博客,汇集成了Python从0到100,共一百节课,帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…...

ZLMRTCClient配置说明与用法(含示例)
webRTC播放视频 后面在项目中会用到通过推拉播放视频流的技术,所以最近预研了一下webRTC 首先需要引入封装好的webRTC客户端的js文件ZLMRTCClient.js 下面是地址需要的自行下载 http://my.zsyou.top/2024/ZLMRTCClient.js 配置说明 new ZLMRTCClient.Endpoint…...
nginx代理服务配置,基于http协议-Linux(CentOS)
基于http协议的nginx代理服务 1. 打开 Nginx 虚拟机80端口配置文件2. 添加代理配置3. 重启nginx服务 nginx代理缓存配置 1. 打开 Nginx 虚拟机80端口配置文件 Nginx 的默认80端口虚拟机配置文件通常位于/etc/nginx/conf.d/default.conf。 vim /etc/nginx/conf.d/default.con…...

Photos框架 - 自定义媒体资源选择器(数据部分)
引言 在iOS开发中,系统已经为我们提供了多种便捷的媒体资源选择方式,如UIImagePickerController和PHPickerViewController。这些方式不仅使用方便、界面友好,而且我们完全不需要担心性能和稳定性问题,因为它们是由系统提供的&…...

Spring Boot + Spring Cloud 入门
运行配置 java -jar spring-boot-config-0.0.1-SNAPSHOT.jar --spring.profiles.activetest --my1.age32 --debugtrue "D:\Program Files\Redis\redis-server.exe" D:\Program Files\Redis\redis.windows.conf "D:\Program Files\Redis\redis-cli.exe" &q…...

怎么使用动态IP地址上网
如何设置动态IP地址上网? 设置动态IP地址上网的步骤如下: 一、了解动态IP地址 动态IP地址是由网络服务提供商(ISP)动态分配给用户的IP地址,它会根据用户的需求和网络情况实时改变。相比于静态IP地址,动态…...

【源码+文档+调试讲解】智慧物流小程序的设计与实现
摘 要 互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。针对高校教师成果信息管理混乱,出错率高,信息安全…...

QT:控件圆角设置、固定窗口大小
实现控件圆角度设置//使用的是setStyleSheet方法 //改变的控件是QTextEdit,如果你想改变其他控件,将QTextEdit进行更换 this->setStyleSheet("QTextEdit{background-color:#FFFFFF;border-top-left-radius:15px;border-top-right-radius:15px;bo…...

【JavaScript】深入理解 `let`、`var` 和 `const`
文章目录 一、var 的声明与特点二、let 的声明与特点三、const 的声明与特点四、let、var 和 const 的对比五、实战示例六、最佳实践 在 JavaScript 中,变量声明是编程的基础,而 let、var 和 const 是三种常用的变量声明方式。本文将详细介绍这三种变量声…...
云监控(华为) | 实训学习day7(10)
水一篇。。。。。。。。。。。。。 强迫症打卡必须要满 企拓 今天没有将东西 2024/7/22 规划学习路线对于进入AI行业至关重要。以下是一个详细的学习路线规划,旨在帮助你从零基础到成为一名合格的AI或大数据分析师: 第一阶段:基础知识建设…...
JS_plus.key.addEventListener监听键盘按键
官方文档:https://www.html5plus.org/doc/zh_cn/key.html 监听事件 plus.key.addEventListener(keydown, e > {console.log("keydown: "e.keyCode) }) plus.key.addEventListener(keyup, e > {console.log("keyup: "e.keyCode) })移除事…...
对话系统(Chat)与自主代理(Agent)对撞
随着生成式AI技术的不断进步,关于其未来发展方向的讨论也愈发激烈。究竟生成式AI的未来是在对话系统(Chat)中展现智慧,还是在自主代理(Agent)中体现能力?这一问题引发了广泛的讨论和探索。 首先…...

sql server 连接报错error 40
做个简单的记录,造成40 的原因有很多,你的错误并不一定就是我遇到的这种情况. 错误描述: 首先我在使用ssms 工具连接的时候是可以正常连接的,也能对数据库进行操作. 在使用 ef core 连接 Sql Server 时报错: Microsoft.Data.SqlClient.SqlException (0x80131904): A network-r…...

邮件安全篇:如何防止邮件泄密?
本文主要讨论组织内部用户违反保密规定通过邮件泄密的场景。其他场景导致邮箱泄密的问题(如账号被盗、邮件系统存在安全漏洞等)不在本文的讨论范围。本文主要从邮件系架构设计、邮件数据防泄漏系统、建立健全规章制度、安全意识培训等方面分别探讨。 1. …...
MySQL查询优化:提升数据库性能的策略
在数据库管理和应用中,优化查询是提高MySQL数据库性能的关键环节。随着数据量的不断增长,如何高效地检索和处理数据成为了一个重要的挑战。本文将介绍一系列优化MySQL查询的策略,帮助开发者和管理员提升数据库的性能。 案例1: 使用索引优化查…...

vue-快速入门
Vue 前端体系、前后端分离 1、概述 1.1、简介 Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,可以高效地开发用户界面。…...

【网络流】——初识(最大流)
网络流-最大流 基础信息引入一些概念基本性质 最大流定义 Ford–Fulkerson 增广Edmons−Karp算法Dinic 算法参考文献 基础信息 引入 假定现在有一个无限放水的自来水厂和一个无限收水的小区,他们之间有多条水管和一些节点构成。 每一条水管有三个属性:…...

【STM32嵌入式系统设计与开发---拓展】——1_10矩阵按键
这里写目录标题 1、矩阵按键2、代码片段分析 1、矩阵按键 通过将4x4矩阵按键的每一行依次设为低电平,同时保持其它行为高电平,然后读取所有列的电平状态,可以检测到哪个按键被按下。如果某列变为低电平,说明对应行和列的按键被按下…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...

Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...