Java-通过IP获取真实地址

文章目录

    • 前言
    • 功能实现
    • 测试

前言

最近写了一个日志系统,需要通过访问的 IP 地址来获取真实的地址,并且存到数据库中,我也是在网上看了一些文章,遂即整理了一下供大家参考。


功能实现

这个是获取正确 IP 地址的方法,可以直接使用的。

/*** 获取 IP 地址*/public static String getIpAddress(ServerHttpRequest request) {HttpHeaders headers = request.getHeaders();String ip = headers.getFirst(ParameterConstants.X_FORWARDED_FOR);if (ip != null && ip.length() != 0 && !ParameterConstants.UNKNOWN.equalsIgnoreCase(ip)) {// 多次反向代理后会有多个ip值,第一个ip才是真实ipif (ip.contains(",")) {ip = ip.split(",")[0];}}if (ip == null || ip.length() == 0 || ParameterConstants.UNKNOWN.equalsIgnoreCase(ip)) {ip = headers.getFirst(ParameterConstants.PROXY_CLIENT_IP);}if (ip == null || ip.length() == 0 || ParameterConstants.UNKNOWN.equalsIgnoreCase(ip)) {ip = headers.getFirst(ParameterConstants.WL_PROXY_CLIENT_IP);}if (ip == null || ip.length() == 0 || ParameterConstants.UNKNOWN.equalsIgnoreCase(ip)) {ip = headers.getFirst(ParameterConstants.HTTP_CLIENT_IP);}if (ip == null || ip.length() == 0 || ParameterConstants.UNKNOWN.equalsIgnoreCase(ip)) {ip = headers.getFirst(ParameterConstants.HTTP_X_FORWARDED_FOR);}if (ip == null || ip.length() == 0 || ParameterConstants.UNKNOWN.equalsIgnoreCase(ip)) {ip = headers.getFirst(ParameterConstants.X_REAL_IP);}if (ip == null || ip.length() == 0 || ParameterConstants.UNKNOWN.equalsIgnoreCase(ip)) {ip = Objects.requireNonNull(request.getRemoteAddress()).getAddress().getHostAddress();if (ip.equals(ParameterConstants.LOCAL_IP_V4) || ip.equals(ParameterConstants.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 (ParameterConstants.CDN_SRC_IP.equalsIgnoreCase(name)|| ParameterConstants.X_FORWARDED_FOR.equalsIgnoreCase(name)|| ParameterConstants.PROXY_CLIENT_IP.equalsIgnoreCase(name)|| ParameterConstants.WL_PROXY_CLIENT_IP.equalsIgnoreCase(name)|| ParameterConstants.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(ParameterConstants.LOCAL_IP_V4) || ip.equals(ParameterConstants.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.javamain 方法测试

在这里插入图片描述


参考博客:
Java如何通过IP获得真实地址:https://blog.csdn.net/qq_39486119/article/details/107857455
集成ip2region实现离线IP地址定位:http://doc.ruoyi.vip/ruoyi/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/19850.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++之装饰器适配器模式

目录 一、装饰器模式 模式思想 模式简介 模式优点 模式缺点 代码实现 情景模拟 代码实现 运行结果 二、适配器模式 模式简介 介绍 优点 缺点 代码实现 情景模拟 一、装饰器模式 模式思想 模式简介 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向…

Sentinel服务器容错简介

spring gateway 详解 服务容错高并发带来的问题服务雪崩效应常见容错方案常见的容错思路1、隔离2、超时3、限流4、熔断5、降级 常见的容错组件 SentinelSentinel 具有以下特征:Sentinel概念和功能相关概念1、资源2、规则 重要功能 服务容错 高并发带来的问题 在微服务架构中&…

深入理解Linux内核 PHY 驱动框架

目录 一、背景 二、硬件拓扑 三、概述 四、PHY控制器驱动 五、PHY驱动解析 1、相关结构体 2、网口和mdio总线设备树配置 3、MAC驱动和mdio控制器注册 4、PHY设备驱动 5、PHY 设备驱动注册和加载 6、以太网卡 PHY 和 MAC 的协作 7、网络操作命令解析 8、设备驱动与…

postman测试接口出现404

postman测试接口出现404 1.用postman调试接口的过程中&#xff0c;出现404的情况&#xff0c;但是接口明明已调到了&#xff0c;而且数据也已经存入数据库了&#xff0c;这让我感到很疑惑。看网上的解决办法检查了我的路径&#xff0c;提交方式、参数类型等都是正确的&#xf…

【实战】 六、用户体验优化 - 加载中和错误状态处理(下) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(十)

文章目录 一、项目起航&#xff1a;项目初始化与配置二、React 与 Hook 应用&#xff1a;实现项目列表三、TS 应用&#xff1a;JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理1~234.用useAs…

加密劫持者攻击教育机构

我们的专家分析了2023年第一季度的当前网络威胁。研究表明&#xff0c;独特事件的数量增加&#xff0c;勒索软件活动激增&#xff0c;特别是针对学术和教育机构。我们记录了大量与就业有关的网络钓鱼邮件&#xff0c;出现了QR网络钓鱼和恶意广告的增加。 我们的研究表明&#…

计算机组成原理课程论文: Intel 80386/80486 的体系架构调研

摘要 本文以Intel 80386/80486体系架构为研究对象&#xff0c;详细介绍了该体系架构的基本概念、特点和优势&#xff0c;分析了其在不同领域的应用情况&#xff0c;并对其未来的发展做出一定的展望和评价。 首先&#xff0c;我们介绍了研究背景和目的&#xff0c;阐述了Intel 8…

windows安装docker

目录 安装docekr Desktop下载安装 解决WSL 问题启用适用于 Linux 的 Windows 子系统检查运行 WSL 2 的要求启用虚拟机功能下载 Linux 内核更新包将 WSL 2 设置为默认版本 运行-可视化界面 安装docekr Desktop 下载 下载地址 Install Docker Desktop on Windows | Docker Docum…

攻防世界-web-ics-05

题目描述: 其他破坏者会利用工控云管理系统设备维护中心的后门入侵系统 题目链接点进去如下&#xff1a; 可以看到界面上有一个设备维护中心&#xff0c;点击设备维护中心&#xff0c;跳转到如下界面 再次点击&#xff0c;发现变成这样了 1. 思路分析 从已知信息来看&#xf…

算法与数据结构(一)--算法复杂性

一.算法复杂性的概念 算法的复杂性是指运行算法所需要的计算机资源的量。需要的时间资源的量称为时间复杂性&#xff0c;需要的空间资源的量称为空间复杂性。 这个量应该集中反映算法的效率&#xff0c;而从运行该算法的实际计算机中抽象出来。换句话说&#xff0c;这个量应该…

【算法集训之线性表篇】Day 08

文章目录 题目基本设计思想思路一思路二 代码实现效果 题目 已知一个整数数列A{a0,a1,a2,…,an-1}&#xff0c;其中0<ai<n(0<i<n)。若存在ap1ap2ap3…apmx且m>n/2(0<pk<n,1<k<m)&#xff0c;则成x为A的主元素。例如A{0,5,5,3,5,7,5,5}&#xff0c;…

【后端面经-架构】RabbitMQ简介

【后端面经-架构】RabbitMQ简介 1. MQ介绍2. RabbitMQ2.1 简介2.2 架构&#xff1a;组件解释2.3 特点2.4 优缺点 面试模拟参考资料 1. MQ介绍 MQ&#xff08;Message Queue&#xff09;用于在应用程序之间相互通信&#xff0c;在消息中发送数据进行通信&#xff0c;而不需要特…