Java根据ip地址获取归属地实例详解

 更新时间:2022年08月30日 15:09:53   作者:温柔yi被时间上锁  
这篇文章主要为大家介绍了Java根据ip地址获取归属地实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

最近,各大平台都新增了评论区显示发言者ip归属地的功能,例如哔哩哔哩,微博,知乎等等。

Java 中是如何获取 IP 属地的

主要分为以下几步

  • 通过 HttpServletRequest 对象,获取用户的 IP 地址
  • 通过 IP 地址,获取对应的省份、城市

首先需要写一个 IP 获取的工具类

因为每一次用户的 Request 请求,都会携带上请求的 IP 地址放到请求头中。

public class IpUtils {
    /**
     * 获取ip地址
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request){
        String ipAddress = null;
        try {
            ipAddress = request.getHeader("X-Forwarded-For");
            if (ipAddress != null && ipAddress.length() != 0 && !"unknown".equalsIgnoreCase(ipAddress)) {
                // 多次反向代理后会有多个ip值,第一个ip才是真实ip
                if (ipAddress.indexOf(",") != -1) {
                    ipAddress = ipAddress.split(",")[0];
                }
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("HTTP_CLIENT_IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getRemoteAddr();
            }
        }catch (Exception e) {
            log.error("IPUtils ERROR ",e);
        }
        return ipAddress;
    }

对这里出现的几个名词解释一下:

  • X-Forwarded-For:一个 HTTP 扩展头部,主要是为了让 Web 服务器获取访问用户的真实 IP 地址。每个 IP 地址,每个值通过逗号+空格分开,最左边是最原始客户端的 IP 地址,中间如果有多层代理,每⼀层代理会将连接它的客户端 IP 追加在 X-Forwarded-For 右边。
  • Proxy-Client-IP:这个一般是经过 Apache http 服务器的请求才会有,用 Apache http 做代理时一般会加上 Proxy-Client-IP 请求头
  • WL-Proxy-Client-IP:也是通过 Apache http 服务器,在 weblogic 插件加上的头。
  • X-Real-IP:一般只记录真实发出请求的客户端IP
  • HTTP_CLIENT_IP:代理服务器发送的HTTP头。如果是“超级匿名代理”,则返回none值。

这里,要着重介绍一下Ip2region项目。

github地址:github.com/lionsoul201…

一个准确率 99.9% 的离线 IP 地址定位库,0.0x 毫秒级查询,ip2region.db 数据库只有数MB,提供了 java,php,c,python,nodejs,golang,c# 等查询绑定和Binary,B树,内存三种查询算法。

内置的三种查询算法

全部的查询客户端单次查询都在 0.x 毫秒级别,内置了三种查询算法

  • memory 算法:整个数据库全部载入内存,单次查询都在0.1x毫秒内,C语言的客户端单次查询在0.00x毫秒级别。
  • binary 算法:基于二分查找,基于ip2region.db文件,不需要载入内存,单次查询在0.x毫秒级别。
  • b-tree 算法:基于btree算法,基于ip2region.db文件,不需要载入内存,单词查询在0.x毫秒级别,比binary算法更快。

使用方法

1、引入ip2region依赖

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

2、下载仓库中的ip2region.db 文件,放到工程resources目录下

3、编写方法加载ip2region文件,对用户ip地址进行转换。

/**
 * 获取ip属地
 * @param ip
 * @return
 * @throws Exception
 */
public static String getCityInfo(String ip) throws Exception {
    //获得文件流时,因为读取的文件是在打好jar文件里面,不能直接通过文件资源路径拿到文件,但是可以在jar包中拿到文件流
    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    Resource[] resources = resolver.getResources("ip2region.db");
    Resource resource = resources[0];
    InputStream is = resource.getInputStream();
    File target = new File("ip2region.db");
    FileUtils.copyInputStreamToFile(is, target);
    is.close();
    if (StringUtils.isEmpty(String.valueOf(target))) {
        log.error("Error: Invalid ip2region.db file");
        return null;
    }
    DbConfig config = new DbConfig();
    DbSearcher searcher = new DbSearcher(config, String.valueOf(target));
    //查询算法
    //B-tree, B树搜索(更快)
    int algorithm = DbSearcher.BTREE_ALGORITHM;
    try {
        //define the method
        Method method;
        method = searcher.getClass().getMethod("btreeSearch", String.class);
        DataBlock dataBlock;
        if (!Util.isIpAddress(ip)) {
            log.error("Error: Invalid ip address");
        }
        dataBlock = (DataBlock) method.invoke(searcher, ip);
        String ipInfo = dataBlock.getRegion();
        if (!StringUtils.isEmpty(ipInfo)) {
            ipInfo = ipInfo.replace("|0", "");
            ipInfo = ipInfo.replace("0|", "");
        }
        return ipInfo;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

4、由于 ip 属地在国内的话,只会展示省份,而国外的话,只会展示国家。所以我们还需要对这个方法进行一下封装,得到获取 IP 属地的信息。

public static String getIpPossession(String ip) throws Exception {
    String cityInfo = IpUtils.getCityInfo(ip);
    if (!StringUtils.isEmpty(cityInfo)) {
        cityInfo = cityInfo.replace("|", " ");
        String[] cityList = cityInfo.split(" ");
        if (cityList.length > 0) {
            // 国内的显示到具体的省
            if ("中国".equals(cityList[0])) {
                if (cityList.length > 1) {
                    return cityList[1];
                }
            }
            // 国外显示到国家
            return cityList[0];
        }
    }
    return "未知";
}

5、编写测试类。

public static void main(String[] args) throws Exception {
    //国内ip
    String ip1 = "220.248.12.158";
    String cityInfo1 = IpUtils.getCityInfo(ip1);
    System.out.println(cityInfo1);
    String address1 = IpUtils.getIpPossession(ip1);
    System.out.println(address1);
    //国外ip
    String ip2 = "67.220.90.13";
    String cityInfo2 = IpUtils.getCityInfo(ip2);
    System.out.println(cityInfo2);
    String address2 = IpUtils.getIpPossession(ip2);
    System.out.println(address2);
}

6、测试结果

项目用到的全部依赖

想了解的小伙伴可以学习一下!

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.36</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.10</version>
</dependency>
<dependency>
    <groupId>org.lionsoul</groupId>
    <artifactId>ip2region</artifactId>
    <version>1.7.2</version>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.11.0</version>
</dependency>

以上就是Java根据ip地址获取归属地实例详解的详细内容,更多关于Java根据ip获取归属地的资料请关注脚本之家其它相关文章!

相关文章

  • Day14基础不牢地动山摇-Java基础

    Day14基础不牢地动山摇-Java基础

    这篇文章主要给大家介绍了关于Java中方法使用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-08-08
  • 基于Java网络编程和多线程的多对多聊天系统

    基于Java网络编程和多线程的多对多聊天系统

    这篇文章主要介绍了基于Java网络编程和多线程的多对多聊天系统,文中有非常详细的代码示例,对正在学习java网络编程的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-04-04
  • JAVA十大排序算法之选择排序详解

    JAVA十大排序算法之选择排序详解

    这篇文章主要介绍了java中的选择排序,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-08-08
  • 浅谈多线程_让程序更高效的运行

    浅谈多线程_让程序更高效的运行

    下面小编就为大家带来一篇浅谈多线程_让程序更高效的运行。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • java安全 ysoserial CommonsCollections1示例解析

    java安全 ysoserial CommonsCollections1示例解析

    这篇文章主要介绍了java安全 ysoserial CommonsCollections1示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • Java与Http协议的详细介绍

    Java与Http协议的详细介绍

    这篇文章主要介绍了Java与Http协议的详细介绍的相关资料,这里提供实例来帮助大家学习理解这部分内容,需要的朋友可以参考下
    2017-09-09
  • Spring Boot 项目做性能监控的操作流程

    Spring Boot 项目做性能监控的操作流程

    这篇文章主要介绍了Spring Boot 项目如何做性能监控,本文通过实例代码图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • 反射机制:getDeclaredField和getField的区别说明

    反射机制:getDeclaredField和getField的区别说明

    这篇文章主要介绍了反射机制:getDeclaredField和getField的区别说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • Java 跳出递归循环问题解决办法

    Java 跳出递归循环问题解决办法

    这篇文章主要介绍了 Java 跳出递归循环问题解决办法的相关资料,需要的朋友可以参考下
    2017-07-07
  • BootStrap Jstree 树形菜单的增删改查的实现源码

    BootStrap Jstree 树形菜单的增删改查的实现源码

    这篇文章主要介绍了BootStrap Jstree 树形菜单的增删改查的实现源码,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-02-02

最新评论