SpringBoot整合Ip2region获取IP地址和定位

SpringBoot整合Ip2region获取IP地址和定位

码农世界 2024-06-18 后端 92 次浏览 0个评论

格式:每个 ip 数据段的 region 信息都固定了格式:国家|区域|省份|城市|ISP

参考地址1

参考地址2

SpringBoot整合Ip2region获取IP地址和定位

SpringBoot整合Ip2region获取IP地址和定位

1.Ip2region的介绍

1.1.Ip2region 是什么

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

1.2.Ip2region 特性

1.2.1 标准化的数据格式

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

1.2.2.数据去重和压缩

xdb 格式生成程序会自动去重和压缩部分数据,默认的全部 IP 数据,生成的 ip2region.xdb 数据库是 11MiB,随着数据的详细度增加数据库的大小也慢慢增大。

1.2.3.极速查询响应

即使是完全基于 xdb 文件的查询,单次查询响应时间在十微秒级别,可通过如下两种方式开启内存加速查询:

vIndex 索引缓存 :使用固定的 512KiB 的内存空间缓存 vector index 数据,减少一次 IO 磁盘操作,保持平均查询效率稳定在10-20微秒之间。

xdb 整个文件缓存:将整个 xdb 文件全部加载到内存,内存占用等同于 xdb 文件大小,无磁盘 IO 操作,保持微秒级别的查询效率。

1.2.4.IP 数据管理框架

2.0 格式的 xdb 支持亿级别的 IP 数据段行数,region 信息也可以完全自定义,例如:你可以在 region 中追加特定业务需求的数据,例如:GPS信息/国际统一地域信息编码/邮编等。也就是你完全可以使用 ip2region 来管理你自己的 IP 定位数据。

2.Java方式

2.1.下载ip2region.db

$ git clone https://github.com/lionsoul2014/ip2region.git

下载这个项目之后到data/文件夹下面找到ip2region.db复制到项目resources下

2.2.maven仓库

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-starter-test

test

org.apache.commons

commons-lang3

3.12.0

    
    
        org.lionsoul
        ip2region
        2.7.0
    
    
        eu.bitwalker
        UserAgentUtils
        1.21
    

2.3.代码

package com.nacl.util;

import eu.bitwalker.useragentutils.UserAgent;

import org.apache.commons.lang3.StringUtils;

import org.lionsoul.ip2region.xdb.Searcher;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.util.FileCopyUtils;

import javax.servlet.http.HttpServletRequest;

import java.io.IOException;

import java.io.InputStream;

import java.net.InetAddress;

import java.net.UnknownHostException;

/**

  • @author HAOYANG

  • @create 2023-08-02 17:03

    */

    public class IpUtils {

    private static final Logger logger = LoggerFactory.getLogger(IpUtils.class);

    private final static String localIp = “127.0.0.1”;

    private static Searcher searcher = null;

    /**

    • 在服务启动时加载 ip2region.db 到内存中
    • 解决打包jar后找不到 ip2region.db 的问题

      */

      static {

      try {

      InputStream ris = IpUtils.class.getResourceAsStream(“/ip2region/ip2region.xdb”);

      byte[] dbBinStr = FileCopyUtils.copyToByteArray(ris);

      searcher = Searcher.newWithBuffer(dbBinStr);

      //注意:不能使用文件类型,打成jar包后,会找不到文件

      logger.debug(“缓存成功!!!!”);

      } catch (IOException e) {

      logger.error(“解析ip地址失败,无法创建搜索器: {}”, e);

      throw new RuntimeException(e);

      }

      }

      /**

      • 获取用户真实IP地址,不使用request.getRemoteAddr();的原因是有可能用户使用了代理软件方式避免真实IP地址,

      • 参考文章: http://developer.51cto.com/art/201111/305181.htm

      • 可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值,究竟哪个才是真正的用户端的真实IP呢?

      • 答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。

      • 如:X-Forwarded-For:192.168.1.110, 192.168.1.120, 192.168.1.130,

      • 192.168.1.100

      • 用户真实IP为: 192.168.1.110

      • @param request

      • @return

        */

        public static String getIp(HttpServletRequest request) {

        String ipAddress;

        try {

        // 以下两个获取在k8s中,将真实的客户端IP,放到了x-Original-Forwarded-For。而将WAF的回源地址放到了 x-Forwarded-For了。

        ipAddress = request.getHeader(“X-Original-Forwarded-For”);

        if (ipAddress == null || “unknown”.equalsIgnoreCase(ipAddress)) {

        ipAddress = request.getHeader(“X-Forwarded-For”);

        }

         //获取nginx等代理的ip
         if (ipAddress == null || "unknown".equalsIgnoreCase(ipAddress)) {
             ipAddress = request.getHeader("x-forwarded-for");
         }
         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 || "unknown".equalsIgnoreCase(ipAddress)) {
             ipAddress = request.getHeader("HTTP_CLIENT_IP");
         }
         if (ipAddress == null || "unknown".equalsIgnoreCase(ipAddress)) {
             ipAddress = request.getHeader("HTTP_X_FORWARDED_FOR");
         }
         // 2.如果没有转发的ip,则取当前通信的请求端的ip(兼容k8s集群获取ip)
         if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
             ipAddress = request.getRemoteAddr();
             // 如果是127.0.0.1,则取本地真实ip
             if (localIp.equals(ipAddress)) {
                 // 根据网卡取本机配置的IP
                 InetAddress inet = null;
                 try {
                     inet = InetAddress.getLocalHost();
                     ipAddress = inet.getHostAddress();
                 } catch (UnknownHostException e) {
                     e.printStackTrace();
                 }
             }
         }
         // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
         if (ipAddress != null && ipAddress.length() > 15) {
             // = 15
             if (ipAddress.indexOf(",") > 0) {
                 ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
             }
         }
        

        } catch (Exception e) {

        logger.error(“解析请求IP失败”, e);

        ipAddress = “”;

        }

        return “0:0:0:0:0:0:0:1”.equals(ipAddress) ? localIp : ipAddress;

        }

        /**

        • 获取访问设备
        • @param request
        • @return

          */

          public static UserAgent getUserAgent(HttpServletRequest request) {

          return UserAgent.parseUserAgentString(request.getHeader(“User-Agent”));

          }

          /**

          • 根据ip获取 城市信息
          • @param ipAddress
          • @return

            */

            public static String getCityInfo(String ipAddress) {

            String cityInfo = null;

            try {

            return searcher.search(ipAddress);

            } catch (Exception e) {

            logger.error(“搜索:{} 失败: {}”,ipAddress, e);

            }

            return null;

            }

            /**

            • 根据ip2region解析ip地址

            • @param ip ip地址

            • @return 解析后的ip地址信息

              */

              public static String getIp2region(String ip) {

              if(searcher == null){

              logger.error(“Error: DbSearcher is null”);

              return null;

              }

              try {

              String ipInfo = searcher.search(ip);

              if (!StringUtils.isEmpty(ipInfo)) {

              ipInfo = ipInfo.replace(“|0”, “”);

              ipInfo = ipInfo.replace(“0|”, “”);

              }

              return ipInfo;

              } catch (Exception e) {

              e.printStackTrace();

              }

              return null;

              }

              /**

              • 获取IP地址
              • @return 本地IP地址

                */

                public static String getHostIp(){

                try{

                return InetAddress.getLocalHost().getHostAddress();

                }catch (UnknownHostException e){

                }

                return localIp;

                }

                /**

                • 获取主机名
                • @return 本地主机名

                  */

                  public static String getHostName(){

                  try{

                  return InetAddress.getLocalHost().getHostName();

                  } catch (UnknownHostException e) {

                  }

                  return “未知”;

                  }

                  }

                  2.4.测试类

                  package com.nacl;

                  import com.nacl.util.IpUtils;

                  import org.junit.jupiter.api.Test;

                  import org.springframework.boot.test.context.SpringBootTest;

                  /**

                  • @author HAOYANG
                  • @create 2023-07-31 15:09

                    */

                    @SpringBootTest

                    public class SensitiveTest {

                    @Test

                    void iptest(){

                    String cityInfo = IpUtils.getCityInfo(“xxx.xxx.xxx.xxx”);

                    System.out.println(cityInfo);

                    }

                    }

转载请注明来自码农世界,本文标题:《SpringBoot整合Ip2region获取IP地址和定位》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,92人围观)参与讨论

还没有评论,来说两句吧...

Top