JAVA使用Ip2region獲取IP定位信息的操作方法
ip2region - 準確率99.9%的離線IP地址定位庫,0.0x毫秒級查詢
ip2region - 是國內(nèi)開發(fā)者開發(fā)的離線IP地址定位庫,針對國內(nèi)IP效果較好,國外的部分IP只能顯示國家。
項目gitee地址:
https://gitee.com/lionsoul/ip2region.git
先安裝依賴
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>1.7.2</version>
</dependency>下載離線IP定位庫
離線數(shù)據(jù)庫在項目的data文件夾下,名稱為ip2region.db,其他2個文件是用于生成離線庫的,可不用下載。
https://gitee.com/lionsoul/ip2region/blob/master/data/ip2region.db
下載到離線數(shù)據(jù)庫后,我們需要讀取這個數(shù)據(jù)庫,我們可以放在項目的resources目錄,但是我不建議這樣做,這樣打包的jar會變得很大,部署時麻煩。
我們指定一個絕對路徑,這個部署的時候也不用每次上傳,這個數(shù)據(jù)庫一般不會修改,如果數(shù)據(jù)庫更新了,單獨上傳即可。
因為我們項目使用阿里云oss,服務器也在阿里云,所以我就把數(shù)據(jù)庫存到oss中,阿里云內(nèi)網(wǎng)讀取還是很快的,這樣免得我修改地址,更新數(shù)據(jù)庫我也只需要在本地上傳到oss即可。
下面我們定義類封裝ip2region
- 記錄映射實體 IpInfo.java
該類用于接受解析后的數(shù)據(jù),我們也可以使用map來接收,我這里就使用模型來組裝數(shù)據(jù)。
類使用 lombok ,如果不喜歡的自行修改為普通類。
import lombok.Data;
/**
* 域名信息.
*
* @author https://www.cnblogs.com/lixingwu
* @date 2022-05-24 15:07:47
*/
@Data
public class IpInfo {
/*** 國家 */
private String country;
/*** 地區(qū) */
private String region;
/*** 省 */
private String province;
/*** 市 */
private String city;
/*** 運營商 */
private String isp;
}ip解析工具類 Ip2regionAnalysis.java
該類主要用于加載數(shù)據(jù)庫和解析IP信息,然后把查詢的結果組裝為IpInfo的;
這個類我使用了使用單例模式(雙重校驗鎖DCL)進行編寫,在構造函數(shù)里加載IP數(shù)據(jù)庫,這樣數(shù)據(jù)庫就只會加載一遍。
類中還用到了工具包hutool,需要自行引入,具體操作自行百度。
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.StreamProgress;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.yunding.vote.domain.IpInfo;
import lombok.extern.slf4j.Slf4j;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbMakerConfigException;
import org.lionsoul.ip2region.DbSearcher;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Optional;
/**
* 使用單例模式(雙重校驗鎖DCL)
*
* @author https://www.cnblogs.com/lixingwu
* @date 2022-05-24 10:45:42
*/
@Slf4j
public class Ip2regionAnalysis {
private volatile static Ip2regionAnalysis analysis;
/**
* TODO 這個數(shù)據(jù)庫地址,改成自己的,不要用這地址啊,這個需要登錄才能下載
* ip數(shù)據(jù)庫地址
*/
public static final String IP_REGION_DB_URL = "https://gitee.com/lionsoul/ip2region/raw/master/data/ip2region.db";
/**
* ip數(shù)據(jù)庫字節(jié)
*/
private final byte[] dbBinStr;
/**
* 初始化,下載ip數(shù)據(jù)庫文件轉(zhuǎn)為為文件輸出流
*/
private Ip2regionAnalysis() {
// 下載IP數(shù)據(jù)庫文件
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
HttpUtil.download(IP_REGION_DB_URL, outputStream, false, new StreamProgress() {
@Override
public void start() {
log.info("下載IP數(shù)據(jù)庫文件...");
}
@Override
public void progress(long progressSize) {
}
@Override
public void finish() {
double fileSize = NumberUtil.div(outputStream.size(), (1024 * 1024), 2);
log.info("IP數(shù)據(jù)庫文件下載成功,數(shù)據(jù)庫文件大小[{}MB]", fileSize);
}
});
dbBinStr = outputStream.toByteArray();
IoUtil.close(outputStream);
}
/**
* 獲取IP解析單例
*
* @return Ip2regionAnalysis
*/
public static Ip2regionAnalysis getInstance() {
if (analysis == null) {
synchronized (Ip2regionAnalysis.class) {
if (analysis == null) {
analysis = new Ip2regionAnalysis();
}
}
}
return analysis;
}
/**
* <p>方法名稱:解析Ip信息.</p>
* <p>詳細描述:.</p>
* <p>創(chuàng)建時間:2022-05-24 11:26:59</p>
* <p>創(chuàng)建作者:lixingwu</p>
* <p>修改記錄:</p>
*
* @param ip IP地址
* @return 國家|區(qū)域|省份|城市|ISP
*/
public Optional<String> getIpInfo(String ip) {
if (IpAddressUtil.validIp(ip)) {
try {
DbConfig config = new DbConfig();
DbSearcher searcher = new DbSearcher(config, dbBinStr);
// 搜索數(shù)據(jù)
DataBlock search = searcher.memorySearch(ip);
// 數(shù)據(jù)格式:國家|區(qū)域|省份|城市|ISP
return Optional.of(search.getRegion());
} catch (DbMakerConfigException | IOException e) {
e.printStackTrace();
log.error("Ip解析失?。簕}", e.toString());
}
}
return Optional.empty();
}
/**
* <p>方法名稱:解析Ip信息.</p>
* <p>詳細描述:.</p>
* <p>創(chuàng)建時間:2022-05-24 11:26:59</p>
* <p>創(chuàng)建作者:lixingwu</p>
* <p>修改記錄:</p>
*
* @param ips IP地址集合
* @return Dict({ ip : info })
*/
public Dict getIpInfo(HashSet<String> ips) {
try {
DbConfig config = new DbConfig();
DbSearcher searcher = new DbSearcher(config, dbBinStr);
DataBlock search;
Dict dataset = Dict.create();
for (String ip : ips) {
if (IpAddressUtil.validIp(ip)) {
search = searcher.memorySearch(ip);
dataset.set(ip, search.getRegion());
}
}
return dataset;
} catch (DbMakerConfigException | IOException e) {
e.printStackTrace();
log.error("Ip解析失敗:{}", e.toString());
}
return Dict.create();
}
/**
* <p>方法名稱:數(shù)字ip獲取信息.</p>
* <p>詳細描述:.</p>
* <p>創(chuàng)建時間:2022-05-24 13:15:23</p>
* <p>創(chuàng)建作者:lixingwu</p>
* <p>修改記錄:</p>
*
* @param ip 數(shù)字IP
* @return 國家|區(qū)域|省份|城市|ISP
*/
public Optional<String> getIpInfo(long ip) {
String longIpv4 = NetUtil.longToIpv4(ip);
return getIpInfo(longIpv4);
}
/**
* <p>方法名稱:獲取請求對象的IP信息.</p>
* <p>詳細描述:.</p>
* <p>創(chuàng)建時間:2022-05-24 11:50:59</p>
* <p>創(chuàng)建作者:lixingwu</p>
* <p>修改記錄:</p>
*
* @param request 請求對象
* @return 國家|區(qū)域|省份|城市|ISP
*/
public Optional<String> getIpInfo(HttpServletRequest request) {
String ip = IpAddressUtil.getIpAddr(request);
return getIpInfo(ip);
}
/**
* <p>方法名稱:獲取IP信息的字典.</p>
* <p>詳細描述:.</p>
* <p>創(chuàng)建時間:2022-05-24 11:52:58</p>
* <p>創(chuàng)建作者:lixingwu</p>
* <p>修改記錄:</p>
*
* @param ip IP地址
* @return the dict
*/
public IpInfo getIpInfoBean(String ip) {
Optional<String> ipInfo = getIpInfo(ip);
IpInfo info = new IpInfo();
if (ipInfo.isPresent()) {
//國家|區(qū)域|省份|城市|ISP
String[] split = StrUtil.split(ipInfo.get(), "|");
info.setCountry(split[0]);
info.setRegion(split[1]);
info.setProvince(split[2]);
info.setCity(split[3]);
info.setIsp(split[4]);
}
return info;
}
/**
* <p>方法名稱:數(shù)字ip獲取信息字典.</p>
* <p>詳細描述:.</p>
* <p>創(chuàng)建時間:2022-05-24 13:15:23</p>
* <p>創(chuàng)建作者:lixingwu</p>
* <p>修改記錄:</p>
*
* @param ip 數(shù)字IP
* @return 國家|區(qū)域|省份|城市|ISP
*/
public IpInfo getIpInfoBean(long ip) {
String longIpv4 = NetUtil.longToIpv4(ip);
return getIpInfoBean(longIpv4);
}
/**
* <p>方法名稱:獲取IP信息的字典.</p>
* <p>詳細描述:.</p>
* <p>創(chuàng)建時間:2022-05-24 11:52:58</p>
* <p>創(chuàng)建作者:lixingwu</p>
* <p>修改記錄:</p>
*
* @param request 請求對象
* @return the dict
*/
public IpInfo getIpInfoBean(HttpServletRequest request) {
String ip = IpAddressUtil.getIpAddr(request);
return getIpInfoBean(ip);
}
/**
* 測試
*/
public static void main(String[] args) {
log.info("121.8.215.106 \t {}", Ip2regionAnalysis.getInstance().getIpInfoBean("121.8.215.106"));
log.info("183.247.152.98 \t {}", Ip2regionAnalysis.getInstance().getIpInfoBean("183.247.152.98"));
log.info("14.29.139.251 \t {}", Ip2regionAnalysis.getInstance().getIpInfoBean("14.29.139.251"));
log.info("183.247.152.98 \t {}", Ip2regionAnalysis.getInstance().getIpInfoBean("183.247.152.98"));
log.info("27.105.130.93 \t {}", Ip2regionAnalysis.getInstance().getIpInfoBean("27.105.130.93"));
log.info("124.205.155.147 \t {}", Ip2regionAnalysis.getInstance().getIpInfoBean("124.205.155.147"));
// 批量解析,返回字典數(shù)據(jù):ip:解析信息
final HashSet<String> ipSet = CollUtil.newHashSet(
"47.92.113.71", "221.226.75.86", "124.205.155.155",
"47.57.188.208", "121.8.215.106", "121.8.215.106"
);
Dict dict = Ip2regionAnalysis.getInstance().getIpInfo(ipSet);
log.info("{}", dict.toString());
log.info("{}\t{}", "121.8.215.106", dict.getStr("121.8.215.106"));
}
}測試輸出
14:19:12.791 [main] DEBUG cn.hutool.log.LogFactory - Use [Slf4j] Logger As Default.
14:19:14.150 [main] INFO util.Ip2regionAnalysis - 下載IP數(shù)據(jù)庫文件...
14:19:14.633 [main] INFO util.Ip2regionAnalysis - IP數(shù)據(jù)庫文件下載成功,數(shù)據(jù)庫文件大小[8.33MB]
14:19:14.645 [main] INFO util.Ip2regionAnalysis - 121.8.215.106 IpInfo(country=中國, region=0, province=廣東省, city=廣州市, isp=電信)
14:19:14.646 [main] INFO util.Ip2regionAnalysis - 183.247.152.98 IpInfo(country=中國, region=0, province=浙江省, city=杭州市, isp=移動)
14:19:14.646 [main] INFO util.Ip2regionAnalysis - 14.29.139.251 IpInfo(country=中國, region=0, province=廣東省, city=深圳市, isp=電信)
14:19:14.646 [main] INFO util.Ip2regionAnalysis - 183.247.152.98 IpInfo(country=中國, region=0, province=浙江省, city=杭州市, isp=移動)
14:19:14.646 [main] INFO util.Ip2regionAnalysis - 27.105.130.93 IpInfo(country=中國, region=0, province=臺灣省, city=臺北, isp=So-Net)
14:19:14.646 [main] INFO util.Ip2regionAnalysis - 124.205.155.147 IpInfo(country=中國, region=0, province=北京, city=北京市, isp=鵬博士)
14:19:14.648 [main] INFO util.Ip2regionAnalysis - {221.226.75.86=中國|0|江蘇省|南京市|電信, 47.57.188.208=中國|0|香港|0|阿里云, 47.92.113.71=中國|0|河北省|張家口市|阿里云, 121.8.215.106=中國|0|廣東省|廣州市|電信, 124.205.155.155=中國|0|北京|北京市|鵬博士}
14:19:14.682 [main] INFO util.Ip2regionAnalysis - 121.8.215.106 中國|0|廣東省|廣州市|電信
在第一次調(diào)用getInstance時會去下載數(shù)據(jù)庫文件會比較耗時,其他后面的操作就很快了,基本上幾毫秒就查詢到了。
所以如果嫌第一次慢的,可以在程序啟動完成后手動調(diào)用,預熱一下,在實際業(yè)務就會使用緩存的數(shù)據(jù)庫了。
實際使用
在項目中我編寫了一個 CommonController.java ,然后使用編寫的類提供了一個接口,用于獲取IP的信息。
import cn.hutool.extra.servlet.ServletUtil;
import com.yunding.vote.common.api.CommonResult;
import com.yunding.vote.common.limiter.RInterfaceLimit;
import com.yunding.vote.domain.IpInfo;
import com.yunding.vote.util.Ip2regionAnalysis;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
/**
* 公共控制層,該類方法不會記錄日志
*/
@RestController
@Api(tags = "公共控制層", description = "公共控制層")
@RequestMapping("/common")
@Slf4j
public class CommonController {
@Resource
private HttpServletRequest request;
@ApiOperation("獲取IP的信息,100QPS")
@GetMapping(value = "/ipInfo/{ip}")
@RInterfaceLimit(rate = 100)
public CommonResult<IpInfo> getIpInfo(@PathVariable String ip) {
String clientIp = ServletUtil.getClientIP(request);
IpInfo ipInfo = Ip2regionAnalysis.getInstance().getIpInfoBean(ip);
return CommonResult.success(ipInfo);
}
}上面這個類只是告訴大家是怎么使用Ip2regionAnalysis這個類的,大家根據(jù)自己的項目自行調(diào)整。
GET http://127.0.0.1:8080/api/v1/common/ipInfo/121.8.215.106
>>>
{
"code": 200,
"data": {
"country": "中國",
"region": 0,
"province": "廣東省",
"city": "廣州市",
"isp": "電信"
},
"message": "操作成功"
}到此這篇關于JAVA使用Ip2region獲取IP定位信息的文章就介紹到這了,更多相關java獲取IP定位信息內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
JDK21新特性Record?Patterns記錄模式詳解(最新推薦)
這篇文章主要介紹了JDK21新特性Record?Patterns記錄模式詳解,本JEP建立在Pattern?Matching?for?instanceof(JEP?394)的基礎上,該功能已在JDK?16中發(fā)布,它與Pattern?Matching?for?switch(JEP?441)共同演進,需要的朋友可以參考下2023-09-09
java用字節(jié)數(shù)組解決FileInputStream讀取漢字出現(xiàn)亂碼問題
這篇文章主要介紹了java用字節(jié)數(shù)組解決FileInputStream讀取漢字出現(xiàn)亂碼問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05
教你怎么用SpringBoot+Mybati-Plus快速搭建代碼
Mybatis自身通過了逆向工程來幫助我們快速生成代碼,但Mybatis-plus卻更加強大,不僅僅可以生成dao,pojo,mapper,還有基本的controller和service層代碼,接下來我們來寫一個簡單的人門案例是看看如何mybatis-plus是怎么實現(xiàn)的,需要的朋友可以參考下2021-06-06
Spring Boot應用監(jiān)控的實戰(zhàn)教程
Spring Boot 提供運行時的應用監(jiān)控和管理功能,下面這篇文章主要給大家介紹了關于Spring Boot應用監(jiān)控的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧2018-05-05

