最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot中集成IP2Region實(shí)現(xiàn)高效IP地址地理位置查詢

 更新時間:2025年12月10日 09:06:31   作者:Knight_AL  
IP2Region是一個高效的IP地址地理位置查詢庫,能夠快速根據(jù)IP地址獲取其地理位置信息,它支持IPv4和IPv6地址的查詢,并提供多種緩存方式來優(yōu)化查詢性能,在這篇博客中,我們將介紹如何將IP2Region集成到SpringBoot項(xiàng)目中,實(shí)現(xiàn)IP地址的地理位置查詢服務(wù)

一、添加 Maven 依賴

首先,在 Spring Boot 項(xiàng)目中使用 IP2Region,你需要在 pom.xml 文件中添加 IP2Region 的 Maven 依賴。

<dependency>
    <groupId>org.lionsoul</groupId>
    <artifactId>ip2region</artifactId>
    <version>3.1.1</version>
</dependency>

該依賴包含了 IP2Region 查詢庫,使得你能夠在 Spring Boot 項(xiàng)目中使用 Searcher 類進(jìn)行高效的 IP 地址查詢。

二、配置數(shù)據(jù)庫文件路徑與版本

在 Spring Boot 的 application.propertiesapplication.yml 中配置 IP2Region 數(shù)據(jù)庫文件的路徑和 IP 版本(IPv4 或 IPv6)。

application.properties

# IP2Region 數(shù)據(jù)庫文件路徑
ip2region.db-path=ip2region_v4.xdb  # 可根據(jù)需要替換為 IPv6 文件路徑
# 版本選擇 IPv4 或 IPv6
ip2region.version=IPv4

application.yml

ip2region:
  db-path: ip2region_v4.xdb  # 可根據(jù)需要替換為 IPv6 文件路徑
  version: IPv4

ip2region_v4.xdb 是 IP2Region 的數(shù)據(jù)庫文件,你需要下載并將其放置在 src/main/resources 目錄下,確保 Spring Boot 能夠通過 classpath 讀取。

三、創(chuàng)建 IP 查詢服務(wù)

接下來,我們將 IP2Region 封裝為一個 Spring Bean,通過 @Service 注解讓 Spring 管理這個服務(wù)類。在 IpService 類中,我們會初始化 Searcher 實(shí)例,并提供查詢 IP 地址的功能。

IpService.java

package com.donglin.service;

import jakarta.annotation.PostConstruct;
import org.lionsoul.ip2region.xdb.Searcher;
import org.lionsoul.ip2region.xdb.Version;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;

@Service
public class IpService {

    private Searcher searcher;

    // 從配置文件中加載數(shù)據(jù)庫路徑和版本
    @Value("${ip2region.db-path}")
    private String dbPath;

    @Value("${ip2region.version}")
    private String version;

    // 服務(wù)啟動時初始化 Searcher
    @PostConstruct
    public void init() throws IOException {
        // 根據(jù)配置選擇 IP 版本
        Version ipVersion = version.equalsIgnoreCase("IPv4") ? Version.IPv4 : Version.IPv6;

        try {
            // 使用 ClassPathResource 加載類路徑中的數(shù)據(jù)庫文件
            Resource resource = new ClassPathResource(dbPath);
            if (!resource.exists()) {
                throw new IOException("Unable to find " + dbPath + " in classpath");
            }

            // 獲取文件的輸入流
            InputStream inputStream = resource.getInputStream();

            // 將 InputStream 保存到臨時文件
            Path tempFile = Files.createTempFile("ip2region", ".xdb");
            try (OutputStream out = new FileOutputStream(tempFile.toFile())) {
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    out.write(buffer, 0, bytesRead);
                }
            }

            // 使用臨時文件創(chuàng)建 Searcher 對象
            searcher = Searcher.newWithFileOnly(ipVersion, tempFile.toString());

        } catch (IOException e) {
            System.out.printf("failed to create searcher with `%s`: %s\n", dbPath, e);
            throw new IOException("Failed to initialize IP2Region searcher", e);
        }
    }

    // 查詢 IP 地理位置
    public String getCityInfo(String ip) {
        try {
            long sTime = System.nanoTime();
            String region = searcher.search(ip);  // 查詢 IP 地址
            long cost = TimeUnit.NANOSECONDS.toMicros(System.nanoTime() - sTime);
            System.out.printf("{region: %s, ioCount: %d, took: %d μs}\n", region, searcher.getIOCount(), cost);
            return region;
        } catch (Exception e) {
            System.out.printf("failed to search(%s): %s\n", ip, e);
            return null;
        }
    }

    // 在 Spring Boot 中使用 @PreDestroy 優(yōu)雅地關(guān)閉 searcher
    public void close() throws IOException {
        if (searcher != null) {
            searcher.close();
        }
    }
}

解析:

  • @PostConstruct:這是 Spring 提供的生命周期注解,表示方法將在 Bean 初始化完成后執(zhí)行。我們在這里初始化 Searcher 實(shí)例,基于配置的數(shù)據(jù)庫文件路徑和 IP 版本。
  • getCityInfo:此方法用于查詢 IP 地址的地理位置信息。它會返回一個字符串,包含 IP 地址的地理位置(如國家、省份、城市等)。

四、創(chuàng)建控制器提供查詢 API

為了讓外部可以查詢 IP 地址,我們創(chuàng)建一個 REST 控制器類 IpController,通過 HTTP GET 請求提供查詢接口。

IpController.java

package com.example.ip2region.controller;

import com.example.ip2region.service.IpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IpController {

    private final IpService ipService;

    @Autowired
    public IpController(IpService ipService) {
        this.ipService = ipService;
    }

    // 查詢 IP 地址的地理信息
    @GetMapping("/get-ip-location")
    public String getIpLocation(@RequestParam String ip) {
        return ipService.getCityInfo(ip);
    }
}

解析:

  • @GetMapping("/get-ip-location"):此注解將 HTTP GET 請求映射到 getIpLocation 方法。通過 @RequestParam 獲取 IP 地址參數(shù),并查詢該 IP 的地理位置。
  • 該控制器提供了一個查詢接口,可以通過 http://localhost:8080/get-ip-location?ip=1.2.3.4 查詢 IP 地址 1.2.3.4 的地理位置。

五、測試

啟動 Spring Boot 應(yīng)用后,可以通過瀏覽器或 Postman 發(fā)起查詢請求:

GET http://localhost:8080/get-ip-location?ip=1.2.3.4

查詢結(jié)果將是 IP 地址 1.2.3.4 的地理位置信息,例如:

{
  "region": "美國|華盛頓|0|谷歌"
}

六、優(yōu)化:使用緩存來加速查詢

IP2Region 支持使用緩存來優(yōu)化查詢性能。你可以通過預(yù)加載 VectorIndex 或整個 XDB 文件的內(nèi)容,將其存儲在內(nèi)存中,從而減少文件 IO 操作,提升查詢速度。

使用 VectorIndex 緩存

package com.donglin.service;

import jakarta.annotation.PostConstruct;
import org.lionsoul.ip2region.xdb.Searcher;
import org.lionsoul.ip2region.xdb.Version;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;

@Service
public class IpService {

    private Searcher searcher;

    @Value("${ip2region.db-path}")
    private String dbPath;

    @Value("${ip2region.version}")
    private String version;

    @PostConstruct
    public void init() throws IOException {
        Version ipVersion = version.equalsIgnoreCase("IPv4") ? Version.IPv4 : Version.IPv6;

        try {
            // ? 1. 從 classpath 讀取 XDB 文件(無論打包與否都兼容)
            Resource resource = new ClassPathResource(dbPath);
            if (!resource.exists()) {
                throw new IOException("無法在 classpath 中找到文件:" + dbPath);
            }

            // ? 2. 先把 XDB 文件寫入臨時文件(VectorIndex 只能基于文件加載)
            Path tempFile = Files.createTempFile("ip2region", ".xdb");
            try (InputStream is = resource.getInputStream()) {
                Files.copy(is, tempFile, java.nio.file.StandardCopyOption.REPLACE_EXISTING);
            }

            // ? 3. 預(yù)加載 VectorIndex(大幅減少 I/O)
            byte[] vIndex;
            try {
                vIndex = Searcher.loadVectorIndexFromFile(tempFile.toString());
                System.out.println("VectorIndex loaded, length = " + vIndex.length);
            } catch (Exception e) {
                throw new IOException("加載 VectorIndex 失敗: " + e.getMessage(), e);
            }

            // ? 4. 創(chuàng)建使用 VectorIndex 緩存的 Searcher
            searcher = Searcher.newWithVectorIndex(ipVersion, tempFile.toString(), vIndex);
            System.out.println("IP2Region searcher initialized with vector index cache.");

        } catch (IOException e) {
            System.err.printf("failed to create searcher with `%s`: %s%n", dbPath, e);
            throw new IOException("Failed to initialize IP2Region searcher", e);
        }
    }

    // 查詢 IP 地理位置
    public String getCityInfo(String ip) {
        try {
            long start = System.nanoTime();
            String region = searcher.search(ip);
            long cost = TimeUnit.NANOSECONDS.toMicros(System.nanoTime() - start);
            System.out.printf("{region: %s, ioCount: %d, took: %d μs}%n",
                    region, searcher.getIOCount(), cost);
            return region;
        } catch (Exception e) {
            System.err.printf("failed to search(%s): %s%n", ip, e);
            return null;
        }
    }

    public void close() throws IOException {
        if (searcher != null) {
            searcher.close();
        }
    }
}

七、總結(jié)

通過將 ip2region 集成到 Spring Boot 中,我們可以非常高效地查詢 IP 地址的地理位置信息。通過預(yù)加載緩存(如 VectorIndex 或整個 XDB 文件),我們可以進(jìn)一步提高查詢性能,減少 IO 壓力,尤其是在高并發(fā)場景下。

以上就是SpringBoot中集成IP2Region實(shí)現(xiàn)高效IP地址地理位置查詢的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot IP地理位置查詢的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • @Async導(dǎo)致controller?404及失效原因解決分析

    @Async導(dǎo)致controller?404及失效原因解決分析

    這篇文章主要為大家介紹了@Async導(dǎo)致controller?404失效問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • maven-compiler-plugin版本指定方式

    maven-compiler-plugin版本指定方式

    這篇文章主要介紹了maven-compiler-plugin版本指定方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • 老生常談java數(shù)組中的常見異常

    老生常談java數(shù)組中的常見異常

    數(shù)組是用來存儲一系列數(shù)據(jù),但它往往被認(rèn)為是一系列相同類型的變量,異常是程序中的一些錯誤,但并不是所有的錯誤都是異常,并且錯誤有時候是可以避免的,接下來讓我們詳細(xì)的了解吧
    2022-03-03
  • Springboot整合Dozer實(shí)現(xiàn)深度復(fù)制的方法

    Springboot整合Dozer實(shí)現(xiàn)深度復(fù)制的方法

    Dozer是一種Java?Bean到Java?Bean的映射器,遞歸地將數(shù)據(jù)從一個對象復(fù)制到另一個對象,它是一個強(qiáng)大的,通用的,靈活的,可重用的和可配置的開源映射框架,本文給大家介紹Springboot整合Dozer的相關(guān)知識,感興趣的朋友跟隨小編一起看看吧
    2022-03-03
  • 使用@Value值注入及配置文件組件掃描

    使用@Value值注入及配置文件組件掃描

    這篇文章主要介紹了使用@Value值注入及配置文件組件掃描方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • java中DateUtils時間工具類詳解

    java中DateUtils時間工具類詳解

    這篇文章主要為大家詳細(xì)介紹了java中DateUtils時間工具類,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • 解決InputStream.available()獲取流大小問題

    解決InputStream.available()獲取流大小問題

    這篇文章主要介紹了解決InputStream.available()獲取流大小問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Java常用集合之Set和Map的用法詳解

    Java常用集合之Set和Map的用法詳解

    這篇文章將通過一些示例為大家詳細(xì)介紹一下Java常用集合中Set和Map的用法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-07-07
  • POS機(jī)如何與Java交互的方式探討

    POS機(jī)如何與Java交互的方式探討

    本文深入探討POS機(jī)與Java語言的交互機(jī)制,詳細(xì)介紹了通過RESTfulAPI、Socket編程和消息隊(duì)列等方式實(shí)現(xiàn)數(shù)據(jù)交換和功能調(diào)用,文章還包含了代碼示例、狀態(tài)圖與關(guān)系圖,幫助開發(fā)者理解和實(shí)現(xiàn)POS機(jī)與Java之間的高效交互
    2024-09-09
  • Java Socket長連接實(shí)現(xiàn)教程及標(biāo)準(zhǔn)示例

    Java Socket長連接實(shí)現(xiàn)教程及標(biāo)準(zhǔn)示例

    Java Socket長連接提供了一種持久通信方式,適用于需要低延遲和高效率的網(wǎng)絡(luò)應(yīng)用,本文將詳細(xì)介紹如何創(chuàng)建Java Socket長連接的客戶端和服務(wù)端,包括它們的工作原理、實(shí)現(xiàn)細(xì)節(jié)、異常處理以及性能優(yōu)化,感興趣的朋友跟隨小編一起看看吧
    2025-09-09

最新評論

千阳县| 革吉县| 河池市| 中山市| 万年县| 榆林市| 镇雄县| 保亭| 洪泽县| 灵山县| 应城市| 太康县| 大余县| 衡南县| 景德镇市| 台前县| 田林县| 五莲县| 五河县| 阳曲县| 凌云县| 杭锦旗| 永靖县| 建始县| 岢岚县| 上栗县| 镇雄县| 漾濞| 铅山县| 云南省| 辽宁省| 聊城市| 兴安县| 浑源县| 山阴县| 东至县| 芦溪县| 松阳县| 乐昌市| 衡阳县| 岳西县|