当前位置: 首页 > news >正文

获取用户ip所在城市

整体流程图

获取当前登录用户所在城市,是一个非常常见的需求,在很多业务场景中用到。

比如:导航的定位功能默认选择的城市,或者一些防盗系统中识别用户两次登录的城市不一样的会有报警提示。

下载geoip2数据库

geoip2是国外的一个免费的IP库,只要注册账号就能下载IP数据库了。

官网地址:https://www.maxmind.com/。

其他下载:https://kohler.lanzouo.com/i3Fkb36wobuh

将IP库保存到电脑的某个目录下

之后使用绝对路径

引入相关依赖

引入geoip相关的依赖包:

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

增加获取城市接口

增加一个根据ip获取所在城市的接口。

创建一个GeoIpController类:

@Tag( name= "geoip操作", description = "geoip操作")
@RestController
@RequestMapping("/v1/web/geoip")
@Validated
public class GeoIpController {@Autowiredprivate GeoIpHelper geoIpHelper;/*** 根据ip获取所在城市** @param ip ip地址* @return 城市*/@NoLogin@Operation(summary = "根据ip获取所在城市", description = "根据ip获取所在城市")@GetMapping("/getCity")public CityDTO getCity(@RequestParam(value = "ip") String ip) {return geoIpHelper.getCity(ip);}
}

这个类中只包含了getCity这一个接口,该接口就是通过ip获取所在国家、省份和城市。

创建GeoIpHelper类:

@Slf4j
@Component
public class GeoIpHelper {private static final String GEO_IP_FILE_NAME = "GeoLite2-City.mmdb";@Value("${shop.mgt.geoIpFilePath:}")private String geoIpFilePath;@Value("${shop.mgt.taobaoIpUrl:}")private String taobaoIpUrl;@Value("${shop.mgt.taobaoIpRequestOff:false}")private Boolean taobaoIpRequestOff;@Autowiredprivate HttpHelper httpHelper;/*** 根据ip获取所在城市** @param ip ip地址* @return 城市*/public CityDTO getCity(String ip) {CityDTO cityFromGeoIp = getCityFromGeoIp(ip);if (Objects.nonNull(cityFromGeoIp) && Objects.nonNull(cityFromGeoIp.getCity())) {return cityFromGeoIp;}if (taobaoIpRequestOff) {return null;}return getCityFromApi(ip);}private CityDTO getCityFromGeoIp(String ip) {String fileUrl = getFileUrl();File file = new File(fileUrl);if (!file.exists()) {log.warn(String.format("%s文件不存在", fileUrl));return null;}try {DatabaseReader reader = new DatabaseReader.Builder(file).build();//解析IP地址InetAddress ipAddress = InetAddress.getByName(ip);// 获取查询结果CityResponse response = reader.city(ipAddress);if (response == null) {return null;}// 国家String country = response.getCountry().getNames().get("zh-CN");// 省份String province = response.getMostSpecificSubdivision().getNames().get("zh-CN");//城市String city = response.getCity().getNames().get("zh-CN");return new CityDTO(ip, country, province, city);} catch (Exception e) {log.error("从GeoIp库中获取城市失败,原因:", e);}return null;}private CityDTO getCityFromApi(String ip) {String url = String.format(taobaoIpUrl, ip);TaoboCityEntity taoboCityEntity = httpHelper.doGet(url, TaoboCityEntity.class);if (Objects.nonNull(taoboCityEntity)) {TaoboCityEntity.TaoboAreaEntity data = taoboCityEntity.getData();if (Objects.nonNull(data)) {return new CityDTO(ip, data.getCountry(), data.getRegion(), data.getCity());}}return null;}private String getFileUrl() {return geoIpFilePath + "/" + GEO_IP_FILE_NAME;}
}

这个类主要是来用读取IP库的数据,通过ip查询国家、省份和城市。

由于ip库有可能不全,或者不是最新的数据。可能会导致根据ip获取不到我们想要的数据的情况。

因此需要做兼容处理,如果从ip库查询不到数据,则再调用一下远程接口获取数据。

调用淘宝接口

创建HttpHelper类:

@Slf4j
@Component
public class HttpHelper {@Autowiredprivate RestTemplate restTemplate;/*** 发送get请求** @param url    url地址* @param tClass 返回值实体* @param <T>    泛型* @return 返回值实体*/public <T> T doGet(String url, Class<T> tClass) {return restTemplate.getForObject(url, tClass);}
}

定义了doGet方法获取用户请求。

创建了RestTemplateConfig类:

@Configuration
public class RestTemplateConfig {@Value("${shop.mgt.rest.template.connectTimeout:3000}")private int connectTimeout;@Value("${shop.mgt.rest.template.readTimeout:50000}")private int readTimeout;@Beanpublic RestTemplate restTemplate(ClientHttpRequestFactory factory) {return new RestTemplate(factory);}@Beanpublic ClientHttpRequestFactory simpleClientHttpRequestFactory() {HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();factory.setConnectTimeout(connectTimeout);factory.setReadTimeout(readTimeout);return factory;}/*** 忽略证书配置*/public static HttpComponentsClientHttpRequestFactory generateHttpRequestFactory()throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {TrustStrategy acceptingTrustStrategy = (x509Certificates, authType) -> true;SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();SSLConnectionSocketFactory connectionSocketFactory = new SSLConnectionSocketFactory(sslContext,new NoopHostnameVerifier());HttpClientBuilder httpClientBuilder = HttpClients.custom();httpClientBuilder.setSSLSocketFactory(connectionSocketFactory);CloseableHttpClient httpClient = httpClientBuilder.build();HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();factory.setHttpClient(httpClient);return factory;}
}

这个类是一个配置类,主要配置了RestTemplate的一些参数,以及https请求忽略证书的情况。

如果不忽略证书,有些情况下,比如:调用测试环境的请求,使用的不是有效的证书,会请求失败。

application.yml文件中增加配置:

shop:mgt:geoIpFilePath: D:\workplace\SpringBoot\kailong_shop\shop_business\src\main\resources\files\geoip2taobaoIpUrl: https://ip.taobao.com/outGetIpInfo?ip=%s&accessKey=alibaba-inc

其中accessKey使用的淘宝的测试key。

测试

代码开发好之后,接下来进行测试。

在浏览器上访问:http://localhost:8011/v1/web/geoip/getCity?ip=123.245.11.177(我的测试路径)

返回了正确的城市

说明根据ip获取所在城市的功能OK了。

需要特别注意的是目前调用淘宝的测试接口,每天有数量限制,达到一定测试就会返回失败。

也可以换成其他平台的接口,或者申请一个付费的accessKey。

http://www.hskmm.com/?act=detail&tid=17127

相关文章:

  • 【Proteus仿真】AT89C51单片机串行数据转换为并行仿真 - 实践
  • 第13章 day14-15 Webpack逆向
  • Viper远程配置踩坑记录
  • 国产智能体脂秤PCBA方案设计
  • 第15章 day18 Ast系列篇
  • 微波雷达模块在智能家居中的具体应用案例有哪些?
  • Ubuntu 桌面快捷方式创建增加记录
  • 队列
  • arm64中的内存屏障指令
  • 三分
  • 完整教程:微服务基础2-网关路由
  • nginx ipv6 proxy配置
  • (三)数仓人必看!ODS 到 DWS 各层设计规范全解析,含同步/存储/质量核心要点
  • 【shell】系统资源不足fork: retry: Resource temporarily unavailable
  • 【语文训练】女乃龙?田力乃龙?
  • 抖动分为3个方面
  • 第20章 Day24 原型链
  • python自动化操作邮件
  • zabbix配置mysql监控
  • redis实现定期关单
  • 第18章 Day22 高阶混淆ast进阶
  • 关于ubuntu 用户切换的细节 su - user 和su user
  • 用 SeaTunnel 同步 MySQL 到 Doris:全量增量 + SQL 过滤
  • 在CodeBolcks下wxSmith的C++编程教程——使用自定义绘制和鼠标处理创建项目
  • trae 配置mysql_mcp
  • Apache NiFi 1.28.1 集群 + Kerberos 认证 + 多租户模式部署
  • 基于Java+SpringBoot+SSM,Flask福聚苑社区团购体系(源码+LW+调试文档+讲解等)/福聚苑社区/团购系统/社区团购/福聚苑/团购/社区/环境/福聚苑小区/在线团购/社区购物
  • 按需引入echarts
  • 软件构造的用户交互设计 4章
  • 自定义制作docker容器自动自愈容器镜像