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ù)庫文件轉為為文件輸出流 */ 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ù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
詳解SpringBoot配置文件啟動時動態(tài)配置參數(shù)方法
這篇文章主要介紹了詳解SpringBoot配置文件啟動時動態(tài)配置參數(shù)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-11-11詳解spring+springmvc+mybatis整合注解
本篇文章主要介紹了詳解spring+springmvc+mybatis整合注解,詳細的介紹了ssm框架的使用,具有一定的參考價值,有興趣的可以了解一下2017-04-04SpringSecurity實現(xiàn)前后端分離的示例詳解
Spring Security默認提供賬號密碼認證方式,具體實現(xiàn)是在UsernamePasswordAuthenticationFilter 中,這篇文章主要介紹了SpringSecurity實現(xiàn)前后端分離的示例詳解,需要的朋友可以參考下2023-03-03