Java 中是如何获取 IP 属地的
细心的小伙伴可能会发现,抖音新上线了 IP 属地的功能,小伙伴在发表动态、发表评论以及聊天的时候,都会显示自己的 IP 属地信息
下面,我就来讲讲,Java 中是如何获取 IP 属地的,主要分为以下几步
通过 HttpServletRequest 对象,获取用户的 IP 地址
通过 IP 地址,获取对应的省份、城市
首先需要写一个 IP 获取的工具类,因为每一次用户的 Request 请求,都会携带上请求的 IP 地址放到请求头中。
public class IpUtil {public static String getIpAddr(ServerHttpRequest request) {HttpHeaders headers = request.getHeaders();String ipAddress = headers.getFirst("X-Forwarded-For");if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = headers.getFirst("Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = headers.getFirst("WL-Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getRemoteAddress().getAddress().getHostAddress();if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {// 根据网卡取本机配置的IPtry {InetAddress inet = InetAddress.getLocalHost();ipAddress = inet.getHostAddress();} catch (UnknownHostException e) {log.error("根据网卡获取本机配置的IP异常", e);}}}// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割if (ipAddress != null && ipAddress.indexOf(",") > 0) {ipAddress = ipAddress.split(",")[0];}return ipAddress;}
}
这里有三个名词,分别是
X-Forwarded-For:一个 HTTP 扩展头部,主要是为了让 Web 服务器获取访问用户的真实 IP 地址。每个 IP 地址,每个值通过逗号+空格分开,最左边是最原始客户端的 IP 地址,中间如果有多层代理,每⼀层代理会将连接它的客户端 IP 追加在 X-Forwarded-For 右边。
X-Real-IP:一般只记录真实发出请求的客户端IP
Proxy-Client-IP:这个一般是经过 Apache http 服务器的请求才会有,用 Apache http 做代理时一般会加上 Proxy-Client-IP 请求头
WL-Proxy-Client-IP:也是通过 Apache http 服务器,在 weblogic 插件加上的头。
在我们获取到用户的 IP 地址后,那么就可以获取对应的 ip 信息了
我在 Github 冲浪的时候,发现了 Ip2region 项目。
一个准确率 99.9% 的离线 IP 地址定位库,0.0x 毫秒级查询,ip2region.db 数据库只有数 MB,提供了 java,php,c,python,nodejs,golang,c# 等查询绑定和Binary,B树,内存三种查询算法。
数据聚合了一些知名 ip 到地名查询提供商的数据,这些是他们官方的的准确率,经测试着实比经典的纯真 IP 定位准确一些。ip2region 的数据聚合自以下服务商的开放 API 或者数据。
80%, 淘宝IP地址库, http://ip.taobao.com/
≈10%, GeoIP, https://geoip.com/
≈2%, 纯真IP库, http://www.cz88.net/
备注:如果上述开放API或者数据都不给开放数据时ip2region将停止数据的更新服务。
每条 ip 数据段都固定了格式:
_城市Id|国家|区域|省份|城市|ISP_
只有中国的数据精确到了城市,其他国家有部分数据只能定位到国家,后前的选项全部是 0,已经包含了全部你能查到的大大小小的国家
生成的数据库文件 ip2region.db 只有几 MB,最小的版本只有 1.5MB,随着数据的详细度增加数据库的大小也慢慢增大,目前还没超过 8MB。
内置的三种查询算法
全部的查询客户端单次查询都在 0.x 毫秒级别,内置了三种查询算法
memory 算法:整个数据库全部载入内存,单次查询都在0.1x毫秒内,C语言的客户端单次查询在0.00x毫秒级别。
binary 算法:基于二分查找,基于ip2region.db文件,不需要载入内存,单次查询在0.x毫秒级别。
b-tree 算法:基于btree算法,基于ip2region.db文件,不需要载入内存,单词查询在0.x毫秒级别,比binary算法更快。
ip2region安装
下面,就让我们给项目引入 ip2region,进行 ip 信息转换吧
首先引入 maven 依赖
<dependency><groupId>org.lionsoul</groupId><artifactId>ip2region</artifactId><version>1.7.2</version>
</dependency>
然后编写一个工具类 IpUtils ,首先需要加载 ip2region.db 文件
static {dbPath = createFtlFileByFtlArray() + "ip2region.db";try {config = new DbConfig();} catch (DbMakerConfigException e) {e.printStackTrace();}try {searcher = new DbSearcher(config, dbPath);} catch (FileNotFoundException e) {e.printStackTrace();}
}
在加载的时候,需要下载仓库中的 ip2region.db 文件,然后放到 resource 目录下
然后,通过内置的三种算法,分别转换用户 ip 地址
public static String getCityInfo(String ip) {if (StringUtils.isEmpty(dbPath)) {log.error("Error: Invalid ip2region.db file");return null;}if(config == null || searcher == null){log.error("Error: DbSearcher or DbConfig is null");return null;}//查询算法//B-tree, B树搜索(更快)int algorithm = DbSearcher.BTREE_ALGORITHM;//Binary,使用二分搜索//DbSearcher.BINARY_ALGORITHM//Memory,加载内存(最快)//DbSearcher.MEMORY_ALGORITYMtry {// 使用静态代码块,减少文件读取操作
// DbConfig config = new DbConfig();
// DbSearcher searcher = new DbSearcher(config, dbPath);//define the methodMethod method = null;switch (algorithm) {case DbSearcher.BTREE_ALGORITHM:method = searcher.getClass().getMethod("btreeSearch", String.class);break;case DbSearcher.BINARY_ALGORITHM:method = searcher.getClass().getMethod("binarySearch", String.class);break;case DbSearcher.MEMORY_ALGORITYM:method = searcher.getClass().getMethod("memorySearch", String.class);break;default:}DataBlock dataBlock = null;if (Util.isIpAddress(ip) == false) {System.out.println("Error: Invalid ip address");}dataBlock = (DataBlock) method.invoke(searcher, ip);String ipInfo = dataBlock.getRegion();if (!StringUtils.isEmpty(ipInfo)) {ipInfo = ipInfo.replace("|0", "");ipInfo = ipInfo.replace("0|", "");}return ipInfo;} catch (Exception e) {e.printStackTrace();}return null;}
下面,我们编写 main 函数进行测试,发现可以正常的解析出 ip 信息
由于 ip 属地在国内的话,只会展示省份,而国外的话,只会展示国家。所以我们还需要对这个方法进行一下封装,得到获取 IP 属地的信息。
/*** 获取IP属地* @param ip* @return*/
public static String getIpPossession(String ip) {String cityInfo = getCityInfo(ip);if (!StringUtils.isEmpty(cityInfo)) {cityInfo = cityInfo.replace("|", " ");String[] cityList = cityInfo.split(" ");if (cityList.length > 0) {// 国内的显示到具体的省if ("中国".equals(cityList[0])) {if (cityList.length > 1) {return cityList[1];}}// 国外显示到国家return cityList[0];}}return "未知";
}
下面,我们在找一个 国外的 IP 测试一下效果。可以看到已经能够正常的显示 IP 属地信息了~
到这里如果获取用户的 IP 属地已经完成啦,如果想要了解关于更多 ip2region 的功能,欢迎访问其 Github 地址进行学习。
项目地址
https://github.com/lionsoul2014/ip2region
码文不易,学到的小伙伴点一点关注哦,一键三连加收藏哦!!!
有不懂的小伙伴可以加下我的微信,我们私底下悄悄内卷~~~
Java 中是如何获取 IP 属地的相关推荐
- java中如何做展示 IP 属地的功能(至尊典藏版)
目录 前言 1.HttpServletRequest 获取 IP 2.Ip2region 3.99.9%准确率 4.多查询客户端的支持 5.Ip2region V2.0 特性 6.ip2region ...
- Java如何获取IP属地 ip2region failed to create searcher with x:java.io.FileNotFoundException:( 系统找不到指定的路径)
目录 引言 获取ip地址 使用ServerHttpRequest获取ip完整地址: 获取ip地址的源代码 接口调用源代码 使用HttpServletRequest获取ip完整地址 获取ip地址的源代码 ...
- Java 通过Request请求获取IP地址
Java 通过Request请求获取IP地址 项目需要将不同省份的用户,展示不同内容,所以需要通过Request请求获取IP地址. 先来贴代码, 如果你要在生产环境使用就直接拿去用吧,我这边已经上线了 ...
- 服务器怎么把信息发送给用户,java中怎么用tcp/ip将服务器的消息发送给多个用户...
java中怎么用tcp/ip将服务器的消息发送给多个用户 关注:253 答案:2 mip版 解决时间 2021-01-31 01:26 提问者╬═掵中注定 2021-01-30 20:03 jav ...
- Java 中几种获取文件路径的方式
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源 | 公众号「码农小胖哥」 1. 前言 Java 开 ...
- java中nonce_java如何获取微信timestamp,nonceStr,signature参数
java如何获取微信timestamp,nonceStr,signature参数 发布时间:2021-01-18 11:46:12 来源:亿速云 阅读:57 作者:小新 这篇文章主要介绍java如何获 ...
- java获取列族的列_在cassandra-cli中如何获取表中的所有列名以及如何在java中使用hector获取它?...
我正在尝试获取列名,但无法获得仅列名称. 在cli我执行命令描述表节点,它返回结果: CREATE TABLE nodes ( key text PRIMARY KEY, id text, score ...
- Socket中EndPoint只获取ip,不要port
EndPoint包含了ip和port,但是只想要获取ip,只能先把EndPoint转为IpEndPoint,然后从IpEndPoint中可以获取ip.具体如下: //EndPoint endPoint ...
- 关于JAVA中使用nbtstat获取地址报错
在JAVA后台想要通过ip地址获得局域网内客户机的MAC地址 最初也是从网上找的例子,用到这条语句: Process process = Runtime.getRuntime().exec(" ...
最新文章
- controll层跳转页面_SpringMVC controller控制页面跳转 | 学步园
- 使用Nginx+Lua(OpenResty)开发高性能Web应用
- android 摄像头参数,获取Android设备上的详细的摄像头信息
- 如何检测链表中是存在循环
- 基于Sql Server 2008的分布式数据库的实践
- Serializer字段和选项
- Git 存储原理及相关实现
- 面试官系统精讲Java源码及大厂真题 - 08 HashMap 源码解析
- 存储过程与触发器的区别
- 为linux添加新字体
- gtk_widget_modify_bg的用法
- JavaScript:在JS中截取字符串的方法
- zk框架实现zul的js代码调用服务器java命令
- html下播放.wav,wav格式文件用什么播放
- 《江村经济》读书摘记
- 互联网家装,风口下飞不起来的“猪”
- STK Components规格书
- 3.6 函数作图与渐近线
- 修改Jupyter Notebook文件默认保存路径
- 使用gcc编译STM32遇到的问题
热门文章
- 对皮肤美白算法的一些研究
- linux pl320 mbox控制器驱动分析-(3) pl320驱动代码分析
- JAVA中判断char是否是中文的几种方法
- 小孩厌学不想上学怎么办
- 联邦学习笔记—《Communication-Efficient Learning of Deep Networks from Decentralized Data》
- Bribe the Prisoners
- Stacked Denoising Autoencoders (SDAE)
- omron欧姆龙NJ NX程序 全自动锂电池二封机,主站NJ501-1400+威纶通触摸屏
- C生万物 | 窥探数组设计的种种陷阱
- Java宇layUi结合xm-select 实现复选框查询功能