利用GeoLite2-City.mmdb實現通過IP地址獲取經緯度以及該IP的所屬地區
本人最近在寫一個小的練手項目,想加上訪問記錄的功能(即獲取訪問者的ip地址從而獲取到該訪問者的經緯度,判斷是在哪個地區訪問的頁面同時將信息插入進數據庫中從而生成一份詳細的訪問記錄)。網上很多可以實現此功能的API,例如騰訊、百度等,但是由於需要申請專屬KEY,而且必須是在線訪問的,所以最終選擇了使用GeoLite2數據庫。
GeoLite2數據庫是免費的IP地理定位數據庫,但是不太準確,通過IP轉換成的經緯度與真實地址相比較還有一定偏差,但是GeoLite2可以離線使用,而且數據還具有豐富性,最重要的是免費。廢話不多說,進入正文。
一、關於獲取本機IP
網上有很多關於獲取本機真實IP的代碼,但是需要注意的有以下兩點:
- 使用Nginx等反向代理軟件, 則不能通過request.getRemoteAddr()獲取IP地址
- 如果使用了多級反向代理的話,X-Forwarded-For的值並不止一個,而是一串IP地址,X-Forwarded-For中第一個非unknown的有效IP字符串,則爲真實IP地址
下面直接上代碼
public static String getIP(HttpServletRequest request) {
String ip = null;
try {
ip = request.getHeader("x-forwarded-for");
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
} catch (Exception e) {
logger.error("IPUtils ERROR ", e);
}
return ip;
}
或者可以是
private static final String UNKNOWN = "unknown";
public static String getRealIP(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
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.getRemoteAddr();
}
return "0:0:0:0:0:0:0:1".equals(ip)?"127.0.0.1":ip;
}
二、GeoLite2-City.mmdb用法
首先簡單說一下基本思路:利用new File()創建一個GeoLite2數據庫實例,之後使用DatabaseReader.Builder讀取GeoLite2數據庫即可。
下載地址:https://download.csdn.net/download/qq_39134664/12086931
下面直接上代碼
/**
*
* @description: 獲得國家
* @param reader GeoLite2 數據庫
* @param ip ip地址
* @return
* @throws Exception
*/
public static String getCountry(DatabaseReader reader, String ip) throws Exception {
return reader.city(InetAddress.getByName(ip)).getCountry().getNames().get("zh-CN");
}
/**
*
* @description: 獲得省份
* @param reader GeoLite2 數據庫
* @param ip ip地址
* @return
* @throws Exception
*/
public static String getProvince(DatabaseReader reader, String ip) throws Exception {
return reader.city(InetAddress.getByName(ip)).getMostSpecificSubdivision().getNames().get("zh-CN");
}
/**
*
* @description: 獲得城市
* @param reader GeoLite2 數據庫
* @param ip ip地址
* @return
* @throws Exception
*/
public static String getCity(DatabaseReader reader, String ip) throws Exception {
return reader.city(InetAddress.getByName(ip)).getCity().getNames().get("zh-CN");
}
/**
*
* @description: 獲得經度
* @param reader GeoLite2 數據庫
* @param ip ip地址
* @return
* @throws Exception
*/
public static Double getLongitude(DatabaseReader reader, String ip) throws Exception {
return reader.city(InetAddress.getByName(ip)).getLocation().getLongitude();
}
/**
*
* @description: 獲得緯度
* @param reader GeoLite2 數據庫
* @param ip ip地址
* @return
* @throws Exception
*/
public static Double getLatitude(DatabaseReader reader, String ip) throws Exception {
return reader.city(InetAddress.getByName(ip)).getLocation().getLatitude();
}
public static void main(String[] args) throws Exception {
// String path = req.getSession().getServletContext().getRealPath("/WEB-INF/classes/GeoLite2-City.mmdb");
String path = "D:/CSDN/GeoLite2-City.mmdb";
// 創建 GeoLite2 數據庫
File database = new File(path);
// 讀取數據庫內容
DatabaseReader reader = new DatabaseReader.Builder(database).build();
// 訪問IP
String ip = "222.222.226.212";
String site = "國家:"+GetAddress.getCountry(reader, ip) + "\n省份:" + GetAddress.getProvince(reader, ip) + "\n城市:" + GetAddress.getCity(reader, ip)+ "\n經度:" + GetAddress.getLongitude(reader, ip)+ "\n維度:" + GetAddress.getLatitude(reader, ip);
System.out.println(site);
}
三、運行結果截圖
四、總結
某些IP地址在GeoLite2數據庫中只能查到國家和省份,或者僅能查到國家(本人測試過部分IP地址,大部分都能通過IP獲取到國家、省份、城市;小部分可以獲取到國家、省份;那些僅能獲取到國家的IP地址所佔比重則是極低的),總的來說GeoLite2數據庫在獲取經緯度以及地理位置信息時還是比較好用的,若對地理位置要求比較精確的話就建議選擇使用騰訊、百度的在線API去實現此功能了。
希望此文可以幫助到有需要的小夥伴,若文中有錯誤歡迎大家評論指出,有問題也歡迎大家在評論區留言,謝謝。