当前位置: 首页 > news >正文

静态解析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>{&quot;id&quot;:&quot;subProcess1&quot;,&quot;name&quot;:&quot;风控对象组&quot;}</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>{&quot;id&quot;:&quot;subProcess1&quot;,&quot;name&quot;:&quot;风控对象组&quot;}</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==&#39;1&#39;}</conditionExpression></sequenceFlow><userTask id="subObject5" name="网关2" objectEntryConditions="" /><sequenceFlow id="sequenceFlow8" name="条件" sourceRef="exclusiveGateway1" targetRef="subObject5"><conditionExpression xsi:type="tFormalExpression">${a==&#39;2&#39;}</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文本,不入库操作流程

说明&#xff1a; activiti本身状态存库&#xff0c;导致效率太低&#xff0c;把中间状态封装成一个载荷类&#xff0c;返回给上游&#xff0c;下次请求时给带着载荷类即可。 1.pom依赖 <dependency><groupId>net.sf.json-lib</groupId><artifactId>js…...

100个python的基本语法知识【上】

0. 变量和赋值&#xff1a; x 5 name “John” 1. 数据类型&#xff1a; 整数&#xff08;int&#xff09; 浮点数&#xff08;float&#xff09; 字符串&#xff08;str&#xff09; 布尔值&#xff08;bool&#xff09; 2. 注释&#xff1a; # 这是单行注释 ""…...

Python从0到100(四十四):读取数据库数据

前言&#xff1a; 零基础学Python&#xff1a;Python从0到100最新最全教程。 想做这件事情很久了&#xff0c;这次我更新了自己所写过的所有博客&#xff0c;汇集成了Python从0到100&#xff0c;共一百节课&#xff0c;帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…...

ZLMRTCClient配置说明与用法(含示例)

webRTC播放视频 后面在项目中会用到通过推拉播放视频流的技术&#xff0c;所以最近预研了一下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开发中&#xff0c;系统已经为我们提供了多种便捷的媒体资源选择方式&#xff0c;如UIImagePickerController和PHPickerViewController。这些方式不仅使用方便、界面友好&#xff0c;而且我们完全不需要担心性能和稳定性问题&#xff0c;因为它们是由系统提供的&…...

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地址上网&#xff1f; 设置动态IP地址上网的步骤如下&#xff1a; 一、了解动态IP地址 动态IP地址是由网络服务提供商&#xff08;ISP&#xff09;动态分配给用户的IP地址&#xff0c;它会根据用户的需求和网络情况实时改变。相比于静态IP地址&#xff0c;动态…...

【源码+文档+调试讲解】智慧物流小程序的设计与实现

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对高校教师成果信息管理混乱&#xff0c;出错率高&#xff0c;信息安全…...

QT:控件圆角设置、固定窗口大小

实现控件圆角度设置//使用的是setStyleSheet方法 //改变的控件是QTextEdit&#xff0c;如果你想改变其他控件&#xff0c;将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 中&#xff0c;变量声明是编程的基础&#xff0c;而 let、var 和 const 是三种常用的变量声明方式。本文将详细介绍这三种变量声…...

云监控(华为) | 实训学习day7(10)

水一篇。。。。。。。。。。。。。 强迫症打卡必须要满 企拓 今天没有将东西 2024/7/22 规划学习路线对于进入AI行业至关重要。以下是一个详细的学习路线规划&#xff0c;旨在帮助你从零基础到成为一名合格的AI或大数据分析师&#xff1a; 第一阶段&#xff1a;基础知识建设…...

JS_plus.key.addEventListener监听键盘按键

官方文档&#xff1a;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技术的不断进步&#xff0c;关于其未来发展方向的讨论也愈发激烈。究竟生成式AI的未来是在对话系统&#xff08;Chat&#xff09;中展现智慧&#xff0c;还是在自主代理&#xff08;Agent&#xff09;中体现能力&#xff1f;这一问题引发了广泛的讨论和探索。 首先…...

sql server 连接报错error 40

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

邮件安全篇:如何防止邮件泄密?

本文主要讨论组织内部用户违反保密规定通过邮件泄密的场景。其他场景导致邮箱泄密的问题&#xff08;如账号被盗、邮件系统存在安全漏洞等&#xff09;不在本文的讨论范围。本文主要从邮件系架构设计、邮件数据防泄漏系统、建立健全规章制度、安全意识培训等方面分别探讨。 1. …...

MySQL查询优化:提升数据库性能的策略

在数据库管理和应用中&#xff0c;优化查询是提高MySQL数据库性能的关键环节。随着数据量的不断增长&#xff0c;如何高效地检索和处理数据成为了一个重要的挑战。本文将介绍一系列优化MySQL查询的策略&#xff0c;帮助开发者和管理员提升数据库的性能。 案例1: 使用索引优化查…...

vue-快速入门

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

【网络流】——初识(最大流)

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

【STM32嵌入式系统设计与开发---拓展】——1_10矩阵按键

这里写目录标题 1、矩阵按键2、代码片段分析 1、矩阵按键 通过将4x4矩阵按键的每一行依次设为低电平&#xff0c;同时保持其它行为高电平&#xff0c;然后读取所有列的电平状态&#xff0c;可以检测到哪个按键被按下。如果某列变为低电平&#xff0c;说明对应行和列的按键被按下…...

内存分配函数malloc kmalloc vmalloc

内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;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. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

cf2117E

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

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; 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哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...