<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          java中如何避免集合死鏈調(diào)用 ?

          共 53415字,需瀏覽 107分鐘

           ·

          2021-09-26 11:16

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”

          優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

          1. 前言

          ?開發(fā)過程中,一些集合 的變動(dòng)會(huì)觸發(fā)任務(wù)去改變 其他的集合,為了保障任務(wù)的正確執(zhí)行,應(yīng)避免出現(xiàn)死循環(huán)調(diào)用,即對(duì)集合之間的影響關(guān)系進(jìn)行一些限制。怕日后遺忘,特在此記錄。

          2. 場(chǎng)景

          • A 集合影響 A 集合。

          • A 集合影響 B 集合,B 集合影響了 A 集合。

          • A 集合影響 B 集合,B 集合影響了 C 集合,C 集合影響了 A 集合。

          • A 集合影響 B 集合、C 集合,B 集合影響了 D 集合,C 集合影響了 E 集合,E 集合影響 A 集合。

          3. 環(huán)境

          3.1 開發(fā)環(huán)境準(zhǔn)備

          • JDK 1.8

          • SpringBoot 2.x

          • Mysql 8

          • redis

          3.2 數(shù)據(jù)準(zhǔn)備

          3.2.1 Mysql數(shù)據(jù)庫表及數(shù)據(jù)

          dp_process表

          CREATE TABLE `dp_process` (
            `ID` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID',
            `NAME` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '名稱',
            `CODE` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '代碼',
            `CATEGORY` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '類型 1=樓宇,2=房地產(chǎn)',
            `IN_COLS` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '輸入集合',
            `OUT_COLS` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '影響集合',
            `REMARK` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '備注',
            `ENABLED` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '是否開啟',
            `STATUS` int DEFAULT NULL COMMENT '狀態(tài) 數(shù)據(jù)狀態(tài):0=正常,1=刪除,失效',
            `CREATED_BY` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '創(chuàng)建人',
            `CREATED_TIME` datetime DEFAULT NULL COMMENT '創(chuàng)建時(shí)間',
            `UPDATED_BY` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人',
            `UPDATED_TIME` datetime DEFAULT NULL COMMENT '更新時(shí)間',
            `REVISION` int DEFAULT '0' COMMENT '樂觀鎖',
            PRIMARY KEY (`ID`) USING BTREE
          ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='數(shù)據(jù)處理 ';

          dp_process 表中的數(shù)據(jù)

          INSERT INTO `gccs`.`dp_process`(`ID`, `NAME`, `CODE`, `CATEGORY`, `IN_COLS`, `OUT_COLS`, `REMARK`, `ENABLED`, `STATUS`, `CREATED_BY`, `CREATED_TIME`, `UPDATED_BY`, `UPDATED_TIME`, `REVISION`) VALUES ('1''B''B''ly''A''B''B''1', 0, NULL, NULL, NULL, NULL, 0);
          INSERT INTO `gccs`.`dp_process`(`ID`, `NAME`, `CODE`, `CATEGORY`, `IN_COLS`, `OUT_COLS`, `REMARK`, `ENABLED`, `STATUS`, `CREATED_BY`, `CREATED_TIME`, `UPDATED_BY`, `UPDATED_TIME`, `REVISION`) VALUES ('2''D''D''ly''B''D''D''1', 0, NULL, NULL, NULL, NULL, 0);
          INSERT INTO `gccs`.`dp_process`(`ID`, `NAME`, `CODE`, `CATEGORY`, `IN_COLS`, `OUT_COLS`, `REMARK`, `ENABLED`, `STATUS`, `CREATED_BY`, `CREATED_TIME`, `UPDATED_BY`, `UPDATED_TIME`, `REVISION`) VALUES ('3''E''E''ly''B''E''E''1', 0, NULL, NULL, NULL, NULL, 0);
          INSERT INTO `gccs`.`dp_process`(`ID`, `NAME`, `CODE`, `CATEGORY`, `IN_COLS`, `OUT_COLS`, `REMARK`, `ENABLED`, `STATUS`, `CREATED_BY`, `CREATED_TIME`, `UPDATED_BY`, `UPDATED_TIME`, `REVISION`) VALUES ('4''G''G''ly''D''G''G''1', 0, NULL, NULL, NULL, NULL, 0);
          INSERT INTO `gccs`.`dp_process`(`ID`, `NAME`, `CODE`, `CATEGORY`, `IN_COLS`, `OUT_COLS`, `REMARK`, `ENABLED`, `STATUS`, `CREATED_BY`, `CREATED_TIME`, `UPDATED_BY`, `UPDATED_TIME`, `REVISION`) VALUES ('5''F''F''ly''D''F''F''1', 0, NULL, NULL, NULL, NULL, 0);

          3.2.2 redis庫數(shù)據(jù)

          keyValue
          A[{ "id": "1","outCols": "B"}]
          B[{"id": "2","outCols": "D"},{"id": "3","outCols": "E"}]
          D[{"id": "4","outCols": "G"},{"id": "5","outCols": "F"}]

          4. 解決方式

          通過遞歸的方式循環(huán)查詢、對(duì)比。

          ?本例主要牽扯到的知識(shí)點(diǎn)有:

          • Stack (棧,先進(jìn)后出)

          • 遞歸

          • redis簡(jiǎn)單增刪操作

          ?本文以修改方法代碼為例,介紹如何實(shí)現(xiàn)防死鏈調(diào)用,非常簡(jiǎn)單。

           /**
               * @create  2021-07-08 更新 數(shù)據(jù)處理
               * @param dpProcess 數(shù)據(jù)處理 模型
               * @param updateNil 全字段更新(新增時(shí)此字段可以忽略): 是:Y 否:N {@link SystemConst.Whether}
               * @return
               */
              @Override
              public int modify(DpProcess dpProcess, String updateNil){
                  
                  // **省略一堆代碼**

                  // 輸入集合統(tǒng)一處理
                  operInclos(dpProcess, orignDpProcess.getInCols());

                  // **省略一堆代碼**
              }

          ?operInclos() 方法 :本文重點(diǎn),主要做了數(shù)據(jù)校驗(yàn)、redis中數(shù)據(jù)更新等一系列操作

           /**
               * @create 輸入集合統(tǒng)一處理 2021/7/11 14:13
               * @param dpProcess 新數(shù)據(jù)處理對(duì)象
               * @param oldClos 原數(shù)據(jù)處理對(duì)象中的輸入集合
               * @return
               */
              private void operInclos(DpProcess dpProcess, String oldClos) {
                  // 新數(shù)據(jù)處理對(duì)象中的輸入集合
                  String inCols = dpProcess.getInCols();

                  // 若新數(shù)據(jù)處理對(duì)象中的輸入集合沒有值,則直接跳過,不進(jìn)行操作
                  if(StringUtils.isNotBlank(inCols)){
                      if(dpProcess.getInCols().contains(dpProcess.getOutCols())){
                          throw new ServiceException("數(shù)據(jù)處理流程配置輸入流程調(diào)用了輸出集合!");
                      }

                      // 數(shù)據(jù)類型轉(zhuǎn)換
                      Set<String> set = new HashSet(Arrays.asList(inCols.split(",")));

                      // 循環(huán)遍歷輸入集合
                      for (String inClo : set) {

                          // 最終需要遍歷的list
                          List<DpProcessVo> childFinalList = new ArrayList<>();

                          // 從redis中獲取當(dāng)前集合的影響關(guān)系
                          String dpProcessJson = (String) redisUtil.get(inClo);

                          // 如果redis中存儲(chǔ)的集合影響關(guān)系不為空,做簡(jiǎn)單的遍歷去重處理
                          if(StringUtils.isNotBlank(dpProcessJson)){

                              // redis中存儲(chǔ)的集合影響關(guān)系列表
                              List<DpProcessVo> children = new ArrayList<>();

                              // 進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換
                              children = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);
                              for (DpProcessVo dpProcessVo1 : children) {
                                  if(dpProcess.getId().equals(dpProcessVo1.getId())){
                                      continue;
                                  }
                                  childFinalList.add(dpProcessVo1);
                              }
                              // 添加本次影響的集合
                              DpProcessVo dpProcess1 = new DpProcessVo();
                              dpProcess1.setId(dpProcess.getId());
                              dpProcess1.setOutCols(dpProcess.getOutCols());
                              childFinalList.add(dpProcess1);
                          }
                          // 如果redis中沒有此輸入集合的影響關(guān)系,則可以直接進(jìn)行添加
                          else{
                              DpProcessVo dpProcess1 = new DpProcessVo();
                              dpProcess1.setId(dpProcess.getId());
                              dpProcess1.setOutCols(dpProcess.getOutCols());
                              childFinalList.add(dpProcess1);
                          }

                          // 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合
                          Stack<DpProcessVo> nodeStack = new Stack<>();
                          // 設(shè)置模型
                          DpProcessVo dpProcessVoTop = new DpProcessVo();
                          dpProcessVoTop.setOutCols(inClo);
                          dpProcessVoTop.setId(dpProcess.getId());
                          nodeStack.add(dpProcessVoTop);

                          // 遍歷需要進(jìn)行死鏈校驗(yàn)的數(shù)據(jù)
                          for (DpProcessVo dpProcessVo : childFinalList) {

                              // 是否添加標(biāo)識(shí)(默認(rèn)為添加,如果集合為死鏈,則進(jìn)行提示)
                              boolean addFlag = true;

                              // 循環(huán)遍歷棧
                              for (DpProcessVo processVo : nodeStack) {
                                  if(processVo.getOutCols().equals(dpProcessVo.getOutCols())){
                                      addFlag = false;
                                      break;
                                  }
                              }
                              if(!addFlag){

                                  throw new ServiceException("數(shù)據(jù)處理流程配置輸入流程調(diào)用了輸出集合!");
                              }
                              // 將dpProcessVo推到這個(gè)堆棧的頂部
                              nodeStack.push(dpProcessVo);

                              // 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合
                              invaldClosInfo(nodeStack);

                              // 移除此堆棧頂部的對(duì)象并將該對(duì)象作為此函數(shù)的值返回
                              nodeStack.pop();

                          }
                      }

                      // 處理需要?jiǎng)h除的集合
                      dealNeedDeleteCols(dpProcess, oldClos, set);

                      // 獲取并設(shè)置最終的集合名稱
                      String finallyCols = StringUtils.join(set.toArray(), ",");
                      dpProcess.setInCols(finallyCols);

                      // 省略一堆更新redis的操作
                  }
              }

          ?invaldClosInfo()方法:遞歸深度遍歷

          /**
               * @create 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合  2021/7/20 22:10
               * @param nodeStack 深度遍歷棧
               * @return void
               */
              public void invaldClosInfo(Stack<DpProcessVo> nodeStack) {

                  // 查看此堆棧頂部的對(duì)象而不將其從堆棧中移除
                  DpProcessVo dpProcessVo = nodeStack.peek();

                  // 從redis中查找此集合影響的流程關(guān)系
                  String dpProcessJson = (String) redisUtil.get(dpProcessVo.getOutCols());
                  // 如果集合沒有影響其他集合,則直接返回
                  if(StringUtils.isBlank(dpProcessJson)){
                      return;
                  }

                  //獲得節(jié)點(diǎn)的子節(jié)點(diǎn),對(duì)于二叉樹就是獲得節(jié)點(diǎn)的左子結(jié)點(diǎn)和右子節(jié)點(diǎn)
                  List<DpProcessVo> children = new ArrayList<>();
                  // redis中原來存儲(chǔ)的信息
                  children = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);

                  // 遍歷集合影響的集合關(guān)系
                  for (DpProcessVo dpProcessVo1 : children) {
                      boolean addFlag = true;
                      for (DpProcessVo processVo : nodeStack) {
                          if(processVo.getOutCols().equals(dpProcessVo1.getOutCols())){
                              addFlag = false;
                              break;
                          }
                      }
                      if(!addFlag){

                          throw new ServiceException("數(shù)據(jù)處理流程配置輸入流程調(diào)用了輸出集合!");
                      }

                      // 將dpProcessVo推到這個(gè)堆棧的頂部
                      nodeStack.push(dpProcessVo1);

                      // 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合
                      invaldClosInfo(nodeStack);

                      // 移除此堆棧頂部的對(duì)象并將該對(duì)象作為此函數(shù)的值返回
                      nodeStack.pop();
                  }
              }

          5.完整代碼

          ?記錄代碼,方便日后復(fù)習(xí)、調(diào)用、重構(gòu)。

          5.1Model

          ?模型主要分兩部分:數(shù)據(jù)處理模型和簡(jiǎn)化版的數(shù)據(jù)處理模型。

          ?DpProcess:數(shù)據(jù)處理模型,數(shù)據(jù)完整的Sql操作

          import com.alibaba.fastjson.annotation.JSONField;
          import com.baomidou.mybatisplus.annotation.*;
          import io.swagger.annotations.ApiModel;
          import io.swagger.annotations.ApiModelProperty;
          import lombok.Data;
          import lombok.EqualsAndHashCode;
          import lombok.experimental.Accessors;

          import java.io.Serializable;
          import java.util.Date;

          /**
           * <p>
           * 數(shù)據(jù)處理 
           * </p>
           *
           * @since 2021-07-08
           */
          @Data
          @EqualsAndHashCode(callSuper = false)
          @Accessors(chain = true)
          @ApiModel(value="DpProcess對(duì)象", description="數(shù)據(jù)處理 ")
          @TableName("dp_process")
          public class DpProcess implements Serializable {

              @TableField(exist = false)
              public static final String ENABLED = "ENABLED";

              @TableField(exist = false)
              public static final String STATUS = "STATUS";

              @TableField(exist = false)
              public static final String CATEGORY = "CATEGORY";

              private static final long serialVersionUID = 1L;

              @ApiModelProperty(value = "ID")
              @TableId(value = "ID"type = IdType.ASSIGN_ID)
              private String id;

              @ApiModelProperty(value = "名稱")
              @TableField("NAME")
              private String name;

              @ApiModelProperty(value = "代碼")
              @TableField("CODE")
              private String code;

              @ApiModelProperty(value = "類型 1=樓宇,2=房地產(chǎn)")
              @TableField("CATEGORY")
              private String category;

              @ApiModelProperty(value = "輸入集合")
              @TableField("IN_COLS")
              private String inCols;

              @ApiModelProperty(value = "影響集合")
              @TableField("OUT_COLS")
              private String outCols;

              @ApiModelProperty(value = "備注")
              @TableField("REMARK")
              private String remark;

              @ApiModelProperty(value = "是否開啟  0:否  1:是")
              @TableField("ENABLED")
              private String enabled;

              @ApiModelProperty(value = "狀態(tài) 數(shù)據(jù)狀態(tài):0=正常,1=刪除,失效")
              @TableField(value = "STATUS", fill = FieldFill.INSERT)
              private Integer status;

              @ApiModelProperty(value = "創(chuàng)建人")
              @TableField(value = "CREATED_BY", fill = FieldFill.INSERT)
              private String createdBy;

              @ApiModelProperty(value = "創(chuàng)建時(shí)間")
              @JSONField(format = "yyyy-MM-dd HH:mm:ss")
              @TableField(value = "CREATED_TIME", fill = FieldFill.INSERT)
              private Date createdTime;

              @ApiModelProperty(value = "更新人")
              @TableField(value = "UPDATED_BY", fill = FieldFill.UPDATE)
              private String updatedBy;

              @ApiModelProperty(value = "更新時(shí)間")
              @JSONField(format = "yyyy-MM-dd HH:mm:ss")
              @TableField(value = "UPDATED_TIME", fill = FieldFill.UPDATE)
              private Date updatedTime;

              @ApiModelProperty(value = "樂觀鎖")
              @Version
              @TableField(value = "REVISION", fill = FieldFill.INSERT)
              private Integer revision;

          }

          DpProcessVo: 數(shù)據(jù)處理簡(jiǎn)單模型,處理redis數(shù)據(jù)結(jié)構(gòu)數(shù)據(jù)。


          import io.swagger.annotations.ApiModel;
          import io.swagger.annotations.ApiModelProperty;
          import lombok.Data;
          import lombok.EqualsAndHashCode;
          import lombok.experimental.Accessors;

          @Data
          @EqualsAndHashCode(callSuper = false)
          @Accessors(chain = true)
          @ApiModel(value="DpProcessVo對(duì)象", description="數(shù)據(jù)處理簡(jiǎn)單模型 ")
          public class DpProcessVo{

              @ApiModelProperty(value = "ID")
              private String id;

              @ApiModelProperty(value = "影響集合")
              private String outCols;

          }

          5.2 Controller

          ?updateNil:讓用戶選擇使用那種更新方式,也可以把接口一拆為二,主要看個(gè)人習(xí)慣。

          /**
               * @create  2021-07-08 更新 數(shù)據(jù)處理
               * @param dpProcess 數(shù)據(jù)處理 模型
               * @param updateNil 全字段更新(新增時(shí)此字段可以忽略): 是:Y 否:N {@link SystemConst.Whether}
               * @return
               */
              @ApiOperation(value="更新",notes = "更新")
              @PostMapping("/modify")
              public Result modify(
                      @ApiParam(name = "dpProcess", value = "數(shù)據(jù)處理 模型", required = true) @RequestBody DpProcess dpProcess,
                      @ApiParam(name = "updateNil", value = "全字段更新(新增時(shí)此字段可以忽略): 是:Y 否:不傳或者隨意傳") @RequestParam(required = false) String updateNil) {
                  int addResult = dpProcessService.modify(dpProcess, updateNil);
                  if (addResult > 0) {
                      return new Result(CommonCode.SUCCESS, "更新成功!");
                  }
                  return new Result(CommonCode.FAIL, "更新失敗!");
              }

          5.3 Service

          ?沒啥好說的,就是一個(gè)接口。

              /**
               * @create 2021-07-08 更新 數(shù)據(jù)處理
               * @param dpProcess 數(shù)據(jù)處理 模型
               * @param updateNil 全字段更新(新增時(shí)此字段可以忽略): 是:Y 否:N {@link SystemConst.Whether}
               * @return
               */
              int modify(DpProcess dpProcess, String updateNil);

          5.4 Service 實(shí)現(xiàn)類

          ?DpRecord:數(shù)據(jù)處理記錄,不是本文重點(diǎn),此處可直接忽略,相關(guān)說明 待 數(shù)據(jù)流程處理文章中提現(xiàn)。

          /**
               * @create  2021-07-08 更新 數(shù)據(jù)處理
               * @param dpProcess 數(shù)據(jù)處理 模型
               * @param updateNil 全字段更新(新增時(shí)此字段可以忽略): 是:Y 否:N {@link SystemConst.Whether}
               * @return
               */
              @Override
              public int modify(DpProcess dpProcess, String updateNil){
                  if(dpProcess == null){
                      throw new ServiceException("數(shù)據(jù)處理模型不能為空!");
                  }
                  // 走更新方法
                  // 通過id查詢數(shù)據(jù)處理 詳情
                  DpProcess orignDpProcess = this.detail(dpProcess.getId());
                  if(dpProcess == null){
                      throw new ServiceException("數(shù)據(jù)處理模型信息不能為空!");
                  }

                  // 如果當(dāng)前任務(wù)已存在,需要先進(jìn)行取消
                  if("0".equals(dpProcess.getEnabled())){
                      if(defaultSchedulingConfigurer.hasTask(dpProcess.getId())){
                          defaultSchedulingConfigurer.cancelTriggerTask(dpProcess.getId());
                      }
                      // 根據(jù)數(shù)據(jù)處理ID查看數(shù)據(jù)庫中是否有需要執(zhí)行的數(shù)據(jù)處理記錄
                      DpRecord dpRecord = dpRecordService.getNeedExecRecordByDppId(dpProcess.getId());
                      // 如果數(shù)據(jù)處理記錄信息為空,則進(jìn)行新增
                      if(dpRecord != null){
                          // 設(shè)置結(jié)束時(shí)間為當(dāng)前時(shí)間
                          dpRecord.setEndTime(new Date());
                          // 運(yùn)行失敗
                          dpRecord.setSucceed("2");
                          dpRecord.setFailedResult("用戶取消操作");
                      }
                      // 對(duì)數(shù)據(jù)處理記錄進(jìn)行更新或者保存
                      dpRecordService.addOrUpdate(dpRecord, null);
                  }

                  // 限制輸出集合不能為空
                  dpProcess.setOutCols(StringUtils.isNotBlank(dpProcess.getOutCols()) ? dpProcess.getOutCols() : orignDpProcess.getOutCols());
                  if(StringUtils.isBlank(dpProcess.getOutCols())){
                      throw new ServiceException("數(shù)據(jù)影響集合不能為空!");
                  }

                  // 輸入集合統(tǒng)一處理
                  operInclos(dpProcess, orignDpProcess.getInCols());

                  // 全字段更新
                  if(SystemConst.Whether.Yes.getCode().equals(updateNil)){
                      if(StringUtils.isBlank(dpProcess.getRemark())){
                          throw new ServiceException("數(shù)據(jù)處理備注不能為空!");
                      }
                      // 備注不能小于20字
                      if(dpProcess.getRemark().length() < 20){
                          throw new ServiceException("數(shù)據(jù)處理備注不能小于20字!");
                      }
                      return dpProcessMapper.alwaysUpdateSomeColumnById(dpProcess);
                  }
                  // 數(shù)據(jù)處理代碼自動(dòng)填充
                  dpProcess.setCode(StringUtils.isBlank(dpProcess.getCode()) ? orignDpProcess.getCode() : dpProcess.getCode());

                  return dpProcessMapper.updateById(dpProcess);
              }

          operInclos() :處理輸入集合的方法

          /**
           * @create 輸入集合統(tǒng)一處理  2021/7/11 14:13
           * @param dpProcess 新數(shù)據(jù)處理對(duì)象
           * @param oldClos 原數(shù)據(jù)處理對(duì)象中的而輸入集合
           * @return
           */
          private void operInclos(DpProcess dpProcess, String oldClos) {
              // 新數(shù)據(jù)處理對(duì)象中的輸入集合
              String inCols = dpProcess.getInCols();

              // 若新數(shù)據(jù)處理對(duì)象中的輸入集合沒有值,則直接跳過,不進(jìn)行操作
              if(StringUtils.isNotBlank(inCols)){
                  if(dpProcess.getInCols().contains(dpProcess.getOutCols())){
                      throw new ServiceException("數(shù)據(jù)處理流程配置輸入流程調(diào)用了輸出集合!");
                  }

                  // 數(shù)據(jù)類型轉(zhuǎn)換
                  Set<String> set = new HashSet(Arrays.asList(inCols.split(",")));

                  // 循環(huán)遍歷輸入集合
                  for (String inClo : set) {

                      // 最終需要遍歷的list
                      List<DpProcessVo> childFinalList = new ArrayList<>();

                      // 從redis中獲取當(dāng)前集合的影響關(guān)系
                      String dpProcessJson = (String) redisUtil.get(inClo);

                      // 如果redis中存儲(chǔ)的集合影響關(guān)系不為空,做簡(jiǎn)單的遍歷去重處理
                      if(StringUtils.isNotBlank(dpProcessJson)){

                          // redis中存儲(chǔ)的集合影響關(guān)系列表
                          List<DpProcessVo> children = new ArrayList<>();

                          // 進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換
                          children = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);
                          for (DpProcessVo dpProcessVo1 : children) {
                              if(dpProcess.getId().equals(dpProcessVo1.getId())){
                                  continue;
                              }
                              childFinalList.add(dpProcessVo1);
                          }
                          // 添加本次影響的集合
                          DpProcessVo dpProcess1 = new DpProcessVo();
                          dpProcess1.setId(dpProcess.getId());
                          dpProcess1.setOutCols(dpProcess.getOutCols());
                          childFinalList.add(dpProcess1);
                      }
                      // 如果redis中沒有此輸入集合的影響關(guān)系,則可以直接進(jìn)行添加
                      else{
                          DpProcessVo dpProcess1 = new DpProcessVo();
                          dpProcess1.setId(dpProcess.getId());
                          dpProcess1.setOutCols(dpProcess.getOutCols());
                          childFinalList.add(dpProcess1);
                      }

                      // 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合
                      Stack<DpProcessVo> nodeStack = new Stack<>();
                      // 設(shè)置模型
                      DpProcessVo dpProcessVoTop = new DpProcessVo();
                      dpProcessVoTop.setOutCols(inClo);
                      dpProcessVoTop.setId(dpProcess.getId());
                      nodeStack.add(dpProcessVoTop);

                      // 遍歷需要進(jìn)行死鏈校驗(yàn)的數(shù)據(jù)
                      for (DpProcessVo dpProcessVo : childFinalList) {

                          // 是否添加標(biāo)識(shí)(默認(rèn)為添加,如果集合為死鏈,則進(jìn)行提示)
                          boolean addFlag = true;

                          // 循環(huán)遍歷棧
                          for (DpProcessVo processVo : nodeStack) {
                              if(processVo.getOutCols().equals(dpProcessVo.getOutCols())){
                                  addFlag = false;
                                  break;
                              }
                          }
                          if(!addFlag){

                              throw new ServiceException("數(shù)據(jù)處理流程配置輸入流程調(diào)用了輸出集合!");
                          }
                          // 將dpProcessVo推到這個(gè)堆棧的頂部
                          nodeStack.push(dpProcessVo);

                          // 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合
                          invaldClosInfo(nodeStack);

                          // 移除此堆棧頂部的對(duì)象并將該對(duì)象作為此函數(shù)的值返回
                          nodeStack.pop();

                      }
                  }

                  // 處理需要?jiǎng)h除的集合
                  dealNeedDeleteCols(dpProcess, oldClos, set);

                  // 獲取并設(shè)置最終的集合名稱
                  String finallyCols = StringUtils.join(set.toArray(), ",");
                  dpProcess.setInCols(finallyCols);

                  // 能走到這一步,說明所有的集合沒有問題,可以進(jìn)行更新操作了(再一次遍歷是為了和上面的校驗(yàn)分開,避免部分?jǐn)?shù)據(jù)被更新)
                  for (String inClo : set) {

                      List<DpProcessVo> dpProcessVoList = new ArrayList<>();
                      // 首先獲取當(dāng)前集合影響的數(shù)據(jù)處理對(duì)象
                      String dpProcessJson = (String) redisUtil.get(inClo);
                      if(StringUtils.isBlank(dpProcessJson)){
                          DpProcessVo dpProcessVo = new DpProcessVo();
                          dpProcessVo.setId(dpProcess.getId());
                          dpProcessVo.setOutCols(dpProcess.getOutCols());
                          dpProcessVoList.add(dpProcessVo);
                          // 進(jìn)行數(shù)據(jù)的存儲(chǔ)
                          redisUtil.set(inClo, JSONArray.toJSON(dpProcessVoList).toString());
                          continue;
                      }

                      // redis中原來存儲(chǔ)的信息
                      List<DpProcessVo> dpProcessVos = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);

                      // 把數(shù)據(jù)處理對(duì)象轉(zhuǎn)換為HashSet
                      HashSet<DpProcessVo> hashSet = new HashSet(dpProcessVos);
                      // 當(dāng)前集合影響的 其他集合列表
                      List<DpProcessVo> childFinalList = new ArrayList<>();

                      // 遍歷redis中存儲(chǔ)的集合影響關(guān)系,并進(jìn)行簡(jiǎn)單去重處理
                      for (DpProcessVo dpProcessVo : hashSet) {
                          if(dpProcessVo.getId().equals(dpProcess.getId())){
                              continue;
                          }
                          childFinalList.add(dpProcessVo);
                      }

                      // 添加上本次影響的集合
                      DpProcessVo dpProcessVo = new DpProcessVo();
                      dpProcessVo.setId(dpProcess.getId());
                      dpProcessVo.setOutCols(dpProcess.getOutCols());
                      // 添加當(dāng)前數(shù)據(jù)數(shù)據(jù)對(duì)象
                      childFinalList.add(dpProcessVo);
                      // 進(jìn)行數(shù)據(jù)的存儲(chǔ)
                      redisUtil.set(inClo, JSONArray.toJSON(childFinalList).toString());
                  }
              }
          }

          invaldClosInfo() : 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合

          /**
           * @create 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合  2021/7/20 22:10
           * @param nodeStack 深度遍歷棧
           * @return void
           */
          public void invaldClosInfo(Stack<DpProcessVo> nodeStack) {

              // 查看此堆棧頂部的對(duì)象而不將其從堆棧中移除
              DpProcessVo dpProcessVo = nodeStack.peek();

              // 從redis中查找此集合影響的流程關(guān)系
              String dpProcessJson = (String) redisUtil.get(dpProcessVo.getOutCols());
              // 如果集合沒有影響其他集合,則直接返回
              if(StringUtils.isBlank(dpProcessJson)){
                  return;
              }

              //獲得節(jié)點(diǎn)的子節(jié)點(diǎn),對(duì)于二叉樹就是獲得節(jié)點(diǎn)的左子結(jié)點(diǎn)和右子節(jié)點(diǎn)
              List<DpProcessVo> children = new ArrayList<>();
              // redis中原來存儲(chǔ)的信息
              children = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);

              // 遍歷集合影響的集合關(guān)系
              for (DpProcessVo dpProcessVo1 : children) {
                  boolean addFlag = true;
                  for (DpProcessVo processVo : nodeStack) {
                      if(processVo.getOutCols().equals(dpProcessVo1.getOutCols())){
                          addFlag = false;
                          break;
                      }
                  }
                  if(!addFlag){

                      throw new ServiceException("數(shù)據(jù)處理流程配置輸入流程調(diào)用了輸出集合!");
                  }

                  // 將dpProcessVo推到這個(gè)堆棧的頂部
                  nodeStack.push(dpProcessVo1);

                  // 驗(yàn)證數(shù)據(jù)處理流程配置輸入流程是否調(diào)用了輸出集合
                  invaldClosInfo(nodeStack);

                  // 移除此堆棧頂部的對(duì)象并將該對(duì)象作為此函數(shù)的值返回
                  nodeStack.pop();
              }
          }

          dealNeedDeleteCols() : 主要處理--原數(shù)據(jù)為 A 集合影響 B 集合,修改為 C 集合影響了 B 集合,此時(shí)需要?jiǎng)h除 A 對(duì) B的影響關(guān)系

          /**
           * @create 處理需要?jiǎng)h除的集合 2021/7/20 17:58
           * @param dpProcess 數(shù)據(jù)處理模型
           * @param oldClos 原來的數(shù)據(jù)處理模型中的集合信息
           * @param set 最新的集合名稱信息
           * @return void
           */
          private void dealNeedDeleteCols(DpProcess dpProcess, String oldClos, Set<String> set) {

              if(StringUtils.isBlank(oldClos)){
                  return;
              }
              // 獲取去重后的集合數(shù)組
              List<String> newColsList = new ArrayList<>(set);

              // 原來的集合數(shù)組
              List<String> oldColsList = Arrays.asList(oldClos.split(","));

              // 獲取兩個(gè)集合的差集
              List<String> reduceList = oldColsList.stream().filter(item -> !newColsList.contains(item)).collect(toList());
              if(reduceList == null || reduceList.size() == 0){
                  return;
              }
              for (String clos : reduceList) {
                  // 獲取redis中的集合
                  String dpProcessJson = (String) redisUtil.get(clos);
                  if(StringUtils.isBlank(dpProcessJson)){
                      continue;
                  }
                  // redis中原來存儲(chǔ)的信息
                  List<DpProcessVo> dpProcessVos = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);
                  // 遍歷刪除的集合中影響的流程ID
                  HashSet<DpProcessVo> hashSet = new HashSet(dpProcessVos);
                  Iterator<DpProcessVo> it = hashSet.iterator();
                  while(it.hasNext()){
                      DpProcessVo dpProcessVo = it.next();
                      if(dpProcessVo.getId().equals(dpProcess.getId())){
                          it.remove();
                      }
                  }
                  // 如果當(dāng)前集合影響的流程為空,則進(jìn)行刪除
                  if(hashSet.isEmpty()){
                      // 進(jìn)行數(shù)據(jù)的存儲(chǔ)
                      redisUtil.delete(clos);
                      continue;
                  }
                  // 進(jìn)行數(shù)據(jù)的存儲(chǔ)
                  redisUtil.set(clos, JSONArray.toJSON(hashSet.toArray()).toString());
              }

          }

          6.測(cè)試

          ?可通過單元測(cè)試等多種方式,本文提供簡(jiǎn)單的測(cè)試數(shù)據(jù)。

          {
              "category""ly",
              "code""F",
              "createdBy""",
              "createdTime": null,
              "enabled""1",
              "id""5",
              "inCols""D",
              "name""F",
              "outCols""L",
              "remark""F",
              "revision": 0,
              "status": 0,
              "updatedBy""",
              "updatedTime": null
            }


            作者 |  學(xué)海無涯519 

          來源 |  cnblogs.com/wgx519/p/15324635.html



          加鋒哥微信: java3459  
          圍觀鋒哥朋友圈,每天推送Java干貨!


          瀏覽 40
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲最大中文在线 | 美国黄色一级A片 | 中文字幕在线观看免费高清完整版在线 | 国内色图 | 免费日皮视频在线观看 |