SpringBoot 快速实现IP地址解析

如果使用本地ip 解析的话,我们将会借助ip2region,该项目维护了一份较为详细的本地ip 地址对应表,如果为了离线环境的使用,需要导入该项目依赖,并指定版本,不同版本的方法可能存在差异。

<dependency><groupId>org.lionsoul</groupId><artifactId>ip2region</artifactId><version>2.6.3</version>
</dependency>

官方gitee:gitee.com/lionsoul/ip…

开发

在使用时需要将 xdb 文件下载到工程文件目录下,使用ip2region即使是完全基于 xdb 文件的查询,单次查询响应时间在十微秒级别,可通过如下两种方式开启内存加速查询:

  • vIndex 索引缓存 :使用固定的 512KiB 的内存空间缓存 vector index 数据,减少一次 IO 磁盘操作,保持平均查询效率稳定在10-20微秒之间。

  • xdb 整个文件缓存:将整个 xdb 文件全部加载到内存,内存占用等同于 xdb 文件大小,无磁盘 IO 操作,保持微秒级别的查询效率。

/*** ip查询*/
@Slf4j
public class IPUtil {private static final String UNKNOWN = "unknown";protected IPUtil(){ }/*** 获取 IP地址* 使用 Nginx等反向代理软件, 则不能通过 request.getRemoteAddr()获取 IP地址* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,* X-Forwarded-For中第一个非 unknown的有效IP字符串,则为真实IP地址*/public static String getIpAddr(HttpServletRequest request) {String ip = request.getHeader("x-forwarded-for");if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;}public static  String getAddr(String ip){String dbPath = "src/main/resources/ip2region/ip2region.xdb";// 1、从 dbPath 加载整个 xdb 到内存。byte[] cBuff;try {cBuff = Searcher.loadContentFromFile(dbPath);} catch (Exception e) {log.info("failed to load content from `%s`: %s\n", dbPath, e);return null;}// 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。Searcher searcher;try {searcher = Searcher.newWithBuffer(cBuff);} catch (Exception e) {log.info("failed to create content cached searcher: %s\n", e);return null;}// 3、查询try {String region = searcher.searchByStr(ip);return region;} catch (Exception e) {log.info("failed to search(%s): %s\n", ip, e);}return null;}
}

这里我们将ip 解析封装成一个工具类,包含获取IP和ip 地址解析两个方法,ip 的解析可以在请求中获取。获取到ip后,需要根据ip ,在xdb 中查找对应的IP地址的解析,由于是本地数据库可能存在一定的缺失,部分ip 存在无法解析的情况。

在线解析

如果想要获取更加全面的ip 地址信息,可使用在线数据库,这里提供的是 whois.pconline.com  的IP解析,该IP解析在我的使用过程中表现非常流畅,而且只有少数的ip 存在无法解析的情况。

@Slf4j
public class AddressUtils {// IP地址查询public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp";// 未知地址public static final String UNKNOWN = "XX XX";public static String getRealAddressByIP(String ip) {String address = UNKNOWN;// 内网不查询if (IpUtils.internalIp(ip)) {return "内网IP";}if (true) {try {String rspStr = sendGet(IP_URL, "ip=" + ip + "&json=true" ,"GBK");if (StrUtil.isEmpty(rspStr)) {log.error("获取地理位置异常 {}" , ip);return UNKNOWN;}JSONObject obj = JSONObject.parseObject(rspStr);String region = obj.getString("pro");String city = obj.getString("city");return String.format("%s %s" , region, city);} catch (Exception e) {log.error("获取地理位置异常 {}" , ip);}}return address;}public static String sendGet(String url, String param, String contentType) {StringBuilder result = new StringBuilder();BufferedReader in = null;try {String urlNameString = url + "?" + param;log.info("sendGet - {}" , urlNameString);URL realUrl = new URL(urlNameString);URLConnection connection = realUrl.openConnection();connection.setRequestProperty("accept" , "*/*");connection.setRequestProperty("connection" , "Keep-Alive");connection.setRequestProperty("user-agent" , "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");connection.connect();in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));String line;while ((line = in.readLine()) != null) {result.append(line);}log.info("recv - {}" , result);} catch (ConnectException e) {log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);} catch (SocketTimeoutException e) {log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);} catch (IOException e) {log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);} catch (Exception e) {log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);} finally {try {if (in != null) {in.close();}} catch (Exception ex) {log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);}}return result.toString();}
}

场景

那么在开发的什么流程获取ip 地址是比较合适的,这里就要用到我们的拦截器了。拦截进入服务的每个请求,进行前置操作,在进入时就完成请求头的解析,ip 获取以及ip 地址解析,这样在后续流程的全环节,都可以复用ip 地址等信息。

/*** 对ip 进行限制,防止IP大量请求*/
@Slf4j
@Configuration
public class IpUrlLimitInterceptor implements HandlerInterceptor{@Overridepublic boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) {//更新全局变量Constant.IP = IPUtil.getIpAddr(httpServletRequest);Constant.IP_ADDR = AddressUtils.getRealAddressByIP(Constant.IP);Constant.URL = httpServletRequest.getRequestURI();return true;}@Overridepublic void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) {//通过本地获取//        获得ip//        String ip = IPUtil.getIpAddr(httpServletRequest);//解析具体地址//        String addr = IPUtil.getAddr(ip);//通过在线库获取//        String ip = IpUtils.getIpAddr(httpServletRequest);//        String ipaddr = AddressUtils.getRealAddressByIP(ipAddr);//        log.info("IP >> {},Address >> {}",ip,ipaddr);}@Overridepublic void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {}
}

如果想要执行我们的ip 解析拦截器,

需要在spring boot的视图层进行拦截才会触发我们的拦截器。

@Configuration
public class WebConfig implements WebMvcConfigurer {@AutowiredIpUrlLimitInterceptor ipUrlLimitInterceptor;//执行ip拦截器@Overridepublic void addInterceptors(InterceptorRegistry regivastry){registry.addInterceptor(ipUrlLimitInterceptor)// 拦截所有请求.addPathPatterns("/**");}
}

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

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

相关文章

第四讲-安装docker

Docker CE 镜像 [来源] 阿里云镜像站 阿里云加速地址 简介 Docker CE 是免费的 Docker 产品的新名称&#xff0c;Docker CE 包含了完整的 Docker 平台&#xff0c;非常适合开发人员和运维团队构建容器 APP。 配置方法 CentOS 7&#xff08;使用 yum 进行安装&#xff09;…

linux 使用nethogs命令查看各个进程使用网络的情况

1&#xff0c;使用nethogs命令查看各个进程使用网络的情况 #yum -y install nethogs 2&#xff0c;使用nethogs命令查看进程使用网络的情况 #nethogs

PHP8知识详解:PHP8的新特性

PHP 8是PHP编程语言的一个主要版本&#xff0c;在2020年11月26日发布。它引入了许多新特性和改进&#xff0c;包括以下一些主要特性&#xff1a; 1. JIT 编译器&#xff1a;PHP 8引入了名为Tracing JIT的即时&#xff08;Just-In-Time&#xff09;编译器。JIT可以将PHP脚本中频…

【C++ 进阶】继承

一.继承的定义格式 基类又叫父类&#xff0c;派生类又叫子类&#xff1b; 二.继承方式 继承方式分为三种&#xff1a; 1.public继承 2.protected继承 3.private继承 基类成员与继承方式的关系共有9种&#xff0c;见下表&#xff1a; 虽然说是有9种&#xff0c;但其实最常用的还…

Stable diffusion 和 Midjourney 怎么选?

通过这段时间的摸索&#xff0c;我将和你探讨&#xff0c;对普通人来说&#xff0c;Stable diffusion 和 Midjourney 怎么选&#xff1f;最重要的是&#xff0c;学好影视后期制作对 AI 绘画创作有哪些帮助&#xff1f;反过来&#xff0c;AI 绘画对影视后期又有哪些帮助&#xf…

28.JavaWeb-Elasticsearch

1.Elasticsearch概述 Elasticsearch 是一个分布式的全文检索引擎。采用Java语言开发&#xff0c;基于Apache协议的开源项目&#xff0c;具有实时搜索&#xff0c;稳定&#xff0c;可靠&#xff0c;快速的特点。 1.1 全文检索引擎 分为通用搜索引擎&#xff08;百度、谷歌&…

【深度学习】【Image Inpainting】Generative Image Inpainting with Contextual Attention

Generative Image Inpainting with Contextual Attention DeepFillv1 (CVPR’2018) 论文&#xff1a;https://arxiv.org/abs/1801.07892 论文代码&#xff1a;https://github.com/JiahuiYu/generative_inpainting 论文摘录 文章目录 效果一览摘要介绍论文贡献相关工作Image…

【Java SE】类和对象

目录 【1】面向对象的初步认识 【1.1】什么是面向对象 【1.2】面向对象与面向过程 【2】类定义和使用 【2.1】简单认识类 【2.2】类的定义格式 【2.3】练习 【2.3.1】定义一个狗类 【2.3.2】定义一个学生类 【3】类的实例化 【3.1】什么是实例化 【3.2】类和对象的…

【Java基础学习打卡18】运算符(上)

目录 前言一、运算符和表达式1.运算符2.表达式 二、算术运算符1.加法运算符2.减法运算符3.乘法运算符4.除法运算符5.取余运算符6.表达式类型自动提升 总结 前言 本文主要介绍运算符和表达式&#xff0c;及运算符中的算术运算符。在 Java 编程中&#xff0c;运算符起着非常重要…

Java 使用 Google Guava 实现接口限流

一、引入依赖 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.0-jre</version> </dependency>二、自定义注解及限流拦截器 自定义注解&#xff1a;Limiter package com.haita…

安装requests模块及其他依赖库的完美解决办法

业务场景 导入requests库时报错&#xff0c;单独离线下载安装requests&#xff0c;发现仍然报错&#xff0c;问题在于requests库有其他依赖库。 WARNING: Retrying (Retry(total1, connectNone, readNone, redirectNone, statusNone)) after connection broken by NewConnect…

PgSQL-使用技巧-如何衡量网络对性能的影响

PgSQL-使用技巧-如何衡量网络对性能的影响 PG数据库和应用之间常见的部件有连接池、负载平衡组件、路由、防火墙等。我们常常不在意或者认为涉及的网络hops对整体性能产生的额外开销是理所当然的。但在很多情况下&#xff0c;它可能会导致严重的性能损失和拖累整体吞吐量。相当…

vue 图片的引入方式

一、import 静态引入 放在script标签顶端 例如 import errowPng from ../../assets/404_images/404.png 二、require 动态引入 可以放在data中 data() {return {imgUrl:require("../../assets/404_images/404.png")};}, require 是赋值过程并且是运行时才执行&…

普通的计算机专业大学生如何学习才能找到好offer

2023年已经将近8月份了&#xff0c;回想到开始努力提高自己的时候还是在今年1月1号。开学就要大二了。 一、目标达成情况总结&#xff1a; 一月份&#xff0c;无意间在网上刷到鹏哥的C语言课程&#xff0c;在鸡汤实力课程已拿到大厂offer的同学喜报 &#xff0c;让我萌发了学技…

深入浅出理解vue2/vue3响应式原理

一、简介 当谈论Vue 2和Vue 3的响应式原理时&#xff0c;我们主要关注的是其数据双向绑定的机制。数据双向绑定是指当数据发生变化时&#xff0c;视图会自动更新&#xff1b;反之&#xff0c;当视图发生变化时&#xff0c;数据也会相应地更新。这种特性让我们在前端开发中更加…

Swift 如何确定 scrollView 已经滑动结束

在 iOS 的 UIScrollView 中&#xff0c;你可以通过实现 UIScrollViewDelegate 的方法来检测滑动结束事件。具体来说&#xff0c;你可以实现以下方法&#xff1a; func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {if !decelerat…

Python 实现接口类的两种方式+邮件提醒+动态导入模块+反射(参考Django中间件源码)

实现抽象类的两种方式 方式一 from abc import ABCMeta from abc import abstractmethodclass BaseMessage(metaclassABCMeta):abstractmethoddef send(self,subject,body,to,name):pass 方式二 class BaseMessage(object):def send(self, subject, body, to, name):raise …

vue3使用响应式数据 + v-model导致响应式失效el-form表单无法输入的问题

文章目录 vue3使用响应式数据 v-model导致响应式失效el-form表单无法输入的问题 vue3使用响应式数据 v-model导致响应式失效el-form表单无法输入的问题 参考文章 重构vue2项目时发现的问题&#xff0c;原始项目使用的是Element-ui。 其实vue3可以使用适配的Element-plus 问…

EasyExcel读取多sheet excel异常

EasyExcel读取多sheet excel异常 场景 使用Spring Boot集成EasyExcel进行导入excel多sheet&#xff0c;执行异常 代码 file是MultipartFile&#xff0c;入参&#xff0c;主要处理流程如下 InputStream is file.getInputStream(); EasyExcel.read(is, SysDict.class, new …

Set集合类详解(附加思维导图)

目录 一、Set集合思维导图 二、set集合类常用方法 2.1、HashSet集合常用方法 2.2、TreeSet集合的使用 三、HashSet、LinkedHashSet、TreeSet的使用场景 四、list和set集合的区别 一、Set集合思维导图 二、set集合类常用方法 2.1、HashSet集合常用方法 ①&#xff1a;add…