java中避免集合死链调用详情

网友投稿 266 2022-12-06

java中避免集合死链调用详情

目录1. 前言2. 场景3. 环境3.1 开发环境准备3.2 数据准备3.2.1 mysql数据库表及数据3.2.2 redis库数据4. 解决方式5.完整代码5.1 Model5.2 Controller5.3 Service5.4 Service 实现类6.测试

1. 前言

开发过程中, 一些集合 的变动会触发任务去 改变 其他的集合 ,为了保障任务的正确执行,应避免出现死循环调用,即对 集合之间的影响关系 进行一些限制。怕日后遗忘,特在此记录。

2. 场景

A 集合影响 A 集合。

A 集合影响 B 集合,B 集合影响了 A 集合。

A 集合影响 B 集合,B 集合影响了 C 集合,C 集合影响了 A 集合。

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

3. 环境

3.1 开发环境准备

JDK 1.8

SpringBoot 2.x

Mysql 8

redis

3.2 数据准备

3.2.1 Mysql数据库表及数据

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=房地产',

`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 '状态 数据状态:0=正常,1=删除,失效',

`CREATED_BY` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',

`CREATED_TIME` datetime DEFAULT NULL COMMENT '创建时间',

`UPDATED_BY` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人',

`UPDATED_TIME` datetime DEFAULT NULL COMMENT '更新时间',

`REVISION` int DEFAULT '0' COMMENT '乐观锁',

PRIMARY KEY (`ID`) USING BTREE

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='数据处理 ';

dp_process 表中的数据

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库数据

key

Value

A

[{ "id": "1","outCols": "B"}]

B

[{"id": "2","outCols": "D"},{"id": "3","outCols": "E"}]

D

[{"id": "4","outCols": "G"},{"id": "5","outCols": "F"}]

4. 解决方式

通过递归的方式循环查询、对比。

本例主要牵扯到的知识点有:

Stack (栈,先进后出)

递归

redis简单增删操作

本文以 修改方法 代码为例,介绍如何实现防死链调用,非常简单。

/**

* @create 2021-07-08 更新 数据处理

* @param dpProcess 数据处理 模型

* @param updateNil 全字段更新(新增时此字段可以忽略): 是:Y 否:N {@link SystemConst.Whether}

* @return

*/

@Override

public int modify(DpProcess dpProcess, String updateNil){

// **省略一堆代码**

// 输入集合统一处理

operInclos(dpProcess, orignDpProcess.getInCols());

// **省略一堆代码**

}

operInclos() 方法 : 重点 ,主要做了数据校验、redis中数据更新等一系列操作

/**

* @create 输入集合统一处理 2021/7/11 14:13

* @param dpProcess 新数据处理对象

* @param oldClos 原数据处理对象中的输入集合

* @return

*/

private void operInclos(DpProcess dpProcess, String oldClos) {

// 新数据处理对象中的输入集合

String inCols = dpProcess.getInCols();

// 若新数据处理对象中的输入集合没有值,则直接跳过,不进行操作

if(StringUtils.isNotBlank(inCols)){

if(dpProcess.getInCols().contains(dpProcess.getOutCols())){

throw new ServiceException("数据处理流程配置输入流程调用了输出集合!");

}

// 数据类型转换

Set set = new HashSet(Arrays.asList(inCols.split(",")));

// 循环遍历输入集合

for (String inClo : set) {

// 最终需要遍历的list

List childFinalList = new ArrayList<>();

// 从redis中获取当前集合的影响关系

String dpProcessjson = (String) redisUtil.get(inClo);

// 如果redis中存储的集合影响关系不为空,做简单的遍历去重处理

if(StringUtils.isNotBlank(dpProcessJson)){

// redis中存储的集合影响关系列表

List children = new ArrayList<>();

// 进行数据类型转换

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中没有此输入集合的影响关系,则可以直接进行添加

else{

DpProcessVo dpProcess1 = new DpProcessVo();

dpProcess1.setId(dpProcess.getId());

dpProcess1.setOutCols(dpProcess.getOutCols());

childFinalList.add(dpProcess1);

}

// 验证数据处理流程配置输入流程是否调用了输出集合

Stack nodeStack = new Stack<>();

// 设置模型

DpProcessVo dpProcessVoTop = new DpProcessVo();

dpProcessVoTop.setOutCols(inClo);

dpProcessVoTop.setId(dpProcess.getId());

nodeStack.add(dpProcessVoTop);

// 遍历需要进行死链校验的数据

for (DpProcessVo dpProcessVo : childFinalList) {

// 是否添加标识(默认为添加,如果集合为死链,则进行提示)

boolean addFlag = true;

// 循环遍历栈

for (DpProcessVo processVo : nodeStack) {

if(processVo.getOutCols().equals(dpProcessVo.getOutCols())){

addFlag = false;

break;

}

}

if(!addFlag){

throw new ServiceException("数据处理流程配置输入流程调用了输出集合!");

}

// 将dpProcessVo推到这个堆栈的顶部

nodeStack.push(dpProcessVo);

// 验证数据处理流程配置输入流程是否调用了输出集合

invaldClosInfo(nodeStack);

// 移除此堆栈顶部的对象并将该对象作为此函数的值返回

nodeStack.pop();

}

}

// 处理需要删除的集合

dealNeedDeleteCols(dpProcess, oldClos, set);

// 获取并设置最终的集合名称

String finallyCols = StringUtils.join(set.toArray(), ",");

dpProcess.setInCols(finallyCols);

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

}

}

invaldClosInfo()方法: 递归深度遍历

/**

* @create 验证数据处理流程配置输入流程是否调用了输出集合 2021/7/20 22:10

* @param nodeStack 深度遍历栈

* @return void

*/

public void invaldClosInfo(Stack nodeStack) {

// 查看此堆栈顶部的对象而不将其从堆栈中移除

DpProcessVo dpProcessVo = nodeStack.peek();

// 从redis中查找此集合影响的流程关系

String dpProcessJson = (String) redisUtil.get(dpProcessVo.getOutCols());

// 如果集合没有影响其他集合,则直接返回

if(StringUtils.isBlank(dpProcessJson)){

return;

}

//获得节点的子节点,对于二叉树就是获得节点的左子结点和右子节点

List children = new ArrayList<>();

// redis中原来存储的信息

children = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);

// 遍历集合影响的集合关系

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("数据处理流程配置输入流程调用了输出集合!");

}

// 将dpProcessVo推到这个堆栈的顶部

nodeStack.push(dpProcessVo1);

// 验证数据处理流程配置输入流程是否调用了输出集合

invaldClosInfo(nodeStack);

// 移除此堆栈顶部的对象并将该对象作为此函数的值返回

nodeStack.pop();

}

}

5.完整代码

记录代码,方便日后复习、调用、重构。

5.1 Model

模型主要分两部分:数据处理模型和简化版的数据处理模型。

DpProcess:数据处理模型,数据完整的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;

/**

*

* 数据处理

*

*

* @since 2021-07-08

*/

@Data

@EqualsAndHashCode(callSuper = false)

@Accessors(chain = true)

@ApiModel(value="DpProcess对象", description="数据处理 ")

@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=房地产")

@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 = "状态 数据状态:0=正常,1=删除,失效")

@TableField(value = "STATUS", fill = FieldFill.INSERT)

private Integer status;

@ApiModelProperty(value = "创建人")

@TableField(value = "CREATED_BY", fill = FieldFill.INSERT)

private String createdBy;

@ApiModelProperty(value = "创建时间")

@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 = "更新时间")

@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: 数据处理简单模型,处理redis数据结构数据。

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对象", description="数据处理简单模型 ")

public class DpProcessVo{

@ApiModelProperty(value = "ID")

private String id;

@ApiModelProperty(value = "影响集合")

private String outCols;

}

5.2 Controller

updateNil:让用户选择使用那种更新方式,也可以把接口一拆为二,主要看个人习惯。

/**

* @create 2021-07-08 更新 数据处理

* @param dpProcess 数据处理 模型

* @param updateNil 全字段更新(新增时此字段可以忽略): 是:Y 否:N {@link SystemConst.Whether}

* @return

*/

@ApiOperation(value="更新",notes = "更新")

@PostMapping("/modify")

public Result modify(

@ApiParam(name = "dpProcess", value = "数据处理 模型", required = true) @RequestBody DpProcess dpProcess,

@ApiParam(name = "updateNil", value = "全字段更新(新增时此字段可以忽略): 是: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

没啥好说的,就是一个接口。

/**

* @create 2021-07-08 更新 数据处理

* @param dpProcess 数据处理 模型

* @param updateNil 全字段更新(新增时此字段可以忽略): 是:Y 否:N {@link SystemConst.Whether}

* @return

*/

int modify(DpProcess dpProcess, String updateNil);

5.4 Service 实现类

DpRecord:数据处理记录,不是本文重点,此处可直接忽略,相关说明 待 数据流程处理文章中提现。

/**

* @create 2021-07-08 更新 数据处理

* @param dpProcess 数据处理 模型

* @param updateNil 全字段更新(新增时此字段可以忽略): 是:Y 否:N {@link SystemConst.Whether}

* @return

*/

@Override

public int modify(DpProcess dpProcess, String updateNil){

if(dpProcess == null){

throw new ServiceException("数据处理模型不能为空!");

}

// 走更新方法

// 通过id查询数据处理 详情

DpProcess orignDpProcess = this.detail(dpProcess.getId());

if(dpProcess == null){

throw new ServiceException("数据处理模型信息不能为空!");

}

// 如果当前任务已存在,需要先进行取消

if("0".equals(dpProcess.getEnabled())){

if(defaultSchedulingConfigurer.hasTask(dpProcess.getId())){

defaultSchedulingConfigurer.cancelTriggerTask(dpProcess.getId());

}

// 根据数据处理ID查看数据库中是否有需要执行的数据处理记录

DpRecord dpRecord = dpRecordService.getNeedExecRecordByDppId(dpProcess.getId());

// 如果数据处理记录信息为空,则进行新增

if(dpRecord != null){

// 设置结束时间为当前时间

dpRecord.setEndTime(new Date());

// 运行失败

dpRecord.setSucceed("2");

dpRecord.setFailedResult("用户取消操作");

}

// 对数据处理记录进行更新或者保存

dpRecordService.addOrUpdate(dpRecord, null);

}

// 限制输出集合不能为空

dpProcess.setOutCols(StringUtils.isNotBlank(dpProcess.getOutCols()) ? dpProcess.getOutCols() : orignDpProcess.getOutCols());

if(StringUtils.isBlank(dpProcess.getOutCols())){

throw new ServiceException("数据影响集合不能为空!");

}

// 输入集合统一处理

operInclos(dpProcess, orignDpProcess.getInCols());

// 全字段更新

if(SystemConst.Whether.Yes.getCode().equals(updateNil)){

if(StringUtils.isBlank(dpProcess.getRemark())){

throw new ServiceException("数据处理备注不能为空!");

}

// 备注不能小于20字

if(dpProcess.getRemark().length() < 20){

throw new ServiceException("数据处理备注不能小于20字!");

}

return dpProcessMapper.alwaysUpdateSomeColumnById(dpProcess);

}

// 数据处理代码自动填充

dpProcess.setCode(StringUtils.isBlank(dpProcess.getCode()) ? orignDpProcess.getCode() : dpProcess.getCode());

return dpProcessMapper.updateById(dpProcess);

}

operInclos() : 处理输入集合的方法

/**

* @create 输入集合统一处理 2021/7/11 14:13

* @param dpProcess 新数据处理对象

* @param oldClos 原数据处理对象中的而输入集合

* @return

*/

private void operInclos(DpProcess dpProcess, String oldClos) {

// 新数据处理对象中的输入集合

String inCols = dpProcess.getInCols();

// 若新数据处理对象中的输入集合没有值,则直接跳过,不进行操作

if(StringUtils.isNotBlank(inCols)){

if(dpProcess.getInCols().contains(dpProcess.getOutCols())){

throw new ServiceException("数据处理流程配置输入流程调用了输出集合!");

}

// 数据类型转换

Set set = new HashSet(Arrays.asList(inCols.split(",")));

// 循环遍历输入集合

for (String inClo : set) {

// 最终需要遍历的list

List childFinalList = new ArrayList<>();

// 从redis中获取当前集合的影响关系

String dpProcessJson = (String) redisUtil.get(inClo);

// 如果redis中存储的集合影响关系不为空,做简单的遍历去重处理

if(StringUtils.isNotBlank(dpProcessJson)){

// redis中存储的集合影响关系列表

List children = new ArrayList<>();

// 进行数据类型转换

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中没有此输入集合的影响关系,则可以直接进行添加

else{

DpProcessVo dpProcess1 = new DpProcessVo();

dpProcess1.setId(dpProcess.getId());

dpProcess1.setOutCols(dpProcess.getOutCols());

childFinalList.add(dpProcess1);

}

// 验证数据处理流程配置输入流程是否调用了输出集合

Stack nodeStack = new Stack<>();

// 设置模型

DpProcessVo dpProcessVoTop = new DpProcessVo();

dpProcessVoTop.setOutCols(inClo);

dpProcessVoTop.setId(dpProcess.getId());

nodeStack.add(dpProcessVoTop);

// 遍历需要进行死链校验的数据

for (DpProcessVo dpProcessVo : childFinalList) {

// 是否添加标识(默认为添加,如果集合为死链,则进行提示)

boolean addFlag = true;

// 循环遍历栈

for (DpProcessVo processVo : nodeStack) {

if(processVo.getOutCols().equals(dpProcessVo.getOutCols())){

addFlag = false;

break;

}

}

if(!addFlag){

throw new ServiceException("数据处理流程配置输入流程调用了输出集合!");

}

// 将dpProcessVo推到这个堆栈的顶部

nodeStack.push(dpProcessVo);

// 验证数据处理流程配置输入流程是否调用了输出集合

invaldClosInfo(nodeStack);

// 移除此堆栈顶部的对象并将该对象作为此函数的值返回

nodeStack.pop();

}

}

// 处理需要删除的集合

dealNeedDeleteCols(dpProcess, oldClos, set);

// 获取并设置最终的集合名称

String finallyCols = StringUtils.join(set.toArray(), ",");

dpProcess.setInCols(finallyCols);

// 能走到这一步,说明所有的集合没有问题,可以进行更新操作了(再一次遍历是为了和上面的校验分开,避免部分数据被更新)

for (String inClo : set) {

List dpProcessVoList = new ArrayList<>();

// 首先获取当前集合影响的数据处理对象

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);

// 进行数据的存储

redisUtil.set(inClo, JSONArray.toJSON(dpProcessVoList).toString());

continue;

}

// redis中原来存储的信息

List dpProcessVos = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);

// 把数据处理对象转换为HashSet

HashSet hashSet = new HashSet(dpProcessVos);

// 当前集合影响的 其他集合列表

List childFinalList = new ArrayList<>();

// 遍历redis中存储的集合影响关系,并进行简单去重处理

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());

// 添加当前数据数据对象

childFinalList.add(dpProcessVo);

// 进行数据的存储

redisUtil.set(inClo, JSONArray.toJSON(childFinalList).toString());

}

}

}

invaldClosInfo() : 验证数据处理流程配置输入流程是否调用了输出集合

/**

* @create 验证数据处理流程配置输入流程是否调用了输出集合 2021/7/20 22:10

* @param nodeStack 深度遍历栈

* @return void

*/

public void invaldClosInfo(Stack nodeStack) {

// 查看此堆栈顶部的对象而不将其从堆栈中移除

http://DpProcessVo dpProcessVo = nodeStack.peek();

// 从redis中查找此集合影响的流程关系

String dpProcessJson = (String) redisUtil.get(dpProcessVo.getOutCols());

// 如果集合没有影响其他集合,则直接返回

if(StringUtils.isBlank(dpProcessJson)){

return;

}

//获得节点的子节点,对于二叉树就是获得节点的左子结点和右子节点

List children = new ArrayList<>();

// redis中原来存储的信息

children = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);

// 遍历集合影响的集合关系

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("数据处理流程配置输入流程调用了输出集合!");

}

// 将dpProcessVo推到这个堆栈的顶部

nodeStack.push(dpProcessVo1);

// 验证数据处理流程配置输入流程是否调用了输出集合

invaldClosInfo(nodeStack);

// 移除此堆栈顶部的对象并将该对象作为此函数的值返回

nodeStack.pop();

}

}

dealNeedDeleteCols() : 主要处理--原数据为 A 集合影响 B 集合,修改为 C 集合影响了 B 集合,此时需要删除 A 对 B的影响关系

/**

* @create 处理需要删除的集合 2021/7/20 17:58

* @param dpProcess 数据处理模型

* @param oldClos 原来的数据处理模型中的集合信息

* @param set 最新的集合名称信息

* @return void

*/

private void dealNeedDeleteCols(DpProcess dpProcess, String oldClos, Set set) {

if(StringUtils.isBlank(oldClos)){

return;

}

// 获取去重后的集合数组

List newColsList = new ArrayList<>(set);

// 原来的集合数组

List oldColsList = Arrays.asList(oldClos.split(","));

// 获取两个集合的差集

List 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中原来存储的信息

List dpProcessVos = JSONArray.parseArray(dpProcessJson, DpProcessVo.class);

// 遍历删除的集合中影响的流程ID

HashSet hashSet = new HashSet(dpProcessVos);

Iterator it = hashSet.iterator();

while(it.hasNext()){

DpProcessVo dpProcessVo = it.next();

if(dpProcessVo.getId().equals(dpProcess.getId())){

it.remove();

}

}

// 如果当前集合影响的流程为空,则进行删除

if(hashSet.isEmpty()){

// 进行数据的存储

redisUtil.delete(clos);

continue;

}

// 进行数据的存储

redisUtil.set(clos, JSONArray.toJSON(hashSet.toArray()).toString());

}

}

6.测试

可通过单元测试等多种方式,本文提供简单的测试数据。

{

"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

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:详解Java volatile 内存屏障底层原理语义
下一篇:Mybatis查询条件包含List的情况说明
相关文章

 发表评论

暂时没有评论,来抢沙发吧~