使用Java获取IP归属地的方法与实现

引言

在网络应用开发中,我们常常需要获取IP地址的归属地信息,这对于数据统计、用户分析和风险控制等方面都非常重要。本文将介绍如何使用Java编程语言获取IP地址的归属地,并提供一个实际的案例。

什么是IP归属地

“IP属地”指IP地址所在省(自治区、直辖市)(针对境内账号)或国家(地区)(针对境外账号),比如上海、北京、江苏;美国、日本等。

使用Java获取IP归属地的方法

我们可以通过调用第三方的IP归属地查询接口,或者使用Java开发者自行解析IP数据库的方式来获取IP归属地信息。

方法一:本地数据库实现:ip2region

1.1、首先下载IP数据库文件:

戳>>>>>>>>>>>>>>>数据库文件

1.2、Java中获取请求IP的方法
private static final String UNKNOWN = "unknown";
    public String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        if (ip.contains(",")) {
            ip = ip.split(",")[0];
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }
2、maven 仓库:
<!-- 离线IP归属地查询 -->
        <dependency>
            <groupId>org.lionsoul</groupId>
            <artifactId>ip2region</artifactId>
            <version>2.7.0</version>
        </dependency>
3.1、完全基于文件的查询

代码中dbPath换成前面下载数据文件绝对路径

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.2、 缓存 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 缓存。
    }
}
3.3、缓存整个 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 对象做成全局对象去跨线程访问。
    }
}

方法二:使用第三方接口

现在有很多第三方提供了IP归属地查询的接口,我们可以通过发送HTTP请求来获取IP的归属地信息:

接口一:查询IP归属地(自动区分v4&v6)
https://api.vore.top/api/IPdata?ip=[IP]

测试代码:

//发送请求使用了hutool依赖
public static void main(String[] args) {
String url = "https://api.vore.top/api/IPdata?ip={0}";
String formatUrl = MessageFormat.format(url, "137.184.160.151");
String result = HttpUtil.get(formatUrl);
System.out.println(result);
}

测试打印结果

{
    "code": 200,
    "msg": "SUCCESS",
    "ipinfo": {
        "type": "ipv4",
        "text": "137.184.160.151",
        "cnip": false
    },
    "ipdata": {
        "info1": "加拿大",
        "info2": "安大略省",
        "info3": "多伦多",
        "isp": "DigitalOcean有限责任公司"
    },
    "adcode": {
        "o": "加拿大安大略省多伦多 - DigitalOcean有限责任公司",
        "p": "加拿大",
        "c": "安大略省",
        "n": "加拿大-安大略省",
        "r": null,
        "a": null,
        "i": false
    },
    "tips": "接口由VORE-API(https:\/\/api.vore.top\/)免费提供",
    "time": 1694417659
}

Process finished with exit code 0
接口二:百度api
http://opendata.baidu.com/api.php?query=117.136.12.79&co=&resource_id=6006&oe=utf8

方法三:在线查询

如果只有少量需求可在线查询,→在线工具在线IP归属地

总结

本文介绍了使用Java获取IP归属地的方法与实现,包括调用第三方接口和解析IP库两种常用方式。通过获取IP归属地信息,我们可以进行地理位置分析和业务逻辑处理,从而更好地优化网站和应用。

希望本文对你有所帮助!

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 中,我们可以使用第三方库来获取 IP归属地信息。其中一个常用的库是 GeoIP2,它基于 MaxMind 的 GeoIP2 数据库。 首先,需要将 GeoIP2 库添加到项目中。可以在 Maven 或 Gradle 构建脚本中添加相应的依赖项。 然后,我们可以使用 GeoIP2 提供的 API 来查询 IP归属地。以下是一个示例代码: ```java import com.maxmind.geoip2.DatabaseReader; import com.maxmind.geoip2.model.CityResponse; import com.maxmind.geoip2.record.Country; import java.io.File; import java.io.IOException; import java.net.InetAddress; public class IPUtils { public static String getIPCountry(String ip) { try { File database = new File("GeoIP2-City.mmdb"); DatabaseReader reader = new DatabaseReader.Builder(database).build(); InetAddress ipAddress = InetAddress.getByName(ip); CityResponse response = reader.city(ipAddress); Country country = response.getCountry(); return country.getName(); } catch (IOException e) { e.printStackTrace(); return null; } } public static void main(String[] args) { String ip = "123.456.789.0"; String country = getIPCountry(ip); System.out.println("IP " + ip + " 的归属地是:" + country); } } ``` 在上述示例中,我们通过 `getIPCountry` 方法传入一个 IP 地址,并在 `main` 方法中调用该方法获取IP归属地信息。具体的归属地信息包括国家、地区、城市等,可以根据需要进行扩展和处理。 需要注意的是,在运行代码之前,我们需要下载并导入 GeoIP2 数据库文件 `GeoIP2-City.mmdb`,该文件包含了 IP 地址和归属地信息的映射关系。可以从 MaxMind 的官网或其他数据源获取该文件。 这样,我们就可以通过 Java获取 IP归属地信息了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值