diff --git a/pom.xml b/pom.xml index e021234..7a38151 100644 --- a/pom.xml +++ b/pom.xml @@ -102,6 +102,12 @@ pagehelper-spring-boot-starter ${pagehelper.version} + + + com.belerweb + pinyin4j + 2.5.1 + diff --git a/src/main/java/com/xly/service/QuoService.java b/src/main/java/com/xly/service/QuoService.java index 8ea411d..385e1e7 100644 --- a/src/main/java/com/xly/service/QuoService.java +++ b/src/main/java/com/xly/service/QuoService.java @@ -2,6 +2,7 @@ package com.xly.service; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.pinyin.PinyinUtil; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson2.JSONObject; import com.xly.entity.ParamRule; @@ -41,7 +42,7 @@ public class QuoService { } List dataAll = session.getCurrentTool().getParamRuleListAll(); //获取产品的参数 - List dataProduct = dataAll.stream().filter(one-> "产品".equals(one.getSGroup()) && !one.getBDynamicParam() ).collect(Collectors.toUnmodifiableList()); + List dataProduct = dataAll.stream().filter(one-> "产品".equals(one.getSGroup()) && !one.getBDynamicParam()).collect(Collectors.toUnmodifiableList()); List dataPart = dataAll.stream().filter(one-> "部件".equals(one.getSGroup()) && !one.getBDynamicParam()).collect(Collectors.toUnmodifiableList()); List datasDynamicPart = dataAll.stream().filter(one-> "sDynamicPart".equals(one.getSParamValue()) && !one.getBDynamicParam()).collect(Collectors.toUnmodifiableList()); List> sAll = new ArrayList<>(); @@ -67,7 +68,11 @@ public class QuoService { product.put("sParamConfigValue",p.getSParamConfigValue()==null?StrUtil.EMPTY:p.getSParamConfigValue()); //获取动态参数 adddynamicData( sValue, dataAll, p, finalArgsOld, sAll, product); - productList.add(product); + if( !"sDynamicPart".equals(p.getSParamValue()) + &&!"sDynamicPartDel".equals(p.getSParamValue()) + ){ + productList.add(product); + } } }); List> partList = new ArrayList<>(); @@ -109,7 +114,7 @@ public class QuoService { datasDynamicPartArray.forEach(one->{ List dataPartDynamic = dataAll.stream().filter(d -> one.equals(d.getSDynamicParam()) - && "新增部件".equals(d.getSDynamicParamName() + && "sDynamicPart".equals(d.getSDynamicParamName() )&&d.getBDynamicParam() ).collect(Collectors.toUnmodifiableList()); if(ObjectUtil.isNotEmpty(dataPartDynamic)){ diff --git a/src/main/java/com/xly/tool/DynamicToolProvider.java b/src/main/java/com/xly/tool/DynamicToolProvider.java index 92760d8..ecdf436 100644 --- a/src/main/java/com/xly/tool/DynamicToolProvider.java +++ b/src/main/java/com/xly/tool/DynamicToolProvider.java @@ -34,12 +34,14 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -188,6 +190,13 @@ public class DynamicToolProvider implements ToolProvider { finalArgs.put(k,v); } }); + if(argsNew.containsKey("删除动态部件")){ + argsNew.put("sDynamicPartDel",argsNew.get("删除动态部件")); + } + if(!argsNew.containsKey("sDynamicPartDel")){ + finalArgs.remove("sDynamicPartDel"); + finalArgs.remove("删除动态部件"); + } // 2 【补全动态参数】动态参数补全 try{ args = applyValues(args, meta.getParamRuleListCheck()); @@ -223,6 +232,7 @@ public class DynamicToolProvider implements ToolProvider { } //判断是否首次进入给提示 如果没有产品名称 产品长 宽 if(!Validator.isValid(args.get("dProductWidth")) + && !Validator.isValid(args.get("sCustomerName")) && !Validator.isValid(args.get("dProductLength")) && !Validator.isValid(args.get("sProductName"))){ String sTsMemo = session.getCurrentTool().getSTsMemo(); @@ -256,110 +266,246 @@ public class DynamicToolProvider implements ToolProvider { * @return void * @Description 获取动态参数 **/ - private List doSetParamgetArgsAfter(Map argsNew,UserSceneSession session){ - //获取当前方法 - //根据新参数获取需要填写参数 + private List doSetParamgetArgsAfter(Map argsNew, UserSceneSession session) { List dynamicParamRule = new ArrayList<>(); - try{ + try { ToolMeta tool = session.getCurrentTool(); Map argsOld = session.getArgs(); Map args = DeepCopyUtils.deepCopy(argsNew); - if(ObjectUtil.isEmpty(argsOld)){ + + if (ObjectUtil.isEmpty(argsOld)) { argsOld = new HashMap<>(); } - //根据新录入的参数获取规则 + List paramRuleDataAll = tool.getParamRuleListAll(); - //动态参数 - List paramRuleData = paramRuleDataAll.stream().filter(one-> - ( ObjectUtil.isNotEmpty(args.get(one.getSParam())) || ObjectUtil.isNotEmpty(args.get(one.getSParamValue()))) + + // 1. 获取动态参数规则 + List paramRuleData = paramRuleDataAll.stream() + .filter(one -> (ObjectUtil.isNotEmpty(args.get(one.getSParam())) + || ObjectUtil.isNotEmpty(args.get(one.getSParamValue()))) && ObjectUtil.isNotEmpty(one.getSDynamicParamRuleSql()) - ).collect(Collectors.toUnmodifiableList()); - //为空的时候需要重新插入不为空 表示之前已经放过了 - AtomicReference> paramRuleDataAllNew = new AtomicReference<>(paramRuleDataAll); - if(ObjectUtil.isNotEmpty(paramRuleData)){ + && !"sDynamicPart".equals(one.getSParamValue()) + && !"sDynamicPartDel".equals(one.getSParamValue()) + ) + .collect(Collectors.toList()); + List paramRuleDataAllNew = new ArrayList<>(paramRuleDataAll); + // 2. 处理非动态参数 + if (ObjectUtil.isNotEmpty(paramRuleData)) { Map finalArgsOld = argsOld; - paramRuleData.forEach(one->{ - Map searMap = new HashMap<>(); - searMap.putAll(args); - //新参数如果值变了移除掉之前插入的 - paramRuleDataAllNew.set(paramRuleDataAll.stream().filter(d -> - !one.getSParam().equals(d.getSDynamicParam()) - || (one.getSParam().equals(d.getSDynamicParam()) && one.getSParamValue().equals(d.getSParamValue())) - ).collect(Collectors.toUnmodifiableList())); + + for (ParamRule one : paramRuleData) { + Map searMap = new HashMap<>(args); + paramRuleDataAllNew.removeIf(d -> + one.getSParam().equals(d.getSDynamicParam()) + && one.getSParamValue().equals(d.getSParamValue()) + ); String sValue = searMap.get(one.getSParam()).toString(); List addValue = new ArrayList<>(); - if(JSONUtil.isTypeJSONArray(sValue)){ - addValue = JSONUtil.toList(sValue,String.class); - }else{ + + if (JSONUtil.isTypeJSONArray(sValue)) { + addValue = JSONUtil.toList(sValue, String.class); + } else { addValue.add(sValue); } - for(String sVaule:addValue){ - //根据值获取动态部件 - List paramRuleDataD = paramRuleDataAllNew.get().stream().filter(d -> - d.getBDynamicParam() - && sValue.equals(d.getSDynamicParam()) - && one.getSParam().equals(d.getSDynamicParamName()) - ).collect(Collectors.toUnmodifiableList()); - - //如果不存在的加入方法参数中 - if(ObjectUtil.isEmpty(paramRuleDataD)){ - searMap.put("sRuleId",one.getSId()); - searMap.put("sTooId",one.getSParentId()); - searMap.put("sParam",one.getSParam()); - searMap.put("sParamValue",sVaule); -// searMap.put("sParamValue",one.getSParamValue()); - searMap.put("sParamName",one.getSParam()); + + for (String sVaule : addValue) { + List paramRuleDataD = paramRuleDataAllNew.stream() + .filter(d -> d.getBDynamicParam() + && sVaule.equals(d.getSDynamicParam()) + && one.getSParam().equals(d.getSDynamicParamName())) + .collect(Collectors.toList()); + + // 如果不存在,则添加 + if (ObjectUtil.isEmpty(paramRuleDataD)) { + searMap.put("sRuleId", one.getSId()); + searMap.put("sTooId", one.getSParentId()); + searMap.put("sParam", one.getSParam()); + searMap.put("sParamValue", sVaule); + searMap.put("sParamName", one.getSParam()); + searMap.put("argsNew", JSONObject.toJSONString(args)); + searMap.put("argsAll", JSONObject.toJSONString(finalArgsOld)); + String sSql = one.getSDynamicParamRuleSql(); - searMap.put("argsNew",JSONObject.toJSONString(args)); - searMap.put("argsAll",JSONObject.toJSONString(finalArgsOld)); - //如果不是SELECT 开头 - List> selectData = new ArrayList<>(); - List> dynamicParamRuleOne = new ArrayList<>(); - if(sSql.replaceAll(" ","").toLowerCase().startsWith("select") - || sSql.replaceAll(" ","").toLowerCase().startsWith("call")){ - try{ - selectData = this.dynamicExeDbService.findSql(searMap, sSql); - if(ObjectUtil.isNotEmpty(selectData)){ + List> dynamicParamRuleOne = new ArrayList<>(); + + if (sSql.replaceAll(" ", "").toLowerCase().startsWith("select") + || sSql.replaceAll(" ", "").toLowerCase().startsWith("call")) { + try { + List> selectData = + this.dynamicExeDbService.findSql(searMap, sSql); + if (ObjectUtil.isNotEmpty(selectData)) { String sData = (ObjectUtil.isNotEmpty(selectData) - && ObjectUtil.isNotEmpty(selectData.get(0).get("sData")))?selectData.get(0).get("sData").toString():StrUtil.EMPTY; - if(ObjectUtil.isNotEmpty(sData)){ - dynamicParamRuleOne = JsonUtils.toList(sData,Map.class); + && ObjectUtil.isNotEmpty(selectData.get(0).get("sData"))) + ? selectData.get(0).get("sData").toString() + : StrUtil.EMPTY; + if (ObjectUtil.isNotEmpty(sData)) { + dynamicParamRuleOne = JsonUtils.toList(sData, Map.class); } } - }catch (Exception e){} - }else{ - //表示过程走自定义参数 + } catch (Exception e) { + log.error("执行动态参数SQL失败", e); + } } - if(ObjectUtil.isNotEmpty(dynamicParamRuleOne)){ - dynamicParamRuleOne.forEach(dynamicParamRuleData->{ - ParamRule paramRule = BeanUtil.toBean(dynamicParamRuleData,ParamRule.class); - if(!RuleCode.CONST.getCode().equals(paramRule.getSRule()) + + if (ObjectUtil.isNotEmpty(dynamicParamRuleOne)) { + for (Map dynamicParamRuleData : dynamicParamRuleOne) { + ParamRule paramRule = BeanUtil.toBean(dynamicParamRuleData, ParamRule.class); + if (!RuleCode.CONST.getCode().equals(paramRule.getSRule()) && ObjectUtil.isNotEmpty(paramRule.getSParamConfig()) - && JSONUtil.isTypeJSON(paramRule.getSParamConfig()) - ){ - try{getConstMeg(paramRule);}catch (Exception e){ e.printStackTrace();} + && JSONUtil.isTypeJSON(paramRule.getSParamConfig())) { + try { + getConstMeg(paramRule); + } catch (Exception e) { + log.error("获取常量配置失败", e); + } } dynamicParamRule.add(paramRule); - }); + } } } } - }); + } + } + + // 3. 处理动态部件 + List sDynamicPart = paramRuleDataAll.stream() + .filter(one -> "sDynamicPart".equals(one.getSParamValue())) + .collect(Collectors.toList()); + // 3. 处理动态部件 + List sDynamicPartDel = paramRuleDataAll.stream() + .filter(one -> "sDynamicPartDel".equals(one.getSParamValue())) + .collect(Collectors.toList()); + //移除的动态部件 + List sDynamicPartDelValue = new ArrayList<>(); + if(ObjectUtil.isNotEmpty(sDynamicPartDel)){ + ParamRule sDynamicPartOneDel = sDynamicPartDel.get(0); + String sValueDel = ObjectUtil.isNotEmpty(args.get(sDynamicPartOneDel.getSParam())) + ? args.get(sDynamicPartOneDel.getSParam()).toString() + : StrUtil.EMPTY; + if (ObjectUtil.isNotEmpty(sValueDel)) { + if (JSONUtil.isTypeJSONArray(sValueDel)) { + sDynamicPartDelValue = JSONUtil.toList(sValueDel, String.class); + } else { + sDynamicPartDelValue.add(sValueDel); + } + } } - List dataAll = new ArrayList<>(paramRuleDataAllNew.get()); + //新增部件 + if (ObjectUtil.isNotEmpty(sDynamicPart) + && ObjectUtil.isNotEmpty(sDynamicPart.get(0)) + && ObjectUtil.isNotEmpty(sDynamicPart.get(0).getSParam())) { + + ParamRule sDynamicPartOne = sDynamicPart.get(0); + String sValue = ObjectUtil.isNotEmpty(args.get(sDynamicPartOne.getSParam())) + ? args.get(sDynamicPartOne.getSParam()).toString() + : StrUtil.EMPTY; + + if (ObjectUtil.isNotEmpty(sValue)) { + List addValueOld = new ArrayList<>(); + + if (JSONUtil.isTypeJSONArray(sValue)) { + addValueOld = JSONUtil.toList(sValue, String.class); + } else { + addValueOld.add(sValue); + } + //新增部件不在删除部件中的 + List finalSDynamicPartDelValue = sDynamicPartDelValue; + List addValue = addValueOld.stream().filter(one-> !finalSDynamicPartDelValue.contains(one)).collect(Collectors.toList()); + //反写值取SESSION + session.getArgs().put(sDynamicPart.get(0).getSParam(),JSONUtil.toJsonStr(addValue)); + session.getArgs().put(sDynamicPart.get(0).getSParamValue(),JSONUtil.toJsonStr(addValue)); + //收集当前有效的动态部件值 + List validDynamicPartValues = new ArrayList<>(); + for (String sVal : addValue) { + if(!finalSDynamicPartDelValue.contains(sVal)){ + validDynamicPartValues.add(sVal); + } + boolean exists = paramRuleDataAllNew.stream() + .anyMatch(d -> sVal.equals(d.getSDynamicParam())); + if (!exists) { + // 获取部件标准参数 + List sDynamicPartCheckAddCopy = paramRuleDataAll.stream() + .filter(d -> ObjectUtil.isNotEmpty(d.getSGroup()) + && !d.getBDynamicParam() + && d.getSGroup().equals("部件") + && d.getBStandardParam()) + .map(d -> { + ParamRule copy = new ParamRule(); + BeanUtils.copyProperties(d, copy); + + // 设置动态参数 + String paramName = d.getSParam().split("-").length > 1 + ? d.getSParam().split("-")[1] + : d.getSParam().split("-")[0]; + copy.setSParam(sVal + "-" + paramName); + + // 拼音转换 + String firstLetters = ""; + try { + firstLetters = PinyinUtil.convertToPinyin(sVal); + } catch (Exception e) { + log.warn("拼音转换失败: {}", sVal); + firstLetters = sVal.substring(0, 1).toUpperCase(); + } + copy.setSParamValue(firstLetters + d.getSParamValue()); + copy.setIOrder(d.getIOrder() + 100000); + copy.setBDynamicParam(true); + copy.setSDynamicParam(sVal); + copy.setSDynamicParamName("sDynamicPart"); + return copy; + }) + .collect(Collectors.toList()); + + if (ObjectUtil.isNotEmpty(sDynamicPartCheckAddCopy)) { + paramRuleDataAllNew.addAll(sDynamicPartCheckAddCopy); + log.info("添加了 {} 个动态部件参数,sVal={}", + sDynamicPartCheckAddCopy.size(), sVal); + } + } else { + log.info("动态部件已存在,跳过: {}", sVal); + } + } + // 移除不在 addValue 中的动态部件 + paramRuleDataAllNew = paramRuleDataAllNew.stream() + .filter(p -> { + // 如果不是动态部件参数,保留 + if (!p.getBDynamicParam() || !"sDynamicPart".equals(p.getSDynamicParamName())) { + return true; + } + // 如果是动态部件参数,检查是否在有效值列表中 + return validDynamicPartValues.contains(p.getSDynamicParam()); + }) + .collect(Collectors.toList()); + log.info("移除无效动态部件后,列表大小: {}", paramRuleDataAllNew.size()); + }else{ + //移除不是动态部件的 + paramRuleDataAllNew = paramRuleDataAllNew.stream() + .filter(p -> !p.getBDynamicParam() || !"sDynamicPart".equals(p.getSDynamicParamName())) + .collect(Collectors.toList()); + log.info("sValue为空,移除所有动态部件"); + } + } + // 4. 合并所有参数 + List dataAll = new ArrayList<>(paramRuleDataAllNew); dataAll.addAll(dynamicParamRule); - paramRuleDataAllNew.set(dataAll); - List newList = new ArrayList<>(paramRuleDataAllNew.get()); - List dynamicParamRuleAll = Validator.deduplicateByParamValue(newList); - List paramRuleList = dynamicParamRuleAll.stream().filter(one-> one.getBTipModel()).collect(Collectors.toUnmodifiableList()); - List paramRuleListCheck = dynamicParamRuleAll.stream().filter(one->one.getBEmpty()).collect(Collectors.toUnmodifiableList()); + + // 5. 去重并设置 + List dynamicParamRuleAll = Validator.deduplicateByParamValue(dataAll); + List paramRuleList = dynamicParamRuleAll.stream() + .filter(one -> one.getBTipModel()) + .collect(Collectors.toList()); + List paramRuleListCheck = dynamicParamRuleAll.stream() + .filter(one -> one.getBEmpty()) + .collect(Collectors.toList()); + session.getCurrentTool().setParamRuleListAll(dynamicParamRuleAll); session.getCurrentTool().setParamRuleListCheck(paramRuleListCheck); session.getCurrentTool().setParamRuleList(paramRuleList); - }catch (Exception e){ + + } catch (Exception e) { e.printStackTrace(); - log.error(e.getMessage()); + log.error("获取动态参数失败: {}", e.getMessage(), e); } return dynamicParamRule; @@ -645,12 +791,18 @@ public class DynamicToolProvider implements ToolProvider { Map data = quoService.getQuoData(args, session); List> sAll = (List>) data.get("sAll"); List> sEmptyData = sAll.stream().filter(one-> BooleanUtil.toBoolean(one.get("bEmpty").toString()) - && (!Validator.isValid(one.get("sValue"))) && !"sDynamicPart".equals(one.get("sName"))).collect(Collectors.toUnmodifiableList()); + && (!Validator.isValid(one.get("sValue"))) + && !"sDynamicPart".equals(one.get("sName")) + && !"sDynamicPartDel".equals(one.get("sName")) + ).collect(Collectors.toUnmodifiableList()); data.remove("sAll"); if(ObjectUtil.isNotEmpty(sEmptyData)){ List missData = session.getCurrentTool().getParamRuleListAll().stream().filter(d -> d.getBEmpty() - && (!Validator.isValid(args.get(d.getSParam()))) && !"sDynamicPart".equals(d.getSParamValue())).collect(Collectors.toUnmodifiableList()); + && (!Validator.isValid(args.get(d.getSParam()))) + && !"sDynamicPart".equals(d.getSParamValue()) + && !"sDynamicPartDel".equals(d.getSParamValue()) + ).collect(Collectors.toUnmodifiableList()); data.put("bTs",true); String sSystemPrompt = SystemPromptGenerator.buildMissParamPrompt(session,missData); session.setSSystemPrompt(sSystemPrompt); @@ -911,7 +1063,10 @@ public class DynamicToolProvider implements ToolProvider { private List checkRequiredParams(Map args, List paramDefs) { Map returnMap = transformationArgs( args, paramDefs); List paramDefsCheck = paramDefs.stream() - .filter(pd -> !"sDynamicPart".equals(pd.getSParamValue())).collect(Collectors.toUnmodifiableList()); + .filter(pd -> + !"sDynamicPart".equals(pd.getSParamValue()) + && !"sDynamicPartDel".equals(pd.getSParamValue()) + ).collect(Collectors.toUnmodifiableList()); paramDefsCheck = paramDefsCheck.stream() .filter(pd -> Boolean.TRUE.equals(pd.getBEmpty()) && pd.getBTipModel()).collect(Collectors.toUnmodifiableList()); paramDefsCheck = paramDefsCheck.stream() diff --git a/src/main/java/com/xly/util/DeepCopyUtils.java b/src/main/java/com/xly/util/DeepCopyUtils.java index ef946dd..63ef35d 100644 --- a/src/main/java/com/xly/util/DeepCopyUtils.java +++ b/src/main/java/com/xly/util/DeepCopyUtils.java @@ -61,10 +61,10 @@ public class DeepCopyUtils { } } - private static T cloneArray(T array) { + public static T cloneArray(T array) { Class componentType = array.getClass().getComponentType(); - if (componentType.isPrimitive()) { + if (componentType !=null && componentType.isPrimitive()) { // 基本类型数组 int length = java.lang.reflect.Array.getLength(array); Object copy = java.lang.reflect.Array.newInstance(componentType, length); diff --git a/src/main/java/com/xly/util/PinyinUtil.java b/src/main/java/com/xly/util/PinyinUtil.java new file mode 100644 index 0000000..c6d20ad --- /dev/null +++ b/src/main/java/com/xly/util/PinyinUtil.java @@ -0,0 +1,53 @@ +package com.xly.util; + +import net.sourceforge.pinyin4j.PinyinHelper; +import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; +import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; +import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; +import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; + +public class PinyinUtil { + + private static final HanyuPinyinOutputFormat FORMAT = new HanyuPinyinOutputFormat(); + + static { + FORMAT.setCaseType(HanyuPinyinCaseType.LOWERCASE); // 小写 + FORMAT.setToneType(HanyuPinyinToneType.WITHOUT_TONE); // 不带声调 + } + + public static String convertToPinyin(Object input) { + if (input == null) { + return ""; + } + + String sVal = input.toString().trim(); + if (sVal.isEmpty()) { + return ""; + } + + try { + StringBuilder result = new StringBuilder(); + char[] chars = sVal.toCharArray(); + + for (char ch : chars) { + // 判断是否为汉字 + if (String.valueOf(ch).matches("[\\u4E00-\\u9FA5]+")) { + String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(ch, FORMAT); + if (pinyinArray != null && pinyinArray.length > 0) { + // 多音字取第一个 + result.append(pinyinArray[0]); + } else { + result.append(ch); // 无法转换保留原字符 + } + } else { + result.append(ch); // 非汉字直接保留 + } + } + + return result.toString() + "_"; + } catch (BadHanyuPinyinOutputFormatCombination e) { + System.err.println("拼音转换异常: " + sVal + ", " + e.getMessage()); + return sVal + "_"; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/xly/util/Validator.java b/src/main/java/com/xly/util/Validator.java index 4c0c81e..d15a897 100644 --- a/src/main/java/com/xly/util/Validator.java +++ b/src/main/java/com/xly/util/Validator.java @@ -36,32 +36,6 @@ public class Validator { } return ObjectUtil.isNotEmpty(obj); } - - /** - * 根据指定 key 对 List> 去重 - * - * @param list 原始列表 - * @param key 去重依据的 key - * @return 去重后的列表(保留首次出现的顺序) - */ - public static List> distinctByKey( - List> list, String key) { - - if (list == null || list.isEmpty()) { - return new ArrayList<>(); - } - - return list.stream() - .filter(item -> item != null && item.get(key) != null) - .collect(Collectors.toMap( - item -> item.get(key), - Function.identity(), - (existing, replacement) -> existing - )) - .values() - .stream() - .collect(Collectors.toList()); - } /*** * @Author 钱豹 * @Date 0:58 2026/7/2