浏览代码

!248 紧急修复 Ip2Region InputStream读取函数导致的OOM问题
Merge pull request !248 from 疯狂的狮子Li/dev

疯狂的狮子Li 7 月之前
父节点
当前提交
a87450ec2c

+ 18 - 2
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java

@@ -1,5 +1,6 @@
 package org.dromara.common.core.utils.ip;
 
+import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.io.resource.ResourceUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.core.exception.ServiceException;
@@ -8,6 +9,7 @@ import org.lionsoul.ip2region.service.Config;
 import org.lionsoul.ip2region.service.Ip2Region;
 import org.lionsoul.ip2region.xdb.Util;
 
+import java.io.File;
 import java.io.InputStream;
 import java.time.Duration;
 
@@ -43,11 +45,18 @@ public class RegionUtils {
             // 因为加载整个xdb文件会耗费非常大的内存,如果你不希望加载整个xdb到内存中,更推荐使用 VIndexCache 或 NoCache(即实时读取文件)策略和 setXdbPath/setXdbFile 加载方法(需要注意的一点,setXdbPath 和 setXdbFile 不支持读取ClassPath(即源码和resource目录)中的文件)。
             // 一般而言,更建议把xdb数据库放到一个指定的文件目录中(即不打包进jar包中),然后使用 NoCache + 配合SearcherPool的并发池读取数据,更方便随时更新xdb数据库
 
+            // TODO 2025年12月23日 Ip2Region封装的 InputStream 读取函数 Searcher.loadContentFromInputStream 在Linux环境下会申请过大的byte[]空间而导致OOM,这里先用临时文件的方案解决,等后续 Ip2Region 更新解决方案
+            // 创建临时文件
+            File v4TempXdb = FileUtil.writeFromStream(ResourceUtil.getStream(DEFAULT_IPV4_XDB_PATH), FileUtil.createTempFile());
+
             // IPv4配置
             Config v4Config = Config.custom()
                 .setCachePolicy(Config.BufferCache)
-                .setXdbInputStream(ResourceUtil.getStream(DEFAULT_IPV4_XDB_PATH))
+                .setXdbFile(v4TempXdb)
+//                .setXdbInputStream(ResourceUtil.getStream(DEFAULT_IPV4_XDB_PATH))
                 .asV4();
+            // 删除临时文件
+            v4TempXdb.delete();
 
             // IPv6配置
             Config v6Config = null;
@@ -55,10 +64,17 @@ public class RegionUtils {
             if (v6XdbInputStream == null) {
                 log.warn("未加载 IPv6 地址库:未在类路径下找到文件 {}。当前仅启用 IPv4 查询。如需启用 IPv6,请将 ip2region_v6.xdb 放置到 resources 目录", DEFAULT_IPV6_XDB_PATH);
             } else {
+                // 创建临时文件
+                File v6TempXdb = FileUtil.writeFromStream(ResourceUtil.getStream(DEFAULT_IPV4_XDB_PATH), FileUtil.createTempFile());
+
                 v6Config = Config.custom()
                     .setCachePolicy(Config.BufferCache)
-                    .setXdbInputStream(v6XdbInputStream)
+                    .setXdbFile(v6TempXdb)
+//                    .setXdbInputStream(v6XdbInputStream)
                     .asV6();
+
+                // 删除临时文件
+                v6TempXdb.delete();
             }
 
             // 初始化Ip2Region实例

+ 4 - 0
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/service/SysDataScopeService.java

@@ -1,7 +1,9 @@
 package org.dromara.common.mybatis.service;
 
 import org.apache.dubbo.config.annotation.DubboReference;
+import org.dromara.common.core.constant.CacheNames;
 import org.dromara.system.api.RemoteDataScopeService;
+import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
 
 /**
@@ -24,6 +26,7 @@ public class SysDataScopeService {
      * @param roleId 角色ID
      * @return 返回角色的自定义权限语句,如果没有找到则返回 null
      */
+    @Cacheable(cacheNames = CacheNames.SYS_ROLE_CUSTOM, key = "#roleId", condition = "#roleId != null")
     public String getRoleCustom(Long roleId) {
         return remoteDataScopeService.getRoleCustom(roleId);
     }
@@ -34,6 +37,7 @@ public class SysDataScopeService {
      * @param deptId 部门ID
      * @return 返回部门及其下级的权限语句,如果没有找到则返回 null
      */
+    @Cacheable(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, key = "#deptId", condition = "#deptId != null")
     public String getDeptAndChild(Long deptId) {
         return remoteDataScopeService.getDeptAndChild(deptId);
     }

+ 22 - 2
ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java

@@ -1,12 +1,19 @@
 package org.dromara.common.translation.core.impl;
 
+import cn.hutool.core.convert.Convert;
 import lombok.AllArgsConstructor;
 import org.apache.dubbo.config.annotation.DubboReference;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.redis.utils.CacheUtils;
 import org.dromara.common.translation.annotation.TranslationType;
 import org.dromara.common.translation.constant.TransConstant;
 import org.dromara.common.translation.core.TranslationInterface;
 import org.dromara.system.api.RemoteUserService;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * 用户昵称翻译实现
  *
@@ -22,9 +29,22 @@ public class NicknameTranslationImpl implements TranslationInterface<String> {
     @Override
     public String translation(Object key, String other) {
         if (key instanceof Long id) {
-            return remoteUserService.selectNicknameByIds(id.toString());
+            String nickname = CacheUtils.get(CacheNames.SYS_NICKNAME, key);
+            if (StringUtils.isNotBlank(nickname)) {
+                return nickname;
+            }
+            return remoteUserService.selectNicknameById(id);
         } else if (key instanceof String ids) {
-            return remoteUserService.selectNicknameByIds(ids);
+            List<String> list = new ArrayList<>();
+            for (Long id : StringUtils.splitTo(ids, Convert::toLong)) {
+                String nickname = CacheUtils.get(CacheNames.SYS_NICKNAME, key);
+                if (StringUtils.isNotBlank(nickname)) {
+                    list.add(nickname);
+                } else {
+                    list.add(remoteUserService.selectNicknameById(id));
+                }
+            }
+            return StringUtils.joinComma(list);
         }
         return null;
     }

+ 10 - 1
ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/UserNameTranslationImpl.java

@@ -1,5 +1,9 @@
 package org.dromara.common.translation.core.impl;
 
+import cn.hutool.core.convert.Convert;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.redis.utils.CacheUtils;
 import org.dromara.common.translation.annotation.TranslationType;
 import org.dromara.common.translation.constant.TransConstant;
 import org.dromara.common.translation.core.TranslationInterface;
@@ -21,6 +25,11 @@ public class UserNameTranslationImpl implements TranslationInterface<String> {
 
     @Override
     public String translation(Object key, String other) {
-        return remoteUserService.selectUserNameById((Long) key);
+        Long userId = Convert.toLong(key);
+        String username = CacheUtils.get(CacheNames.SYS_USER_NAME, userId);
+        if (StringUtils.isNotBlank(username)) {
+            return username;
+        }
+        return remoteUserService.selectUserNameById(userId);
     }
 }