Selaa lähdekoodia

交易市场平台(供应商)

wwh 1 päivä sitten
vanhempi
commit
0ec011954d

+ 22 - 12
baqing-admin/src/main/java/com/ruoyi/web/modules/diagnosis/support/ConsultAskerIpRegionResolver.java

@@ -10,6 +10,7 @@ import com.ruoyi.common.constant.Constants;
10 10
 import com.ruoyi.common.utils.StringUtils;
11 11
 import com.ruoyi.common.utils.http.HttpUtils;
12 12
 import com.ruoyi.common.utils.ip.AddressUtils;
13
+import com.ruoyi.common.utils.ip.Ip2RegionUtils;
13 14
 import com.ruoyi.common.utils.ip.IpUtils;
14 15
 
15 16
 /**
@@ -31,27 +32,40 @@ public class ConsultAskerIpRegionResolver
31 32
         {
32 33
             return "内网区";
33 34
         }
34
-        if (!RuoYiConfig.isAddressEnabled())
35
-        {
36
-            return "未知区";
37
-        }
38 35
         try
39 36
         {
40 37
             String rspStr = HttpUtils.sendGet(AddressUtils.IP_URL, "ip=" + normalized + "&json=true", Constants.GBK);
41 38
             if (StringUtils.isEmpty(rspStr))
42 39
             {
43
-                log.warn("IP 区县解析失败: {}", normalized);
44
-                return "未知区";
40
+                log.warn("IP 区县在线解析失败,尝试 ip2region: {}", normalized);
41
+                return resolveDistrictLabelByIp2Region(normalized);
45 42
             }
46 43
             JSONObject obj = JSON.parseObject(rspStr);
47 44
             String district = firstNonEmpty(obj.getString("region"), obj.getString("city"), obj.getString("pro"));
45
+            if (StringUtils.isEmpty(district))
46
+            {
47
+                log.warn("IP 区县在线解析无结果,尝试 ip2region: {}", normalized);
48
+                return resolveDistrictLabelByIp2Region(normalized);
49
+            }
48 50
             return formatDistrictLabel(district);
49 51
         }
50 52
         catch (Exception ex)
51 53
         {
52
-            log.warn("IP 区县解析异常 ip={}: {}", normalized, ex.getMessage());
54
+            log.warn("IP 区县在线解析异常 ip={},尝试 ip2region: {}", normalized, ex.getMessage());
55
+            return resolveDistrictLabelByIp2Region(normalized);
56
+        }
57
+    }
58
+
59
+    private String resolveDistrictLabelByIp2Region(String ip)
60
+    {
61
+        String region = Ip2RegionUtils.searchRegion(ip);
62
+        String district = Ip2RegionUtils.extractDistrictName(region);
63
+        if (StringUtils.isEmpty(district))
64
+        {
65
+            log.warn("IP 区县 ip2region 解析失败: {}", ip);
53 66
             return "未知区";
54 67
         }
68
+        return formatDistrictLabel(district);
55 69
     }
56 70
 
57 71
     static String formatDistrictLabel(String raw)
@@ -61,14 +75,10 @@ public class ConsultAskerIpRegionResolver
61 75
             return "未知区";
62 76
         }
63 77
         String name = raw.trim();
64
-        if (name.endsWith("区"))
78
+        if (name.endsWith("区") || name.endsWith("县"))
65 79
         {
66 80
             return name;
67 81
         }
68
-        if (name.endsWith("县"))
69
-        {
70
-            return name.substring(0, name.length() - 1) + "区";
71
-        }
72 82
         if (name.endsWith("市") || name.endsWith("州") || name.endsWith("盟"))
73 83
         {
74 84
             return name;

+ 18 - 0
baqing-admin/src/test/java/com/ruoyi/web/modules/diagnosis/support/ConsultAskerIpRegionResolverTest.java

@@ -1,9 +1,11 @@
1 1
 package com.ruoyi.web.modules.diagnosis.support;
2 2
 
3 3
 import static org.junit.jupiter.api.Assertions.assertEquals;
4
+import static org.junit.jupiter.api.Assertions.assertNotNull;
4 5
 
5 6
 import org.junit.jupiter.api.DisplayName;
6 7
 import org.junit.jupiter.api.Test;
8
+import com.ruoyi.common.utils.ip.Ip2RegionUtils;
7 9
 
8 10
 @DisplayName("ConsultAskerIpRegionResolver")
9 11
 class ConsultAskerIpRegionResolverTest
@@ -17,4 +19,20 @@ class ConsultAskerIpRegionResolverTest
17 19
         assertEquals("那曲市", ConsultAskerIpRegionResolver.formatDistrictLabel("那曲市"));
18 20
         assertEquals("未知区", ConsultAskerIpRegionResolver.formatDistrictLabel(""));
19 21
     }
22
+
23
+    @Test
24
+    @DisplayName("ip2region 区县名提取")
25
+    void extractDistrictNameFromIp2Region()
26
+    {
27
+        assertEquals("深圳市", Ip2RegionUtils.extractDistrictName("中国|广东省|深圳市|电信|CN"));
28
+        assertEquals("Brisbane", Ip2RegionUtils.extractDistrictName("Australia|Queensland|Brisbane|0|AU"));
29
+    }
30
+
31
+    @Test
32
+    @DisplayName("ip2region 离线查询")
33
+    void searchRegionOffline()
34
+    {
35
+        String region = Ip2RegionUtils.searchRegion("114.114.114.114");
36
+        assertNotNull(region);
37
+    }
20 38
 }

+ 8 - 0
pom.xml

@@ -30,6 +30,7 @@
30 30
         <poi.version>4.1.2</poi.version>
31 31
         <velocity.version>2.3</velocity.version>
32 32
         <jwt.version>0.9.1</jwt.version>
33
+        <ip2region.version>3.3.7</ip2region.version>
33 34
         <!-- override dependency version -->
34 35
         <tomcat.version>9.0.112</tomcat.version>
35 36
         <logback.version>1.2.13</logback.version>
@@ -183,6 +184,13 @@
183 184
                 <version>${kaptcha.version}</version>
184 185
             </dependency>
185 186
 
187
+            <!-- 离线 IP 归属地 -->
188
+            <dependency>
189
+                <groupId>org.lionsoul</groupId>
190
+                <artifactId>ip2region</artifactId>
191
+                <version>${ip2region.version}</version>
192
+            </dependency>
193
+
186 194
             <!-- 定时任务-->
187 195
             <dependency>
188 196
                 <groupId>com.ruoyi</groupId>

+ 6 - 0
ruoyi-common/pom.xml

@@ -113,6 +113,12 @@
113 113
             <artifactId>javax.servlet-api</artifactId>
114 114
         </dependency>
115 115
 
116
+        <!-- 离线 IP 归属地 -->
117
+        <dependency>
118
+            <groupId>org.lionsoul</groupId>
119
+            <artifactId>ip2region</artifactId>
120
+        </dependency>
121
+
116 122
     </dependencies>
117 123
 
118 124
 </project>

+ 130 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/Ip2RegionUtils.java

@@ -0,0 +1,130 @@
1
+package com.ruoyi.common.utils.ip;
2
+
3
+import java.io.InputStream;
4
+import org.lionsoul.ip2region.service.Config;
5
+import org.lionsoul.ip2region.service.Ip2Region;
6
+import org.slf4j.Logger;
7
+import org.slf4j.LoggerFactory;
8
+import com.ruoyi.common.utils.StringUtils;
9
+
10
+/**
11
+ * ip2region 离线 IP 归属地查询工具。
12
+ */
13
+public final class Ip2RegionUtils
14
+{
15
+    private static final Logger log = LoggerFactory.getLogger(Ip2RegionUtils.class);
16
+
17
+    private static final String XDB_CLASSPATH = "/ip2region/ip2region_v4.xdb";
18
+
19
+    private static volatile Ip2Region ip2Region;
20
+
21
+    private static volatile boolean initAttempted;
22
+
23
+    private Ip2RegionUtils()
24
+    {
25
+    }
26
+
27
+    /**
28
+     * 查询 IP 归属地原始字符串,格式:Country|Province|City|ISP|Code。
29
+     */
30
+    public static String searchRegion(String ip)
31
+    {
32
+        if (StringUtils.isEmpty(ip))
33
+        {
34
+            return null;
35
+        }
36
+        Ip2Region service = getIp2Region();
37
+        if (service == null)
38
+        {
39
+            return null;
40
+        }
41
+        try
42
+        {
43
+            return service.search(ip.trim());
44
+        }
45
+        catch (Exception ex)
46
+        {
47
+            log.warn("ip2region 查询失败 ip={}: {}", ip, ex.getMessage());
48
+            return null;
49
+        }
50
+    }
51
+
52
+    /**
53
+     * 从 ip2region 结果中提取可用于区县展示的名称。
54
+     */
55
+    public static String extractDistrictName(String region)
56
+    {
57
+        if (StringUtils.isEmpty(region))
58
+        {
59
+            return null;
60
+        }
61
+        String[] parts = region.split("\\|");
62
+        String city = parts.length > 2 ? nullIfZero(parts[2]) : null;
63
+        String province = parts.length > 1 ? nullIfZero(parts[1]) : null;
64
+        String country = parts.length > 0 ? nullIfZero(parts[0]) : null;
65
+        return firstNonEmpty(city, province, country);
66
+    }
67
+
68
+    private static Ip2Region getIp2Region()
69
+    {
70
+        if (!initAttempted)
71
+        {
72
+            synchronized (Ip2RegionUtils.class)
73
+            {
74
+                if (!initAttempted)
75
+                {
76
+                    initAttempted = true;
77
+                    ip2Region = createIp2Region();
78
+                }
79
+            }
80
+        }
81
+        return ip2Region;
82
+    }
83
+
84
+    private static Ip2Region createIp2Region()
85
+    {
86
+        try (InputStream inputStream = Ip2RegionUtils.class.getResourceAsStream(XDB_CLASSPATH))
87
+        {
88
+            if (inputStream == null)
89
+            {
90
+                log.warn("ip2region 数据库未找到: {}", XDB_CLASSPATH);
91
+                return null;
92
+            }
93
+            Config v4Config = Config.custom()
94
+                    .setCachePolicy(Config.BufferCache)
95
+                    .setXdbInputStream(inputStream)
96
+                    .asV4();
97
+            return Ip2Region.create(v4Config, null);
98
+        }
99
+        catch (Exception ex)
100
+        {
101
+            log.error("ip2region 初始化失败", ex);
102
+            return null;
103
+        }
104
+    }
105
+
106
+    private static String nullIfZero(String value)
107
+    {
108
+        if (StringUtils.isEmpty(value) || "0".equals(value.trim()))
109
+        {
110
+            return null;
111
+        }
112
+        return value.trim();
113
+    }
114
+
115
+    private static String firstNonEmpty(String... values)
116
+    {
117
+        if (values == null)
118
+        {
119
+            return null;
120
+        }
121
+        for (String value : values)
122
+        {
123
+            if (StringUtils.isNotEmpty(value))
124
+            {
125
+                return value;
126
+            }
127
+        }
128
+        return null;
129
+    }
130
+}

BIN
ruoyi-common/src/main/resources/ip2region/ip2region_v4.xdb