Java 中是如何獲取 IP 屬地的

?細心的小伙伴可能會發(fā)現(xiàn)化戳,抖音新上線了IP屬地的功能,小伙伴在發(fā)表動態(tài)埋凯、發(fā)表評論以及聊天的時候点楼,都會顯示自己的IP屬地信息


下面扫尖,我就來講講,Java中是如何獲取IP屬地的掠廓,主要分為以下幾步

通過 HttpServletRequest 對象藏斩,獲取用戶的IP地址

通過 IP 地址,獲取對應的省份却盘、城市

首先需要寫一個IP獲取的工具類狰域,因為每一次用戶的Request請求,都會攜帶上請求的IP地址放到請求頭中黄橘。

public class IpUtil {

? ? public static String getIpAddr(ServerHttpRequest request) {

? ? ? ? HttpHeaders headers = request.getHeaders();

? ? ? ? String ipAddress = headers.getFirst("X-Forwarded-For");

? ? ? ? if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {

? ? ? ? ? ? ipAddress = headers.getFirst("Proxy-Client-IP");

? ? ? ? }

? ? ? ? if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {

? ? ? ? ? ? ipAddress = headers.getFirst("WL-Proxy-Client-IP");

? ? ? ? }

? ? ? ? if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {

? ? ? ? ? ? ipAddress = request.getRemoteAddress().getAddress().getHostAddress();

? ? ? ? ? ? if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {

? ? ? ? ? ? ? ? // 根據(jù)網(wǎng)卡取本機配置的IP

? ? ? ? ? ? ? ? try {

? ? ? ? ? ? ? ? ? ? InetAddress inet = InetAddress.getLocalHost();

? ? ? ? ? ? ? ? ? ? ipAddress = inet.getHostAddress();

? ? ? ? ? ? ? ? } catch (UnknownHostException e) {

? ? ? ? ? ? ? ? ? ? log.error("根據(jù)網(wǎng)卡獲取本機配置的IP異常", e);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? // 對于通過多個代理的情況兆览,第一個IP為客戶端真實IP,多個IP按照','分割

? ? ? ? if (ipAddress != null && ipAddress.indexOf(",") > 0) {

? ? ? ? ? ? ipAddress = ipAddress.split(",")[0];

? ? ? ? }

? ? ? ? return ipAddress;

? ? }

}

這里有三個名詞塞关,分別是

X-Forwarded-For一個 HTTP擴展頭部抬探,主要是為了讓Web服務器獲取訪問用戶的真實IP地址。每個IP地址帆赢,每個值通過逗號+空格分開小压,最左邊是最原始客戶端的IP地址,中間如果有多層代理椰于,每?層代理會將連接它的客戶端IP追加在X-Forwarded-For右邊怠益。

X-Real-IP:一般只記錄真實發(fā)出請求的客戶端IP

Proxy-Client-IP:這個一般是經(jīng)過Apache http服務器的請求才會有,用Apache http做代理時一般會加上Proxy-Client-IP請求頭

WL-Proxy-Client-IP:也是通過 Apache http 服務器瘾婿,在weblogic插件加上的頭蜻牢。

在我們獲取到用戶的IP地址后,那么就可以獲取對應的ip信息了

我在Github沖浪的時候偏陪,發(fā)現(xiàn)了Ip2region項目抢呆。

一個準確率99.9%的離線IP地址定位庫,0.0x毫秒級查詢笛谦,ip2region.db數(shù)據(jù)庫只有數(shù)MB抱虐,提供了 java,php,c,python,nodejs,golang,c# 等查詢綁定和BinaryB樹饥脑,內存三種查詢算法恳邀。

數(shù)據(jù)聚合了一些知名ip到地名查詢提供商的數(shù)據(jù),這些是他們官方的的準確率好啰,經(jīng)測試著實比經(jīng)典的純真IP定位準確一些轩娶。ip2region的數(shù)據(jù)聚合自以下服務商的開放API或者數(shù)據(jù)儿奶。

80%, 淘寶IP地址庫, http://ip.taobao.com/

≈10%, GeoIP, https://geoip.com/

≈2%, 純真IP庫, http://www.cz88.net/

備注:如果上述開放API或者數(shù)據(jù)都不給開放數(shù)據(jù)時ip2region將停止數(shù)據(jù)的更新服務框往。

每條ip數(shù)據(jù)段都固定了格式:

_城市Id|國家|區(qū)域|省份|城市|ISP_

只有中國的數(shù)據(jù)精確到了城市,其他國家有部分數(shù)據(jù)只能定位到國家闯捎,后前的選項全部是0椰弊,已經(jīng)包含了全部你能查到的大大小小的國家

生成的數(shù)據(jù)庫文件ip2region.db只有幾MB许溅,最小的版本只有1.5MB,隨著數(shù)據(jù)的詳細度增加數(shù)據(jù)庫的大小也慢慢增大秉版,目前還沒超過8MB贤重。

內置的三種查詢算法

全部的查詢客戶端單次查詢都在0.x毫秒級別,內置了三種查詢算法

memory算法:整個數(shù)據(jù)庫全部載入內存清焕,單次查詢都在0.1x毫秒內并蝗,C語言的客戶端單次查詢在0.00x毫秒級別。

binary算法:基于二分查找秸妥,基于ip2region.db文件滚停,不需要載入內存,單次查詢在0.x毫秒級別粥惧。

b-tree算法:基于btree算法键畴,基于ip2region.db文件,不需要載入內存突雪,單詞查詢在0.x毫秒級別起惕,比binary算法更快。

ip2region安裝

下面咏删,就讓我們給項目引入ip2region惹想,進行ip信息轉換吧

首先引入maven依賴

<dependency>

????<groupId>org.lionsoul</groupId>

????<artifactId>ip2region</artifactId>

????<version>1.7.2</version>

</dependency>

然后編寫一個工具類IpUtils,首先需要加載ip2region.db文件

static?{

????dbPath?=?createFtlFileByFtlArray()?+?"ip2region.db";

????try?{

????????config?=?new?DbConfig();

????}?catch?(DbMakerConfigException?e)?{

????????e.printStackTrace();

????}

????try?{

????????searcher?=?new?DbSearcher(config,?dbPath);

????}?catch?(FileNotFoundException?e)?{

????????e.printStackTrace();

????}

}

在加載的時候督函,需要下載倉庫中的ip2region.db文件勺馆,然后放到resource目錄下

然后,通過內置的三種算法侨核,分別轉換用戶ip地址

????public?static?String?getCityInfo(String?ip)?{

????????if?(StringUtils.isEmpty(dbPath))?{

????????????log.error("Error:?Invalid?ip2region.db?file");

????????????return?null;

????????}

????????if(config?==?null?||?searcher?==?null){

????????????log.error("Error:?DbSearcher?or?DbConfig?is?null");

????????????return?null;

????????}

????????//查詢算法

????????//B-tree,?B樹搜索(更快)

????????int?algorithm?=?DbSearcher.BTREE_ALGORITHM;

????????//Binary,使用二分搜索

????????//DbSearcher.BINARY_ALGORITHM

????????//Memory,加載內存(最快)

????????//DbSearcher.MEMORY_ALGORITYM

????????try?{

????????????//?使用靜態(tài)代碼塊草穆,減少文件讀取操作

//????????????DbConfig?config?=?new?DbConfig();

//????????????DbSearcher?searcher?=?new?DbSearcher(config,?dbPath);

????????????//define?the?method

????????????Method?method?=?null;

????????????switch?(algorithm)?{

????????????????case?DbSearcher.BTREE_ALGORITHM:

????????????????????method?=?searcher.getClass().getMethod("btreeSearch",?String.class);

????????????????????break;

????????????????case?DbSearcher.BINARY_ALGORITHM:

????????????????????method?=?searcher.getClass().getMethod("binarySearch",?String.class);

????????????????????break;

????????????????case?DbSearcher.MEMORY_ALGORITYM:

????????????????????method?=?searcher.getClass().getMethod("memorySearch",?String.class);

????????????????????break;

????????????????default:

????????????}

????????????DataBlock?dataBlock?=?null;

????????????if?(Util.isIpAddress(ip)?==?false)?{

????????????????System.out.println("Error:?Invalid?ip?address");

????????????}

????????????dataBlock?=?(DataBlock)?method.invoke(searcher,?ip);

????????????String?ipInfo?=?dataBlock.getRegion();

????????????if?(!StringUtils.isEmpty(ipInfo))?{

????????????????ipInfo?=?ipInfo.replace("|0",?"");

????????????????ipInfo?=?ipInfo.replace("0|",?"");

????????????}

????????????return?ipInfo;

????????}?catch?(Exception?e)?{

????????????e.printStackTrace();

????????}

????????return?null;

????}

下面,我們編寫main函數(shù)進行測試搓译,發(fā)現(xiàn)可以正常的解析出ip信息

由于 ip 屬地在國內的話悲柱,只會展示省份,而國外的話些己,只會展示國家豌鸡。所以我們還需要對這個方法進行一下封裝,得到獲取 IP 屬地的信息段标。

/**

?*?獲取IP屬地

?*?@param?ip

?*?@return

?*/

public?static?String?getIpPossession(String?ip)?{

????String?cityInfo?=?getCityInfo(ip);

????if?(!StringUtils.isEmpty(cityInfo))?{

????????cityInfo?=?cityInfo.replace("|",?"?");

????????String[]?cityList?=?cityInfo.split("?");

????????if?(cityList.length?>?0)?{

????????????//?國內的顯示到具體的省

????????????if?("中國".equals(cityList[0]))?{

????????????????if?(cityList.length?>?1)?{

????????????????????return?cityList[1];

????????????????}

????????????}

????????????//?國外顯示到國家

????????????return?cityList[0];

????????}

????}

????return?"未知";

}

下面涯冠,我們在找一個 國外的IP測試一下效果”婆樱可以看到已經(jīng)能夠正常的顯示IP屬地信息了~

到這里如果獲取用戶的 IP 屬地已經(jīng)完成啦蛇更,如果想要了解關于更多ip2region的功能,歡迎訪問其Github地址進行學習。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?項目地址

https://github.com/lionsoul2014/ip2region

碼文不易派任,學到的小伙伴點一點關注哦砸逊,一鍵三連加收藏哦!U乒洹师逸!

有不懂的小伙伴可以加下我的微信,我們私底下悄悄內卷~~~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末豆混,一起剝皮案震驚了整個濱河市篓像,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌皿伺,老刑警劉巖遗淳,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異心傀,居然都是意外死亡屈暗,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門脂男,熙熙樓的掌柜王于貴愁眉苦臉地迎上來养叛,“玉大人,你說我怎么就攤上這事宰翅∑” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵汁讼,是天一觀的道長淆攻。 經(jīng)常有香客問我,道長嘿架,這世上最難降的妖魔是什么瓶珊? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮耸彪,結果婚禮上伞芹,老公的妹妹穿的比我還像新娘。我一直安慰自己蝉娜,他們只是感情好唱较,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著召川,像睡著了一般南缓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上荧呐,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天汉形,我揣著相機與錄音纸镊,去河邊找鬼。 笑死获雕,一個胖子當著我的面吹牛薄腻,可吹牛的內容都是我干的收捣。 我是一名探鬼主播届案,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼罢艾!你這毒婦竟也來了楣颠?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤咐蚯,失蹤者是張志新(化名)和其女友劉穎童漩,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體春锋,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡矫膨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了期奔。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侧馅。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖呐萌,靈堂內的尸體忽然破棺而出馁痴,到底是詐尸還是另有隱情,我是刑警寧澤肺孤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布罗晕,位于F島的核電站,受9級特大地震影響赠堵,放射性物質發(fā)生泄漏小渊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一茫叭、第九天 我趴在偏房一處隱蔽的房頂上張望粤铭。 院中可真熱鬧,春花似錦杂靶、人聲如沸梆惯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽垛吗。三九已至,卻和暖如春烁登,著一層夾襖步出監(jiān)牢的瞬間怯屉,已是汗流浹背蔚舀。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留锨络,地道東北人赌躺。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像羡儿,于是被迫代替她去往敵國和親礼患。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內容