java根据用户请求获取ip地址,并解析省市信息

目录

  • 1.选型
    • 1.1 实现方式
      • 1.1.1 本地文件解析
      • 1.1.2 数据库查询
      • 1.1.3 第三方API代理
      • 1.2 常用ip定位库
        • 1.2.1 Ip2region
        • 1.2.2 GeoLite2
        • 1.2.3 IP2Location
        • 1.2.4 ipapi
        • 1.2.5 QQWry
        • 1.2.6 其他
        • 1.3 选择
        • 2.pom.xml依赖
        • 3.代码示例

          1.选型

          1.1 实现方式

          Java可以实现IP地址解析和省市区信息查询,但是需要借助一些外部数据源或数据库来实现。常用的方法有以下几种:

          1.1.1 本地文件解析

          可以通过下载最新的IP地址段数据文件,然后在程序中解析该文件来获取IP地址对应的省市区等信息。不过这种方法需要手动维护IP库文件,并且更新和查询速度可能较慢,不适合高并发或大规模的应用场景。

          1.1.2 数据库查询

          可以将IP地址段数据存储在数据库中,然后根据用户请求的IP地址来查询对应的省市区等信息。常用的数据库有MySQL、Oracle、SQL Server等。这种方法可以提高查询效率和精度,并支持更灵活的查询方式,但是需要考虑数据库的设计和优化问题。

          1.1.3 第三方API代理

          使用第三方IP查询API代理来实现纯Java的IP地址解析和省市区信息查询。比如通过调用百度地图API、高德地图API等第三方服务来获取IP地址对应的位置信息。这种方法可以免去自行搭建IP数据库的麻烦,同时也能保证查询结果的准确性和实时性,但需要考虑API使用频率和费用等问题。

          1.2 常用ip定位库

          1.2.1 Ip2region

          Ip2region:Ip2region是一个基于Java的IP地址定位库,提供了快速而准确的IP查询服务。它将全球IP地址划分为多级区域,可以根据IP地址获取对应的省市区信息、运营商等详细信息。

          1.2.2 GeoLite2

          GeoLite2:一款免费的IP地址库,由MaxMind公司开发和维护,提供高精度的IP地址定位服务。可通过下载数据库文件或使用API来查询IP地址对应的位置信息。

          1.2.3 IP2Location

          IP2Location:一款商业化的IP地址库,提供全球范围内的IP地址定位服务,支持IPv4/IPv6地址解析。可通过订阅服务或购买数据库文件来使用。

          1.2.4 ipapi

          ipapi:一款云端IP地址查询API,提供高效和准确的IP地址定位服务。支持JSON/XML格式的返回数据,可根据用户需求选择不同的套餐和服务计划。

          1.2.5 QQWry

          QQWry:国内最广泛使用的IP地址库之一,提供了IP地址到省市区县、运营商等信息的映射。可通过下载最新版的dat文件或使用API来实现IP地址定位。

          1.2.6 其他

          国内还有很多其他的定位库,如淘宝、新浪、搜狐等ip库,有兴趣的朋友自己了解下。

          1.3 选择

          综合下面几种情况考虑最后选择了 Ip2region

          1.数据来源和准确性:数据是否完整、数据覆盖率、精度和实效性等。

          2.许可协议和商业使用:是否需要授权、是否可用于商业用途、是否收费等。

          3.支持的语言和平台

          2.pom.xml依赖

          我自己使用的springboot项目,基础依赖就不列举了

            cn.hutool hutool-all 5.4.2   org.lionsoul ip2region 2.7.0   org.projectlombok lombok provided 

          3.代码示例

          实体类接收国家、省市等信息。

          @Data
          public class IpLocation implements Serializable { @ApiModelProperty("ip地址")
              private String ip;
              @ApiModelProperty("国家")
              private String country;
              @ApiModelProperty("省")
              private String province;
              @ApiModelProperty("省")
              private String city;
              @ApiModelProperty("服务商")
              private String isp;
          }
          

          工具类:

          @Slf4j
          //@UtilityClass
          public class IpUtils { /**
               * 字符常量0
               */
              private static final String ZERO="0";
              /**
               * 本级ip
               */
              private static final String LOCALHOST="127.0.0.1";
              /**
               * 获取客户端的IP地址
               */
              public static String getIpAddress(HttpServletRequest request) { String 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 || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr();
                      if (LOCALHOST.equals(ipAddress)) { // 根据网卡取本机配置的IP
                          InetAddress inet = null;
                          try { inet = InetAddress.getLocalHost();
                              ipAddress = inet.getHostAddress();
                          } catch (UnknownHostException e) { e.printStackTrace();
                          }
                      }
                  }
                  // 对于通过多个代理转发的情况,取第一个非unknown的IP地址。
                  // 这里假设第一个IP为真实IP,后面的为代理IP。
                  if (ipAddress != null && ipAddress.length() > 15) { if (ipAddress.indexOf(",") > 0) { ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                      }
                  }
                  return ipAddress;
              }
              /**
               * 根据iP获取归属地信息
               * @return
               */
              public static IpLocation getLocation(String ip) { IpLocation location = new IpLocation();
                  location.setIp(ip);
                  try (InputStream inputStream = IpUtils.class.getResourceAsStream("/ip2region.xdb");) { byte[] bytes = IoUtil.readBytes(inputStream);
                      Searcher searcher = Searcher.newWithBuffer(bytes);
                      String region = searcher.search(ip);
                      if (StrUtil.isAllNotBlank(region)) { // xdb返回格式 国家|区域|省份|城市|ISP,
                          // 只有中国的数据绝大部分精确到了城市,其他国家部分数据只能定位到国家,后前的选项全部是0
                          String[] result = region.split("\\|");
                          location.setCountry(ZERO.equals(result[0])?StrUtil.EMPTY:result[0]);
                          location.setProvince(ZERO.equals(result[2])?StrUtil.EMPTY:result[2]);
                          location.setCity(ZERO.equals(result[3])?StrUtil.EMPTY:result[3]);
                          location.setIsp(ZERO.equals(result[4])?StrUtil.EMPTY:result[4]);
                      }
                      searcher.close();
                  } catch (Exception e) { log.error("ip地址解析异常,error:{}",e);
                      return location;
                  }
                  return location;
              }
          }
          

          在官网地址,将data目录下的ip2region.xdb文件复制到resource下。

          在百度输入ip地址查询,可以查到自己本地公网地址,测试如下(这里为了方便,直接写在了工具类里):

          如果需要测试 IP 地址查询功能,可以尝试使用一些公共的 IP 地址,例如:

          • 8.8.8.8:谷歌公共 DNS 地址,位于美国。
          • 114.114.114.114:中国电信公共 DNS 地址,位于中国。
          • 1.1.1.1:Cloudflare 公共 DNS 地址,位于澳大利亚。
          • 208.67.222.222:OpenDNS 公共 DNS 地址,位于美国。
          • 176.103.130.130:AdGuard 公共 DNS 地址,位于荷兰。