Java使用ip2region获取用户的ip归属地的详细步骤

 更新时间:2025年05月06日 10:20:15   作者:哈密瓜Q  
ip2region 是一个离线IP地址定位库和IP定位数据管理框架,能实现10微秒级别的查询效率,提供了众多主流编程语言的xdb数据生成和查询客户端实现,本文给大家介绍了如何使用ip2region获取用户的ip归属地的详细步骤,需要的朋友可以参考下

1. ip2region 简介

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

每个 ip 数据段的 region 信息都固定了格式:国家|区域|省份|城市|ISP,只有中国的数据绝大部分精确到了城市,其他国家部分数据只能定位到国家,后前的选项全部是0。

2. 使用步骤

2.1 下载资源

下载 ip2region 后,将ip2region.xdb (如下图)复制到项目的resources/ipdb文件夹下。

2.2 引入依赖

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

2.3 编写工具类

2.3.1 获取 IP 地址

根据用户请求获取用户真实 IP 地址:

/**
 * 在 Nginx 等代理之后获取用户真实 IP 地址
 * @return 用户的真实 IP 地址
 */
public static String getIpAddress(HttpServletRequest request) {
    if (request == null) {
        return null;
    }
    String ip = request.getHeader("x-forwarded-for");
    if (isIpaddress(ip)) {
        ip = request.getHeader("Proxy-Client-IP");
    }
    if (isIpaddress(ip)) {
        ip = request.getHeader("WL-Proxy-Client-IP");
    }
    if (isIpaddress(ip)) {
        ip = request.getHeader("HTTP_CLIENT_IP");
    }
    if (isIpaddress(ip)) {
        ip = request.getHeader("HTTP_X_FORWARDED_FOR");
    }
    if (isIpaddress(ip)) {
        ip = request.getRemoteAddr();
        if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
            //根据网卡取本机配置的IP
            try {
                InetAddress inet = InetAddress.getLocalHost();
                ip = inet.getHostAddress();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
        }
    }
    return ip;
}

如果有使用 Nginx 等代理服务器则需进行配置[云笔记系统没有配置也可以正常使用],例如在nginx.conf文件中进行如下配置:

location / {
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

其中

  • Host:获取客户端(client)的真实域名和端口号
  • X-Real-IP:获取客户端真实 IP 地址
  • X-Forwarded-For:也是获取客户端真实 IP 地址,如果有多层代理时会获取客户端真实 IP 及每层代理服务器的 IP 地址
  • X-Forwarded-Proto:获取客户端的真实协议(如 http、https)
  1. getRemoteAddr()用于获取没有代理服务器情况下用户的 IP 地址
  2. 当用户的请求经过一个代理服务器后到达最终服务器,此时在最终服务器端通过getRemoteAddr()只能得到代理服务器的 IP 地址,通过在代理服务器中配置proxy_set_header X-Real-IP $remote_addr,最终的服务器可以通过X-Real-IP获取用户的真实 IP 地址。
  3. 当用户的请求经过多个代理服务器后到达最终服务器时,配置proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for后可通过X-Forwarded-For获取用户真实 IP 地址(请求通过第一台 nginx时:X-Forwarded-For = X-Real-IP = 用户真实 IP 地址;请求通过第二台 nginx 时:X-Forwarded-For = 用户真实 IP 地址, X-Real-IP = 上一台 nginx 的 IP 地址 )。
  4. 获取客户端的IP地址不仅可以通过proxy_set_header X-real-ip $remote_addr;获取,也可以通过proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;获取。

2.3.2 根据 IP 地址获取 IP 归属地

/**
 * 根据 IP 地址返回归属地,国内返回但省份,国外返回到国家
 * @param ip IP 地址
 * @return IP 归属地
 */
public static String getIpRegion(String ip) {
    initIp2regionResource();
    HashMap<String, String> cityInfo = new HashMap<>();
    String searchIpInfo = getCityInfo(ip);
    //-------------------------------------------------------
    //searchIpInfo 的数据格式: 国家|区域|省份|城市|ISP
    //192.168.31.160 0|0|0|内网IP|内网IP
    //47.52.236.180 中国|0|香港|0|阿里云
    //220.248.12.158 中国|0|上海|上海市|联通
    //164.114.53.60 美国|0|华盛顿|0|0
    //-------------------------------------------------------
    String[] splitIpInfo = searchIpInfo.split("\\|");
    cityInfo.put("ip",ip);
    cityInfo.put("searchInfo", searchIpInfo);
    cityInfo.put("country",splitIpInfo[0]);
    cityInfo.put("region",splitIpInfo[1]);
    cityInfo.put("province",splitIpInfo[2]);
    cityInfo.put("city",splitIpInfo[3]);
    cityInfo.put("ISP",splitIpInfo[3]);

    //--------------国内属地返回省份--------------
    if ("中国".equals(cityInfo.get("country"))){
        return cityInfo.get("province");
    }
    //------------------内网 IP----------------
   if ("0".equals(cityInfo.get("country"))){
        if ("内网IP".equals(cityInfo.get("ISP"))){
            return "";
        }
        else return "";
    }
   //--------------国外属地返回国家--------------
    else {
        return cityInfo.get("country");
    }
}

2.3.3 完整代码

IPUtils.java3:

import org.lionsoul.ip2region.xdb.Searcher;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import org.springframework.util.FileCopyUtils;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;

@Component
public class IPUtils {
    private static Searcher searcher;

    /**
     * 在 Nginx 等代理之后获取用户真实 IP 地址
     * @return 用户的真实 IP 地址
     */
    public static String getIpAddress(HttpServletRequest request) {
        if (request == null) {
            return null;
        }
        String ip = request.getHeader("x-forwarded-for");
        if (isIpaddress(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (isIpaddress(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (isIpaddress(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (isIpaddress(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (isIpaddress(ip)) {
            ip = request.getRemoteAddr();
            if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
                //根据网卡取本机配置的IP
                try {
                    InetAddress inet = InetAddress.getLocalHost();
                    ip = inet.getHostAddress();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
            }
        }
        return ip;
    }

    /**
     * 判断是否为 IP 地址
     * @param ip  IP 地址
     */
    public static boolean isIpaddress(String ip) {
        return ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip);
    }

    /**
     * 获取本地 IP 地址
     * @return 本地 IP 地址
     */
    public static String getHostIp() {
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return "127.0.0.1";
    }

    /**
     * 获取主机名
     * @return 本地主机名
     */
    public static String getHostName() {
        try {
            return InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return "未知";
    }

    /**
     * 根据 IP 地址从 ip2region.db 中获取地理位置
     * @param ip IP 地址
     * @return IP归属地
     */
    public static String getCityInfo(String ip) {
        try {
            return searcher.search(ip);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 在服务启动时加载 ip2region.db 到内存中
     * 解决打包 jar 后找不到 ip2region.db 的问题
     * @throws Exception 出现异常应该直接抛出终止程序启动,避免后续 invoke 时出现更多错误
     */
    @PostConstruct
    private static void initIp2regionResource() {
        try {
            InputStream inputStream = new ClassPathResource("/ipdb/ip2region.xdb").getInputStream();
            byte[] dbBinStr = FileCopyUtils.copyToByteArray(inputStream);
            // 创建一个完全基于内存的查询对象
            searcher = Searcher.newWithBuffer(dbBinStr);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据 IP 地址返回归属地,国内返回但省份,国外返回到国家
     * @param ip IP 地址
     * @return IP 归属地
     */
    public static String getIpRegion(String ip) {
        initIp2regionResource();
        HashMap<String, String> cityInfo = new HashMap<>();
        String searchIpInfo = getCityInfo(ip);
        //-------------------------------------------------------
        //searchIpInfo 的数据格式: 国家|区域|省份|城市|ISP
        //192.168.31.160 0|0|0|内网IP|内网IP
        //47.52.236.180 中国|0|香港|0|阿里云
        //220.248.12.158 中国|0|上海|上海市|联通
        //164.114.53.60 美国|0|华盛顿|0|0
        //-------------------------------------------------------
        String[] splitIpInfo = searchIpInfo.split("\\|");
        cityInfo.put("ip",ip);
        cityInfo.put("searchInfo", searchIpInfo);
        cityInfo.put("country",splitIpInfo[0]);
        cityInfo.put("region",splitIpInfo[1]);
        cityInfo.put("province",splitIpInfo[2]);
        cityInfo.put("city",splitIpInfo[3]);
        cityInfo.put("ISP",splitIpInfo[3]);

        //--------------国内属地返回省份--------------
        if ("中国".equals(cityInfo.get("country"))){
            return cityInfo.get("province");
        }
        //------------------内网 IP----------------
       if ("0".equals(cityInfo.get("country"))){
            if ("内网IP".equals(cityInfo.get("ISP"))){
                return "";
            }
            else return "";
        }
       //--------------国外属地返回国家--------------
        else {
            return cityInfo.get("country");
        }
    }

}

2.4 结果测试

测试代码:

@Test
public void test04(){
    System.out.println(IPUtils.getIpRegion("117.28.182.162"));
}

测试结果:

福建省

到此这篇关于Java使用ip2region获取用户的ip归属地的详细步骤的文章就介绍到这了,更多相关Java ip2region获取IP归属地内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java连接MySQL数据库增删改查的通用方法(推荐)

    Java连接MySQL数据库增删改查的通用方法(推荐)

    下面小编就为大家带来一篇Java连接MySQL数据库增删改查的通用方法(推荐)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • Gson之toJson和fromJson方法的具体使用

    Gson之toJson和fromJson方法的具体使用

    Gson是Google的一个开源项目,可以将Java对象转换成JSON,也可能将JSON转换成Java对象。本文就详细的介绍了toJson和fromJson方法的具体使用,感兴趣的可以了解一下
    2021-11-11
  • Java实现两个随机数组合并进行排序的方法

    Java实现两个随机数组合并进行排序的方法

    本文主要介绍了Java实现两个随机数组合并进行排序的方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • spring基础概念AOP与动态代理理解

    spring基础概念AOP与动态代理理解

    这篇文章主要为大家详细介绍了spring基础概念AOP与动态代理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • 2021最新IDEA的各种快捷键汇总

    2021最新IDEA的各种快捷键汇总

    掌握idea的各种快捷键,可以帮助我们开发程序,今天小编给大家带来几种比较常用的idea快捷键及一些快捷键介绍,对idea快捷键相关知识,感兴趣的朋友一起看看吧
    2021-05-05
  • 基于SpringBoot创建Web页面并热更新的操作步骤

    基于SpringBoot创建Web页面并热更新的操作步骤

    SpringBoot是一个用于快速开发单个微服务的框架,它基于 Spring 框架,简化了Spring应用的初始化过程和开发流程,本文给大家介绍了如何基于SpringBoot创建Web页面并热更新,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2023-11-11
  • 实例解析如何正确使用Java数组

    实例解析如何正确使用Java数组

    同一种类型数据的集合。其实数组就是一个容器。运算的时候有很多数据参与运算,那么首先需要做的是什么下面我们就一起来看看。
    2016-07-07
  • Java POI读取excel中数值精度损失问题解决

    Java POI读取excel中数值精度损失问题解决

    这篇文章主要介绍了Java POI读取excel中数值精度损失问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • springboot静态资源的配置方式

    springboot静态资源的配置方式

    这篇文章主要介绍了springboot静态资源的配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • Java中compareTo()和compare()方法使用及区别详解

    Java中compareTo()和compare()方法使用及区别详解

    这篇文章主要介绍了Java中compareTo()和compare()方法使用及区别的相关资料,compareTo()方法用于定义类的自然排序,适用于具有单一、固定排序方式的场景,compare()方法提供自定义排序的灵活性,适用于需要根据不同规则对对象进行排序的场景,需要的朋友可以参考下
    2025-01-01

最新评论