当前位置: 首页 > news >正文

获取请求IP以及IP解析成省份

某些业务需要获取请求IP以及将IP解析成省份之类的,于是我写了一个工具类,可以直接COPY

/*** IP工具类* @author xxl* @since 2023/11/9*/
@Slf4j
public class IPUtils {/*** 过滤本地地址*/public static final String LOCAL_ADDRESS = "127.0.0.1";public static final String LOOP_BACK_ADDRESS = "0:0:0:0:0:0:0:1";/*** 离线查询IP地址的数据文件,这个文件去ip2region GitHub官方仓库获取*/private static  String IP_ADDRESS_FILE_PATH ;/*** 前从 xdb 文件中加载出来 VectorIndex 数据,然后全局缓存,* 每次创建 Searcher 对象的时候使用全局的 VectorIndex 缓存可以减少一次固定的 IO 操作,* 从而加速查询,减少 IO 压力。*/private static  byte[] vIndex= null;private static Searcher searcher = null;static {try {//这个ip2region.xdb我是放在/resources/data/ip2region.xdb目录下的String fileName = "/data/ip2region.xdb";File existFile = FileUtil.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName);if(!FileUtil.exist(existFile)) {InputStream resourceAsStream = IPUtils.class.getResourceAsStream(fileName);FileUtil.writeFromStream(resourceAsStream, existFile);}IP_ADDRESS_FILE_PATH = existFile.getPath();// 从 db 中预先加载 VectorIndex 缓存,并且把这个得到的数据作为全局变量,后续反复使用。vIndex = Searcher.loadVectorIndexFromFile(IP_ADDRESS_FILE_PATH);// 使用全局的 vIndex 创建带 VectorIndex 缓存的查询对象。searcher = Searcher.newWithVectorIndex(IP_ADDRESS_FILE_PATH, vIndex);} catch (Exception e) {throw new RuntimeException("IPUtils class load error", e);}}/*** 每个线程需要单独创建一个独立的 Searcher 对象,但是都共享全局的制度 vIndex 缓存。* @param ip IP* @return IP地址*/public static String getCity(String ip)  {String search = null;try {search = searcher.search(ip);} catch (Exception e) {throw new RuntimeException("getCity fail",e);}return search;}/*** 获取 IP** @param request 请求* @return 字符串*/public static String getIp(HttpServletRequest request) {String ip = null;try {//解析IPip = new ChainUtils<>(request.getHeader("X-Forwarded-For"))//多次反向代理后会有多个ip值,第一个ip才是真实ip.chain(re -> StrUtil.isNotBlank(re) ? (re.contains(DOT) ? re.substring(0, re.indexOf(DOT)) : EMPTY) : re)//依次查找IP.chain(re -> StrUtil.isNotBlank(re) ? re : request.getHeader("X-Real-IP")).chain(re -> StrUtil.isNotBlank(re) ? re : request.getHeader("Proxy-Client-IP")).chain(re -> StrUtil.isNotBlank(re) ? re : request.getHeader("WL-Proxy-Client-IP")).chain(re -> StrUtil.isNotBlank(re) ? re : request.getHeader("HTTP_CLIENT_IP")).chain(re -> StrUtil.isNotBlank(re) ? re : request.getHeader("HTTP_X_FORWARDED_FOR")).chain(re -> StrUtil.isNotBlank(re) ? re : request.getRemoteAddr())//过滤本地地址.chain(re -> StrUtil.isNotBlank(re) ? (LOOP_BACK_ADDRESS.equals(re) ? LOCAL_ADDRESS : re) : re).getValue(true);} catch (Exception e) {log.error("getIp fail", e);}return ip;}
}

使用以上工具类需要以下依赖和一个自定义工具类

<!--    解析IP    -->
<dependency><groupId>org.lionsoul</groupId><artifactId>ip2region</artifactId><version>2.7.0</version>
</dependency>
<!--   hutool     -->
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.20</version>
</dependency>

ChainUtil:为什么写这个工具类在解析请求中的IP参考了https://blog.csdn.net/chwshuang/article/details/71940858此博客中部分代码如下图可以发现有很多if判断,很难看不好维护。于是就写了以下的工具类

/*** @author: xxl* @since: 2023/11/9* @description: 解决if,else地狱*/
@AllArgsConstructor
public  class ChainUtil<T> {/*** 存储的值*/private T value;public <E> ChainUtil<E> chain(Function<T,E> function) {return new ChainUtil<>(function.apply(value));}/*** 获取存储的值** @param isNullForException 如果存储的值为null是否抛出异常* @return T*/public T getValue(boolean isNullForException) {if (isNullForException) {Assert.notNull(value, () -> new RuntimeException("chain value is null"));}return value;}
}

if地狱

在这里插入图片描述

http://www.lryc.cn/news/226035.html

相关文章:

  • YOLOv8-seg改进:复现HIC-YOLOv5,HIC-YOLOv8-seg助力小目标分割
  • vscode 终端进程启动失败: shell 可执行文件“C:\Windows\System32\WindowsPower
  • 【中间件篇-Redis缓存数据库02】Redis高级特性和应用(慢查询、Pipeline、事务、Lua)
  • 栈 和 队列
  • 【推荐】一款AI写作大师、问答、绘画工具-「智元兔 AI」
  • 阿里云付费用户破100万 用户规模亚洲最大
  • 人工智能基础——Python:Matplotlib与绘图设计
  • Ubuntu 配置 Github 的 SSH keys
  • Flink—— Flink Data transformation(转换)
  • 前端读取文件当文件选择相同文件名的文件,内容不会变化
  • PHP 服装销售管理系统mysql数据库web结构layUI布局apache计算机软件工程网页wamp
  • 用于图像处理的高斯滤波器 (LoG) 拉普拉斯
  • 【h5 uniapp】 滚动 滚动条,数据跟着变化
  • ModStartBlog v8.5.0 评论开关布局调整,系统后台全面优化
  • django|报错SQLite 3.8.3 or later is required的解决方案
  • 通达OA get_datas.php前台sql注入-可获取数据库session登入后台漏洞复现 [附POC]
  • 苹果官方:所有国行iPhone 15系列都在中国生产!
  • Oracle 安装及 Spring 使用 Oracle
  • element-ui 表格 点击选中
  • 畅通工程之局部最小花费问题 (C++)
  • Sql 异常 + Error
  • 基于UNI-APP实现适配器并保证适配器和实现的调用一致
  • 使用jdk21预览版 --enable-preview
  • js中的跳转都有哪些格式
  • 无重复字符的最长子串
  • C语言--输入10个数字,要求输出其中值最大的元素和该数字是第几个数
  • 如何做好功能测试,提升测试质量和效率?
  • 高德地图添加信息弹窗,信息弹窗是单独的组件
  • Apache Arrow优点
  • 【Linux权限:系统中的数字锁与安全之门】