JAVA使用Ip2region獲取IP定位信息的操作方法
ip2region - 準(zhǔn)確率99.9%的離線IP地址定位庫,0.0x毫秒級查詢
ip2region - 是國內(nèi)開發(fā)者開發(fā)的離線IP地址定位庫,針對國內(nèi)IP效果較好,國外的部分IP只能顯示國家。
項(xiàng)目gitee地址:
https://gitee.com/lionsoul/ip2region.git
先安裝依賴
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>1.7.2</version>
</dependency>下載離線IP定位庫
離線數(shù)據(jù)庫在項(xiàng)目的data文件夾下,名稱為ip2region.db,其他2個(gè)文件是用于生成離線庫的,可不用下載。
https://gitee.com/lionsoul/ip2region/blob/master/data/ip2region.db
下載到離線數(shù)據(jù)庫后,我們需要讀取這個(gè)數(shù)據(jù)庫,我們可以放在項(xiàng)目的resources目錄,但是我不建議這樣做,這樣打包的jar會(huì)變得很大,部署時(shí)麻煩。
我們指定一個(gè)絕對路徑,這個(gè)部署的時(shí)候也不用每次上傳,這個(gè)數(shù)據(jù)庫一般不會(huì)修改,如果數(shù)據(jù)庫更新了,單獨(dú)上傳即可。
因?yàn)槲覀冺?xiàng)目使用阿里云oss,服務(wù)器也在阿里云,所以我就把數(shù)據(jù)庫存到oss中,阿里云內(nèi)網(wǎng)讀取還是很快的,這樣免得我修改地址,更新數(shù)據(jù)庫我也只需要在本地上傳到oss即可。
下面我們定義類封裝ip2region
- 記錄映射實(shí)體 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;
/*** 運(yùn)營商 */
private String isp;
}ip解析工具類 Ip2regionAnalysis.java
該類主要用于加載數(shù)據(jù)庫和解析IP信息,然后把查詢的結(jié)果組裝為IpInfo的;
這個(gè)類我使用了使用單例模式(雙重校驗(yàn)鎖DCL)進(jìn)行編寫,在構(gòu)造函數(shù)里加載IP數(shù)據(jù)庫,這樣數(shù)據(jù)庫就只會(huì)加載一遍。
類中還用到了工具包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;
/**
* 使用單例模式(雙重校驗(yàn)鎖DCL)
*
* @author https://www.cnblogs.com/lixingwu
* @date 2022-05-24 10:45:42
*/
@Slf4j
public class Ip2regionAnalysis {
private volatile static Ip2regionAnalysis analysis;
/**
* TODO 這個(gè)數(shù)據(jù)庫地址,改成自己的,不要用這地址啊,這個(gè)需要登錄才能下載
* 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>詳細(xì)描述:.</p>
* <p>創(chuàng)建時(shí)間: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>詳細(xì)描述:.</p>
* <p>創(chuàng)建時(shí)間: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>詳細(xì)描述:.</p>
* <p>創(chuàng)建時(shí)間: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>詳細(xì)描述:.</p>
* <p>創(chuàng)建時(shí)間: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>詳細(xì)描述:.</p>
* <p>創(chuàng)建時(shí)間: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>詳細(xì)描述:.</p>
* <p>創(chuàng)建時(shí)間: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>詳細(xì)描述:.</p>
* <p>創(chuàng)建時(shí)間: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=移動(dòng))
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=移動(dòng))
14:19:14.646 [main] INFO util.Ip2regionAnalysis - 27.105.130.93 IpInfo(country=中國, region=0, province=臺(tái)灣省, city=臺(tái)北, 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í)會(huì)去下載數(shù)據(jù)庫文件會(huì)比較耗時(shí),其他后面的操作就很快了,基本上幾毫秒就查詢到了。
所以如果嫌第一次慢的,可以在程序啟動(dòng)完成后手動(dòng)調(diào)用,預(yù)熱一下,在實(shí)際業(yè)務(wù)就會(huì)使用緩存的數(shù)據(jù)庫了。
實(shí)際使用
在項(xiàng)目中我編寫了一個(gè) CommonController.java ,然后使用編寫的類提供了一個(gè)接口,用于獲取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;
/**
* 公共控制層,該類方法不會(huì)記錄日志
*/
@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);
}
}上面這個(gè)類只是告訴大家是怎么使用Ip2regionAnalysis這個(gè)類的,大家根據(jù)自己的項(xiàng)目自行調(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": "操作成功"
}到此這篇關(guān)于JAVA使用Ip2region獲取IP定位信息的文章就介紹到這了,更多相關(guān)java獲取IP定位信息內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java 實(shí)現(xiàn)隨機(jī)驗(yàn)證碼功能簡單實(shí)例
這篇文章主要介紹了Java 實(shí)現(xiàn)隨機(jī)驗(yàn)證碼功能簡單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-04-04
詳解SpringBoot配置文件啟動(dòng)時(shí)動(dòng)態(tài)配置參數(shù)方法
這篇文章主要介紹了詳解SpringBoot配置文件啟動(dòng)時(shí)動(dòng)態(tài)配置參數(shù)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
詳解spring+springmvc+mybatis整合注解
本篇文章主要介紹了詳解spring+springmvc+mybatis整合注解,詳細(xì)的介紹了ssm框架的使用,具有一定的參考價(jià)值,有興趣的可以了解一下2017-04-04
SpringSecurity實(shí)現(xiàn)前后端分離的示例詳解
Spring Security默認(rèn)提供賬號密碼認(rèn)證方式,具體實(shí)現(xiàn)是在UsernamePasswordAuthenticationFilter 中,這篇文章主要介紹了SpringSecurity實(shí)現(xiàn)前后端分離的示例詳解,需要的朋友可以參考下2023-03-03

