程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 若依框架
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 若依框架
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • 快速入门

  • 后端手册

  • 前端手册

  • 组件文档

  • 数据库分析

  • 集成插件

    • 集成 Docker 实现一键部署
    • 升级 Spring Boot 到 3.x 版本
    • 集成 Ehcache 实现本地缓存切换
    • 集成 WebSocket 实现实时通信
    • 集成 Electron 实现桌面应用程序
    • 集成 Atomikos 实现分布式事务
    • 集成 MinIO 实现分布式文件存储
    • 集成 Easy-ES 实现分布式全文检索
    • 使用 `localStorage` 代替 `cookie`
    • 使用 Undertow 替代 Tomcat 容器
    • 集成 Actuator 实现优雅关闭应用
    • 集成 AJ-Captcha 实现滑块验证码
    • 集成 Sharding-JDBC 实现分库分表
    • 集成 JustAuth 实现第三方授权登录
    • 集成 `watermark-dom` 实现页面水印
    • 集成 MyBatis-Plus 实现 MyBatis 增强
    • 集成 EasyExcel 实现 Excel 表格增强
    • 集成 Knife4j 实现 Swagger 文档增强
    • 集成 Redisson 实现 Redis 分布式锁
    • 集成 IP2Region 实现离线 IP 地址定位
      • 1. 引入依赖
      • 2. 创建 RegionUtil 工具类
      • 3. 修改 AddressUtils 类
      • 4. 添加离线 IP 地址库插件
      • 5. 添加离线 IP 地址库
      • 6. 测试与验证
    • 42集成 JSEncrypt 实现密码加密传输
    • 集成 HttpClient 实现 HTTP 接口增强
    • 集成 Druid 实现数据库密码加密功能
    • 集成 Browscap 实现用户代理解析
    • 集成 Dynamic-DataSource 实现多数据源增强
  • 若依框架
  • 集成插件
scholar
2024-08-31
目录

集成 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

此依赖将引入 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

# 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

# 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
集成 Redisson 实现 Redis 分布式锁
42集成 JSEncrypt 实现密码加密传输

← 集成 Redisson 实现 Redis 分布式锁 42集成 JSEncrypt 实现密码加密传输→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式