Java-通过IP获取真实地址
文章目录
- 前言
- 功能实现
- 测试
前言
最近写了一个日志系统,需要通过访问的 IP 地址来获取真实的地址,并且存到数据库中,我也是在网上看了一些文章,遂即整理了一下供大家参考。
功能实现
这个是获取正确 IP 地址的方法,可以直接使用的。
public static final String UNKNOWN = "unknown";public static final String X_FORWARDED_FOR = "x-forwarded-for";public static final String PROXY_CLIENT_IP = "Proxy-Client-IP";public static final String WL_PROXY_CLIENT_IP = "WL-Proxy-Client-IP";public static final String HTTP_CLIENT_IP = "HTTP_CLIENT_IP";public static final String HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR";public static final String X_REAL_IP = "X-Real-IP";public static final String LOCAL_IP_V4 = "127.0.0.1";public static final String LOCAL_IP_V6 = "0:0:0:0:0:0:0:1";public static final String CDN_SRC_IP = "cdn-src-ip";/*** 获取 IP 地址*/public static String getIpAddress(ServerHttpRequest request) {HttpHeaders headers = request.getHeaders();String ip = headers.getFirst(X_FORWARDED_FOR);if (ip != null && ip.length() != 0 && !UNKNOWN.equalsIgnoreCase(ip)) {// 多次反向代理后会有多个ip值,第一个ip才是真实ipif (ip.contains(",")) {ip = ip.split(",")[0];}}if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = headers.getFirst(PROXY_CLIENT_IP);}if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = headers.getFirst(WL_PROXY_CLIENT_IP);}if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = headers.getFirst(HTTP_CLIENT_IP);}if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = headers.getFirst(HTTP_X_FORWARDED_FOR);}if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = headers.getFirst(X_REAL_IP);}if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = Objects.requireNonNull(request.getRemoteAddress()).getAddress().getHostAddress();if (ip.equals(LOCAL_IP_V4) || ip.equals(LOCAL_IP_V6)) {// 根据网卡取本机配置的IPInetAddress inet = null;try {inet = InetAddress.getLocalHost();ip = inet.getHostAddress();} catch (UnknownHostException e) {e.printStackTrace();}}}return ip;}/*** 获取请求IP.* @return String ip*/public static String getIpAddress(HttpServletRequest request) {String ip = null;Enumeration<?> enu = request.getHeaderNames();while (enu.hasMoreElements()) {String name = (String) enu.nextElement();if (CDN_SRC_IP.equalsIgnoreCase(name)|| X_FORWARDED_FOR.equalsIgnoreCase(name)|| PROXY_CLIENT_IP.equalsIgnoreCase(name)|| WL_PROXY_CLIENT_IP.equalsIgnoreCase(name)|| X_REAL_IP.equalsIgnoreCase(name)) {ip = request.getHeader(name);}if (org.apache.commons.lang3.StringUtils.isNotBlank(ip)){break;}}if (StringUtils.isBlank(ip)){ip = request.getRemoteAddr();}if (ip.equals(LOCAL_IP_V4) || ip.equals(LOCAL_IP_V6)) {// 根据网卡取本机配置的IPInetAddress inet = null;try {inet = InetAddress.getLocalHost();ip = inet.getHostAddress();} catch (UnknownHostException e) {e.printStackTrace();}}return ip;}
通过以上方法你可以获取到访问者的 IP 地址,只有获取到了 IP 地址,才能够拿到真实的地址
通过 IP 获取真实地址的方法有很多种,这里我只说两个:
- 方式一:离线 IP 地址定位查询
- 方式二:在线 IP 地址定位查询
方式一 我们需要在本地保存一个 IP 地址定位的文档,方式二就是通过 http 请求的方式访问一些可以查询 IP 地址所属地理位置的网址。
方式一就是查询比较快,但是有些地址可能查询不到,方式二就是基本上都能查到,但是要建立请求,会有点慢,所以将二者结合起来就行了。
导入依赖:
<!-- 离线IP地址定位库 --><dependency><groupId>org.lionsoul</groupId><artifactId>ip2region</artifactId><version>1.7.2</version></dependency><!-- ali地域 --><dependency><groupId>com.maxmind.geoip2</groupId><artifactId>geoip2</artifactId><version>2.6.0</version></dependency>
添加离线 IP 地址库:
在 src/main/resources
下新建 ip2region
复制文件 ip2region.db
到目录下
------------------ ip2region.db 资源下载 -----------------
链接:百度网盘
提取码:v7se
---------------------------------------------------------
添加工具类:
RegionUtil.java
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Objects;import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import org.lionsoul.ip2region.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;/*** 根据ip离线查询地址** @author ruoyi*/
public class RegionUtil {private static final Logger log = LoggerFactory.getLogger(RegionUtil.class);private static final String JAVA_TEMP_DIR = "java.io.tmpdir";static DbConfig config = null;static DbSearcher searcher = null;// 初始化IP库static {try {// 因为jar无法读取文件,复制创建临时文件String dbPath = Objects.requireNonNull(RegionUtil.class.getResource("/ip2region/ip2region.db")).getPath();File file = new File(dbPath);if (!file.exists()) {String tmpDir = System.getProperties().getProperty(JAVA_TEMP_DIR);dbPath = tmpDir + "ip2region.db";file = new File(dbPath);ClassPathResource cpr = new ClassPathResource("ip2region" + File.separator + "ip2region.db");InputStream resourceAsStream = cpr.getInputStream();FileUtils.copyInputStreamToFile(resourceAsStream, file);}config = new DbConfig();searcher = new DbSearcher(config, dbPath);log.info("bean [{}]", config);log.info("bean [{}]", searcher);} catch (Exception e) {log.error("init ip region error:{}", e.toString());}}/*** 解析IP** @param ip* @return*/public static String getRegion(String ip) {try {// dbif (searcher == null || StringUtils.isEmpty(ip)) {log.error("DbSearcher is null");return StringUtils.EMPTY;}long startTime = System.currentTimeMillis();// 查询算法Method method = searcher.getClass().getMethod("memorySearch", String.class);DataBlock dataBlock = null;if (!Util.isIpAddress(ip)) {log.warn("warning: Invalid ip address");}dataBlock = (DataBlock) method.invoke(searcher, ip);String result = dataBlock.getRegion();long endTime = System.currentTimeMillis();log.debug("region use time[{}] result[{}]", endTime - startTime, result);return result;} catch (Exception e) {log.error("error:{}", e.toString());}return StringUtils.EMPTY;}}
PureNetUtils.java
package com.mike.common.core.utils;import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;/*** 网络访问工具类*/
public class PureNetUtils {private static final Logger log = LoggerFactory.getLogger(PureNetUtils.class);/*** get方法直接调用post方法** @param url 网络地址* @return 返回网络数据*/public static String get(String url) {return post(url, null);}/*** 设定post方法获取网络资源,如果参数为null,实际上设定为get方法** @param url 网络地址* @param param 请求参数键值对* @return 返回读取数据*/public static String post(String url, Map<String, String> param) {HttpURLConnection conn = null;try {URL u = new URL(url);conn = (HttpURLConnection) u.openConnection();StringBuilder sb = null;if (param != null) {// 如果请求参数不为空sb = new StringBuilder();/** A URL connection can be used for input and/or output. Set the* DoOutput flag to true if you intend to use the URL connection* for output, false if not. The default is false.*/// 默认为false,post方法需要写入参数,设定trueconn.setDoOutput(true);// 设定post方法,默认getconn.setRequestMethod("POST");// 获得输出流OutputStream out = conn.getOutputStream();// 对输出流封装成高级输出流BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));// 将参数封装成键值对的形式for (Map.Entry<String, String> s : param.entrySet()) {sb.append(s.getKey()).append("=").append(s.getValue()).append("&");}// 将参数通过输出流写入writer.write(sb.deleteCharAt(sb.toString().length() - 1).toString());writer.close();// 一定要关闭,不然可能出现参数不全的错误sb = null;}conn.connect();// 建立连接sb = new StringBuilder();// 获取连接状态码int recode = conn.getResponseCode();BufferedReader reader = null;if (recode == 200) {// Returns an input stream that reads from this open connection// 从连接中获取输入流InputStream in = conn.getInputStream();// 对输入流进行封装reader = new BufferedReader(new InputStreamReader(in));String str = null;sb = new StringBuilder();// 从输入流中读取数据while ((str = reader.readLine()) != null) {sb.append(str).append(System.getProperty("line.separator"));}// 关闭输入流reader.close();if (sb.toString().length() == 0) {return null;}return sb.toString().substring(0,sb.toString().length() - System.getProperty("line.separator").length());}} catch (Exception e) {e.printStackTrace();return null;} finally {if (conn != null)// 关闭连接conn.disconnect();}return null;}/*** 获取 ip 所属地址** @param ip IP 地址* @return 所属地址*/public static String getAlibaba(String ip) {Map<String, String> map = new HashMap<>();map.put("ip", ip);map.put("accessKey", "alibaba-inc");String result = PureNetUtils.post("http://ip.taobao.com/outGetIpInfo", map);log.info("{} => POST: http://ip.taobao.com/outGetIpInfo || result: {}", ip, result);String address = null;if (StringUtils.isNotBlank(result)) {JSONObject jsonObject = JSONObject.parseObject(result);// 请求成功,解析响应数据if ("query success".equals(jsonObject.get("msg"))) {JSONObject dataMap = JSONObject.parseObject(jsonObject.getString("data"));String country = dataMap.getString("country");String region = dataMap.getString("region");String city = dataMap.getString("city");address = country + region + city;}}return address;}}
AddressUtils .java
import com.mike.common.core.utils.PureNetUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** 获取地址类** @author ruoyi*/
public class AddressUtils {private static final Logger log = LoggerFactory.getLogger(AddressUtils.class);// 未知地址public static final String UNKNOWN = "未知地址";public static String getRealAddress(String ip) {// 内网不查询if (internalIp(ip)) {return "内网IP";}try {String rspStr = RegionUtil.getRegion(ip);if (StringUtils.isNotEmpty(rspStr)) {String[] obj = rspStr.split("\\|");String region = obj[2];String city = obj[3];return String.format("%s%s", region, city);}} catch (Exception e) {log.error("获取地理位置异常 {}", e.toString());}// ali地域查询return PureNetUtils.getAlibaba(ip);}/* 判断是否是内网IP */public static boolean internalIp(String ipAddress) {boolean isInnerIp = false;long ipNum = getIpNum(ipAddress);/** 私有IP:A类 10.0.0.0-10.255.255.255 B类 172.16.0.0-172.31.255.255 C类* 192.168.0.0-192.168.255.255 当然,还有127这个网段是环回地址*/long aBegin = getIpNum("10.0.0.0");long aEnd = getIpNum("10.255.255.255");long bBegin = getIpNum("172.16.0.0");long bEnd = getIpNum("172.31.255.255");long cBegin = getIpNum("192.168.0.0");long cEnd = getIpNum("192.168.255.255");isInnerIp = isInner(ipNum, aBegin, aEnd)|| isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd)|| ipAddress.equals("127.0.0.1");return isInnerIp;}/* 获取IP数 */private static long getIpNum(String ipAddress) {String[] ip = ipAddress.split("\\.");long a = Integer.parseInt(ip[0]);long b = Integer.parseInt(ip[1]);long c = Integer.parseInt(ip[2]);long d = Integer.parseInt(ip[3]);return a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d;}private static boolean isInner(long userIp, long begin, long end) {return (userIp >= begin) && (userIp <= end);}public static void main(String[] args) {String realAddress = getRealAddress("117.136.79.113");System.out.println("realAddress = " + realAddress);}
}String region = dataMap.getString("region");String city = dataMap.getString("city");address = country + region + city;}}return address;}/* 获取IP数 */private static long getIpNum(String ipAddress) {String[] ip = ipAddress.split("\\.");long a = Integer.parseInt(ip[0]);long b = Integer.parseInt(ip[1]);long c = Integer.parseInt(ip[2]);long d = Integer.parseInt(ip[3]);return a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d;}private static boolean isInner(long userIp, long begin, long end) {return (userIp >= begin) && (userIp <= end);}public static void main(String[] args) {String realAddress = getRealAddress("117.136.79.113");System.out.println("realAddress = " + realAddress);}
}
测试
运行 AddressUtils.java
的 main
方法测试
参考博客:
Java如何通过IP获得真实地址:https://blog.csdn.net/qq_39486119/article/details/107857455
集成ip2region实现离线IP地址定位:http://doc.ruoyi.vip/ruoyi/
相关文章:

Java-通过IP获取真实地址
文章目录 前言功能实现测试 前言 最近写了一个日志系统,需要通过访问的 IP 地址来获取真实的地址,并且存到数据库中,我也是在网上看了一些文章,遂即整理了一下供大家参考。 功能实现 这个是获取正确 IP 地址的方法,可…...
Java代码实现word转PDF
import com.spire.doc.Document; import com.spire.doc.FileFormat; import lombok.extern.slf4j.Slf4j; public class WordConvertPdf { /** * word转pdf * param wordPathName word文件路径及名称 * param pdfPathName pdf生成路径及名称 */ public static void wordToPdf(…...
Java设计模式-简单工厂(Simple Factory)模式
介绍 简单工厂(Simple Factory)模式,又称为静态工厂方法(Static Factory Method)模式。 由一个工厂类来创建具体产品,即创建具体类的实例。 简单工厂模式从概念上涉及三个角色: 抽象产品角色…...
微软所有业务线梳理
目录 一、Windows 二、Office 三、Surface 四、Xbox 五、Azure 六、Dynamics 七、LinkedIn 八、Bing...

SDN系统方法 | 1. 概述
随着互联网和数据中心流量的爆炸式增长,SDN已经逐步取代静态路由交换设备成为构建网络的主流方式,本系列是免费电子书《Software-Defined Networks: A Systems Approach》的中文版,完整介绍了SDN的概念、原理、架构和实现方式。原文: Softwar…...

【数据分享】1929-2022年全球站点的逐日平均压力数据(Shp\Excel\12000个站点)
气象数据是在各项研究中都经常使用的数据,气象指标包括气温、风速、降水、能见度等指标,说到气象数据,最详细的气象数据是具体到气象监测站点的数据! 对于具体到监测站点的气象数据,之前我们分享过1929-2022年全球气象…...

Profibus DP主站转Modbus TCP网关profibus从站地址范围
远创智控YC-DPM-TCP网关。这款产品在Profibus总线侧实现了主站功能,在以太网侧实现了ModbusTcp服务器功能,为我们的工业自动化网络带来了全新的可能。 远创智控YC-DPM-TCP网关是如何实现这些功能的呢?首先,让我们来看看它的Profib…...

MySQL子查询
😇作者介绍:一个有梦想、有理想、有目标的,且渴望能够学有所成的追梦人。 🎆学习格言:不读书的人,思想就会停止。——狄德罗 ⛪️个人主页:进入博主主页 🗼专栏系列:进入MySQL专栏知…...
学IT上培训班有用吗?
在学习IT技术的过程中,你是否也被安利过各种五花八门的技术培训班?这些培训班都是怎样向你宣传的,你又对此抱有着怎样的态度呢?在培训班里学技术,真的有用吗? 首先,IT行业是一个充满机遇和挑战…...

BI如何对接金蝶云星空数据源?奥威BI SaaS平台有绝招
传统BI部署时需要大量硬件和软件支持,而SaaS BI不仅不需要,还能让企业的数据可视化分析变得更加简单便捷,因此已经渐渐成为数字化时代的BI新趋势。那么,SaaS BI平台是如何快速接入数据完成数据可视化分析的?下面就以奥…...
鼎镁科技冲刺A股上市失败,董事长涂季冰三年薪水超过6000万元
7月15日,上海证券交易所披露的信息显示,因鼎镁新材料科技股份有限公司(下称“鼎镁科技”)审核不通过,上海证券交易所终止其发行上市审核。这意味着,鼎镁科技此次上市之旅彻底失败。 据贝多财经了解…...
PostgreSQL【应用 02】扩展SQL之C语言函数(编写、编译、载入)实例分享
C语言函数 1.准备1.1 开发文档1.2 工具安装 2.开始2.1 编写C语言函数2.2 编译和链接动态载入的函数 通过使用 PostgreSQL 的 C 函数接口,我们可以编写用 C 语言实现的函数,并将其集成到数据库中。这些函数可以在 SQL 查询中像其他内置函数一样被调用&…...

day37-框架
0目录 框架 1.框架介绍 2. SSM三大框架简介 3.Mybatis 4.拓展 1.框架介绍 1.1 为什么使用框架? (1)框架效率高,成本低 (2)框架是别人写好的构建,我们只需学会如何使用它(可维护性…...

基于STM32单片机的智能家居烟雾温度火灾防盗报警的设计与实现
功能介绍 以STM32单片机作为主控系统;LCD1602液晶显示屏来显示显示测得的值;SR501人体红外感应是否有人进行防盗;通过烟雾传感器MQ-2获取前的烟雾值;通过DHT11温湿度传感器来获取当前的温湿度;所有的信息通过通过esp82…...

jenkins 采用ssh方式连接gitlab连接不上
一、gitlab 添加jenkins服务器的公钥 jenkins 生成秘钥命令 ssh-keygen -t rsa2.jenkins 秘钥地址: cd /root/.ssh3.复制公钥 到gitlab 添加 cat id_rsa_pub4.添加私钥到jenkins cat id_rsa5.绑定(顺利的话到这里就结束了) ࿰…...

前缀和模板算法
一)模板前缀和 【模板】前缀和_牛客题霸_牛客网 (nowcoder.com) 前缀和:快速的得出数组中某一段连续区间的和 暴力破解的话需要从头到尾的进行遍历,时间复杂度就可以达到O(N),而前缀和时间复杂度是可以达到O(1)的 第一步:预处理创建出一个前缀和数组dp&a…...
SpringBoot 启动输出 Git 版本信息(2023/07/11)
SpringBoot 启动输出 Git 版本信息 文章目录 SpringBoot 启动输出 Git 版本信息1. 环境依赖2. pom.xml 配置3. 启动类配置 为了方便记录项目打包时的 Git 版本,本文将介绍如何将 Git 版本信息打包进 JAR 文件,并在项目启动时输出。 1. 环境依赖 SpringB…...
SSH客户端连接远程服务器
目录 一、什么是客户端连接远程服务器 二、什么是服务端连接远程服务器 三、查看网络信息 1、图形程序查看网络信息 2、命令查看网络信息 四、SSH客户端(Linux) 五、SSH客户端(windows) 六、SSH远程服务器 一、什么是客户…...
“深入理解Redis:高性能缓存与数据存储的秘密“
标题:深入理解Redis:高性能缓存与数据存储的秘密 在现代应用程序的开发中,缓存和数据存储是非常重要的组成部分。它们不仅可以提高应用程序的性能,还可以减轻数据库和网络的负载。其中,Redis作为一种高性能的内存数据存…...

【论文阅读笔记】Attack-Resistant Federated Learning with Residual-based Reweighting
个人阅读笔记,如有错误欢迎指出 Arxiv 2019 [1912.11464] Attack-Resistant Federated Learning with Residual-based Reweighting (arxiv.org) 问题: 联邦学习容易受到后门攻击 创新: 提出一种基于残差的重新加权聚合算法 聚合算法…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...

佰力博科技与您探讨热释电测量的几种方法
热释电的测量主要涉及热释电系数的测定,这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中,积分电荷法最为常用,其原理是通过测量在电容器上积累的热释电电荷,从而确定热释电系数…...
【Go语言基础【12】】指针:声明、取地址、解引用
文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...

C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...

day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...