JAVA使用Ip2region獲取IP定位信息的操作方法
ip2region – 準確率99.9%的離線IP地址定位庫,0.0x毫秒級查詢
ip2region – 是國內開發者開發的離線IP地址定位庫,針對國內IP效果較好,國外的部分IP隻能顯示國傢。
項目gitee地址:
https://gitee.com/lionsoul/ip2region.git
先安裝依賴
<dependency> <groupId>org.lionsoul</groupId> <artifactId>ip2region</artifactId> <version>1.7.2</version> </dependency>
下載離線IP定位庫
離線數據庫在項目的data文件夾下,名稱為ip2region.db
,其他2個文件是用於生成離線庫的,可不用下載。
https://gitee.com/lionsoul/ip2region/blob/master/data/ip2region.db
下載到離線數據庫後,我們需要讀取這個數據庫,我們可以放在項目的resources
目錄,但是我不建議這樣做,這樣打包的jar會變得很大,部署時麻煩。
我們指定一個絕對路徑,這個部署的時候也不用每次上傳,這個數據庫一般不會修改,如果數據庫更新瞭,單獨上傳即可。
因為我們項目使用阿裡雲oss,服務器也在阿裡雲,所以我就把數據庫存到oss中,阿裡雲內網讀取還是很快的,這樣免得我修改地址,更新數據庫我也隻需要在本地上傳到oss即可。
下面我們定義類封裝ip2region
- 記錄映射實體 IpInfo.java
該類用於接受解析後的數據,我們也可以使用map來接收,我這裡就使用模型來組裝數據。
類使用 lombok ,如果不喜歡的自行修改為普通類。
import lombok.Data; /** * 域名信息. * * @author https://www.cnblogs.com/lixingwu * @date 2022-05-24 15:07:47 */ @Data public class IpInfo { /*** 國傢 */ private String country; /*** 地區 */ private String region; /*** 省 */ private String province; /*** 市 */ private String city; /*** 運營商 */ private String isp; }
ip解析工具類 Ip2regionAnalysis.java
該類主要用於加載數據庫和解析IP信息,然後把查詢的結果組裝為IpInfo的;
這個類我使用瞭使用單例模式(雙重校驗鎖DCL)進行編寫,在構造函數裡加載IP數據庫,這樣數據庫就隻會加載一遍。
類中還用到瞭工具包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 這個數據庫地址,改成自己的,不要用這地址啊,這個需要登錄才能下載 * ip數據庫地址 */ public static final String IP_REGION_DB_URL = "https://gitee.com/lionsoul/ip2region/raw/master/data/ip2region.db"; /** * ip數據庫字節 */ private final byte[] dbBinStr; /** * 初始化,下載ip數據庫文件轉為為文件輸出流 */ private Ip2regionAnalysis() { // 下載IP數據庫文件 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); HttpUtil.download(IP_REGION_DB_URL, outputStream, false, new StreamProgress() { @Override public void start() { log.info("下載IP數據庫文件..."); } @Override public void progress(long progressSize) { } @Override public void finish() { double fileSize = NumberUtil.div(outputStream.size(), (1024 * 1024), 2); log.info("IP數據庫文件下載成功,數據庫文件大小[{}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>創建時間:2022-05-24 11:26:59</p> * <p>創建作者:lixingwu</p> * <p>修改記錄:</p> * * @param ip IP地址 * @return 國傢|區域|省份|城市|ISP */ public Optional<String> getIpInfo(String ip) { if (IpAddressUtil.validIp(ip)) { try { DbConfig config = new DbConfig(); DbSearcher searcher = new DbSearcher(config, dbBinStr); // 搜索數據 DataBlock search = searcher.memorySearch(ip); // 數據格式:國傢|區域|省份|城市|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>創建時間:2022-05-24 11:26:59</p> * <p>創建作者: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>方法名稱:數字ip獲取信息.</p> * <p>詳細描述:.</p> * <p>創建時間:2022-05-24 13:15:23</p> * <p>創建作者:lixingwu</p> * <p>修改記錄:</p> * * @param ip 數字IP * @return 國傢|區域|省份|城市|ISP */ public Optional<String> getIpInfo(long ip) { String longIpv4 = NetUtil.longToIpv4(ip); return getIpInfo(longIpv4); } /** * <p>方法名稱:獲取請求對象的IP信息.</p> * <p>詳細描述:.</p> * <p>創建時間:2022-05-24 11:50:59</p> * <p>創建作者:lixingwu</p> * <p>修改記錄:</p> * * @param request 請求對象 * @return 國傢|區域|省份|城市|ISP */ public Optional<String> getIpInfo(HttpServletRequest request) { String ip = IpAddressUtil.getIpAddr(request); return getIpInfo(ip); } /** * <p>方法名稱:獲取IP信息的字典.</p> * <p>詳細描述:.</p> * <p>創建時間:2022-05-24 11:52:58</p> * <p>創建作者: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()) { //國傢|區域|省份|城市|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>方法名稱:數字ip獲取信息字典.</p> * <p>詳細描述:.</p> * <p>創建時間:2022-05-24 13:15:23</p> * <p>創建作者:lixingwu</p> * <p>修改記錄:</p> * * @param ip 數字IP * @return 國傢|區域|省份|城市|ISP */ public IpInfo getIpInfoBean(long ip) { String longIpv4 = NetUtil.longToIpv4(ip); return getIpInfoBean(longIpv4); } /** * <p>方法名稱:獲取IP信息的字典.</p> * <p>詳細描述:.</p> * <p>創建時間:2022-05-24 11:52:58</p> * <p>創建作者: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")); // 批量解析,返回字典數據: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數據庫文件…
14:19:14.633 [main] INFO util.Ip2regionAnalysis – IP數據庫文件下載成功,數據庫文件大小[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|廣東省|廣州市|電信
在第一次調用getInstance時會去下載數據庫文件會比較耗時,其他後面的操作就很快瞭,基本上幾毫秒就查詢到瞭。
所以如果嫌第一次慢的,可以在程序啟動完成後手動調用,預熱一下,在實際業務就會使用緩存的數據庫瞭。
實際使用
在項目中我編寫瞭一個 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
這個類的,大傢根據自己的項目自行調整。
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定位信息內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Java獲取用戶IP屬地模擬抖音詳解
- Java根據ip地址獲取歸屬地實例詳解
- SpringBoot使用ip2region獲取地理位置信息的方法
- Mybatis + js 實現下拉列表二級聯動效果
- Java單例模式的6種實現方式詳解