Java使用ip2region獲取用戶的ip歸屬地的詳細(xì)步驟
1. ip2region 簡(jiǎn)介
ip2region 是一個(gè)離線IP地址定位庫(kù)和IP定位數(shù)據(jù)管理框架,能實(shí)現(xiàn)10微秒級(jí)別的查詢效率,提供了眾多主流編程語(yǔ)言的xdb數(shù)據(jù)生成和查詢客戶端實(shí)現(xiàn)。
每個(gè) ip 數(shù)據(jù)段的 region 信息都固定了格式:國(guó)家|區(qū)域|省份|城市|ISP,只有中國(guó)的數(shù)據(jù)絕大部分精確到了城市,其他國(guó)家部分?jǐn)?shù)據(jù)只能定位到國(guó)家,后前的選項(xiàng)全部是0。
2. 使用步驟
2.1 下載資源
下載 ip2region 后,將ip2region.xdb (如下圖)復(fù)制到項(xiàng)目的resources/ipdb
文件夾下。
2.2 引入依賴
<dependency> <groupId>org.lionsoul</groupId> <artifactId>ip2region</artifactId> <version>2.6.5</version> </dependency>
2.3 編寫工具類
2.3.1 獲取 IP 地址
根據(jù)用戶請(qǐng)求獲取用戶真實(shí) IP 地址:
/** * 在 Nginx 等代理之后獲取用戶真實(shí) IP 地址 * @return 用戶的真實(shí) IP 地址 */ public static String getIpAddress(HttpServletRequest request) { if (request == null) { return null; } String ip = request.getHeader("x-forwarded-for"); if (isIpaddress(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (isIpaddress(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (isIpaddress(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (isIpaddress(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (isIpaddress(ip)) { ip = request.getRemoteAddr(); if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) { //根據(jù)網(wǎng)卡取本機(jī)配置的IP try { InetAddress inet = InetAddress.getLocalHost(); ip = inet.getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); } } } return ip; }
如果有使用 Nginx 等代理服務(wù)器則需進(jìn)行配置[云筆記系統(tǒng)沒有配置也可以正常使用],例如在nginx.conf
文件中進(jìn)行如下配置:
location / { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }
其中
- Host:獲取客戶端(client)的真實(shí)域名和端口號(hào)
- X-Real-IP:獲取客戶端真實(shí) IP 地址
- X-Forwarded-For:也是獲取客戶端真實(shí) IP 地址,如果有多層代理時(shí)會(huì)獲取客戶端真實(shí) IP 及每層代理服務(wù)器的 IP 地址
- X-Forwarded-Proto:獲取客戶端的真實(shí)協(xié)議(如 http、https)
getRemoteAddr()
用于獲取沒有代理服務(wù)器情況下用戶的 IP 地址- 當(dāng)用戶的請(qǐng)求經(jīng)過一個(gè)代理服務(wù)器后到達(dá)最終服務(wù)器,此時(shí)在最終服務(wù)器端通過
getRemoteAddr()
只能得到代理服務(wù)器的 IP 地址,通過在代理服務(wù)器中配置proxy_set_header X-Real-IP $remote_addr
,最終的服務(wù)器可以通過X-Real-IP
獲取用戶的真實(shí) IP 地址。 - 當(dāng)用戶的請(qǐng)求經(jīng)過多個(gè)代理服務(wù)器后到達(dá)最終服務(wù)器時(shí),配置
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for
后可通過X-Forwarded-For
獲取用戶真實(shí) IP 地址(請(qǐng)求通過第一臺(tái) nginx時(shí):X-Forwarded-For = X-Real-IP = 用戶真實(shí) IP 地址;請(qǐng)求通過第二臺(tái) nginx 時(shí):X-Forwarded-For = 用戶真實(shí) IP 地址, X-Real-IP = 上一臺(tái) nginx 的 IP 地址 )。 - 獲取客戶端的IP地址不僅可以通過
proxy_set_header X-real-ip $remote_addr;
獲取,也可以通過proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
獲取。
2.3.2 根據(jù) IP 地址獲取 IP 歸屬地
/** * 根據(jù) IP 地址返回歸屬地,國(guó)內(nèi)返回但省份,國(guó)外返回到國(guó)家 * @param ip IP 地址 * @return IP 歸屬地 */ public static String getIpRegion(String ip) { initIp2regionResource(); HashMap<String, String> cityInfo = new HashMap<>(); String searchIpInfo = getCityInfo(ip); //------------------------------------------------------- //searchIpInfo 的數(shù)據(jù)格式: 國(guó)家|區(qū)域|省份|城市|ISP //192.168.31.160 0|0|0|內(nèi)網(wǎng)IP|內(nèi)網(wǎng)IP //47.52.236.180 中國(guó)|0|香港|0|阿里云 //220.248.12.158 中國(guó)|0|上海|上海市|聯(lián)通 //164.114.53.60 美國(guó)|0|華盛頓|0|0 //------------------------------------------------------- String[] splitIpInfo = searchIpInfo.split("\\|"); cityInfo.put("ip",ip); cityInfo.put("searchInfo", searchIpInfo); cityInfo.put("country",splitIpInfo[0]); cityInfo.put("region",splitIpInfo[1]); cityInfo.put("province",splitIpInfo[2]); cityInfo.put("city",splitIpInfo[3]); cityInfo.put("ISP",splitIpInfo[3]); //--------------國(guó)內(nèi)屬地返回省份-------------- if ("中國(guó)".equals(cityInfo.get("country"))){ return cityInfo.get("province"); } //------------------內(nèi)網(wǎng) IP---------------- if ("0".equals(cityInfo.get("country"))){ if ("內(nèi)網(wǎng)IP".equals(cityInfo.get("ISP"))){ return ""; } else return ""; } //--------------國(guó)外屬地返回國(guó)家-------------- else { return cityInfo.get("country"); } }
2.3.3 完整代碼
IPUtils.java3:
import org.lionsoul.ip2region.xdb.Searcher; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Component; import org.springframework.util.FileCopyUtils; import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; import java.io.InputStream; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.HashMap; @Component public class IPUtils { private static Searcher searcher; /** * 在 Nginx 等代理之后獲取用戶真實(shí) IP 地址 * @return 用戶的真實(shí) IP 地址 */ public static String getIpAddress(HttpServletRequest request) { if (request == null) { return null; } String ip = request.getHeader("x-forwarded-for"); if (isIpaddress(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (isIpaddress(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (isIpaddress(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (isIpaddress(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (isIpaddress(ip)) { ip = request.getRemoteAddr(); if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) { //根據(jù)網(wǎng)卡取本機(jī)配置的IP try { InetAddress inet = InetAddress.getLocalHost(); ip = inet.getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); } } } return ip; } /** * 判斷是否為 IP 地址 * @param ip IP 地址 */ public static boolean isIpaddress(String ip) { return ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip); } /** * 獲取本地 IP 地址 * @return 本地 IP 地址 */ public static String getHostIp() { try { return InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); } return "127.0.0.1"; } /** * 獲取主機(jī)名 * @return 本地主機(jī)名 */ public static String getHostName() { try { return InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException e) { e.printStackTrace(); } return "未知"; } /** * 根據(jù) IP 地址從 ip2region.db 中獲取地理位置 * @param ip IP 地址 * @return IP歸屬地 */ public static String getCityInfo(String ip) { try { return searcher.search(ip); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 在服務(wù)啟動(dòng)時(shí)加載 ip2region.db 到內(nèi)存中 * 解決打包 jar 后找不到 ip2region.db 的問題 * @throws Exception 出現(xiàn)異常應(yīng)該直接拋出終止程序啟動(dòng),避免后續(xù) invoke 時(shí)出現(xiàn)更多錯(cuò)誤 */ @PostConstruct private static void initIp2regionResource() { try { InputStream inputStream = new ClassPathResource("/ipdb/ip2region.xdb").getInputStream(); byte[] dbBinStr = FileCopyUtils.copyToByteArray(inputStream); // 創(chuàng)建一個(gè)完全基于內(nèi)存的查詢對(duì)象 searcher = Searcher.newWithBuffer(dbBinStr); } catch (Exception e) { e.printStackTrace(); } } /** * 根據(jù) IP 地址返回歸屬地,國(guó)內(nèi)返回但省份,國(guó)外返回到國(guó)家 * @param ip IP 地址 * @return IP 歸屬地 */ public static String getIpRegion(String ip) { initIp2regionResource(); HashMap<String, String> cityInfo = new HashMap<>(); String searchIpInfo = getCityInfo(ip); //------------------------------------------------------- //searchIpInfo 的數(shù)據(jù)格式: 國(guó)家|區(qū)域|省份|城市|ISP //192.168.31.160 0|0|0|內(nèi)網(wǎng)IP|內(nèi)網(wǎng)IP //47.52.236.180 中國(guó)|0|香港|0|阿里云 //220.248.12.158 中國(guó)|0|上海|上海市|聯(lián)通 //164.114.53.60 美國(guó)|0|華盛頓|0|0 //------------------------------------------------------- String[] splitIpInfo = searchIpInfo.split("\\|"); cityInfo.put("ip",ip); cityInfo.put("searchInfo", searchIpInfo); cityInfo.put("country",splitIpInfo[0]); cityInfo.put("region",splitIpInfo[1]); cityInfo.put("province",splitIpInfo[2]); cityInfo.put("city",splitIpInfo[3]); cityInfo.put("ISP",splitIpInfo[3]); //--------------國(guó)內(nèi)屬地返回省份-------------- if ("中國(guó)".equals(cityInfo.get("country"))){ return cityInfo.get("province"); } //------------------內(nèi)網(wǎng) IP---------------- if ("0".equals(cityInfo.get("country"))){ if ("內(nèi)網(wǎng)IP".equals(cityInfo.get("ISP"))){ return ""; } else return ""; } //--------------國(guó)外屬地返回國(guó)家-------------- else { return cityInfo.get("country"); } } }
2.4 結(jié)果測(cè)試
測(cè)試代碼:
@Test public void test04(){ System.out.println(IPUtils.getIpRegion("117.28.182.162")); }
測(cè)試結(jié)果:
福建省
到此這篇關(guān)于Java使用ip2region獲取用戶的ip歸屬地的詳細(xì)步驟的文章就介紹到這了,更多相關(guān)Java ip2region獲取IP歸屬地內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot應(yīng)用啟動(dòng)內(nèi)置Tomcat的過程源碼分析
這篇文章主要介紹了SpringBoot應(yīng)用啟動(dòng)內(nèi)置Tomcat的過程分析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07JetBrains IntelliJ IDEA 2020安裝與使用教程詳解
這篇文章主要介紹了JetBrains IntelliJ IDEA 2020安裝與使用教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06基于spring boot排除掃描類的三種方式小結(jié)
這篇文章主要介紹了spring boot排除掃描類的三種方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08SpringSecurity?表單登錄的實(shí)現(xiàn)
本文主要介紹了SpringSecurity?表單登錄的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12JAVA PDF操作之實(shí)現(xiàn)截取N頁(yè)和多個(gè)PDF合并
這篇文章主要為大家詳細(xì)介紹了java關(guān)于PDF的一些操作,例如截取N頁(yè)并生成新文件,轉(zhuǎn)圖片以及多個(gè)PDF合并,文中的示例代碼講解詳細(xì),感興趣的可以了解下2025-01-01SpringBoot之@ConditionalOnProperty注解使用方法
在平時(shí)業(yè)務(wù)中,我們需要在配置文件中配置某個(gè)屬性來(lái)決定是否需要將某些類進(jìn)行注入,讓Spring進(jìn)行管理,而@ConditionalOnProperty能夠?qū)崿F(xiàn)該功能,文中有詳細(xì)的代碼示例,需要的朋友可以參考下2023-05-05maven的settings.xml、pom.xml配置文件使用詳解
本文詳解了Maven中的配置文件settings.xml和pom.xml,闡述了它們的作用、配置項(xiàng)以及優(yōu)先級(jí)順序,settings.xml存在于Maven安裝目錄和用戶目錄下,分別作用于全局和當(dāng)前用戶,pom.xml位于項(xiàng)目根路徑下2024-09-09Elasticsearch?percolate?查詢示例詳解
這篇文章主要為大家介紹了Elasticsearch?percolate?查詢示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01Java畢業(yè)設(shè)計(jì)之多用戶宿舍管理系統(tǒng)的實(shí)現(xiàn)
這篇文章主要介紹了基于Java實(shí)現(xiàn)的多用戶宿舍管理系統(tǒng),本文采用了jsp、servlet、jdbc等技術(shù),文中示例代碼講解詳細(xì),需要的可以參考一下2022-02-02