ip2region - 准确率99.9%的离线IP地址定位库,0.0x毫秒级查询
ip2region - 是国内开发者开发的离线IP地址定位库,针对国内IP效果较好,国外的部分IP只能显示国家。
项目gitee地址:
1 |
https://gitee测试数据/lionsoul/ip2region.git |
先安装依赖
1 2 3 4 5 |
< dependency > < groupId >org.lionsoul</ groupId > < artifactId >ip2region</ artifactId > < version >1.7.2</ version > </ dependency > |
下载离线IP定位库
离线数据库在项目的data文件夹下,名称为 ip2region.db ,其他2个文件是用于生成离线库的,可不用下载。
1 |
https://gitee测试数据/lionsoul/ip2region/blob/master/data/ip2region.db |
下载到离线数据库后,我们需要读取这个数据库,我们可以放在项目的 resources 目录,但是我不建议这样做,这样打包的jar会变得很大,部署时麻烦。
我们指定一个绝对路径,这个部署的时候也不用每次上传,这个数据库一般不会修改,如果数据库更新了,单独上传即可。
因为我们项目使用阿里云oss,服务器也在阿里云,所以我就把数据库存到oss中,阿里云内网读取还是很快的,这样免得我修改地址,更新数据库我也只需要在本地上传到oss即可。
下面我们定义类封装ip2region
记录映射实体 IpInfo.java该类用于接受解析后的数据,我们也可以使用map来接收,我这里就使用模型来组装数据。
类使用 lombok ,如果不喜欢的自行修改为普通类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import lombok.Data; /** * 域名信息. * * @author https://HdhCmsTestcnblogs测试数据/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 ,需要自行引入,具体操作自行百度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
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://HdhCmsTestcnblogs测试数据/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测试数据/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的信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
import cn.hutool.extra.servlet.ServletUtil; import com.yunding.vote测试数据mon.api.CommonResult; import com.yunding.vote测试数据mon.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 这个类的,大家根据自己的项目自行调整。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
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定位信息内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
原文链接:https://HdhCmsTestcnblogs测试数据/lixingwu/p/16317568.html
查看更多关于JAVA使用Ip2region获取IP定位信息的操作方法的详细内容...