集成 IP2Region 实现离线 IP 地址定位
# 集成 IP2Region 实现离线 IP 地址定位
IP2Region 是一个高效的离线 IP 地址定位库,适用于不希望使用在线服务进行 IP 地址定位的场景。通过集成 IP2Region,可以减少对外部 API 的依赖,提升系统的稳定性和安全性。以下是如何在若依项目中集成 IP2Region 实现离线 IP 地址定位的详细步骤。
# 1. 引入依赖
首先,在 ruoyi-common/pom.xml
文件中添加 IP2Region 的 Maven 依赖:
<!-- 离线 IP 地址定位库 -->
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>1.7.2</version>
</dependency>
1
2
3
4
5
6
2
3
4
5
6
此依赖将引入 IP2Region 库,为项目提供 IP 地址定位功能。
# 2. 创建 RegionUtil 工具类
为了方便在项目中使用 IP2Region 进行 IP 地址定位,我们可以创建一个 RegionUtil
工具类。新建 RegionUtil.java
文件,并添加以下内容:
package com.ruoyi.common.utils;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Method;
import org.apache.commons.io.FileUtils;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import org.lionsoul.ip2region.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
/**
* 根据 IP 离线查询地址工具类
*
* 该类用于通过 IP2Region 库根据 IP 地址获取地理位置信息。
*
* @author ruoyi
*/
public class RegionUtil {
private static final Logger log = LoggerFactory.getLogger(RegionUtil.class);
private static final String JAVA_TEMP_DIR = "java.io.tmpdir";
static DbConfig config = null;
static DbSearcher searcher = null;
/**
* 初始化 IP 数据库
*/
static {
try {
// 因为 JAR 文件无法直接读取文件, 需要复制创建临时文件
String dbPath = RegionUtil.class.getResource("/ip2region/ip2region.db").getPath();
File file = new File(dbPath);
if (!file.exists()) {
String tmpDir = System.getProperties().getProperty(JAVA_TEMP_DIR);
dbPath = tmpDir + "ip2region.db";
file = new File(dbPath);
ClassPathResource cpr = new ClassPathResource("ip2region" + File.separator + "ip2region.db");
InputStream resourceAsStream = cpr.getInputStream();
if (resourceAsStream != null) {
FileUtils.copyInputStreamToFile(resourceAsStream, file);
}
}
config = new DbConfig();
searcher = new DbSearcher(config, dbPath);
log.info("IP2Region 初始化完成");
} catch (Exception e) {
log.error("IP2Region 初始化失败: {}", e.getMessage());
}
}
/**
* 根据 IP 获取地理位置
*
* @param ip IP 地址
* @return 地理位置字符串
*/
public static String getRegion(String ip) {
try {
if (searcher == null || StringUtils.isEmpty(ip)) {
log.error("DbSearcher 实例为空");
return StringUtils.EMPTY;
}
// 查询算法,使用内存查询
int algorithm = DbSearcher.MEMORY_ALGORITYM;
Method method = null;
switch (algorithm) {
case DbSearcher.BTREE_ALGORITHM:
method = searcher.getClass().getMethod("btreeSearch", String.class);
break;
case DbSearcher.BINARY_ALGORITHM:
method = searcher.getClass().getMethod("binarySearch", String.class);
break;
case DbSearcher.MEMORY_ALGORITYM:
method = searcher.getClass().getMethod("memorySearch", String.class);
break;
}
DataBlock dataBlock = null;
if (!Util.isIpAddress(ip)) {
log.warn("无效的 IP 地址: {}", ip);
return StringUtils.EMPTY;
}
dataBlock = (DataBlock) method.invoke(searcher, ip);
String result = dataBlock.getRegion();
log.debug("IP 地址解析结果: {}", result);
return result;
} catch (Exception e) {
log.error("IP 地址解析失败: {}", e.getMessage());
return StringUtils.EMPTY;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# 3. 修改 AddressUtils 类
为了在整个项目中使用 IP2Region 进行 IP 地址定位,我们需要修改 AddressUtils
类,以集成新的 IP 地址解析方法。修改 AddressUtils.java
文件,添加以下内容:
package com.ruoyi.common.utils.ip;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.utils.RegionUtil;
import com.ruoyi.common.utils.StringUtils;
/**
* 获取地址类
*
* 根据 IP 获取地理位置的工具类,支持内网 IP 识别与外网 IP 定位。
*
* @author ruoyi
*/
public class AddressUtils {
private static final Logger log = LoggerFactory.getLogger(AddressUtils.class);
// 未知地址
public static final String UNKNOWN = "XX XX";
/**
* 根据 IP 获取地理位置
*
* @param ip IP 地址
* @return 地理位置字符串
*/
public static String getRealAddressByIP(String ip) {
String address = UNKNOWN;
// 内网 IP 不查询
if (IpUtils.internalIp(ip)) {
return "内网 IP";
}
if (RuoYiConfig.isAddressEnabled()) {
try {
String rspStr = RegionUtil.getRegion(ip);
if (StringUtils.isEmpty(rspStr)) {
log.error("获取地理位置异常: {}", ip);
return UNKNOWN;
}
String[] location = rspStr.split("\\|");
String region = location[2];
String city = location[3];
return String.format("%s %s", region, city);
} catch (Exception e) {
log.error("获取地理位置异常: {}", e.getMessage());
}
}
return address;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 4. 添加离线 IP 地址库插件
将离线 IP 地址库插件和相关代码解压到项目中。
提示:可以下载插件相关包和代码实现,将 ip2region.db
文件放置到 src/main/resources/ip2region
目录下。
# 5. 添加离线 IP 地址库
在 src/main/resources
目录下新建 ip2region
文件夹,并将 ip2region.db
文件复制到该目录下。
# 6. 测试与验证
完成上述配置后,重新启动项目,测试 AddressUtils.getRealAddressByIP(ip)
方法,验证是否能够正确解析 IP 地址的地理位置。
注意事项
- IP 数据库更新:由于 IP 地址分配是动态变化的,建议定期更新
ip2region.db
数据库,以确保地理位置解析的准确性。 - 内网 IP 处理:系统默认不对内网 IP 进行地理位置解析,直接返回 "内网 IP"。
- JAR 部署兼容:工具类中的文件处理方式已兼容 JAR 部署模式,无需额外调整。
通过集成 IP2Region,可以在若依项目中实现离线 IP 地址定位,减少对外部依赖,并提升系统的稳定性和性能。
编辑此页 (opens new window)
上次更新: 2024/12/28, 18:32:08