JAVA使用Ip2region获取IP定位信息的操作方法

网友投稿 795 2022-07-28


目录先安装依赖下载离线IP定位库下面我们定义类封装ip2region测试输出实际使用

ip2region - 准确率99.9%的离线IP地址定位库,0.0x毫秒级查询

ip2region - 是国内开发者开发的离线IP地址定位库,针对国内IP效果较好,国外的部分IP只能显示国家。

项目gitee地址:

https://gitee.com/lionsoul/ip2region.git

先安装依赖

org.lionsoul

ip2region

1.7.2

下载离线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://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://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;

}

/**

*

方法名称:解析Ip信息.

*

详细描述:.

*

创建时间:2022-05-24 11:26:59

*

*

修改记录:

*

* @param ip IP地址

* @return 国家|区域|省份|城市|ISP

*/

public Optional 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();

}

/**

*

方法名称:解析Ip信息.

*

详细描述:.

*

创建时间:2022-05-24 11:26:59

*

*

修改记录:

*

* @param ips IP地址集合

* @return Dict({ ip : info })

*/

public Dict getIpInfo(HashSet 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();

}

/**

*

方法名称:数字ip获取信息.

*

详细描述:.

*

创建时间:2022-05-24 13:15:23

*

*

修改记录:

*

* @param ip 数字IP

* @return 国家|区域|省份|城市|ISP

*/

public Optional getIpInfo(long ip) {

String longIpv4 = NetUtil.longToIpv4(ip);

return getIpInfo(longIpv4);

}

/**

*

方法名称:获取请求对象的IP信息.

*

详细描述:.

*

创建时间:2022-05-24 11:50:59

*

*

修改记录:

*

* @param request 请求对象

* @return 国家|区域|省份|城市|ISP

*/

public Optional getIpInfo(HttpServletRequest request) {

String ip = IpAddressUtil.getIpAddr(request);

return getIpInfo(ip);

}

/**

*

方法名称:获取IP信息的字典.

*

详细描述:.

*

创建时间:2022-05-24 11:52:58

*

*

修改记录:

*

* @param ip IP地址

* @return the dict

*/

public IpInfo getIpInfoBean(String ip) {

Optional 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;

}

/**

*

方法名称:数字ip获取信息字典.

*

详细描述:.

*

创建时间:2022-05-24 13:15:23

*

*

修改记录:

*

* @param ip 数字IP

* @return 国家|区域|省份|城市|ISP

*/

public IpInfo getIpInfoBean(long ip) {

String longIpv4 = NetUtil.longToIpv4(ip);

return getIpInfoBean(longIpv4);

}

/**

*

方法名称:获取IP信息的字典.

*

详细描述:.

*

创建时间:2022-05-24 11:52:58

*

*

修改记录:

*

* @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 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.sWlNZTNpringframework.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 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": "操作成功"

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java实现断点下载功能的示例代码(java断点续传下载)
下一篇:MQ的分类组成优缺点测试点入门教程(不属于MQ的优点的是)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~