java实现用一个变量表示多个属性的状态
1、流程启动及状态流转举例(场景:同一份数据在多个流程中流转,确定各流程自己的状态)
1.发起流程核心代码
/** * 二进制方式 * @param orgId * @param node * @param contractIds */ private void startWithPosition(String orgId, String node, List<String> contractIds){ CONTRACTAPPROVE currentNode = CONTRACTAPPROVE.valueOf(node); ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() .processDefinitionKey(currentNode.getDefKey()) .latestVersion() .singleResult(); if(processDefinition == null) { throw new BusinessException(BusinessCode.CLIENT_ERROR.getCode(), "流程定义不存在"); } //全局流程中所有处于未审批和执行中的流程状态int值 List<Integer> allNoPermitState = Arrays.stream(CONTRACTAPPROVE.values()) .map(e -> Arrays.asList(ApprovalState.WAIT.getCode(), ApprovalState.EXECUTE.getCode()) .stream() .map(s -> Integer.valueOf(s) << e.getStateIndex()) .collect(Collectors.toList())) .flatMap(Collection::stream) .collect(Collectors.toList()); List<ContractEntity> contractList = contractMapper.selectBatchIds(contractIds); Map<String, ContractEntity> collect = contractList.stream() .filter(e -> e.getApprovalState() != null && allNoPermitState.contains(Integer.valueOf(e.getApprovalState()))) .collect(Collectors.toMap(ContractEntity::getId, e -> e)); if(CollUtil.isNotEmpty(collect)) { throw new BusinessException(BusinessCode.CLIENT_ERROR.getCode(), "以下合同已存在进行中的审批:" + JSON.toJSONString(collect.keySet())); } String processDefinitionId = processDefinition.getId(); for(ContractEntity contract : contractList) { String approvalNode = contract.getApprovalNode() == null ? CONTRACTAPPROVE.CONTRACT_PRICE_APPROVE.getCode() : contract.getApprovalNode(); CONTRACTAPPROVE dbNode = CONTRACTAPPROVE.getByCode(approvalNode); Assert.isTrue(currentNode.getCode().compareTo(dbNode.getCode()) >= 0, () -> { throw new BusinessException(BusinessCode.CLIENT_ERROR.getCode(), String.format( "合同%s当前所处的阶段【%s】不支持逆向流程发起!!!,正常顺序\n(价格报批0000 0001->合同会签0000 0011->合同发布0000 0111->合同变更 0000 1111->合同终止 0001 1111)", contract.getId(), approvalNode)); }); contract.setApprovalNode(node); String approvalState = contract.getApprovalState(); Integer approvalStateNumber = StringUtils.isNotEmpty(approvalState)? Integer.valueOf(approvalState): 0; Map<String, Object> map = BeanUtil.beanToMap(contract); map.put("beanName", "contractFlowEventListener"); flowDefinitionService.startProcessInstanceById(processDefinitionId, currentNode.getCode(), "true", map); String waitCode = ApprovalState.WAIT.getCode(); Integer currentNodeState = Integer.valueOf(waitCode)<<currentNode.getStateIndex(); Integer globalState = currentNodeState | approvalStateNumber; contract.setApprovalState(String.valueOf(globalState)); contractMapper.updateById(contract); } }
2.获取多个流程
private List<Map<String, String>> positionList() { return Arrays.stream(CONTRACTAPPROVE.values()).map(e -> new LinkedHashMap<String, String>() {{ put(e.name(), e.getName() + "," + e.getCode()); }}).collect(Collectors.toList()); }
3、流程组装成枚举
package cn.togeek.geekbidder.crm.contract.service; import cn.togeek.foundation.web.api.BusinessCode; import cn.togeek.foundation.web.exception.BusinessException; import java.util.Arrays; import java.util.Optional; import org.springframework.util.Assert; public enum CONTRACTAPPROVE { /** * 价格报批0000 0001,合同会签0000 0011、合同发布0000 0111、合同变更 0000 1111、合同终止 0001 1111 */ CONTRACT_PRICE_APPROVE("价格报批", "0000 0001", 0,"Process_lzkpuzut") { @Override CONTRACTAPPROVE[] getNearNode() { return new CONTRACTAPPROVE[]{null, CONTRACT_SIGN_APPROVE}; } }, CONTRACT_SIGN_APPROVE("合同会签", "0000 0011", 3,"Process_lzl5psyn") { @Override CONTRACTAPPROVE[] getNearNode() { return new CONTRACTAPPROVE[]{CONTRACT_PRICE_APPROVE, CONTRACT_PUBLISH_APPROVE}; } }, CONTRACT_PUBLISH_APPROVE("合同发布", "0000 0111", 6,"Process_lzl5r66s") { @Override CONTRACTAPPROVE[] getNearNode() { return new CONTRACTAPPROVE[]{CONTRACT_SIGN_APPROVE, CONTRACT_CHANGE_APPROVE}; } }, CONTRACT_CHANGE_APPROVE("合同变更", "0000 1111",9,"Process_lzl5tu36") { @Override CONTRACTAPPROVE[] getNearNode() { return new CONTRACTAPPROVE[]{CONTRACT_PUBLISH_APPROVE, CONTRACT_TERMINATE_APPROVE}; } }, CONTRACT_TERMINATE_APPROVE("合同终止", "0001 1111", 12,"Process_lzl5t5h6") { @Override CONTRACTAPPROVE[] getNearNode() { return new CONTRACTAPPROVE[]{CONTRACT_CHANGE_APPROVE, null}; } }; private final String name; private final String code; //状态所在二进制位左移的位数 private final Integer stateIndex; private final String defKey; public String getName() { return name; } public String getCode() { return code; } public Integer getStateIndex() { return stateIndex; } public String getDefKey() { return defKey; } CONTRACTAPPROVE(String name, String code, Integer stateIndex, String defKey) { this.name = name; this.code = code; this.stateIndex = stateIndex; this.defKey = defKey; } /** * * 获取当前节点的相邻节点 * @return */ abstract CONTRACTAPPROVE[] getNearNode(); public static CONTRACTAPPROVE getByCode(String code) { Optional<CONTRACTAPPROVE> any = Arrays.stream(CONTRACTAPPROVE.values()).filter(n -> n.getCode().equals(code)).findAny(); Assert.isTrue(any.isPresent(), () -> { throw new BusinessException(BusinessCode.CLIENT_ERROR.getCode(), "流程编码错误!!!"); }); return any.get(); } }
4、监听回调
package cn.togeek.geekbidder.crm.contract.service; import cn.hutool.core.convert.Convert; import cn.hutool.core.util.HexUtil; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import lombok.AllArgsConstructor; import cn.togeek.foundation.util.DateTimeHelper; import cn.togeek.foundation.web.api.BusinessCode; import cn.togeek.foundation.web.exception.BusinessException; import cn.togeek.geekbidder.crm.contract.entity.ContractEntity; import cn.togeek.geekbidder.crm.contract.enums.ApprovalState; import cn.togeek.geekbidder.crm.contract.mapper.ContractNewMapper; import cn.togeek.maple.process.api.enums.FlowCommentEnum; import cn.togeek.maple.process.api.model.ListenerEvent; import cn.togeek.maple.process.api.model.ListenerEventSource; import java.time.LocalDate; import java.util.Map; import java.util.Objects; import org.flowable.engine.RuntimeService; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** * @author hanle * @description * @date 2024/8/6 13:44 * @Company 西安图迹信息科技有限公司 */ @Component @AllArgsConstructor public class ContractFlowEventListener implements ApplicationListener<ListenerEventSource> { @Autowired private RuntimeService runtimeService; @Autowired private ContractNewMapper contractNewMapper; /** * 流程结束监听 * * @param event */ @Override public void onApplicationEvent(ListenerEventSource event) { callBackWithStateCal(event); } /** * 二进制操作方式 * @param event */ public void callBackWithPositionCal(ListenerEventSource event){ ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() .processInstanceId(event.getListenerEvent().getProcessInstanceId()) .singleResult(); if(Objects.isNull(processInstance)) { return; } Map<String, Object> processVariables = processInstance.getProcessVariables(); String id = String.valueOf(processVariables.get("id")); ListenerEvent listenerEvent = event.getListenerEvent(); String approvalResults = listenerEvent.getApprovalResults(); LambdaUpdateWrapper<ContractEntity> wrapper = new LambdaUpdateWrapper<ContractEntity>().eq(ContractEntity::getId, id); ContractEntity contractEntity = contractNewMapper.selectById(id); Assert.notNull(contractEntity, () -> { throw new BusinessException(BusinessCode.CLIENT_ERROR.getCode(), String.format( "合同id为"+ id + "的合同不存在,可能已被删除,请检查!!!")); }); CONTRACTAPPROVE dbNode = CONTRACTAPPROVE.getByCode(contractEntity.getApprovalNode()); CONTRACTAPPROVE nextNode = dbNode.getNearNode()[1]; //上一个流程节点结束时将全局流程节点改为下一个节点 if(nextNode!=null) { contractEntity.setApprovalNode(nextNode.getCode()); } Integer dbFinalState = Integer.valueOf(contractEntity.getApprovalState()); String state = Integer.toString(dbFinalState, 2); //向左偏移量 Integer offsetLft = dbNode.getStateIndex(); //3个bit位代表状态 int bitPoint = 3; state = StrUtil.padPre(state, bitPoint + offsetLft, "0"); String statePre = state.substring(state.length() - offsetLft, state.length()); Integer preStateInt = Integer.valueOf(StringUtils.hasLength(statePre) ? statePre : "0", 2); if(FlowCommentEnum.NORMAL.getType().equals(approvalResults)) { // 审批通过 Integer pass = Integer.valueOf(ApprovalState.CHANGE.getCode()); int curNodeState = pass << offsetLft; int globalNodeState = curNodeState | preStateInt; contractEntity.setContractState(String.valueOf(globalNodeState)); } else if(FlowCommentEnum.REJECT.getType().equals(approvalResults)) { // 审批驳回 Integer reject = Integer.valueOf(ApprovalState.TERMINATION.getCode()); int curNodeState = reject << offsetLft; int globalNodeState = curNodeState | preStateInt; contractEntity.setContractState(String.valueOf(globalNodeState)); } contractNewMapper.updateById(contractEntity); } /** * 常规操作 * @param event */ public void callBackWithStateCal(ListenerEventSource event){ ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() .processInstanceId(event.getListenerEvent().getProcessInstanceId()) .singleResult(); if(Objects.isNull(processInstance)) { return; } Map<String, Object> processVariables = processInstance.getProcessVariables(); String id = String.valueOf(processVariables.get("id")); ListenerEvent listenerEvent = event.getListenerEvent(); String approvalResults = listenerEvent.getApprovalResults(); ContractEntity contractEntity = contractNewMapper.selectById(id); Assert.notNull(contractEntity, () -> { throw new BusinessException(BusinessCode.CLIENT_ERROR.getCode(), String.format( "合同id为"+ id + "的合同不存在,可能已被删除,请检查!!!")); }); ContractApproveGlobal dbNode = ContractApproveGlobal.getByCode(contractEntity.getApprovalNode()); ContractApproveGlobal nextNode = dbNode.getNearNode()[1]; //上一个流程节点结束时将全局流程节点改为下一个节点 if(nextNode!=null) { contractEntity.setApprovalNode(nextNode.getCode()); } if(FlowCommentEnum.NORMAL.getType().equals(approvalResults)) { // 审批通过 contractEntity.setContractState(null); } else if(FlowCommentEnum.REJECT.getType().equals(approvalResults)) { // 审批驳回 contractEntity.setContractState(ApprovalState.TERMINATION.getCode()); } contractNewMapper.updateById(contractEntity); } }