您的位置:首页 > 新闻 > 会展 > 关键词优化排名易下拉效率_长沙定制网页设计_企业网站优化服务_武威网站seo

关键词优化排名易下拉效率_长沙定制网页设计_企业网站优化服务_武威网站seo

2024/10/6 16:24:31 来源:https://blog.csdn.net/weixin_55850954/article/details/142712867  浏览:    关键词:关键词优化排名易下拉效率_长沙定制网页设计_企业网站优化服务_武威网站seo
关键词优化排名易下拉效率_长沙定制网页设计_企业网站优化服务_武威网站seo

背景

在流程图中,时常会涉及到分支的判断,进入判断逻辑后,我们一般只会从分支的一个出口出来,然后往下继续执行,这在流程引擎中,称之为排他网关(Exclusive Gateway),排他网关用于在流程执行过程中做出决策,基于流程中的条件来选择一个唯一的路径继续执行。

下面我们以登录为例,在登录流程中,会依次执行下列流程:

  • 账号定位:根据入参定位账号信息
  • 密码检查:根据获取的账号信息,以及输入的密码,比对密码信息是否正确
  • 状态检查:检查用户状态,判断是否被盗、冻结等
  • 登录核身判断:
    1. 状态检查通过,颁发登录token
    2. 状态检查不通过,设置核身相关信息,如核身类型等
  • 创建token:状态检查通过,则下发登录态token,若不通过,下发核身token

具体的流程图如下所示:

画板

设计思路

原先的执行方式
  • 根据流程id,解析流程配置文件,获取ActivitiFlow
  • 遍历ActivitiFlow的所有节点,依次执行节点活动

画板

修改后的执行方式
  • 根据流程id,解析流程配置文件,获取ActivitiFlow
  • 执行流程节点活动
    • 对于ServiceTask,转为IServiceTask执行execute方法
    • 对于排他网关,转为IExeclusiveGateway执行parseCredential方法
  • 节点执行完毕后,根据sequenceFlow连线信息,获取下一个节点(对于网关,会加上凭证credential的判断,来决策下一个节点)

画板

实现

首先,我们根据上述流程图,定义流程文件内容如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<activiti id="register_flow"><!--节点定义--><startEvent id="startEvent"/><serviceTask id="userLocate" name="userLocate" description="账号定位" class="com.yang.business.activiti.login.UserLocateActivity"/><serviceTask id="passwordCheck" name="passwordCheck" description="密码检查" class="com.yang.business.activiti.login.PasswordCheckActivity"/><serviceTask id="userAccountStatusCheck" name="userAccountStatusCheck" description="账号状态检查" class="com.yang.business.activiti.login.UserAccountStatusCheckActivity"/><exclusiveGateway id="needBuildIdentityAction" name="needBuildIdentityAction" description="是否需要转核身" class="com.yang.business.activiti.login.NeedTransfer2IdentityExclusiveGateway"/><serviceTask id="buildIdentityAction" name="buildIdentityAction" description="核身行为构建" class="com.yang.business.activiti.login.BuildIdentityActionActivity"/><serviceTask id="buildUserToken" name="buildUserToken" description="创建用户token" class="com.yang.business.activiti.common.BuildUserTokenActivity"/><endEvent id="endEvent"/><!--节点执行顺序编排--><sequenceFlow source="startEvent" target="userLocate"/><sequenceFlow source="userLocate" target="passwordCheck"/><sequenceFlow source="passwordCheck" target="userAccountStatusCheck"/><sequenceFlow source="userAccountStatusCheck" target="needBuildIdentityAction"/><sequenceFlow source="needBuildIdentityAction" target="buildIdentityAction" credential="identity"/><sequenceFlow source="needBuildIdentityAction" target="buildUserToken" credential="login"/><sequenceFlow source="buildIdentityAction" target="buildUserToken"/><sequenceFlow source="buildUserToken" target="endEvent"/>
</activiti>

对于节点与节点之间的联系,是通过sequenceFlow来实现的,而目前我们的sequenceFlow只有source和target这两个信息,前者表示来源,后者表示去处,此时的sequenceFlow是没有阻塞条件的,当出现一个source有多个target时,我们可以在sequenceFlow加上阻塞条件,用于根据上下文信息,决策需要走哪一条路径。修改后的sequenceFlow如下,我们新增一个crendential字段,用于表示当上下文中凭证信息为相关值时,才可以走这条连线。

package com.yang.core.infrastructure.flow.activiti.model;import lombok.Data;import java.io.Serializable;@Data
public class SequenceFlowNode implements Serializable {private String source;private String target;private String credential;}

在上一节中,我们定义的activitiFlow流程模型结构如下,此时的activitiFlow对sequenceFlow不感知,因为之前涉及的时候,不存在一个来源对应多个去处的连线,所以获取节点顺序,依次执行即可。

package com.yang.core.infrastructure.flow.activiti.model;import java.util.ArrayList;
import java.util.List;public class ActivitiFlow {private String id;private List<FlowNode> flowNodeList = new ArrayList<>();public void addFlowNode(FlowNode flowNode) {this.flowNodeList.add(flowNode);}public List<FlowNode> getFlowNodeList() {return this.flowNodeList;}public String getId() {return id;}public void setId(String id) {this.id = id;}
}

当前模型显然无法支持我们的排他网关,因为排他网关的入口是一个,但是出口可以是多个的,而List结构,只能支持一对一的顺序串联,所以我们对ActivitiFlow模型进行改造,使其能支持我们的一对多逻辑,同时,对模型进行充血,将一些决策逻辑收敛到模型中。

package com.yang.core.infrastructure.flow.activiti.model;import lombok.Data;
import org.apache.commons.lang3.StringUtils;import java.util.List;
import java.util.Map;@Data
public class ActivitiFlow {private String id;private FlowNode startNode;private FlowNode endNode;private List<SequenceFlowNode> sequenceFlowNodeList;private Map<String, FlowNode> nodeId2FlowNodeMap;public FlowNode chooseNextNode(FlowNode curNode, String credential) {String sourceNodeId = curNode.getId();String targetNodeId = null;for (SequenceFlowNode sequenceFlowNode : sequenceFlowNodeList) {if (!sequenceFlowNode.getSource().equals(sourceNodeId)) {continue;}if (StringUtils.isEmpty(sequenceFlowNode.getCredential())) {continue;}if (sequenceFlowNode.getCredential().equals(credential)) {targetNodeId = sequenceFlowNode.getTarget();break;}}return nodeId2FlowNodeMap.get(targetNodeId);}public FlowNode getNextNode(FlowNode curNode) {String sourceNodeId = curNode.getId();String targetNodeId = null;for (SequenceFlowNode sequenceFlowNode : sequenceFlowNodeList) {if (sequenceFlowNode.getSource().equals(sourceNodeId)) {targetNodeId = sequenceFlowNode.getTarget();break;}}return nodeId2FlowNodeMap.get(targetNodeId);}
}

因为ActivitiFlow的模型结构有所变更,因此,我们需要修改对应的解析器,以适应当前结构。首先修改XmlActivitiFileParser的parseSequenceFlowNode方法,增加对credential字段的解析:

 /*** 解析流程执行顺序节点* @param attributes* @return*/private SequenceFlowNode parseSequenceFlowNode(NamedNodeMap attributes) {Node sourceNode = attributes.getNamedItem("source");Node targetNode = attributes.getNamedItem("target");if (sourceNode != null && targetNode != null) {SequenceFlowNode sequenceFlowNode = new SequenceFlowNode();sequenceFlowNode.setSource(sourceNode.getNodeValue());sequenceFlowNode.setTarget(targetNode.getNodeValue());Node credentialNode = attributes.getNamedItem("credential");if (credentialNode != null) {sequenceFlowNode.setCredential(credentialNode.getNodeValue());}return sequenceFlowNode;}return null;}

其次,修改AbstractActivitiParser,使其能正确解析ActivitiFlow

package com.yang.core.infrastructure.flow.activiti.parser;import com.yang.api.common.ErrorCode;
import com.yang.api.common.exception.UicException;
import com.yang.core.infrastructure.flow.activiti.enums.FlowNodeType;
import com.yang.core.infrastructure.flow.activiti.model.ActivitiFlow;
import com.yang.core.infrastructure.flow.activiti.model.FlowNode;
import com.yang.core.infrastructure.flow.activiti.model.SequenceFlowNode;
import com.yang.core.infrastructure.utils.SpringContextUtil;import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;public abstract class AbstractActivitiFileParser implements IActivitiFileParser{/*** 填充流程节点内容* @param flowNode* @param flowNodeType*/protected void richFlowNode(FlowNode flowNode, FlowNodeType flowNodeType) {if (flowNodeType != FlowNodeType.SERVICE_TASK && flowNodeType != FlowNodeType.EXCLUSIVE_GATEWAY) {return;}try {// 填充target对象Class<?> aClass = Class.forName(flowNode.getClassPath());Object target = SpringContextUtil.getBeanByType(aClass);flowNode.setTarget(target);} catch (ClassNotFoundException e) {e.printStackTrace();}}/*** 根据连线顺序,对流程节点进行排序,构建相应的流程flow* @param fileName* @param flowNodeList* @param sequenceFlowNodeList* @return*/protected ActivitiFlow buildActivitiFlow(String fileName,List<FlowNode> flowNodeList,List<SequenceFlowNode> sequenceFlowNodeList) {String startNodeId = getStartNodeId(sequenceFlowNodeList);String endNodeId = getEndNodeId(sequenceFlowNodeList);Map<String, FlowNode> nodeId2FlowNodeMap = flowNodeList.stream().collect(Collectors.toMap(FlowNode::getId, Function.identity()));ActivitiFlow activitiFlow = new ActivitiFlow();activitiFlow.setId(fileName);activitiFlow.setStartNode(nodeId2FlowNodeMap.get(startNodeId));activitiFlow.setEndNode(nodeId2FlowNodeMap.get(endNodeId));activitiFlow.setNodeId2FlowNodeMap(nodeId2FlowNodeMap);activitiFlow.setSequenceFlowNodeList(sequenceFlowNodeList);return activitiFlow;}/*** 获取结束节点id* @param sequenceFlowNodeList* @return*/private String getEndNodeId(List<SequenceFlowNode> sequenceFlowNodeList) {List<String> oneNodeIds = filterCountOneNodeId(sequenceFlowNodeList);Set<String> oneNodeIdSet = new HashSet<>(oneNodeIds);String endNodeId = null;for (SequenceFlowNode sequenceFlowNode : sequenceFlowNodeList) {String target = sequenceFlowNode.getTarget();if (oneNodeIdSet.contains(target)) {endNodeId = target;break;}}return endNodeId;}/*** 获取开始节点id* @param sequenceFlowNodeList* @return*/private String getStartNodeId(List<SequenceFlowNode> sequenceFlowNodeList) {List<String> oneNodeIds = filterCountOneNodeId(sequenceFlowNodeList);Set<String> oneNodeIdSet = new HashSet<>(oneNodeIds);String startNodeId = null;for (SequenceFlowNode sequenceFlowNode : sequenceFlowNodeList) {String source = sequenceFlowNode.getSource();if (oneNodeIdSet.contains(source)) {startNodeId = source;break;}}return startNodeId;}/*** 过滤计数次数只有1次的nodeId,只有startEvent和endEvent会计数1次,其他都是两次,如果是网关,那么次数会更多* @param sequenceFlowNodeList* @return*/private List<String> filterCountOneNodeId(List<SequenceFlowNode> sequenceFlowNodeList) {Map<String, Integer> countNodeIdMap = new HashMap<>();for (SequenceFlowNode sequenceFlowNode : sequenceFlowNodeList) {Integer sourceCount = countNodeIdMap.getOrDefault(sequenceFlowNode.getSource(), 0);countNodeIdMap.put(sequenceFlowNode.getSource(), sourceCount + 1);Integer targetCount = countNodeIdMap.getOrDefault(sequenceFlowNode.getTarget(), 0);countNodeIdMap.put(sequenceFlowNode.getTarget(), targetCount + 1);}List<String> countOneNodeIds = new ArrayList<>();countNodeIdMap.forEach((nodeId, count) -> {if (count == 1) {countOneNodeIds.add(nodeId);}});if (countOneNodeIds.size() > 2) {throw new UicException(ErrorCode.ACTIVITI_PARSER_ERROR);}return countOneNodeIds;}}

最后,修改ActivitiManager类,对排他网关做定制处理,根据网关返回的凭证值,决策出下一个节点是哪一个。

package com.yang.core.infrastructure.flow.activiti;import com.yang.api.common.ErrorCode;
import com.yang.api.common.exception.UicException;
import com.yang.core.infrastructure.flow.activiti.enums.FlowNodeType;
import com.yang.core.infrastructure.flow.activiti.function.IExclusiveGateway;
import com.yang.core.infrastructure.flow.activiti.function.IServiceTask;
import com.yang.core.infrastructure.flow.activiti.model.ActivitiFlow;
import com.yang.core.infrastructure.flow.activiti.model.FlowNode;
import com.yang.core.infrastructure.flow.activiti.parser.IActivitiFileParser;
import com.yang.core.infrastructure.flow.activiti.request.ActivitiEngineRequest;
import com.yang.core.infrastructure.flow.activiti.response.ActivitiEngineResponse;
import com.yang.core.infrastructure.utils.SpringContextUtil;import java.util.HashMap;
import java.util.Map;public class ActivitiFlowManager {private static Map<String, ActivitiFlow> id2ActivitiFlowCache = new HashMap<>();public static ActivitiFlow getActivitiFlow(String flowName) {ActivitiFlow activitiFlow = id2ActivitiFlowCache.get(flowName);if (activitiFlow != null) {return activitiFlow;}IActivitiFileParser iActivitiFileParser = SpringContextUtil.getBeanByType(IActivitiFileParser.class);synchronized (flowName.intern()) {activitiFlow = id2ActivitiFlowCache.get(flowName);if (activitiFlow != null) {return activitiFlow;}activitiFlow = iActivitiFileParser.parseActivitiFlow(flowName);if (activitiFlow == null) {throw new UicException(ErrorCode.ACTIVITI_NOT_FOUND_ERROR);}id2ActivitiFlowCache.put(flowName, activitiFlow);}return activitiFlow;}/*** 流程引擎执行方法* @param flowName* @param activitiEngineRequest* @return* @param <Request>* @param <Response>*/public static <Request, Response> ActivitiEngineResponse<Response> startEngine(String flowName,ActivitiEngineRequest<Request> activitiEngineRequest) {ActivitiFlow activitiFlow = getActivitiFlow(flowName);ActivitiEngineResponse<Response> activitiEngineResponse = new ActivitiEngineResponse<>();FlowNode curNode = activitiFlow.getStartNode();while (curNode != null) {FlowNodeType flowNodeType = curNode.getFlowNodeType();FlowNode nextFlow = null;switch (flowNodeType) {case START_EVENT:break;case END_EVENT:break;case SERVICE_TASK:executeServiceTask(activitiEngineRequest, activitiEngineResponse, curNode);break;case EXCLUSIVE_GATEWAY:nextFlow = executeExclusiveGateway(activitiEngineRequest, activitiEngineResponse, curNode, activitiFlow);break;}if (nextFlow != null) {curNode = nextFlow;} else {curNode = activitiFlow.getNextNode(curNode);}}return activitiEngineResponse;}private static <Request, Response> FlowNode executeExclusiveGateway(ActivitiEngineRequest<Request> activitiEngineRequest,ActivitiEngineResponse<Response> activitiEngineResponse,FlowNode curNode,ActivitiFlow activitiFlow) {IExclusiveGateway iExclusiveGateway = (IExclusiveGateway) curNode.getTarget();String credential = iExclusiveGateway.chooseNextNode(activitiEngineRequest, activitiEngineResponse);return activitiFlow.chooseNextNode(curNode, credential);}private static <Request, Response> void executeServiceTask(ActivitiEngineRequest<Request> activitiEngineRequest,ActivitiEngineResponse<Response> activitiEngineResponse, FlowNode flowNode) {IServiceTask iServiceTask = (IServiceTask) flowNode.getTarget();iServiceTask.execute(activitiEngineRequest, activitiEngineResponse);}
}

这里的IExclusiveGateway类定义如下:

package com.yang.core.infrastructure.flow.activiti.function;import com.yang.core.infrastructure.flow.activiti.request.ActivitiEngineRequest;
import com.yang.core.infrastructure.flow.activiti.response.ActivitiEngineResponse;public interface IExclusiveGateway extends IActivitiService {public static final String CREDENTIAL = "credential";default void execute(ActivitiEngineRequest request, ActivitiEngineResponse response) {String credential = chooseNextNode(request, response);request.getContext().put(CREDENTIAL, credential);}String chooseNextNode(ActivitiEngineRequest request, ActivitiEngineResponse response);}

其具体实现示例如下:

package com.yang.business.activiti.login;import com.yang.api.common.ErrorCode;
import com.yang.api.common.exception.UicException;
import com.yang.core.infrastructure.flow.activiti.function.IExclusiveGateway;
import com.yang.core.infrastructure.flow.activiti.request.ActivitiEngineRequest;
import com.yang.core.infrastructure.flow.activiti.response.ActivitiEngineResponse;
import org.springframework.stereotype.Component;@Component
public class NeedTransfer2IdentityExclusiveGateway implements IExclusiveGateway {@Overridepublic String chooseNextNode(ActivitiEngineRequest request, ActivitiEngineResponse response) {Object needIdentityObj = response.getContext().get("needIdentity");if (needIdentityObj != null) {boolean needIdentity = (Boolean) needIdentityObj;if (needIdentity) {return "identity";}return "login";}throw new UicException(ErrorCode.ACTIVITI_EXECUTE_ERROR);}
}
测试

这里准备两个账号,一个普通账号,一个被盗账号,被盗账号会进入登录转核身节点,在该节点中,会打印控制台信息——“登录转核身======”,依次登录普通账号和被盗账号,结果如下:

规则引擎决策

上述实现方式,有一个问题在于,我们的判断条件是一个隐式的判断条件,即sequenceFlow线条上指定的credential值和IExclusiveGateway网关产出的值相同时,可以进入该sequenceFlow线条指引的分支连线。这其实就是一个等于的判断,但是这种判断方式不够灵活,如果我们后续的需求是某个值大于、小于或不等于时,才能进行分支,那么显然现在这种方式是不能满足的,因此,我们需要引入规则引擎,通过执行规则引擎的方式,来进行决策。

整体的思路如下:

  • 网关节点,根据业务流程需要进行判断,并设置流程上下文值
  • 网关节点执行完毕后,根据sequenceFlow条件,和流程上下文信息,调用规则引擎,判断是否符合条件,符合条件则走到sequenceFlow对应分支
流程上下文参数简化

之前定义的ActivitiRequest和ActivitiResponse类的内容如下:


@Data
public class ActivitiEngineRequest <T> implements Serializable {/*** 场景code*/private String scenarioCode;private T baseRequest;private Map<String, Object> context = new HashMap<>();
}@Data
public class ActivitiEngineResponse <T> implements Serializable {/*** 场景code*/private String scenarioCode;private T response;private Map<String, Object> context = new HashMap<>();
}

这两个类的字段有些重复,包括场景code和流程上下文context字段,特别是流程上下文字段,当我们需要塞值到上下文中时,有时候不好判断要放request的上下文还是response的上下文,其实感觉这里放request和放response都可以,为了减少歧义,这里将这两个类进行聚合,收敛到一个类中,即ActivitiExecuteContext类,其内容如下:

package com.yang.core.infrastructure.flow.activiti.context;import lombok.Data;import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;@Data
public class ActivitiExecuteContext<Request, Response> implements Serializable {/*** 场景code*/private String scenarioCode;private Request baseRequest;private Response baseResponse;private Map<String, Object> context = new HashMap<>();
}

通过ActivitiExecuteContext来替换原先的ActivitiEngineRequest和ActivitiEngineResponse, 所以要修改之前用到过那两个类的接口和实现:

package com.yang.core.infrastructure.flow.activiti.function;import com.yang.core.infrastructure.flow.activiti.context.ActivitiExecuteContext;public interface IActivitiService {void execute(ActivitiExecuteContext activitiExecuteContext);
}package com.yang.core.infrastructure.flow.activiti.function;import com.yang.core.infrastructure.flow.activiti.context.ActivitiExecuteContext;public interface IExclusiveGateway extends IActivitiService {default void execute(ActivitiExecuteContext activitiExecuteContext) {parseCredential(activitiExecuteContext);}void parseCredential(ActivitiExecuteContext activitiExecuteContext);}package com.yang.core.infrastructure.flow.activiti.function;import com.yang.core.infrastructure.flow.activiti.context.ActivitiExecuteContext;
public interface IServiceTask<DomainRequest, DomainResponse> extends IActivitiService {default void execute(ActivitiExecuteContext activitiExecuteContext) {DomainRequest domainRequest = buildDomainRequest(activitiExecuteContext);if (domainRequest != null) {DomainResponse domainResponse = apply(domainRequest);attachment(domainResponse, activitiExecuteContext);return;}doElse(activitiExecuteContext);}/*** 默认不实现,一般先转为domain Request,然后调用领域层方法,进行转化,doElse适用于目前领域层无法支持相关实现,顾需要在activity层进行适配的逻辑*/default void doElse(ActivitiExecuteContext activitiExecuteContext) {}/*** 入参转化* @param activitiExecuteContext* @return*/DomainRequest buildDomainRequest(ActivitiExecuteContext activitiExecuteContext);/*** 领域服务调用* @param domainRequest* @return*/DomainResponse apply(DomainRequest domainRequest);/*** 领域服务调用结果填充* @param domainResponse* @param activitiExecuteContext*/void attachment(DomainResponse domainResponse, ActivitiExecuteContext activitiExecuteContext);
}
引入规则引擎

市面上常见的开源规则引擎有easy-rules、 Drools、Aviator,这里使用Aviator来作为规则引擎进行决策,首先引入相关的依赖:

 <dependency><groupId>com.googlecode.aviator</groupId><artifactId>aviator</artifactId><version>5.1.4</version></dependency>

然后创建相关的工具类

package com.yang.core.infrastructure.rule;import com.googlecode.aviator.AviatorEvaluator;import java.util.HashMap;
import java.util.Map;public class AviatorUtil {public static Object execute(String condition, Map<String, Object> env) {return AviatorEvaluator.execute(condition, env);}public static boolean match(String condition, Map<String, Object> env) {return (Boolean) execute(condition, env);}public static void main(String[] args) {Map<String, Object> env = new HashMap<>();env.put("flow", "identity");String condition = "flow == 'identity'";System.out.println(match(condition, env));}
}
修改流程配置

原先的网关连线,通过credential来拦截是否符合条件,现在我们引入规则引擎后,可以在sequenceFlow上,通过表达式来进行拦截判断,首先修改sequenceFlow,添加condition条件字段

package com.yang.core.infrastructure.flow.activiti.model;import lombok.Data;import java.io.Serializable;@Data
public class SequenceFlowNode implements Serializable {private String source;private String target;private String condition;}

然后修改流程配置文件

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<activiti id="register_flow"><!--节点定义--><startEvent id="startEvent"/><serviceTask id="userLocate" name="userLocate" description="账号定位" class="com.yang.business.activiti.login.UserLocateActivity"/><serviceTask id="passwordCheck" name="passwordCheck" description="密码检查" class="com.yang.business.activiti.login.PasswordCheckActivity"/><serviceTask id="userAccountStatusCheck" name="userAccountStatusCheck" description="账号状态检查" class="com.yang.business.activiti.login.UserAccountStatusCheckActivity"/><exclusiveGateway id="needBuildIdentityAction" name="needBuildIdentityAction" description="是否需要转核身" class="com.yang.business.activiti.login.NeedTransfer2IdentityExclusiveGateway"/><serviceTask id="buildIdentityAction" name="buildIdentityAction" description="核身行为构建" class="com.yang.business.activiti.login.BuildIdentityActionActivity"/><serviceTask id="buildUserToken" name="buildUserToken" description="创建用户token" class="com.yang.business.activiti.common.BuildUserTokenActivity"/><endEvent id="endEvent"/><!--节点执行顺序编排--><sequenceFlow source="startEvent" target="userLocate"/><sequenceFlow source="userLocate" target="passwordCheck"/><sequenceFlow source="passwordCheck" target="userAccountStatusCheck"/><sequenceFlow source="userAccountStatusCheck" target="needBuildIdentityAction"/><sequenceFlow source="needBuildIdentityAction" target="buildIdentityAction" condition="flow == 'identity'"/><sequenceFlow source="needBuildIdentityAction" target="buildUserToken" condition="flow == 'login'"/><sequenceFlow source="buildIdentityAction" target="buildUserToken"/><sequenceFlow source="buildUserToken" target="endEvent"/>
</activiti>

从上面的配置文件中,我们可以看出,当上下文的flow值为identity时,走buildIdentityAction节点,当上下文的flow值为login时,走buildUserToken节点,那么,在网关节点needBuildIdentityAction中,它的作用就是根据流程当前执行内容,对流程上下文的flow进行赋值,其具体实现如下:

package com.yang.business.activiti.login;import com.yang.api.common.ErrorCode;
import com.yang.api.common.exception.UicException;
import com.yang.core.infrastructure.flow.activiti.context.ActivitiExecuteContext;
import com.yang.core.infrastructure.flow.activiti.function.IExclusiveGateway;
import org.springframework.stereotype.Component;@Component
public class NeedTransfer2IdentityExclusiveGateway implements IExclusiveGateway {@Overridepublic void parseCredential(ActivitiExecuteContext activitiExecuteContext) {Object needIdentityObj = activitiExecuteContext.getContext().get("needIdentity");if (needIdentityObj != null) {boolean needIdentity = (Boolean) needIdentityObj;if (needIdentity) {activitiExecuteContext.getContext().put("flow", "identity");return;}activitiExecuteContext.getContext().put("flow", "login");return;}throw new UicException(ErrorCode.ACTIVITI_EXECUTE_ERROR);}
}

然后,因为我们之前将决策的逻辑放到activitiFlow类中,所以这里需要对activitiFlow的决策方法进行修改,修改内容如下:

package com.yang.core.infrastructure.flow.activiti.model;import com.yang.core.infrastructure.rule.AviatorUtil;
import lombok.Data;import java.util.ArrayList;
import java.util.List;
import java.util.Map;@Data
public class ActivitiFlow {private String id;private FlowNode startNode;private FlowNode endNode;private List<SequenceFlowNode> sequenceFlowNodeList;private Map<String, FlowNode> nodeId2FlowNodeMap;public FlowNode chooseNextNode(FlowNode curNode, Map<String, Object> flowContext) {String sourceNodeId = curNode.getId();String targetNodeId = null;List<SequenceFlowNode> sequenceFlowNodes = new ArrayList<>();for (SequenceFlowNode sequenceFlowNode : sequenceFlowNodeList) {if (sequenceFlowNode.getSource().equals(sourceNodeId)) {sequenceFlowNodes.add(sequenceFlowNode);}}if (sequenceFlowNodes.size() == 1) {targetNodeId = sequenceFlowNodes.get(0).getTarget();} else {// 网关判断for (SequenceFlowNode sequenceFlowNode : sequenceFlowNodes) {String condition = sequenceFlowNode.getCondition();if (AviatorUtil.match(condition, flowContext)) {targetNodeId = sequenceFlowNode.getTarget();break;}}}return nodeId2FlowNodeMap.get(targetNodeId);}}
测试

启动项目,分别测试普通账号和被盗账号,结果如下:

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com