From cbe576ecfa1248807cb5e56f6eb3bbe4fe2f9262 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=A7=8B=E8=BE=9E=E6=9C=AA=E5=AF=92?= <545073804@qq.com>
Date: Thu, 11 Dec 2025 12:55:22 +0800
Subject: [PATCH 1/2] =?UTF-8?q?feat=20IP=E5=9C=B0=E5=9D=80=E8=A1=8C?=
=?UTF-8?q?=E6=94=BF=E5=8C=BA=E5=9F=9F=E7=A6=BB=E7=BA=BF=E6=9F=A5=E8=AF=A2?=
=?UTF-8?q?=E6=94=AF=E6=8C=81IPv6=EF=BC=88=E5=B7=B2=E6=8F=90=E4=BE=9B?=
=?UTF-8?q?=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81=EF=BC=8C=E5=BC=80=E5=8F=91?=
=?UTF-8?q?=E8=80=85=E8=87=AA=E8=A1=8C=E5=86=B3=E5=AE=9A=E6=98=AF=E5=90=A6?=
=?UTF-8?q?=E4=BD=BF=E7=94=A8=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 2 +-
.../{ip2region.xdb => ip2region_v4.xdb} | Bin
.../common/core/utils/ip/AddressUtils.java | 43 +-----
.../common/core/utils/ip/Ip2RegionHelper.java | 146 ++++++++++++++++++
.../common/core/utils/ip/RegionUtils.java | 51 ------
5 files changed, 155 insertions(+), 87 deletions(-)
rename ruoyi-admin/src/main/resources/{ip2region.xdb => ip2region_v4.xdb} (100%)
create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/Ip2RegionHelper.java
delete mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java
diff --git a/pom.xml b/pom.xml
index 8b603c29e..ee9aef2df 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,7 +38,7 @@
1.80
1.16.7
- 2.7.0
+ 3.3.0
2.28.22
diff --git a/ruoyi-admin/src/main/resources/ip2region.xdb b/ruoyi-admin/src/main/resources/ip2region_v4.xdb
similarity index 100%
rename from ruoyi-admin/src/main/resources/ip2region.xdb
rename to ruoyi-admin/src/main/resources/ip2region_v4.xdb
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java
index 2fe3bd7b6..7c797a2d7 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java
@@ -20,51 +20,24 @@ public class AddressUtils {
public static final String UNKNOWN_IP = "XX XX";
// 内网地址
public static final String LOCAL_ADDRESS = "内网IP";
- // 未知地址
- public static final String UNKNOWN_ADDRESS = "未知";
public static String getRealAddressByIP(String ip) {
// 处理空串并过滤HTML标签
ip = HtmlUtil.cleanHtmlTag(StringUtils.blankToDefault(ip,""));
// 判断是否为IPv4
- if (NetUtils.isIPv4(ip)) {
- return resolverIPv4Region(ip);
- }
+ boolean isIPv4 = NetUtils.isIPv4(ip);
// 判断是否为IPv6
- if (NetUtils.isIPv6(ip)) {
- return resolverIPv6Region(ip);
- }
+ boolean isIPv6 = NetUtils.isIPv6(ip);
// 如果不是IPv4或IPv6,则返回未知IP
- return UNKNOWN_IP;
- }
-
- /**
- * 根据IPv4地址查询IP归属行政区域
- * @param ip ipv4地址
- * @return 归属行政区域
- */
- private static String resolverIPv4Region(String ip){
+ if (!isIPv4 && !isIPv6) {
+ return UNKNOWN_IP;
+ }
// 内网不查询
- if (NetUtils.isInnerIP(ip)) {
+ if ((isIPv4 && NetUtils.isInnerIP(ip)) || (isIPv6 && NetUtils.isInnerIPv6(ip))) {
return LOCAL_ADDRESS;
}
- return RegionUtils.getCityInfo(ip);
- }
-
- /**
- * 根据IPv6地址查询IP归属行政区域
- * @param ip ipv6地址
- * @return 归属行政区域
- */
- private static String resolverIPv6Region(String ip){
- // 内网不查询
- if (NetUtils.isInnerIPv6(ip)) {
- return LOCAL_ADDRESS;
- }
- log.warn("ip2region不支持IPV6地址解析:{}", ip);
- // 不支持IPv6,不再进行没有必要的IP地址信息的解析,直接返回
- // 如有需要,可自行实现IPv6地址信息解析逻辑,并在这里返回
- return UNKNOWN_ADDRESS;
+ // Tips:Ip2Region 提供了精简的IPv6地址库,精简的IPv6地址库并不能完全支持IPv6地址的查询,且准确度上可能会存在问题,如需要准确的IPv6地址查询,建议自行实现
+ return Ip2RegionHelper.getRegion(ip);
}
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/Ip2RegionHelper.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/Ip2RegionHelper.java
new file mode 100644
index 000000000..d52210a6d
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/Ip2RegionHelper.java
@@ -0,0 +1,146 @@
+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;
+import org.dromara.common.core.utils.StringUtils;
+import org.lionsoul.ip2region.service.Config;
+import org.lionsoul.ip2region.service.Ip2Region;
+import org.lionsoul.ip2region.xdb.Util;
+
+import java.io.File;
+import java.time.Duration;
+
+/**
+ * IP地址行政区域助手工具类
+ * 参考地址:ip2region xdb java 查询客户端实现
+ * xdb数据库文件下载:ip2region data
+ *
+ * @author 秋辞未寒
+ */
+@Slf4j
+public class Ip2RegionHelper {
+
+ // 默认IPv4地址库文件路径
+ // 下载地址:https://gitee.com/lionsoul/ip2region/blob/master/data/ip2region_v4.xdb
+ public static final String DEFAULT_IPV4_XDB_PATH = "ip2region_v4.xdb";
+
+ // 默认IPv6地址库文件路径
+ // 下载地址:https://gitee.com/lionsoul/ip2region/blob/master/data/ip2region_v6.xdb
+ public static final String DEFAULT_IPV6_XDB_PATH = "ip2region_v6.xdb";
+
+ // 未知地址
+ public static final String UNKNOWN_ADDRESS = "未知";
+
+
+ // Ip2Region服务实例
+ private static Ip2Region ip2Region;
+
+ // 初始化Ip2Region服务实例
+ static {
+ try {
+ // 创建临时文件用于处理IP离线数据库xdb文件
+ File v4TempXdb = FileUtil.writeFromStream(ResourceUtil.getStream(DEFAULT_IPV4_XDB_PATH), FileUtil.createTempFile());
+// File v6TempXdb = FileUtil.writeFromStream(ResourceUtil.getStream(DEFAULT_IPV6_XDB_PATH), FileUtil.createTempFile());
+
+ // IPv4配置
+ Config v4Config = Config.custom()
+ .setCachePolicy(Config.BufferCache)
+ .setXdbPath(v4TempXdb.getPath())
+ .asV4();
+ // IPv6配置
+// Config v6Config = Config.custom()
+// .setCachePolicy(Config.BufferCache)
+// .setXdbPath(v6TempXdb.getPath())
+// .asV6(FileUtil.createRandomAccessFile(v6TempXdb, FileMode.r));
+
+ // 初始化Ip2Region实例
+ Ip2RegionHelper.ip2Region = Ip2Region.create(v4Config, null);
+// Ip2RegionHelper.ip2Region = Ip2Region.create(v4Config, v6Config);
+
+ // 删除临时文件
+ // 注意:因为使用的 CachePolicy 为 BufferCache,BufferCache是加载整个xdb文件到内存中,所以临时文件的删除不会影响到正常的使用。如果使用的是 VIndexCache 或 NoCache(即实时读取文件),删除临时文件会导致xdb数据库读取不到而无法使用。
+ // CachePolicy的三种策略:BufferCache(全量读取xdb到内存中)、VIndexCache(按需读取并缓存)、NoCache(实时读取)
+ // 一般而言,更建议把xdb数据库放到一个指定的文件目录中(即不打包进jar包中),然后使用 NoCache + 配合SearcherPool的并发池读取数据,更方便随时更新xdb数据库
+ v4TempXdb.delete();
+// v6TempXdb.delete();
+ log.info("Ip2RegionHelper初始化成功,加载IP地址库数据成功!");
+ } catch (Exception e) {
+ throw new ServiceException("Ip2RegionHelper初始化失败,原因:{}", e.getMessage());
+ }
+ }
+
+
+ /**
+ * 根据IP地址离线获取城市
+ *
+ * @param ipString ip地址字符串
+ */
+ public static String getRegion(String ipString) {
+ try {
+ String region = ip2Region.search(ipString);
+ if (StringUtils.isBlank(region)) {
+ region = UNKNOWN_ADDRESS;
+ }
+ return region;
+ } catch (Exception e) {
+ log.error("IP地址离线获取城市异常 {}", ipString);
+ return UNKNOWN_ADDRESS;
+ }
+
+ }
+
+ /**
+ * 根据IP地址离线获取城市
+ *
+ * @param ipBytes ip地址字节数组
+ */
+ public static String getRegion(byte[] ipBytes) {
+ try {
+ String region = ip2Region.search(ipBytes);
+ if (StringUtils.isBlank(region)) {
+ region = UNKNOWN_ADDRESS;
+ }
+ return region;
+ } catch (Exception e) {
+ log.error("IP地址离线获取城市异常 {}", Util.ipToString(ipBytes));
+ return UNKNOWN_ADDRESS;
+ }
+ }
+
+ /**
+ * 关闭Ip2Region服务
+ */
+ public static void close() {
+ if (ip2Region == null) {
+ return;
+ }
+ try {
+ ip2Region.close(10000);
+ } catch (Exception e) {
+ log.error("Ip2Region服务关闭异常", e);
+ }
+ }
+
+ /**
+ * 关闭Ip2Region服务
+ *
+ * @param timeout 关闭超时时间
+ */
+ public static void close(final Duration timeout) {
+ if (ip2Region == null) {
+ return;
+ }
+ if (timeout == null) {
+ close();
+ return;
+ }
+ try {
+ ip2Region.close(timeout.toMillis());
+ } catch (Exception e) {
+ log.error("Ip2Region服务关闭异常", e);
+ }
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java
deleted file mode 100644
index c9e867899..000000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.dromara.common.core.utils.ip;
-
-import cn.hutool.core.io.resource.NoResourceException;
-import cn.hutool.core.io.resource.ResourceUtil;
-import lombok.extern.slf4j.Slf4j;
-import org.dromara.common.core.exception.ServiceException;
-import org.dromara.common.core.utils.StringUtils;
-import org.lionsoul.ip2region.xdb.Searcher;
-
-/**
- * 根据ip地址定位工具类,离线方式
- * 参考地址:集成 ip2region 实现离线IP地址定位库
- *
- * @author lishuyan
- */
-@Slf4j
-public class RegionUtils {
-
- // IP地址库文件名称
- public static final String IP_XDB_FILENAME = "ip2region.xdb";
-
- private static final Searcher SEARCHER;
-
- static {
- try {
- // 1、将 ip2region 数据库文件 xdb 从 ClassPath 加载到内存。
- // 2、基于加载到内存的 xdb 数据创建一个 Searcher 查询对象。
- SEARCHER = Searcher.newWithBuffer(ResourceUtil.readBytes(IP_XDB_FILENAME));
- log.info("RegionUtils初始化成功,加载IP地址库数据成功!");
- } catch (NoResourceException e) {
- throw new ServiceException("RegionUtils初始化失败,原因:IP地址库数据不存在!");
- } catch (Exception e) {
- throw new ServiceException("RegionUtils初始化失败,原因:" + e.getMessage());
- }
- }
-
- /**
- * 根据IP地址离线获取城市
- */
- public static String getCityInfo(String ip) {
- try {
- // 3、执行查询
- String region = SEARCHER.search(StringUtils.trim(ip));
- return region.replace("0|", "").replace("|0", "");
- } catch (Exception e) {
- log.error("IP地址离线获取城市异常 {}", ip);
- return "未知";
- }
- }
-
-}
From 455ec9a2f12cb058759080cff8dadb9395cadeb7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=A7=8B=E8=BE=9E=E6=9C=AA=E5=AF=92?= <545073804@qq.com>
Date: Thu, 11 Dec 2025 13:04:47 +0800
Subject: [PATCH 2/2] =?UTF-8?q?update=20IP=E5=9C=B0=E5=9D=80=E8=A1=8C?=
=?UTF-8?q?=E6=94=BF=E5=8C=BA=E5=9F=9F=E5=8A=A9=E6=89=8B=E7=B1=BB=E9=87=8D?=
=?UTF-8?q?=E5=91=BD=E5=90=8D=E4=BB=A5=E5=8C=B9=E9=85=8D=E5=85=B6=E5=B7=A5?=
=?UTF-8?q?=E5=85=B7=E7=B1=BB=E7=9A=84=E5=8A=9F=E8=83=BD=E5=AE=9A=E4=BD=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../org/dromara/common/core/utils/ip/AddressUtils.java | 2 +-
.../ip/{Ip2RegionHelper.java => RegionUtils.java} | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
rename ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/{Ip2RegionHelper.java => RegionUtils.java} (94%)
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java
index 7c797a2d7..fe36d9cc0 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java
@@ -37,7 +37,7 @@ public class AddressUtils {
return LOCAL_ADDRESS;
}
// Tips:Ip2Region 提供了精简的IPv6地址库,精简的IPv6地址库并不能完全支持IPv6地址的查询,且准确度上可能会存在问题,如需要准确的IPv6地址查询,建议自行实现
- return Ip2RegionHelper.getRegion(ip);
+ return RegionUtils.getRegion(ip);
}
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/Ip2RegionHelper.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java
similarity index 94%
rename from ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/Ip2RegionHelper.java
rename to ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java
index d52210a6d..a2d210c10 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/Ip2RegionHelper.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java
@@ -13,14 +13,14 @@ import java.io.File;
import java.time.Duration;
/**
- * IP地址行政区域助手工具类
+ * IP地址行政区域工具类
* 参考地址:ip2region xdb java 查询客户端实现
* xdb数据库文件下载:ip2region data
*
* @author 秋辞未寒
*/
@Slf4j
-public class Ip2RegionHelper {
+public class RegionUtils {
// 默认IPv4地址库文件路径
// 下载地址:https://gitee.com/lionsoul/ip2region/blob/master/data/ip2region_v4.xdb
@@ -53,11 +53,11 @@ public class Ip2RegionHelper {
// Config v6Config = Config.custom()
// .setCachePolicy(Config.BufferCache)
// .setXdbPath(v6TempXdb.getPath())
-// .asV6(FileUtil.createRandomAccessFile(v6TempXdb, FileMode.r));
+// .asV6();
// 初始化Ip2Region实例
- Ip2RegionHelper.ip2Region = Ip2Region.create(v4Config, null);
-// Ip2RegionHelper.ip2Region = Ip2Region.create(v4Config, v6Config);
+ RegionUtils.ip2Region = Ip2Region.create(v4Config, null);
+// RegionUtils.ip2Region = Ip2Region.create(v4Config, v6Config);
// 删除临时文件
// 注意:因为使用的 CachePolicy 为 BufferCache,BufferCache是加载整个xdb文件到内存中,所以临时文件的删除不会影响到正常的使用。如果使用的是 VIndexCache 或 NoCache(即实时读取文件),删除临时文件会导致xdb数据库读取不到而无法使用。