Browse Source

add 新增 ip2region 实现离线IP地址定位库

疯狂的狮子li 2 years ago
parent
commit
56d7023e41

+ 9 - 0
pom.xml

@@ -37,6 +37,8 @@
         <xxl-job.version>2.3.1</xxl-job.version>
         <lombok.version>1.18.26</lombok.version>
         <bouncycastle.version>1.72</bouncycastle.version>
+        <!-- 离线IP地址定位库 -->
+        <ip2region.version>2.7.0</ip2region.version>
 
         <!-- 临时修复 snakeyaml 漏洞 -->
         <snakeyaml.version>1.33</snakeyaml.version>
@@ -258,6 +260,13 @@
                 <version>${alibaba-ttl.version}</version>
             </dependency>
 
+            <!-- 离线IP地址定位库 ip2region -->
+            <dependency>
+                <groupId>org.lionsoul</groupId>
+                <artifactId>ip2region</artifactId>
+                <version>${ip2region.version}</version>
+            </dependency>
+
             <!-- 临时修复 snakeyaml 漏洞 -->
             <dependency>
                 <groupId>org.yaml</groupId>

BIN
ruoyi-admin/src/main/resources/ip2region.xdb


+ 6 - 0
ruoyi-common/pom.xml

@@ -159,6 +159,12 @@
             <artifactId>bcprov-jdk15to18</artifactId>
         </dependency>
 
+        <!-- 离线IP地址定位库 -->
+        <dependency>
+            <groupId>org.lionsoul</groupId>
+            <artifactId>ip2region</artifactId>
+        </dependency>
+
     </dependencies>
 
 </project>

+ 2 - 29
ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java

@@ -1,12 +1,7 @@
 package com.ruoyi.common.utils.ip;
 
-import cn.hutool.core.lang.Dict;
 import cn.hutool.core.net.NetUtil;
 import cn.hutool.http.HtmlUtil;
-import cn.hutool.http.HttpUtil;
-import com.ruoyi.common.config.RuoYiConfig;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.utils.JsonUtils;
 import com.ruoyi.common.utils.StringUtils;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
@@ -21,40 +16,18 @@ import lombok.extern.slf4j.Slf4j;
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 public class AddressUtils {
 
-    // IP地址查询
-    public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp";
-
     // 未知地址
     public static final String UNKNOWN = "XX XX";
 
     public static String getRealAddressByIP(String ip) {
-        String address = UNKNOWN;
         if (StringUtils.isBlank(ip)) {
-            return address;
+            return UNKNOWN;
         }
         // 内网不查询
         ip = "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : HtmlUtil.cleanHtmlTag(ip);
         if (NetUtil.isInnerIP(ip)) {
             return "内网IP";
         }
-        if (RuoYiConfig.isAddressEnabled()) {
-            try {
-                String rspStr = HttpUtil.createGet(IP_URL)
-                    .body("ip=" + ip + "&json=true", Constants.GBK)
-                    .execute()
-                    .body();
-                if (StringUtils.isEmpty(rspStr)) {
-                    log.error("获取地理位置异常 {}", ip);
-                    return UNKNOWN;
-                }
-                Dict obj = JsonUtils.parseMap(rspStr);
-                String region = obj.getStr("pro");
-                String city = obj.getStr("city");
-                return String.format("%s %s", region, city);
-            } catch (Exception e) {
-                log.error("获取地理位置异常 {}", ip);
-            }
-        }
-        return UNKNOWN;
+        return RegionUtils.getCityInfo(ip);
     }
 }

+ 66 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/RegionUtils.java

@@ -0,0 +1,66 @@
+package com.ruoyi.common.utils.ip;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.resource.ClassPathResource;
+import cn.hutool.core.util.ObjectUtil;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.file.FileUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.lionsoul.ip2region.xdb.Searcher;
+
+import java.io.File;
+
+/**
+ * 根据ip地址定位工具类,离线方式
+ * 参考地址:<a href="https://gitee.com/lionsoul/ip2region/tree/master/binding/java">集成 ip2region 实现离线IP地址定位库</a>
+ *
+ * @author lishuyan
+ */
+@Slf4j
+public class RegionUtils {
+
+    private static final Searcher SEARCHER;
+
+    static {
+        String fileName = "/ip2region.xdb";
+        File existFile = FileUtils.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName);
+        if (!FileUtils.exist(existFile)) {
+            ClassPathResource fileStream = new ClassPathResource(fileName);
+            if (ObjectUtil.isEmpty(fileStream.getStream())) {
+                throw new ServiceException("RegionUtils初始化失败,原因:IP地址库数据不存在!");
+            }
+            FileUtils.writeFromStream(fileStream.getStream(), existFile);
+        }
+
+        String dbPath = existFile.getPath();
+
+        // 1、从 dbPath 加载整个 xdb 到内存。
+        byte[] cBuff;
+        try {
+            cBuff = Searcher.loadContentFromFile(dbPath);
+        } catch (Exception e) {
+            throw new ServiceException("RegionUtils初始化失败,原因:从ip2region.xdb文件加载内容失败!" + e.getMessage());
+        }
+        // 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。
+        try {
+            SEARCHER = Searcher.newWithBuffer(cBuff);
+        } catch (Exception e) {
+            throw new ServiceException("RegionUtils初始化失败,原因:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 根据IP地址离线获取城市
+     */
+    public static String getCityInfo(String ip) {
+        try {
+            ip = ip.trim();
+            // 3、执行查询
+            String region = SEARCHER.search(ip);
+            return region.replace("0|", "").replace("|0", "");
+        } catch (Exception e) {
+            log.error("IP地址离线获取城市异常 {}", ip);
+            return "未知";
+        }
+    }
+}