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 編寫(xiě)工具類
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)沒(méi)有配置也可以正常使用],例如在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()用于獲取沒(méi)有代理服務(wù)器情況下用戶的 IP 地址- 當(dāng)用戶的請(qǐng)求經(jīng)過(guò)一個(gè)代理服務(wù)器后到達(dá)最終服務(wù)器,此時(shí)在最終服務(wù)器端通過(guò)
getRemoteAddr()只能得到代理服務(wù)器的 IP 地址,通過(guò)在代理服務(wù)器中配置proxy_set_header X-Real-IP $remote_addr,最終的服務(wù)器可以通過(guò)X-Real-IP獲取用戶的真實(shí) IP 地址。 - 當(dāng)用戶的請(qǐng)求經(jīng)過(guò)多個(gè)代理服務(wù)器后到達(dá)最終服務(wù)器時(shí),配置
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for后可通過(guò)X-Forwarded-For獲取用戶真實(shí) IP 地址(請(qǐng)求通過(guò)第一臺(tái) nginx時(shí):X-Forwarded-For = X-Real-IP = 用戶真實(shí) IP 地址;請(qǐng)求通過(guò)第二臺(tái) nginx 時(shí):X-Forwarded-For = 用戶真實(shí) IP 地址, X-Real-IP = 上一臺(tái) nginx 的 IP 地址 )。 - 獲取客戶端的IP地址不僅可以通過(guò)
proxy_set_header X-real-ip $remote_addr;獲取,也可以通過(guò)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 的問(wèn)題
* @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)文章
Java連接MySQL數(shù)據(jù)庫(kù)增刪改查的通用方法(推薦)
下面小編就為大家?guī)?lái)一篇Java連接MySQL數(shù)據(jù)庫(kù)增刪改查的通用方法(推薦)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08
Java實(shí)現(xiàn)兩個(gè)隨機(jī)數(shù)組合并進(jìn)行排序的方法
本文主要介紹了Java實(shí)現(xiàn)兩個(gè)隨機(jī)數(shù)組合并進(jìn)行排序的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
spring基礎(chǔ)概念A(yù)OP與動(dòng)態(tài)代理理解
這篇文章主要為大家詳細(xì)介紹了spring基礎(chǔ)概念A(yù)OP與動(dòng)態(tài)代理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10
基于SpringBoot創(chuàng)建Web頁(yè)面并熱更新的操作步驟
SpringBoot是一個(gè)用于快速開(kāi)發(fā)單個(gè)微服務(wù)的框架,它基于 Spring 框架,簡(jiǎn)化了Spring應(yīng)用的初始化過(guò)程和開(kāi)發(fā)流程,本文給大家介紹了如何基于SpringBoot創(chuàng)建Web頁(yè)面并熱更新,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11
Java POI讀取excel中數(shù)值精度損失問(wèn)題解決
這篇文章主要介紹了Java POI讀取excel中數(shù)值精度損失問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
Java中compareTo()和compare()方法使用及區(qū)別詳解
這篇文章主要介紹了Java中compareTo()和compare()方法使用及區(qū)別的相關(guān)資料,compareTo()方法用于定義類的自然排序,適用于具有單一、固定排序方式的場(chǎng)景,compare()方法提供自定義排序的靈活性,適用于需要根據(jù)不同規(guī)則對(duì)對(duì)象進(jìn)行排序的場(chǎng)景,需要的朋友可以參考下2025-01-01

