作为技能人,那!
这个功能要怎么实现呢?

实在要想实现这个功能还是非常的随意马虎,基于现成 GeoLite2离线库+免费的在线解析资源,5分钟就能整合了;

在整合之前,我们先大略理解一下,要想拿到用户的位置信息,有那些办法:

Unknowntagjsp全网的 IP 归属地显示带你5分钟加上就是这么简略 jQuery

终端定位

我们的手机等电子设备都是带有GPS定位功能的,APP可以申请权限获取用户所处的经纬度坐标,根据坐标,就可以知道到用户所处的位置;比如百度、高德等舆图厂商,就供应了完善的SDK,能非常方便的集成到运用,快速根据经纬度获取详细的位置详细;

优点

快捷;准确;偏差小。

缺陷

依赖硬件支持;依赖用户授权,如果用户不授权,APP将拿不到经纬度信息,导致失落败;

IP地址解析

用户向做事端发起的要求都会带上IP地址,做事端拿到IP地址后,就能基于IP解析出用户的所处的位置;

优点

无需授权,只要用户跟做事端交互,做事端就能拿到对应的IP信息

缺陷

准确性不高,位置可能存在偏差;IP库更新不及时,导致部分IP归属地解析失落败。

三方终端上报

比如,我们骑共享单车的时候,我们的位置信息便是通过单车的设备上报到做事器;

优点

由三方终端基于GPS定位上报,不会获取个人设备的信息;准确快捷;专业设备,偏差小;

缺陷

用户无法干预,信息会被迫逼迫上传至做事端,用户无法取消上传;

下面就来试着将 GeoLite2 免费 IP 库整合值SpringBoot项目,来获取用户的归属地信息;

1什么是GeoLite2?

GeoLite2数据库是免费的IP地理定位数据库;

优点:

离线库,不须要网络数据库丰富速率快免费

缺陷:

准确度不高,存在偏差数据更新慢2下载 GeoLite2 离线库

官网地址:https://www.maxmind.com/en/home

下载过程轻微有点点麻烦,这里下载了一份最新的,放在网盘,须要测试的可以直接通过这个链接下载:https://www.123pan.com/s/xPY9-J37vH

3SpringBoot 获取用户的IP工具类public class IpUtils {/ 获取用户IP @param request @return/public static String getIpAddr(HttpServletRequest request) {String ip = request.getHeader(&#34;x-forwarded-for");if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("X-Real-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("http_client_ip");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_X_FORWARDED_FOR");}// 如果是多级代理,那么取第一个ip为客户ipif (ip != null && ip.indexOf(",") != -1) {ip = ip.substring(ip.lastIndexOf(",") + 1).trim();}return ip;}}Controller获取HttpServletRequest通过上面的工具类,即可获取用户要求的真实IP;为了避免重复事情,这里也可以利用AOP解析出用户的IP信息,放到用户的要求工具中@RestControllerpublic class IpController {@GetMapping("/user/ip")public String userIp(HttpServletRequest request) {// 这里就能拿到用户的真实IPreturn IpUtils.getIpAddr(request);}}4SpringBoot 整合 GeoLite2添加依赖<dependency><groupId>com.maxmind.geoip2</groupId><artifactId>geoip2</artifactId><version>2.3.0</version></dependency><dependency><groupId>com.maxmind.db</groupId><artifactId>maxmind-db</artifactId><version>1.0.0</version></dependency>工具类public class GeoIpUtils {private static DatabaseReader reader;private static void init() {try {// 创建 GeoLite2 数据库 Reader// 这里可以放在本地磁盘,也可以随项目放在resource目录下File database = new File("F:\\web\\GeoLite2-City.mmdb");// 读取数据库内容reader = new DatabaseReader.Builder(database).build();} catch (Exception ex) {}}public static void getCityByIP(String ip) throws Exception {if (null == reader) {init();}InetAddress ipAddress = InetAddress.getByName(ip);// 获取查询结果CityResponse response = reader.city(ipAddress);// 获取国家信息Country country = response.getCountry();System.out.println("国家信息:" + JSON.toJSONString(country));// 获取省份Subdivision subdivision = response.getMostSpecificSubdivision();System.out.println("省份信息:" + JSON.toJSONString(subdivision));//城市City city = response.getCity();System.out.println("城市信息:" + JSON.toJSONString(city));// 获取城市Location location = response.getLocation();System.out.println("经纬度信息:" + JSON.toJSONString(location));}}测试public static void main(String[] args) throws Exception {String ip = "183.19.xxx.138";GeoIpUtils.getCityByIP(ip);}输出结果:国家信息:{"geoNameId":1814991,"isoCode":"CN","name":"China","names":{"de":"China","ru":"Китай","pt-BR":"China","ja":"中国","en":"China","fr":"Chine","zh-CN":"中国","es":"China"}}省份信息:{"geoNameId":1809935,"isoCode":"GD","name":"Guangdong","names":{"en":"Guangdong","fr":"Province de Guangdong","zh-CN":"广东"}}城市信息:{"geoNameId":1998011,"name":"Yanqianlaocun","names":{"en":"Yanqianlaocun","zh-CN":"岩前老村落"}}经纬度信息:{"accuracyRadius":500,"latitude":23.3255,"longitude":116.5007,"timeZone":"Asia/Shanghai"}

就这么大略,轻轻松松就能拿到用户IP所处的国家、省份、城市、经纬度等详细信息,可以根据自己的业务须要,对这些数据再做进一步的封装。

5GeoLite2的其他用法

上面先容的时SpringBoot整合GeoLite2,同样在其他的一些场景下,也是可以利用GeoLite2获取归属地信息;

整合至Nignx,获取用户归属地信息Nginx 整合 GeoLite2 来解析用户的归属地信息,在代理层就直接整理好对应的数据;ELK中整合GeoLite2ELK 日志整理的时候,可以通过GeoLite2 获取用户的IP归属地信息;然后通过Kibana,就能非常直不雅观的展示用户的地域分布情形;ELK搭建,这才是看日志的精确姿势6在线方案

上面一开始先容GeoLite2时就列举了其离线库更新收录不及时的问题,可能导致一些IP在离线库中并不存在,查找的时候,就会报AddressNotFoundException的缺点,如下示例:

碰着这种要求,我们要怎么办呢?

下面就来先容几种在线IP归属地获取的办法,当本地离线库无法获取的时候,就可以利用三方的在线库,来补充完善;

在线获取的优点:

IP更新及时准确度高

缺陷

三方依赖性强须要付费,免费版本一样平常都有各种限定

以下示例中的xxx.xxx.xxx.xxx均代表ip地址;

百度

地址:https://opendata.baidu.com/api.php?query=xxx.xxx.xxx.xxx&resource_id=6006&co=&oe=utf8

相应数据:

{ "status": "0", "t": "", "set_cache_time": "", "data": [ { "ExtendedLocation": "", "OriginQuery": "183.19.xxx.138", "appinfo": "", "disp_type": 0, "fetchkey": "183.19.xxx.138", "location": "广东省肇庆市 电信", "origip": "183.19.xxx.138", "origipquery": "183.19.xxx.138", "resourceid": "6006", "role_id": 0, "shareImage": 1, "showLikeShare": 1, "showlamp": "1", "titlecont": "IP地址查询", "tplt": "ip" } ]}

status即是0表示成功,1表示失落败;可能存在status即是0,但是data中没有数据的情形。

ip-api接口本机的IP信息http://ip-api.com/json/指定国际化http://ip-api.com/json/?lang=zh-CN指定IP查询http://ip-api.com/json/xxx.xxx.xxx.xxx?lang=zh-CN返回数据:{"status": "success","country": "中国","countryCode": "CN","region": "GD","regionName": "广东","city": "岩前老村落","zip": "","lat": 23.3255,"lon": 116.5007,"timezone": "Asia/Shanghai","isp": "Chinanet","org": "Chinanet GD","as": "AS4134 CHINANET-BACKBONE","query": "183.19.xxx.138"}搜狐IP查询

地址:http://pv.sohu.com/cityjson?ie=utf-8

返回数据比较的大略:

var returnCitySN = {"cip": "xxx.xxx.xxx.xxx", "cid": "440300", "cname": "广东省深圳市"};太平洋IP地址查询

地址:http://whois.pconline.com.cn/ipJson.jsp?ip=xxx.xxx.xxx.xxx&json=true

返回数据:

{ "ip": "183.17.xxx.138", "pro": "广东省", "proCode": "440000", "city": "深圳市", "cityCode": "440300", "region": "", "regionCode": "0", "addr": "广东省深圳市 电信", "regionNames": "", "err": ""}淘宝API接口

http://ip.taobao.com/service/getIpInfo.php?ip=xxx.xxx.xxx.xxx

{ "code": 0, "data": { "ip": "183.17.xxx.138", "country": "中国", "area": "", "region": "广东", "city": "深圳", "county": "XX", "isp": "电信" }}

code即是0表示成功,1表示失落败

126

地址:https://ip.ws.126.net/ipquery?ip=xxx.xxx.xxx.xxx

相应数据:

var lo="广东省", lc="肇庆市"; var localAddress={city:"肇庆市", province:"广东省"}

相应的数据比较的大略

IP信息

地址:https://ip.useragentinfo.com/json?ip=xxx.xxx.xxx.xxx

相应数据:

{ "country": "中国", "short_name": "CN", "province": "广东省", "city": "肇庆市", "area": "德庆县", "isp": "电信", "net": "", "ip": "183.19.xxx.138", "code": 200, "desc": "success"}

这么多的姿势,实现起来是不是就非常的随意马虎了;如果你对IP解析的需求比较依赖,也完备可以通过离线加这么多在线的办法,开拓一个单独的IP解析模块,作为公司的根本做事,供应给内部其他模块利用。

示例目录:https://github.com/vehang/ehang-spring-boot/tree/main/spring-boot-004-request-validate/src/main/java/com/ehang/validate/geoip

来源:公众年夜众号—— 一行Java