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

目录
  • 引言
  • Java 中是如何获取 IP 属地的
    • 首先需要写一个 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获取归属地的资料请关注我们其它相关文章!

(0)

相关推荐

  • java获取IP归属地全网显示开源库使用

    目录 引言 Java如何获取IP属地 Ip2region开源项目 99.9%准确率: 多查询客户端的支持 Ip2region V2.0 特性 ip2region xdb java 查询客户端实现 IDEA中做个测试 编译测试程序 查询测试 bench 测试 引言 细心的朋友应该会发现,最近,继新浪微博之后,头条.腾讯.抖音.知乎.快手.小红书等各大平台陆陆续续都上线了“网络用户IP地址显示功能”,境外用户显示的是国家,国内的用户显示的省份,而且此项显示无法关闭,归属地强制显示. 作为技术人,那!

  • java调用淘宝api联网查询ip归属地

    淘宝返回的数据为:{"code":0,"data":{"country":"\u4e2d\u56fd","country_id":"CN","area":"\u534e\u4e1c","area_id":"300000","region":"\u5c71\u4e1c\u7701&

  • java IP归属地功能实现详解

    目录 第一步:如何拿到用户的真实IP 1.1内网IP和外网IP 1.2.为什么有时候获取到的客户端IP有问题? 第二步:如何解析IP 第一步:如何拿到用户的真实IP 大家都知道,我们一般想访问公网,一般必须具备上网环境,那么我们开通宽带之后,运营商会给我们分配一个IP地址.一般IP地址我们都是自动分配的.所以我们不知道本机地址是什么?想知道自己的ip公网地址,可以通过百度搜索IP查看自己的ip位置 那么问题来了.百度是怎么知道我的公网IP的? 一般情况,用户访问我们的服务网络拓扑如下: 用户通过

  • Java获取手机号码归属地的实现

    遇到一个需求, 需要发送短信给全球各地的用户, 但是各大运营商的API都是 区分 国内 和 国际, 但是我们只有电话号码, 只能自己添加一个方法, 判断号码的归属地, 然后再分别调用相应区域的API. 引入依赖包 <!-- 电话号码工具类 --> <dependency> <groupId>com.googlecode.libphonenumber</groupId> <artifactId>libphonenumber</artifact

  • Java手机号码工具类示例详解(判断运营商、获取归属地)

    所需引用Jar包 <dependency> <groupId>com.googlecode.libphonenumber</groupId> <artifactId>geocoder</artifactId> <version>2.15</version> </dependency> <dependency> <groupId>com.googlecode.libphonenumber&

  • java使用淘宝API读写json实现手机归属地查询功能代码

    一般查询手机归属地内容应该很好用json格式保存,在网上找到了淘宝的归属地API,并下了处理json相关的jar包,做了这个手机归属地查询功能 复制代码 代码如下: package com.think.java; import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.net.MalformedURLException;import java.net

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

    目录 引言 Java 中是如何获取 IP 属地的 首先需要写一个 IP 获取的工具类 内置的三种查询算法 使用方法 项目用到的全部依赖 引言 最近,各大平台都新增了评论区显示发言者ip归属地的功能,例如哔哩哔哩,微博,知乎等等. Java 中是如何获取 IP 属地的 主要分为以下几步 通过 HttpServletRequest 对象,获取用户的 IP 地址 通过 IP 地址,获取对应的省份.城市 首先需要写一个 IP 获取的工具类 因为每一次用户的 Request 请求,都会携带上请求的 IP 

  • C#根据IP地址查询所属地区实例详解

    ip-api.com接口(解析 json需要引入Newtonsoft.Json.dll ): /// <summary> /// 根据IP 获取物理地址 /// </summary> /// <param name="ip">Ip地址</param> /// <returns></returns> public static string GetIpAddress(string ip) { string url =

  • C#使用有道ip地址查询接口方法实例详解

    本文实例讲述了C#使用有道ip地址查询接口方法.分享给大家供大家参考.具体实现方法如下: #region 读取http://www.yodao.com接口IP地址 /// <summary> /// 读取http://www.yodao.com接口IP地址 /// </summary> public static string GetstringIpAddress(string strIP)//strIP为IP { string sURL = "http://www.yo

  • Java使用Scanner类获取用户输入实例详解

    创建 Scanner 对象的基本语法: Scanner s = new Scanner(System.in); Scanner 类的 next() 方法 import java.util.Scanner; class Test{ public static void main(String[] args){ String s; Scanner userInput = new Scanner(System.in); System.out.print("Input String: ");

  • FasfDFS整合Java实现文件上传下载功能实例详解

    在上篇文章给大家介绍了FastDFS安装和配置整合Nginx-1.13.3的方法,大家可以点击查看下. 今天使用Java代码实现文件的上传和下载.对此作者提供了Java API支持,下载fastdfs-client-java将源码添加到项目中.或者在Maven项目pom.xml文件中添加依赖 <dependency> <groupId>org.csource</groupId> <artifactId>fastdfs-client-java</arti

  • Java 中HttpURLConnection附件上传的实例详解

    Java 中HttpURLConnection附件上传的实例详解 整合了一个自己写的采用Http做附件上传的工具,分享一下! 示例代码: /** * 以Http协议传输文件 * * @author mingxue.zhang@163.com * */ public class HttpPostUtil { private final static char[] MULTIPART_CHARS = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJK

  • Android Studio获取SHA1值实例详解

    Android Studio获取SHA1值实例详解 前言 使用百度地图的小伙伴们都会知道获取百度地图的密钥需要SHA1和包名,在Eclipse中,我们可以很方便的得知SHA1值,如下图: 但是在Android Studio中,该怎么获取SHA1的值呢?不要着急,马上呈上~ Android Studio获取SHA1值 强大的Android Studio为我们提供了Terminal这个工具,我们可以通过他进行相应命令从而获取所需内容. Java中提供了Keytool工具去让我们管理证书,那么接下来我

  • Java对象深复制与浅复制实例详解

     Java对象深复制与浅复制实例详解 我们在遇到一些业务场景的时候经常需要对对象进行复制,对于对象的复制一般有两种方式,深复制和浅复制 浅复制:对象的复制仅是对象本身,对象引用的其它对方并不会复制. 深复制:对象的复制包含对象引用的对象. Java所有对象的基类提供了clone方法,但是这个方法是protected native修饰,因此只暴露给之类去重写,外部是无法直接调用的. 我们现在来测试两种复制,首选是浅复制,浅复制要实现Cloneable接口. // 课程对象 class Class

  • java 实现websocket的两种方式实例详解

    一.介绍 1.两种方式,一种使用tomcat的websocket实现,一种使用spring的websocket 2.tomcat的方式需要tomcat 7.x,JEE7的支持. 3.spring与websocket整合需要spring 4.x,并且使用了socketjs,对不支持websocket的浏览器可以模拟websocket使用 二.方式一:tomcat 使用这种方式无需别的任何配置,只需服务端一个处理类, 服务器端代码 package com.Socket; import java.io

  • Java使用AES加密和解密的实例详解

    Java使用AES加密和解密的实例详解 前言: AES的基本要求是,采用对称分组密码体制,密钥长度的最少支持为128.192.256,分组长度128位,算法应易于各种硬件和软件实现.1998年NIST开始AES第一轮分析.测试和征集,共产生了15个候选算法.1999年3月完成了第二轮AES2的分析.测试.2000年10月2日美国政府正式宣布选中比利时密码学家Joan Daemen 和 Vincent Rijmen 提出的一种密码算法RIJNDAEL 作为 AES. 在应用方面,尽管DES在安全上

随机推荐