SpringBoot通过ip获取归属地,你应该知道的几种方式。

这篇具有很好参考价值的文章主要介绍了SpringBoot通过ip获取归属地,你应该知道的几种方式。。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Hi,大家好,我是抢老婆酸奶的小肥仔。

在日常我们逛网站的时候会发现我们登录后会出现归属地信息,例如:我在广州登录会显示广东广州,有些更加精确的会显示到区县。

SpringBoot通过ip获取归属地,你应该知道的几种方式。,spring boot,tcp/ip,后端

那么我们来看看有哪些方式来获取归属地信息?今天我们来聊一聊。

公共方法:

获取用户ip地址:

/**
 * @author: jiangjs
 * @description: 获取当前真实IP
 * @date: 2022/5/23 16:42
 **/
public class GetUserIP {

    public static final Logger log = LoggerFactory.getLogger(GetUserIP.class);

    public static String getUserIpAddress(HttpServletRequest request){
        try {
            String realIp = request.getHeader("X-Real-IP");
            String forwardedIp = request.getHeader("X-Forwarded-For");
            String clientIp = request.getHeader("Proxy-Client-IP");
            String proxyIp = request.getHeader("WL-Proxy-Client-IP");
            String httpClientIp = request.getHeader("HTTP_CLIENT_IP");
            String xForwardedIp = request.getHeader("HTTP_X_FORWARDED_FOR");
            String remoteAddress = InetAddress.getLocalHost().getHostAddress();
            if(StringUtils.isNotEmpty(forwardedIp) && !"unKnown".equalsIgnoreCase(forwardedIp)){
                //多次反向代理后会有多个Ip值,第一个Ip才是真实Ip
                int index = forwardedIp.indexOf(",");
                if(index != -1){
                    return forwardedIp.substring(0,index);
                }else{
                    return forwardedIp;
                }
            }
            return StringUtils.isNoneBlank(realIp) && !"unKnown".equalsIgnoreCase(realIp) ? realIp :
            StringUtils.isNoneBlank(clientIp) && !"unKnown".equalsIgnoreCase(clientIp) ? clientIp :
            StringUtils.isNoneBlank(proxyIp) && !"unKnown".equalsIgnoreCase(proxyIp) ? proxyIp :
            StringUtils.isNoneBlank(httpClientIp) && !"unKnown".equalsIgnoreCase(httpClientIp) ? httpClientIp :
            StringUtils.isNoneBlank(xForwardedIp) && !"unKnown".equalsIgnoreCase(xForwardedIp) ? xForwardedIp : remoteAddress;
        }catch (Exception e){
            e.printStackTrace();
            log.error("获取用户Ip报错:{}",e.getMessage());
        }
        return "";
    }
}

1、Ip2Region

Ip2Region:见名知意,就是ip转换成区域。根据码云上的简介,Ip2Region是一个离线IP地址定位库和IP定位数据管理框架,能够10微妙级别的查询效率,提供众多主流编程语言的xdb数据生成和查询客户端实现。

1.1 特性

其主要特性有以下几点:

1.1.1 IP数据管理框架

xdb 支持亿级别的 IP 数据段行数,默认的 region 信息都固定了格式:国家|区域|省份|城市|ISP,缺省的地域信息默认是0。 region 信息支持完全自定义,我们可以按照自己的需求来管理IP定位数据。

1.1.2 数据去重和压缩

xdb 格式生成程序会自动去重和压缩部分数据,默认的全部 IP 数据,生成的 ip2region.xdb 数据库是 11MiB,随着数据的详细度增加数据库的大小也慢慢增大。

1.1.3 极速查询响应

基于xdb文件查询单次响应时间在10微妙级别,可以通过以下添加内存的方式加速查询:

  1. vIndex 索引缓存 :使用固定的 512KiB 的内存空间缓存 vector index 数据,减少一次 IO 磁盘操作,保持平均查询效率稳定在10-20微秒之间。
  2. xdb 整个文件缓存:将整个 xdb 文件全部加载到内存,内存占用等同于 xdb 文件大小,无磁盘 IO 操作,保持微秒级别的查询效率。

1.2 代码实现

1.2.1 引入jar包
<dependency>
  <groupId>org.lionsoul</groupId>
  <artifactId>ip2region</artifactId>
  <version>2.6.5</version>
</dependency>
1.2.2 封装工具
/**
 * @author: jiangjs
 * @description: 创建Ip2Region工具类
 * @date: 2022/7/28 14:31
 **/
@Component
public class Ip2RegionUtil {
    public static final Logger log = LoggerFactory.getLogger(Ip2RegionUtil.class);

    /**
     * 将整个库进行缓存到内存,基于这个库创建查询对象来实现基于文件的查询
     * 获取Searcher
     */
    private Searcher getSearcher() throws IOException {
        //获取地址下的库数据
        byte[] bytes = Searcher.loadContentFromFile("D:\ipchange\ip2region\ip2region.xdb");
        return Searcher.newWithBuffer(bytes);
    }

    /**
     * 根据ip地址直接返回国家、省、城市信息
     * @param ip ip
     * @return 返回地址
     */
    public String changeIpToAddress(String ip){
        //获取searcher
        Searcher searcher = null;
        try {
            searcher = getSearcher();
            return searcher.search(ip);
        }catch (Exception e){
            log.error(String.format("ip转地址报错:%s",e.getMessage()));
            e.printStackTrace();
            return "";
        }finally {
            try {
                if (Objects.nonNull(searcher)){
                    searcher.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }

    }
}

ip2region.xdb:为ip对应地址的xdb文件,这个需要不定期的进行更新,更新方法可参考ip2region的码云地址。

1.3 测试

我们提供两个方法,一个方法直接获取ip地址,另一个通过ip138获取到的ip地址,传入到方法进行归属地的查询。

@RestController
@RequestMapping("/ip2region")
public class Ip2RegionChangeController {

    @Autowired
    private Ip2RegionUtil regionUtil;

    @GetMapping("/getIpToAddress.do")
    public ResultUtil<String> getIpToAddressNoIp(HttpServletRequest request){
        String userIp = GetUserIP.getUserIpAddress(request);
        return ResultUtil.success(regionUtil.changeIpToAddress(userIp));
    }
    @GetMapping("/getIpToAddress.do/{ip}")
    public ResultUtil<String> getIpToAddress(@PathVariable("ip") String ip){
        return ResultUtil.success(regionUtil.changeIpToAddress(ip));
    }
}

直接在浏览器上进行访问:

1、直接访问

SpringBoot通过ip获取归属地,你应该知道的几种方式。,spring boot,tcp/ip,后端

2、通过ip138查询的IP

SpringBoot通过ip获取归属地,你应该知道的几种方式。,spring boot,tcp/ip,后端

通过测试的结果我们可以看到,直接获取到内网的地址并没有解析出地址,而是直接提示了内网。而通过ip138查询到外网地址,能够正常的解析出地址。

2、geoip2

geopip2:是国外的,一个只有100kb的数据库,小巧实用,加载时间极短,查询效率高,项目只包含大陆用户需要的中国IP地址段。geopip2是免费的,里面既包含地理信息,同时也包含了经纬度。GeoIP依赖MaxMind的IP数据,需要频繁更新。

大家有兴趣的话可以直接取git上看看介绍。

2.1 代码实现

2.1.1 引入jar包
<dependency>
  <groupId>com.maxmind.geoip2</groupId>
  <artifactId>geoip2</artifactId>
  <version>2.8.1</version>
</dependency>
2.1.2 封装工具
/**
 * @author: jiangjs
 * @description:
 * @date: 2022/5/23 15:12
 **/
public class GeoLiteUtil {

    public static final Logger log = LoggerFactory.getLogger(GeoLiteUtil.class);

    /**
     * 获取ip所在国家
     * @param ip 需查询的IP
     * @return 返回查询结果
     * @throws UnknownHostException 异常
     */
    private static String getCountry(String ip) throws Exception {
        DatabaseReader reader = getDatabaseReader();
        return Objects.nonNull(reader) ? reader.city(InetAddress.getByName(ip)).getCountry().getNames().get("zh-CN") : "";
    }

    /**
     * 获取ip所在省份
     * @param ip 需查询的IP
     * @return 返回查询结果
     * @throws UnknownHostException 异常
     */
    private static String getProvince(String ip) throws Exception {
        DatabaseReader reader = getDatabaseReader();
        return Objects.nonNull(reader) ? reader.city(InetAddress.getByName(ip)).getMostSpecificSubdivision().getNames().get("zh-CN") : "";

    }

    /**
     * 获取ip所在市
     * @param ip 需查询的IP
     * @return 返回查询结果
     * @throws UnknownHostException 异常
     */
    private static String getCity(String ip) throws Exception {
        DatabaseReader reader = getDatabaseReader();
        return Objects.nonNull(reader) ? reader.city(InetAddress.getByName(ip)).getCity().getNames().get("zh-CN") : "";
    }

    /**
     * 获取ip所在经纬度
     * @param ip 需查询的IP
     * @return 返回查询结果
     * @throws UnknownHostException 异常
     */
    private static JSONObject getLongitudeAndLatitude (String ip) throws Exception {
        DatabaseReader reader = getDatabaseReader();
        JSONObject resJson = new JSONObject();
        resJson.put("latitude",0d);
        resJson.put("longitude",0d);
        if (Objects.nonNull(reader)){
            //获取纬度信息
            Double latitude = reader.city(InetAddress.getByName(ip)).getLocation().getLatitude();
            //获取经度信息
            Double longitude = reader.city(InetAddress.getByName(ip)).getLocation().getLongitude();
            resJson.put("latitude",latitude);
            resJson.put("longitude",longitude);
        }
        return resJson;
    }

    private static DatabaseReader getDatabaseReader(){
        InputStream stream = null;
        try {
            stream = GeoLiteUtil.class.getClassLoader().getResourceAsStream("static/geo/GeoLite2-City.mmdb");
            return new DatabaseReader.Builder(stream).build();
        }catch (Exception e){
            e.printStackTrace();
            log.error("获取geolite2数据库报错:{}",e.getMessage());
        }finally {
            try {
                if (Objects.nonNull(stream)){
                    stream.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 根据Ip获取归属信息
     * @param ip 用户Ip
     * @return 返回查询结果
     * @throws Exception 异常
     */
    public static JSONObject getIpToAddress(String ip) throws Exception {
        StringJoiner address = new StringJoiner(",");
        address.add(getCountry(ip));
        address.add(getProvince(ip));
        address.add(getCity(ip));
        JSONObject resJson = GeoLiteUtil.getLongitudeAndLatitude(ip);
        resJson.put("address",String.valueOf(address));
        return resJson;
    }
}

getDatabaseReader() :读取本地的GeoLite2-City.mmdb并创建DatabaseReader对象。后续使用这个对象来根据Ip读取国家、省级、市级、经纬度等信息。

2.2 测试

测试也跟ip2region一样,提供两个方法,一个测试内网,一个传递外网进行测试。

@RestController
@RequestMapping("/change/ip")
public class GeoIpChangeController {

    @Resource
    private GeoIpChangeService geoIpChangeService;
    @GetMapping("/getIpAddress.do/{ip}")
    public ResultUtil<JSONObject> getIpAddress(@PathVariable("ip") String ip, HttpServletRequest request){
        try {
            return ResultUtil.success(GeoLiteUtil.getIpToAddress(ip));
        }catch (Exception e){
            e.printStackTrace();
        }
        return ResultUtil.error("获取ip对应地址等信息报错");
    }

    @GetMapping("/getLocationIpAddress.do")
    public ResultUtil<JSONObject> getLocationIpAddress( HttpServletRequest request){
        String userIp = GetUserIP.getUserIpAddress();
        try {
            return ResultUtil.success(GeoLiteUtil.getIpToAddress(userIp));
        }catch (Exception e){
            e.printStackTrace();
        }
        return ResultUtil.error("获取ip对应地址等信息报错");
    }
}

直接在浏览器上进行访问:

1、直接访问

SpringBoot通过ip获取归属地,你应该知道的几种方式。,spring boot,tcp/ip,后端

SpringBoot通过ip获取归属地,你应该知道的几种方式。,spring boot,tcp/ip,后端

2、通过外网查询的IP

SpringBoot通过ip获取归属地,你应该知道的几种方式。,spring boot,tcp/ip,后端

通过测试的结果我们可以看到,在解析内网ip时直接报错,提示数据库中没有这个ip。而通过外网地址就能够正常的解析出地址。

3、页面抓取

网络上有很多这种根据ip查询归属地的网站,因此我们可以通过调用其接口,通过返回页面来抓取归属地信息。例如:我们常用的ip138就有可以抓取到。

抓取页面就需要解析页面,解析页面我们可以使用jsoup。

3.1 引入jar包

<dependency>
  <groupId>org.jsoup</groupId>
  <artifactId>jsoup</artifactId>
  <version>1.15.2</version>
</dependency>

3.2 封装方法

/**
 * @author: jiangjs
 * @description:
 * @date: 2023/9/20 16:12
 **/
public class Ip138ChangeUtil {

    private static final String URL = "http://www.ip138.com/iplookup.asp?ip=";
    private static final Logger log = LoggerFactory.getLogger(Ip138ChangeUtil.class);
    public static JSONObject getIpToAddress(String ip) throws IOException {
        JSONObject resJson = new JSONObject();
        Document document = Jsoup.connect(URL + ip + "&action=2").get();
        Elements es = document.select("script").eq(1);
        for (Element e : es) {
            String[] data = e.data().split("var");
            for (String variable : data) {
                if (variable.contains("=") && variable.contains("ip_result")){
                    String[] va = StringUtils.split(variable, "=");
                    String value = va[1].trim().substring(0,va[1].trim().length() - 1);
                    JSONObject object = JSONObject.parseObject(value);
                    log.info(String.format("获取到的数据值:%s",value));
                    resJson.put("address", object.getString("ASN归属地"));
                }
            }
        }
        return resJson;
    }
}

工具类中通过访问地址获取到Document对象,然后在进行解析,从而拿到归属地信息。

3.3 测试

@RestController
@RequestMapping("/ip138")
public class Ip138ChangeController {
    @GetMapping("/getIpToAddress.do/{ip}")
    public ResultUtil<JSONObject> getIpToAddress(@PathVariable("ip") String ip){
        try {
            return ResultUtil.success(Ip138ChangeUtil.getIpToAddress(ip));
        } catch (IOException e) {
            e.printStackTrace();
            return ResultUtil.error("查询失败");
        }
    }
}

直接访问地址:

SpringBoot通过ip获取归属地,你应该知道的几种方式。,spring boot,tcp/ip,后端

从结果来看,其可以精确到区的。

【总结】

上述中介绍了三种通过Ip获取归属地的方法,相比较而言:

ip2region相对用的比较多,很多博客、技术文档都会进行介绍,而且封装使用也比较简单,执行速度也比较快;

geoip2:相对比较细,可以根据需求直接获取国家,省级等信息,但是伴随的就是封装稍微复杂点,而且在解析内网时,由于数据库中没有对应ip而报错。

页面抓取:这个就不推荐了,毕竟依赖于第三方,如果服务挂了的话就没法使用了。

至于选择ip2region还是geoip2,这个就要看具体的也无需求。

对了,ip2region和geoip2要去经常更新库哦。

好了,今天就跟大家叨叨到这,谢谢大家。

码云地址:https://gitee.com/lovequeena/iptoaddress.git文章来源地址https://www.toymoban.com/news/detail-845125.html

到了这里,关于SpringBoot通过ip获取归属地,你应该知道的几种方式。的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Java获取IP及归属地

    Java获取IP及归属地

    最近我们发现各大社交平台都出现了一个新的功能:IP属地。 比如某乎: 这个IP属地是怎么做到的呢?今天我来教教你,保证你看完直呼Easy~ 1.Java网络编程 2.Servlet 通过运行这个方法,可以看到,控制台打印了IP和城市信息,也就是我们想要的 IP属地信息 啦! 在你的项目里,

    2024年02月11日
    浏览(35)
  • java获取ip地址以及ip归属地工具类

    java获取ip地址以及ip归属地工具类

    需要ip2region.db文件,可以前往github下载 欢迎访问我的博客网站: www.yqiu.top

    2024年02月22日
    浏览(7)
  • Java根据IP地址获取对应归属地

    Java根据IP地址获取对应归属地

    最近,各大平台都新增了评论区显示发言者ip归属地的功能,例如哔哩哔哩,微博,知乎等等,下面,就来讲讲,Java 中是如何获取 IP 属地的 在Java中有多种获取IP地址的方式,就不一一介绍了,给出了一个最常用的IP地址获取方式,仅供参考,代码如下: 对这里出现的几个名词解释

    2023年04月24日
    浏览(7)
  • k8s~你应该知道的ip和你应该知道的端口

    k8s~你应该知道的ip和你应该知道的端口

    Node IP Cluster IP Pod IP Container IP node ip是指k8s节点的ip地址,这个ip是具体的服务器,它上面的端口是node port,是真实服务器上的端口。 在 Kubernetes 中,ClusterIP 是指 Service 类型中的一种,它为集群内部的其他资源提供了一个虚拟 IP 地址。这个虚拟 IP 只在集群内部可见,用于将请

    2024年02月04日
    浏览(5)
  • 使用 ip2region 获取用户的 IP 归属地

    使用 ip2region 获取用户的 IP 归属地

    ip2region 是一个离线IP地址定位库和IP定位数据管理框架,能实现10微秒级别的查询效率,提供了众多主流编程语言的xdb数据生成和查询客户端实现。 每个 ip 数据段的 region 信息都固定了格式: 国家|区域|省份|城市|ISP ,只有中国的数据绝大部分精确到了城市,其他国家部分数

    2024年02月13日
    浏览(8)
  • 知道一个服务器IP应该怎么进入

    知道一个服务器IP应该怎么进入

    首先我是国内,访问国外的网站比如谷歌等,访问特别慢,有时候甚至登录不进去。 现在知道了一个台湾或者国外的服务器应该怎么登录进去呢? 知道服务器IP之后,你还需要知道服务器的远程端口+帐号+密码才能登录的。 知道上面信息之后,大家可以在本地电脑试试。 通

    2024年02月04日
    浏览(7)
  • SpringBoot如何通过Nginx代理获取真实IP

    springboot作为后台代码,获取到的登录IP是前台的代理服务器地址,并不是用户的真实IP地址,让我们在做统计的时候无从下手。下面是一个后台获取IP地址的类,本质上没有什么问题,问题在于,Nginx给你的就是一个代理之后的地址,所以你当然获取不到真实的地址了。 那么如

    2024年01月17日
    浏览(37)
  • Mysql数据库--修改root密码的几种方法(忘记密码&知道密码)

    Mysql数据库--修改root密码的几种方法(忘记密码&知道密码)

    🍁 通过 alter user root identified by \\\'新密码\\\'; 🍁 通过 set password for 用户名@\\\'用户地址\\\' = \\\'新密码\\\'; 2.1.1 🎈 停止mysql服务 2.1.2 🎈 创建mysql-init-file.txt文件 2.1.3 🎈 init-file的权限(最好赋权一下) 2.1.3 🎈 使用–init-file选项启动mysql服务 2.1.4 🎈 新密码连接测试(密码:Zyl@123321)

    2024年02月08日
    浏览(40)
  • vue获取当前路由的几种方式

    第一种 第二种 通过getCurrentInstance 获取当前的组件实例,从而通过其获取router,然后胡德当前路由地址 第三种 第四种 第五种

    2024年02月13日
    浏览(7)
  • 快速查看本机公网IP的几种方法

    快速查看本机公网IP的几种方法

    链接: https://ifconfig.me/ 命令行 链接: https://ifconfig.io/ 命令行 链接:https://ifconfig.co/ 命令行 链接:https://ipinfo.io/ 命令行 【完】

    2024年02月11日
    浏览(9)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包