Java使用ip2region解析ip获取地区位置
创始人
2024-11-14 10:06:15

文章目录

  • 一、Ip2region 是什么
  • 二、ip2region xdb 生成实现
    • 1.编译安装
    • 2.数据生成
  • 三、Java使用ip2region
    • 1.引入依赖
    • 2.完全基于文件的查询
    • 3.缓存 VectorIndex 索引
    • 4.缓存整个 xdb 数据
    • 5.将ip2region.xdb放在resource


一、Ip2region 是什么

Ip2region 一个 github 的开源项目,即 Ip2region 开源项目。
项目地址:https://github.com/lionsoul2014/ip2region

ip2region - 是一个离线IP地址定位库和IP定位数据管理框架,10微秒级别的查询效率,提供了众多主流编程语言的 xdb数据生成和查询客户端实现。

ip2region是完全基于 xdb 文件的查询,单次查询响应时间在十微秒级别

已经有的客户端:Java、C#、php、C、Python、Node.js、PHP 拓展(PHP 5 和 PHP 7)等;

二、ip2region xdb 生成实现

如果不想生成可以直接使用github下载
https://github.com/lionsoul2014/ip2region/blob/master/data/ip2region.xdb

下载Ip2region项目

1.编译安装

通过 maven 来编译可运行 jar 程序:

# cd 到 maker/java 根目录 mvn clean compile package 

然会会在当前目录的 target 目录下得到一个 ip2region-maker-{version}.jar 的打包文件。

2.数据生成

通过 java -jar ip2region-maker-{version}.jar 来生成 ip2region.xdb 二进制文件:

➜  java git:(java_xdb_maker) ✗ java -jar ./target/ip2region-maker-1.0.0.jar  ip2region xdb maker java -jar ip2region-maker-{version}.jar [command options] options:  --src string    source ip text file path  --dst string    destination binary xdb file path 

例如,通过默认的 data/ip.merge.txt 原数据,在当前目录生成一个 ip2region.xdb 二进制文件:

➜  java git:(java_xdb_maker) ✗ java -jar ./target/ip2region-maker-1.0.0.jar --src=../../data/ip.merge.txt --dst=./ip2region.xdb # 会看到一堆输出,最终会看到如下输出表示运行成功 ... 2022-07-15 20:21:29 INFO  org.lionsoul.ip2region.xdb.Maker try to write the vector index block ... 2022-07-15 20:21:29 INFO  org.lionsoul.ip2region.xdb.Maker try to write the segment index ptr ... 2022-07-15 20:21:29 INFO  org.lionsoul.ip2region.xdb.Maker write done, dataBlocks: 13804, indexBlocks: (683591, 720221), indexPtr: (982904, 11065984) 2022-07-15 20:21:29 INFO  org.lionsoul.ip2region.MakerTest Done, elapsed: 50 s 

三、Java使用ip2region

1.引入依赖

     org.lionsoul     ip2region     2.7.0  

在Maven里面添加依赖,防止把这个xdb文件编译:

   maven-resources-plugin                   xdb                 

2.完全基于文件的查询

import org.lionsoul.ip2region.xdb.Searcher; import java.io.*; import java.util.concurrent.TimeUnit;  public class SearcherTest {     public static void main(String[] args) {         // 1、创建 searcher 对象         String dbPath = "ip2region.xdb file path";         Searcher searcher = null;         try {             searcher = Searcher.newWithFileOnly(dbPath);         } catch (IOException e) {             System.out.printf("failed to create searcher with `%s`: %s\n", dbPath, e);             return;         }          // 2、查询         try {             String ip = "1.2.3.4";             long sTime = System.nanoTime();             String region = searcher.search(ip);             long cost = TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime));             System.out.printf("{region: %s, ioCount: %d, took: %d μs}\n", region, searcher.getIOCount(), cost);         } catch (Exception e) {             System.out.printf("failed to search(%s): %s\n", ip, e);         }          // 3、关闭资源         searcher.close();                  // 备注:并发使用,每个线程需要创建一个独立的 searcher 对象单独使用。     } } 

3.缓存 VectorIndex 索引

我们可以提前从 xdb 文件中加载出来 VectorIndex 数据,然后全局缓存,每次创建 Searcher 对象的时候使用全局的 VectorIndex 缓存可以减少一次固定的 IO 操作,从而加速查询,减少 IO 压力。

import org.lionsoul.ip2region.xdb.Searcher; import java.io.*; import java.util.concurrent.TimeUnit;  public class SearcherTest {     public static void main(String[] args) {         String dbPath = "ip2region.xdb file path";          // 1、从 dbPath 中预先加载 VectorIndex 缓存,并且把这个得到的数据作为全局变量,后续反复使用。         byte[] vIndex;         try {             vIndex = Searcher.loadVectorIndexFromFile(dbPath);         } catch (Exception e) {             System.out.printf("failed to load vector index from `%s`: %s\n", dbPath, e);             return;         }          // 2、使用全局的 vIndex 创建带 VectorIndex 缓存的查询对象。         Searcher searcher;         try {             searcher = Searcher.newWithVectorIndex(dbPath, vIndex);         } catch (Exception e) {             System.out.printf("failed to create vectorIndex cached searcher with `%s`: %s\n", dbPath, e);             return;         }          // 3、查询         try {             String ip = "1.2.3.4";             long sTime = System.nanoTime();             String region = searcher.search(ip);             long cost = TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime));             System.out.printf("{region: %s, ioCount: %d, took: %d μs}\n", region, searcher.getIOCount(), cost);         } catch (Exception e) {             System.out.printf("failed to search(%s): %s\n", ip, e);         }                  // 4、关闭资源         searcher.close();          // 备注:每个线程需要单独创建一个独立的 Searcher 对象,但是都共享全局的制度 vIndex 缓存。     } } 

4.缓存整个 xdb 数据

我们也可以预先加载整个 ip2region.xdb 的数据到内存,然后基于这个数据创建查询对象来实现完全基于文件的查询,类似之前的 memory search。

import org.lionsoul.ip2region.xdb.Searcher; import java.io.*; import java.util.concurrent.TimeUnit;  public class SearcherTest {     public static void main(String[] args) {         String dbPath = "ip2region.xdb file path";          // 1、从 dbPath 加载整个 xdb 到内存。         byte[] cBuff;         try {             cBuff = Searcher.loadContentFromFile(dbPath);         } catch (Exception e) {             System.out.printf("failed to load content from `%s`: %s\n", dbPath, e);             return;         }          // 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。         Searcher searcher;         try {             searcher = Searcher.newWithBuffer(cBuff);         } catch (Exception e) {             System.out.printf("failed to create content cached searcher: %s\n", e);             return;         }          // 3、查询         try {             String ip = "1.2.3.4";             long sTime = System.nanoTime();             String region = searcher.search(ip);             long cost = TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime));             System.out.printf("{region: %s, ioCount: %d, took: %d μs}\n", region, searcher.getIOCount(), cost);         } catch (Exception e) {             System.out.printf("failed to search(%s): %s\n", ip, e);         }                  // 4、关闭资源 - 该 searcher 对象可以安全用于并发,等整个服务关闭的时候再关闭 searcher         // searcher.close();          // 备注:并发使用,用整个 xdb 数据缓存创建的查询对象可以安全的用于并发,也就是你可以把这个 searcher 对象做成全局对象去跨线程访问。     } } 

5.将ip2region.xdb放在resource

 import cn.hutool.core.io.IoUtil; import lombok.extern.slf4j.Slf4j; import org.lionsoul.ip2region.xdb.Searcher; import org.springframework.core.io.ClassPathResource; import java.io.*;  @Slf4j public class IpdbUtils { 	private static Searcher searcher;  	/** 	 *    	 *   解决打包jar后找不到 ip2region.db 的问题 	 */ 	public static String getIpAddress(String ip){ 		if ("127.0.0.1".equals(ip) || ip.startsWith("192.168")) { 			return "局域网"; 		} 		if (searcher == null) { 			try { 				ClassPathResource resource = new ClassPathResource("ipdb/ip2region.xdb"); 				InputStream inputStream = resource.getInputStream(); 				byte[] bytes = IoUtil.readBytes(inputStream); 				searcher = Searcher.newWithBuffer(bytes); 			} catch (Exception e) { 				log.error("failed to create content cached searcher: ", e); 				return null; 			} 		} 		// 3、查询 		String region=null; 		try { 			region = searcher.search(ip); 		} catch (Exception e) { 			throw new RuntimeException("获取IP地址异常"); 		} 		return region; 	}  }  

相关内容

热门资讯

裸辞做“一人公司”,我后悔了 去年这个时候,一位以色列程序员正在东南亚旅行。他顺手把一个在脑子里转了很久的想法做成了产品,一个让任...
南京建成国内首个Pre-6G试... 4月21日,2026全球6G技术与产业生态大会在南京开幕。全息互动技术展台前,一名远在北京的工作人员...
超梵求职受邀参加“2025抖音... 超梵求职受邀参加“2025抖音巨量引擎成人教育行业生态大会”,探讨分享优质内容传播,服务万千学员。 ...
摩托罗拉Razr 2026(R... IT之家 4 月 22 日消息,摩托罗拉宣布新一代 Razr 折叠手机将于 4 月 29 日在美国发...
库克卸任,特纳斯领航:苹果新纪... 苹果首席执行官蒂姆·库克将卸任,硬件工程主管约翰·特纳斯将接任,苹果公司今天宣布此事。 库克将在夏季...