GeoLite2—IP地理定位数据库
GeoLite2—IP地理定位数据库
1.基本介绍
GeoLite2数据库是免费的IP地理定位数据库;
优点:
- 离线库,不需要网络
- 数据库丰富
- 速度快
- 免费
缺点:
- 准确度不高,存在偏差
- 数据更新慢
2.下载 GeoLite2 离线库
官网地址:https://www.maxmind.com/en/home
下载过程稍微有点点麻烦,这里下载了一份最新的,放在网盘,需要测试的可以直接通过这个链接下载:https://www.123pan.com/s/xPY9-J37vH
3.SpringBoot 获取用户的IP
-
工具类
public class IpUtils { /** * 获取用户IP * @param request * @return */ public static String getIpAddr(HttpServletRequest request) { String ip = request.getHeader("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为客户ip if (ip != null && ip.indexOf(",") != -1) { ip = ip.substring(ip.lastIndexOf(",") + 1).trim(); } return ip; } }
-
Controller获取HttpServletRequest
通过上面的工具类,即可获取用户请求的真实IP;
为了避免重复工作,这里也可以使用AOP解析出用户的IP信息,放到用户的请求对象中
@RestController public class IpController { @GetMapping("/user/ip") public String userIp(HttpServletRequest request) { // 这里就能拿到用户的真实IP return IpUtils.getIpAddr(request); } }
4.SpringBoot 整合 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 = "222.**.14.59";
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"}}
省份信息:{"names":{}}
城市信息:{"names":{}}
经纬度信息:{"accuracyRadius":1000,"latitude":34.7732,"longitude":113.722,"timeZone":"Asia/Shanghai"}
5.在线方案
上面一开始介绍GeoLite2时就列举了其离线库更新收录不及时的问题,可能导致一些IP在离线库中并不存在,查找的时候,就会报AddressNotFoundException
的错误,如下示例:
遇到这种请求,我们要怎么办呢?
下面就来介绍几种在线IP归属地获取的方式,当本地离线库无法获取的时候,就可以利用三方的在线库,来补充完善;
在线获取的优点:
- IP更新及时
- 准确度高
缺点
- 三方依赖性强
- 需要付费,免费版本一般都有各种限制