静态解析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矩阵按键的每一行依次设为低电平,同时保持其它行为高电平,然后读取所有列的电平状态,可以检测到哪个按键被按下。如果某列变为低电平,说明对应行和列的按键被按下…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...