当前位置: 首页> 娱乐> 明星 > 徐州模板建站哪家好_湖北网站推广公司渠道_宁波网站建设团队_宁波关键词排名优化

徐州模板建站哪家好_湖北网站推广公司渠道_宁波网站建设团队_宁波关键词排名优化

时间:2025/8/23 9:28:08来源:https://blog.csdn.net/jspyth/article/details/142653776 浏览次数:0次
徐州模板建站哪家好_湖北网站推广公司渠道_宁波网站建设团队_宁波关键词排名优化

文章目录

    • 摘要
    • 实现过程
      • 思路
      • GeoLite2 IP库文件引入
        • 准备工作
        • 代码实现
      • Ipdata API
        • 准备工作
          • 官网账号注册
          • 创建API Key
          • API文档:
        • 代码实现
    • 完整代码
    • 总结

摘要

  本文详解如何封装一个根据IP获取所在国家地区的接口。不管是网站、APP还是PC软件,如果你的目标客户包含国内和海外,那必然有多语言等需要区分用户所在区域的功能,虽然说IP定位会有开VPN的特殊场景影响导致不准确(国内被定位到海外,一般来说产品可接受),并且APP本身有其他判断用户所在地的方式,比如安卓可以通过GPS,但是对于一个完整的方案来说,在客户端其他更准确的方式失效或者由于用户不给APP权限导致无法使用时,有一个IP查询的接口对接也是一个必要的兜底方式。

实现过程

思路

  世界范围内IP的数据是不停在更新的,为确保尽可能多的IP能通过接口查询到对应的所在区域,我们需要更新尽量频繁的数据源,ipdata是个不错的选择,它提供API,传入IP即可返回IP相关的国家、城市、时区等信息,但是Ipdata免费调用次数只有一天1500次,需要更多调用次数得花钱。所以我们搭配一个固定的ip数据文件GeoLite2-City.mmdb查询,优先从项目集成的数据文件查询,查询不到才去调用ipdata,并且还可以做个ipdata调用结果的缓存设计,毕竟一个ip属于什么国家是不会频繁变化的,你哪怕缓存几天,都能大大降低ipdata调用次数的浪费。

GeoLite2 IP库文件引入

准备工作

  你可以直接从MaxMind的官方网站上下载GeoLite2-City.mmdb数据库文件:下载链接。
  服务器部署的时候将文件放到服务器上,如果是容器部署服务将文件挂载到容器的自定义目录中,比如我举例叫/home/my_dir/目录。

代码实现

  Maven依赖:

<dependency><groupId>com.maxmind.geoip2</groupId><artifactId>geoip2</artifactId><version>2.8.1</version>
</dependency>

  写一个根据GeoLite2-City.mmdb数据文件查询IP所在国家编码的方法,如果是IP属于中国并且IP在数据文件中,就会返回”CN“:

private String getCountry(String ip) throws IOException, GeoIp2Exception {// 容器中读取数据文件的路径File database = new File("/home/my_dir/GeoLite2-City.mmdb");// 读取数据库内容DatabaseReader reader = new DatabaseReader.Builder(database).build();InetAddress ipAddress = InetAddress.getByName(ip);// 获取查询结果CityResponse response = reader.city(ipAddress);//获取countryCountry country = response.getCountry();return country.getIsoCode();
}

Ipdata API

准备工作

  接下来进入我们的重点,我们来看ipdata的调用方式和实现。

官网账号注册

  官网注册页地址:官网。
在这里插入图片描述

创建API Key

  登录后你能看到官方为每个用户账号分配了一个API key:
在这里插入图片描述

API文档:

  从接口文档可以看出调用方式非常简单,Ip+API key GET请求即可,接口文档地址:文档。
在这里插入图片描述

代码实现

  我们来看下ipdata调用逻辑的代码实现:

private Map<String, String> getCountryByIpData(String ip) {String url = "https://api.ipdata.co/" + ip + "?api-key=" + ipDataSecret;String resultStr = HttpUtils.get(url, null);JSONObject resultObject = JSON.parseObject(resultStr);Map<String, String> result = new HashMap<>();if (resultObject != null) {result.put("countryCode", resultObject.getString("country_code"));result.put("countryName", resultObject.getString("country_name"));result.put("regionCode", resultObject.getString("region_code"));result.put("city", resultObject.getString("city"));String timeZoneStr = resultObject.getString("time_zone");if (timeZoneStr != null) {JSONObject timeZoneObject = JSON.parseObject(timeZoneStr);result.put("timeZone", timeZoneObject.getString("name"));}}return result;
}

完整代码

  接下来给读者提供完整的代码实现:

// 优先查询数据库文件,查询不到才使用ipdata
public String getUserCountryCodeByIp(String ip) {log.info("Enter service.");String code = null;try {code = getCountry(ip);if (StringUtils.isBlank(code)) {code = getUserCountryCodeByIpData(ip).getCountryCode();}} catch (IOException | GeoIp2Exception e) {log.error("Get country code error, msg is [{}]", e.getMessage());code = getUserCountryCodeByIpData(ip).getCountryCode();} catch (Exception ex) {ex.printStackTrace();code = getUserCountryCodeByIpData(ip).getCountryCode();}return code;
}private String getCountry(String ip) throws IOException, GeoIp2Exception {// 容器中读取数据文件的路径File database = new File("/home/my_dir/GeoLite2-City.mmdb");// 读取数据库内容DatabaseReader reader = new DatabaseReader.Builder(database).build();InetAddress ipAddress = InetAddress.getByName(ip);// 获取查询结果CityResponse response = reader.city(ipAddress);//获取countryCountry country = response.getCountry();return country.getIsoCode();
}public GetCountryCodeVo getUserCountryCodeByIpData(String ip) {log.info("Enter service.");GetCountryCodeVo result = new GetCountryCodeVo();result.setIp(ip);result.setCountryCode("");try {long timestamp = System.currentTimeMillis();String redisStr = redisUtil.getString("Data_all:" + ip);// 如果缓存里有则不查ipdata了if (redisStr != null) {log.info("ip:{}, redis IP_ipData_all result:{}.", ip, redisStr);result.setCountryCode(redisStr.split(":")[0].equals("-") ? "" : redisStr.split(":")[0]);result.setCountryName(redisStr.split(":")[1].equals("-") ? "" : redisStr.split(":")[1]);result.setRegionCode(redisStr.split(":")[2].equals("-") ? "" : redisStr.split(":")[2]);result.setCity(redisStr.split(":")[3].equals("-") ? "" : redisStr.split(":")[3]);result.setTimeZone(redisStr.split(":")[4].equals("-") ? "" : redisStr.split(":")[4]);} else {Map<String, String> container = getCountryByIpData(ip);result.setCountryCode(container.get("countryCode"));result.setCountryName(container.get("countryName"));result.setRegionCode(container.get("regionCode"));result.setCity(container.get("city"));result.setTimeZone(container.get("timeZone"));String allInfoStr = (StringUtils.isBlank(result.getCountryCode()) ? "-" : result.getCountryCode()) + ":"+ (StringUtils.isBlank(result.getCountryName()) ? "-" : result.getCountryName()) + ":"+ (StringUtils.isBlank(result.getRegionCode()) ? "-" : result.getRegionCode()) + ":"+ (StringUtils.isBlank(result.getCity()) ? "-" : result.getCity()) + ":"+ (StringUtils.isBlank(result.getTimeZone()) ? "-" : result.getTimeZone());redisUtil.setString("Data_all:" + ip, allInfoStr, 7 * 24 * 60 * 60);}} catch (Exception ex) {ex.printStackTrace();return result;}log.info("Leave service.");return result;
}private Map<String, String> getCountryByIpData(String ip) {String url = "https://api.ipdata.co/" + ip + "?api-key=" + ipDataSecret;String resultStr = HttpUtils.get(url, null);JSONObject resultObject = JSON.parseObject(resultStr);Map<String, String> result = new HashMap<>();if (resultObject != null) {result.put("countryCode", resultObject.getString("country_code"));result.put("countryName", resultObject.getString("country_name"));result.put("regionCode", resultObject.getString("region_code"));result.put("city", resultObject.getString("city"));String timeZoneStr = resultObject.getString("time_zone");if (timeZoneStr != null) {JSONObject timeZoneObject = JSON.parseObject(timeZoneStr);result.put("timeZone", timeZoneObject.getString("name"));}}return result;}

总结

  这个方案已经是比较完整的实现了,实际项目中按此方案实现后,基本上只需观察ipdata的使用量,我的例子把结果缓存了七天,也就是说同一个IP七天内最多只会触发一次ipdata查询调用,基本上只需要按日活去买合适的调用次数套餐就行了,不会造成浪费,算是给老板省老鼻子钱了,当然,不差钱的话可以不做缓存方案。

关键字:徐州模板建站哪家好_湖北网站推广公司渠道_宁波网站建设团队_宁波关键词排名优化

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: