From d5457ed99cf483f18ebf51aae225a8d24f73c1e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Wed, 1 Apr 2026 09:51:09 +0800 Subject: [PATCH] =?UTF-8?q?fix=20=E4=BF=AE=E5=A4=8D=20DeptExcelConverter?= =?UTF-8?q?=20=E5=AD=98=E5=9C=A8=E7=9A=84=E5=86=85=E5=AD=98=E6=B3=84?= =?UTF-8?q?=E6=BC=8F=E9=97=AE=E9=A2=98=20=E4=B8=8E=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/listener/DeptExcelConverter.java | 76 ++++++++++++------- .../system/listener/DeptExcelOptions.java | 22 +++--- 2 files changed, 61 insertions(+), 37 deletions(-) diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/DeptExcelConverter.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/DeptExcelConverter.java index 2225adf39..c2d6c8460 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/DeptExcelConverter.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/DeptExcelConverter.java @@ -1,7 +1,8 @@ package org.dromara.system.listener; -import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.tree.Tree; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; import lombok.RequiredArgsConstructor; import org.apache.fesod.sheet.converters.Converter; import org.apache.fesod.sheet.enums.CellDataTypeEnum; @@ -18,69 +19,92 @@ import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeUnit; /** * Excel 部门转换处理 + * + * @author AprilWind */ @RequiredArgsConstructor -@Component public class DeptExcelConverter implements Converter { - private static final ThreadLocal> TL_ID_TO_NAME = new ThreadLocal<>(); + private static final String CACHE_KEY = "dept:excel"; - private static final ThreadLocal> TL_NAME_TO_ID = new ThreadLocal<>(); + /** + * Caffeine 缓存:key=CACHE_KEY,value=[idToName, nameToId],5分钟过期 + */ + private static final Cache DEPT_CACHE = Caffeine.newBuilder() + .expireAfterWrite(30, TimeUnit.SECONDS) + .build(); - private void initThreadCache() { - Map idMap = TL_ID_TO_NAME.get(); - if (CollUtil.isNotEmpty(idMap)) { - return; - } + private DeptMaps getDeptMaps() { + ISysDeptService deptService = SpringUtils.getBean(ISysDeptService.class); + return DEPT_CACHE.get(CACHE_KEY, k -> { + Map> deptPathToTreeMap = buildDeptPathMap(deptService); + Map idToName = new HashMap<>(); + Map nameToId = new HashMap<>(); + deptPathToTreeMap.forEach((name, treeNode) -> { + Long deptId = treeNode.getId(); + idToName.put(deptId, name); + nameToId.put(name, deptId); + }); + return new DeptMaps(idToName, nameToId); + }); + } - Map> deptPathToTreeMap = TreeBuildUtils.buildTreeNodeMap( - SpringUtils.getBean(ISysDeptService.class).selectDeptTreeList(new SysDeptBo()), + /** + * 构建部门路径 → 树节点映射,供 Converter 和 Options 共用 + */ + static Map> buildDeptPathMap(ISysDeptService deptService) { + return TreeBuildUtils.buildTreeNodeMap( + deptService.selectDeptTreeList(new SysDeptBo()), "/", Tree::getName ); - - Map idToName = new HashMap<>(); - Map nameToId = new HashMap<>(); - deptPathToTreeMap.forEach((name, treeNode) -> { - Long deptId = treeNode.getId(); - idToName.put(deptId, name); - nameToId.put(name, deptId); - }); - - TL_ID_TO_NAME.set(idToName); - TL_NAME_TO_ID.set(nameToId); } + /** + * 指定 Java 类型:Long(部门ID) + */ @Override public Class supportJavaTypeKey() { return Long.class; } + /** + * 指定 Excel 类型:字符串 + */ @Override public CellDataTypeEnum supportExcelTypeKey() { return CellDataTypeEnum.STRING; } + /** + * 【导入】Excel 填写的部门完整路径 → 转为 ID + */ @Override public Long convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { String deptName = cellData.getStringValue(); if (StringUtils.isBlank(deptName)) { return null; } - initThreadCache(); - return TL_NAME_TO_ID.get().get(deptName); + return getDeptMaps().nameToId().get(deptName); } + /** + * 【导出】部门 ID → 转为 Excel 显示的完整路径名称 + */ @Override public WriteCellData convertToExcelData(Long value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (value == null) { return new WriteCellData<>(""); } - initThreadCache(); - String deptName = TL_ID_TO_NAME.get().getOrDefault(value, ""); + String deptName = getDeptMaps().idToName().getOrDefault(value, ""); return new WriteCellData<>(deptName); } + + private record DeptMaps(Map idToName, Map nameToId) { + } + } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/DeptExcelOptions.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/DeptExcelOptions.java index 993518a22..88377876d 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/DeptExcelOptions.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/DeptExcelOptions.java @@ -1,30 +1,30 @@ package org.dromara.system.listener; -import cn.hutool.core.lang.tree.Tree; import lombok.RequiredArgsConstructor; -import org.dromara.common.core.utils.TreeBuildUtils; +import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.excel.core.ExcelOptionsProvider; -import org.dromara.system.domain.bo.SysDeptBo; import org.dromara.system.service.ISysDeptService; import org.springframework.stereotype.Component; -import java.util.List; -import java.util.Map; import java.util.Set; /** * Excel 部门下拉选项数据源 + * + * @author AprilWind */ @RequiredArgsConstructor -@Component public class DeptExcelOptions implements ExcelOptionsProvider { - private final ISysDeptService deptService; - + /** + * 获取下拉选项数据 + * + * @return 下拉选项列表 + */ @Override public Set getOptions() { - List> trees = deptService.selectDeptTreeList(new SysDeptBo()); - Map> treeMap = TreeBuildUtils.buildTreeNodeMap(trees, "/", Tree::getName); - return treeMap.keySet(); + ISysDeptService deptService = SpringUtils.getBean(ISysDeptService.class); + return DeptExcelConverter.buildDeptPathMap(deptService).keySet(); } + }