IP属地信息哪里来的?手把手教你实现通过IP查询属地信息
本文主要讲解IP查询属地信息的实现方法,以及基于Spring Boot实现IP属地信息查询项目。
〇、前言
近日,多个网络公众平台纷纷公开显示用户的IP属地
,并且用户无法开启或关闭此功能。
用户的IP信息,平台是怎么知道的?
其大致流程是这样的:
用户
的手机、电脑等设备必须通过网络运营商(电信、移动等)进行联网服务,这个连接网络的过程中,基站、路由器将为该设备动态分配一个IP
;用户
发布一篇文章或微博,或者进行评论时,就会向平台服务器
发送一个HTTP请求
。而IP
信息,就包含在这个HTTP请求头
里;平台服务器
接收到请求信息,就可以通过HTTP请求(Request请求)
信息解析出该用户的IP
。
在这个过程中,请求信息
只包含IP
,并不包含用户的属地信息
。
另外,对于交互式平台
来说,《互联网交互式服务安全管理要求》(GA 1277.1-2020)的第1部分 基本要求
的第8.3条 日志与用户数据记录
明确,平台必须记录用户的活动、信息发布等操作的IP地址及源端口
。详见:http://www.beian.gov.cn/portal/downloadcenter 。
平台如何通过IP查询到属地信息?
一种方案是请求第三方IP属地信息服务
的API,通过该接口查询用户的IP属地信息
。但这种方案通常是按量付费
的,大的平台请求量巨大,不划算。
另外一种方案是使用离线的IP地址数据库
,该数据库通常是一个文件,甚至可能是cvs
文件、txt
文件。
该数据库一般是由专业人士通过专业技术人工生成,其中记录了大量的IP地址(段)
,并记录了该IP地址(段)
所属的国家
、省份
、城市
、运营商名称
、邮政编码
、经纬度
等信息。
接下来,将基于Java
和MaxMind
的IP地址数据库
,讲解如何实现通过IP获取属地信息
。
一、下载IP地址库
提供离线IP地址数据库
的平台有很多,比如:
- http://www.ipip.net
- https://user.ip138.com/ip/lib/
这些平台通常是付费
的,价格不菲。不过也有平台提供免费
版,比如:
- https://www.maxmind.com/en/geoip2-services-and-databases
MaxMind
平台提供的IP地址数据库
有免费
和付费
两种版本。
虽然免费版更新比较慢,但对于精确度不高的项目来说,够用。
MaxMind
的免费版IP地址数据库
叫做GeoLite2
,其下载方式如下。
1、注册并登录账号
访问如下地址,注册平台账号;
- https://www.maxmind.com/en/geolite2/signup
访问如下地址,登录账号;
- https://www.maxmind.com/en/account/login
登录成功后进入如下页面:
2、下载IP地址数据库
访问左侧的Download Files
按钮,进入IP地址数据库
下载页面,如下图所示:
我们选择精确到City
的免费版mmdb
格式的IP地址数据库
文件,并下载。
下载完成后是一个压缩包,打开即可看到mmdb
格式的数据库文件。
mmdb
即MaxMind Database
,是MaxMind
设计的一种用于存储IP地址数据信息的数据库,其采用二分查找树来加速IP信息的查询。
二、IP地址数据库的简单使用
根据MaxMind
的开发文档,该数据库的使用方法很简单,一共分两步:
1、导入依赖包
<dependency><groupId>com.maxmind.geoip2</groupId><artifactId>geoip2</artifactId><version>2.16.1</version>
</dependency>
2、配置并查询
File database = new File("/path/to/maxmind-database.mmdb")// This reader object should be reused across lookups as creation of it is expensive.
// 译:这个reader对象应该在整个查找中重用,因为创建它的成本很高。
DatabaseReader reader = new DatabaseReader.Builder(database).build();// If you want to use caching at the cost of a small (~2MB) memory overhead:
// 译:如果要以较小的内存开销(约2MB)为代价使用缓存,请执行以下操作:
// new DatabaseReader.Builder(file).withCache(new CHMCache()).build();InetAddress ipAddress = InetAddress.getByName("128.101.101.101");CityResponse response = reader.city(ipAddress);Country country = response.getCountry();
System.out.println(country.getIsoCode());
详情:https://dev.maxmind.com/geoip/geolocate-an-ip/databases
三、Spring Boot中使用IP地址库
以下代码只展示关键部分。完整代码详见后文。
1、创建Spring Boot项目
创建完成的Spring Boot项目目录结构,如下图所示。
其中,将下载的IP地址数据库
文件,放在resources文件夹
中的mmdb目录
下。
2、导入依赖
在pom.xml
文件中,导入如下依赖。
<!-- GeoIp2的依赖 -->
<dependency><groupId>com.maxmind.geoip2</groupId><artifactId>geoip2</artifactId><version>2.16.1</version>
</dependency>
3、创建IP属地信息实体
在entity包
下,新建一个名为Ip2CityEntity
的实体,用来保存查询后的IP属地信息
。
代码如下,逻辑见注释。
package com.zxdmy.tool.entity;import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;import java.io.Serializable;/*** IP属地信息实体类** @author 拾年之璐* @since 2022/5/1 13:24*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
public class Ip2CityEntity implements Serializable {private static final long serialVersionUID = 1L;/*** IP地址*/private String ip;/*** 国家名称*/private String country;/*** 省份名称*/private String province;/*** 城市名称*/private String city;/*** 经度*/private Double longitude;/*** 维度*/private Double latitude;/*** 查询耗时*/private String cost;
}
4、创建并实现查询工具类
在utils包
中,新建名为GeoIPUtils
的工具类,实现通过IP查询属地信息功能
方法。
详细代码如下所示,具体逻辑见注释。
package com.zxdmy.tool.utils;import com.maxmind.db.CHMCache;
import com.maxmind.geoip2.DatabaseReader;
import com.maxmind.geoip2.model.CityResponse;
import com.maxmind.geoip2.record.*;
import com.zxdmy.tool.entity.Ip2CityEntity;import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;/*** GeoIP数据库操作工具类** @author 拾年之璐* @since 2022/5/1 12:53*/
public class GeoIPUtils {/*** 数据库文件所在的路径(resources文件内)*/private static final String mmdbPath = "mmdb/GeoLite2-City.mmdb";/*** 设置返回的语言:简体中文*/private static final String CHS = "zh-CN";/*** 读取resources文件中的静态数据库*/private static final InputStream mmdbStream = GeoIPUtils.class.getClassLoader().getResourceAsStream(mmdbPath);/*** 数据库加载器,全局静态,只加载一次*/private static DatabaseReader databaseReader;// 静态代码块,初始化时执行一次static {try {databaseReader = new DatabaseReader.Builder(mmdbStream).withCache(new CHMCache()).build();} catch (IOException e) {e.printStackTrace();}}/*** 通过IP查询地址信息** @param ip IP地址* @return 城市地址信息*/public static Ip2CityEntity getIpInfo(String ip) {Ip2CityEntity ip2CityEntity = new Ip2CityEntity();try {// 获取主机的IP(IP可以是域名)InetAddress inetAddress = InetAddress.getByName(ip);// 通过数据库查询该IP的信息CityResponse response = databaseReader.city(inetAddress);// 解析国家String countryName = response.getCountry().getNames().get(CHS);// 解析二级分支(一般是省份)String provinceName = response.getMostSpecificSubdivision().getNames().get(CHS);// 解析城市String cityName = response.getCity().getNames().get(CHS);// 解析坐标Location location = response.getLocation();// 写入实体ip2CityEntity.setIp(ip).setCountry(countryName).setProvince(provinceName).setCity(cityName)// 经度.setLatitude(location.getLatitude())// 维度.setLongitude(location.getLongitude());} catch (Exception e) {System.out.println(e.getMessage());return null;}return ip2CityEntity;}}
5、调用工具类实现具体业务
接下来就可以在控制类
、服务类
或切面
等场景中,根据实际业务需求,调用GeoIPUtils工具类
中的通过IP查询属地信息
静态方法,获取某个IP
的属地信息。
下面是一种使用实例。
package com.zxdmy.tool.controller;import com.zxdmy.tool.entity.Ip2CityEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;import static com.zxdmy.tool.utils.GeoIPUtils.getIpInfo;/*** 请求查询的控制器** @author 拾年之璐* @since 2022/5/1 17:19*/
@Controller
public class IPController {/*** 请求的入口** @param ip IP地址* @return 查询结果*/@GetMapping({"query"})@ResponseBodypublic Ip2CityEntity index(@RequestParam(name = "ip", required = false) String ip) {// 请求的开始时间long start = System.currentTimeMillis();// 查询结果Ip2CityEntity ip2CityEntity = getIpInfo(ip);// 判断查询结果if (null != ip2CityEntity) {// 写入查询耗时ip2CityEntity.setCost(System.currentTimeMillis() - start + " ms");}// 返回return ip2CityEntity;}
}
四、结果演示与源码下载
在作者的演示项目
中,控制类
的实现方法如下图所示,查询返回的是JSON数据
。
4.1 线上演示
注:
线上演示
项目不提供长久服务,随时下线。若无法访问,请使用本地演示
。
直接访问演示项目
的主页将查询访问者的IP属地信息
。
主页连接(点击可访问):
- http://ip.tool.zxdmy.com
访问结果如下图所示。
如果通过Get方式
传入IP参数
,则将查询该IP的属地信息
。
访问格式如下:
- http://ip.tool.zxdmy.com/?ip=114.44.227.87
访问结果如下图所示。
4.2 本地演示
本地演示前,请先保证本机有
JDK 1.8
环境。
访问如下链接,即可下载演示项目的jar包
。
https://download.csdn.net/download/cxh_1231/85259992
使用如下命令运行jar包
即可启动项目
java -jar Ip2CityDemo-1.1.jar
详情如下图所示。
关闭该CMD命令行窗口
,即结束项目。
4.3 源码下载
请访问如下链接下载。
https://download.csdn.net/download/cxh_1231/85259992
— End —
IP属地信息哪里来的?手把手教你实现通过IP查询属地信息相关推荐
- 手把手教你实现显示IP归属地
手把手教你实现显示IP归属地 实现原理 获取IP地址 调用IP归属地接口: 近年来,根据<国家互联网用户账号名称信息管理规定>要求互联网用户账号服务平台标注IP地址属地信息,微信公众号.抖 ...
- mysql sql注入怎么获取数据_手把手教你通过SQL注入盗取数据库信息
目录数据库结构 注入示例判断共有多少字段 判断字段的显示位置 显示登录用户和数据库名 获取所有数据库名 获取对应数据库的表 获取对应表的字段 获取所有的用户密码 我们都是善良的银!一生戎码只为行侠仗义 ...
- NAS如何外网访问?手把手教你申请公网IP(收藏)
上次的那篇NAS的文章有着很不错的热度,首先是感谢观众老爷们的大力支持啦,那么这篇文章主要是回答一些评论中的问题,而且也为那些第一次接触NAS的小伙伴提供一个简单的参考,如果对这方面想有所了解的,请耐 ...
- 用计算机配置打印机IP,网络打印机怎么设置ip(手把手教你设置打印机IP地址)...
如何设置打印机IP地址,是一个长期以来困好多小伙伴的一个问题,那今天我们就以 HP Laserjet Pro 100 MFP M128系列打印机为例,为大家介绍一下打印机IP地址的设置方法~ 步骤一: ...
- python字典输入学生信息_用Python创建一个学生字典并可以查询其中信息
展开全部 你可以试试这个---------------------------------------------------------- # -*- coding:UTF-8 -*- studen ...
- java学生签到系统视频教程_手把手教你做一个Java web学生信息、选课、签到考勤、成绩管理系统附带完整源码及视频开发教程...
四个阶段的Java web学生信息系统视频教程终于录制完成了,系统用到的知识点有:jsp+servlet+mysql+jquery+ajax,前端采用的是当下最流行的easyui管理框架,全部采用面向 ...
- 手把手教你利用Java获取图片GPS信息
你知道的越多,不知道的就越多,业余的像一棵小草! 成功路上并不拥挤,因为坚持的人不多. 编辑:业余草 推荐:https://www.xttblog.com/?p=5251 一张图片能包含很多敏感信息, ...
- 【Python实战】爬虫教程千千万,一到实战全完蛋?今天手把手教你一键采集某网站图书信息数据啦~排名第一的竟是...(爬虫+数据可视化)
前言 一本本书,是一扇扇窗,为追求知识的人打开认知世界的窗口 一本本书,是一双双翅膀,让追求理想的人张开翅膀翱翔 所有文章完整的素材+源码都在
- 手把手教你JavaEE的分页查询、分页展示,有了这个,你的项目又多了一个谈资
前言: 我们在写项目的时候,往往有一些项目的信息展示.而展示的数据量往往是很大的,这时候,加入一个分页的功能往往是最理想的选择. 先简单描述一下功能: 根据你的数据量和指定的页面展示数据条数,进行查询 ...
- 隐藏表白技能,python教你如何使用图片exif信息隐藏表白,教你如何修改,查询exif信息。
" 隐藏表白技能" 你有想过一张图片所包含的信息吗?你有想过一张图片可以为你隐藏表达一些内容吗?你有想过图片的隐藏信息可以为你表达你想要说明的东西吗?以及你可以 用图片去表达你的爱 ...
最新文章
- atitit. java jsoup html table的读取解析 总结
- Android中Sharedpreferences牵涉到跨进程时不能实时读取的问题
- html股票数据代码,股票数据的网站抓取(4.2)代码优化
- Spring Boot EasyPoi导出Excel下载
- Google比Baidu快(发一个无聊的帖)
- 小鹏汽车北京车展发布免费加电、电池租赁计划以及低空飞行汽车
- Git GUI,Git Bash,Git CMD标签之间的区别
- EC600S-CN CAT1通信模组,2G退网升级4G如何选择,QuecPython开发资源下载
- java踩坑记-getResourceAsStream
- 修复被破坏了的linux文件系统分区表,修复被破坏了的linux文件系统分区表
- MarkDown在VSCode环境下使用
- swper 实现滑动切换功能的两种方式
- 关于O(log2n)的个人理解
- 数字信号处理(3)- z变换
- 客户满意度测评模型-层次分析法模型」
- 基于FPGA的数字秒表设计(含程序)
- 软件测试物理机环境基础
- Windows10最优设置
- 区块链--拜占庭将军问题--区块链
- 2021-08-10校网比赛C题