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

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

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定位信息内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java如何根据IP获取当前区域天气信息详解

    大致思路是客户端发起请求,我们首先根据请求获取到外网IP,然后再根据外网IP获取到用户所在城市,最后根据城市获取到天气信息 获取外网IP 万网获取外网IP地址:www.net.cn/static/cust- /** * @Description:获取客户端外网ip 此方法要接入互联网才行,内网不行 **/ public static String getPublicIp() { try { String path = "http://www.net.cn/static/customercare/

  • java如何获取用户登录ip、浏览器信息、SessionId

    目录 java获取用户登录ip.浏览器信息.SessionId 1.获取用户登录ip 2.获取用户所使用的浏览器信息 3.获取用户SessionId 获取用户登录的ip地址(考虑多种请求头的情况) java获取用户登录ip.浏览器信息.SessionId 1.获取用户登录ip //获取用户登录ip; String loginIp = request.getHeader("X-Forwarded-For"); if (loginIp == null || loginIp.length()

  • java根据ip地址获取详细地域信息的方法

    互联网有很多接口可以实现通过ip查询到具体的位置,如下: 通过淘宝IP地址库获取IP位置 请求接口(GET):http://ip.taobao.com/service/getIpInfo.php?ip=[ip地址字串] 响应信息:(json格式的)国家 .省(自治区或直辖市).市(县).运营商 返回数据格式: {"code":0,"data":{"ip":"210.75.225.254","country"

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

    目录 先安装依赖 下载离线IP定位库 下面我们定义类封装ip2region 测试输出 实际使用 ip2region - 准确率99.9%的离线IP地址定位库,0.0x毫秒级查询 ip2region - 是国内开发者开发的离线IP地址定位库,针对国内IP效果较好,国外的部分IP只能显示国家. 项目gitee地址: https://gitee.com/lionsoul/ip2region.git 先安装依赖 <dependency> <groupId>org.lionsoul</

  • java反射之获取类的信息方法(推荐)

    本文接上文"老生常谈反射之Class类的使用(必看篇)",以编写一个用来获取类的信息(成员函数.成员变量.构造函数)的工具类来讲解"反射之获取类的信息" 1.获取成员函数信息 /** * 获取成员函数信息 * @param obj */ public static void printClassMethodMessage(Object obj){ //获取类的信息 获取类的类类型 Class c = obj.getClass(); //获取类的名称 System.o

  • Java利用ip2region实现获取IP地址详情

    最近有个需求是通过ip地址获取地址详情,没有弄过相关的接口,通过查资料搞定之后赶紧记录分享一下 一开始我是通过api的方法获取但是总是报错获取不到所以改用了ip2region离线ip解析的方法获取的,废话不多说看操作. 首先要下载ip2region.db 下载地址:百度网盘 请输入提取码​​​​​​ 提取码:vik5 配置依赖 <dependency> <groupId>org.lionsoul</groupId> <artifactId>ip2region

  • ThinkPHP使用UTFWry地址库进行IP定位实例

    可以在官网的 http://www.thinkphp.cn/extend/223.html下载IP定位扩展类库,或者下载扩展包( http://www.thinkphp.cn/down/253.html)里面也已经包含该扩展类了.如果是单独下载的上传类库,把解压后的IpLocation.class.php 放入ThinkPHP/Extend/Library/ORG/Net/(如果没有请手动创建)目录下面. 一.获取IP地址 如果你仅仅需要获取用户访问的IP地址,那么直接使用系统内置的get_cl

  • SpringBoot使用ip2region获取地理位置信息的方法

    目录 1.简介 2.引入依赖 3.测试 4.测试结果 1.简介 ip2region,准确率99.9%的离线IP地址定位库,0.0x毫秒级查询,数据库文件大小只有1.5M,提供了java,php,c,python,nodejs,golang,c#等查询绑定和Binary,B树,内存三种查询算法,仓库地址: https://gitee.com/lionsoul/ip2region 2.引入依赖 <!-- Ip地址获取 --> <dependency> <groupId>ne

  • java获取IP归属地全网显示开源库使用

    目录 引言 Java如何获取IP属地 Ip2region开源项目 99.9%准确率: 多查询客户端的支持 Ip2region V2.0 特性 ip2region xdb java 查询客户端实现 IDEA中做个测试 编译测试程序 查询测试 bench 测试 引言 细心的朋友应该会发现,最近,继新浪微博之后,头条.腾讯.抖音.知乎.快手.小红书等各大平台陆陆续续都上线了“网络用户IP地址显示功能”,境外用户显示的是国家,国内的用户显示的省份,而且此项显示无法关闭,归属地强制显示. 作为技术人,那!

  • Java根据Request获取客户端IP

    在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr() ,这种方法在大部分情况下都是有效的.但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了. 如果使用了反向代理软件,将http://192.168.1.110:2046/ 的URL反向代理为http://www.xxx.com/ 的URL时,用request.getRemoteAddr() 方法获取的IP地址是:127.0.0.1 或 192.168.1.110 ,而并不是客

  • Java利用Request请求如何获取IP地址对应的省份、城市详解

    前言 最近的一个项目中需要将不同省份的用户,展示不同内容,所以需要通过Request请求获取IP地址, 然后通过IP获取IP对应省份. 这里的操作步骤一共有步: 1. 通过Request获取IP 2. 通过IP获取对应省份.城市 3. 通过设置的省份和IP对应省份进行比对,展示内容 通过Request获取IP 可以参考我的另外一篇文章[Java 通过Request请求获取IP地址]下面是代码: public class IpAdrressUtil { /** * 获取Ip地址 * @param

  • java获取redis日志信息与动态监控信息的方法

    效果展示如下所示: 实时监控 redis环境信息和日志列表 Redis配置 在windows下安装的redis,在安装目录找到redis.windows.conf文件,修改以下字段(按实际情况设置): slowlog-log-slower-than 100 slowlog-max-len 1000000 slowlog-log-slower-than:是配置需要日志记录的命令执行时间,单位是微秒,也就是说配置为100,会记录命令执行时间为0.1ms以上的记录.如果设置为0,就会记录所有执行过的命

随机推荐