关于在子线程中获取不到HttpServletRequest对象的问题

这篇文章主要分享一下项目里遇到的获取request对象为null的问题,具体是在登录的时候触发的邮箱提醒,获取客户端ip地址,然后通过ip地址定位获取定位信息,从而提示账号在哪里登录。

但是登录却发现获取request对象的时候报错了。

 具体的代码如下:这个异常是自己手动抛出的。

package cn.edu.sgu.www.mhxysy.util;import cn.edu.sgu.www.mhxysy.consts.MimeType;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import cn.edu.sgu.www.mhxysy.restful.JsonResult;
import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import com.alibaba.fastjson.JSON;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** http工具类* @author heyunlin* @version 1.0*/
public class HttpUtils {/*** 获取HttpServletRequest对象* @return HttpServletRequest*/public static HttpServletRequest getRequest() {RequestAttributes attributes = RequestContextHolder.getRequestAttributes();if (attributes != null ) {return ((ServletRequestAttributes) attributes).getRequest();}throw new GlobalException(ResponseCode.ERROR, "获取request对象失败");}}

在项目其他地方也有用这个工具了获取HttpServletRequest对象,都能获取到,觉得很是奇怪。点进去RequestContextHolder这个类的代码里看了一下,好像找到问题了~

这是基于ThreadLocal实现的,所以有了子线程无法访问父线程中设置的数据问题,不知道开发者为什么不用InheritThreadLocal来避免这个问题0v0

于是,把涉及获取request对象ip地址获取的代码放在线程外面,这样就避免了空指针问题了~

package cn.edu.sgu.www.mhxysy.chain.login.impl;import cn.edu.sgu.www.mhxysy.chain.login.UserLoginHandler;
import cn.edu.sgu.www.mhxysy.config.property.EmailProperties;
import cn.edu.sgu.www.mhxysy.config.property.SystemSettingsProperties;
import cn.edu.sgu.www.mhxysy.entity.location.Location;
import cn.edu.sgu.www.mhxysy.util.EmailUtils;
import cn.edu.sgu.www.mhxysy.util.IpUtils;
import cn.edu.sgu.www.mhxysy.util.LocationUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;/*** @author heyunlin* @version 1.0*/
@Component
public class EmailSendHandler implements UserLoginHandler {private Object params;private UserLoginHandler next;private final EmailUtils emailUtils;private final EmailProperties emailProperties;private final SystemSettingsProperties systemSettingsProperties;@Autowiredpublic EmailSendHandler(EmailUtils emailUtils,EmailProperties emailProperties,SystemSettingsProperties systemSettingsProperties) {this.emailUtils = emailUtils;this.emailProperties = emailProperties;this.systemSettingsProperties = systemSettingsProperties;}@Overridepublic void handle() {if (emailProperties.isEnable()) {String ip = IpUtils.getIp();String username = (String) params;String zoneId = systemSettingsProperties.getZoneId();// 定义日期格式DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");new Thread(() -> {try {String address = "广东广州";Location location = LocationUtils.getLocation(ip);if (systemSettingsProperties.isUseRealLocation()) {String locationAddress = location.getAddress();if (locationAddress != null) {address = locationAddress;}}String text = "您的账号" + username + "在" + address + "登录了。" +"[" + LocalDateTime.now(ZoneId.of(zoneId)).format(formatter) + "]";emailUtils.sendMessage(text);} catch (Exception e) {e.printStackTrace();}}).start();}if (next != null) {next.handle();}}@Overridepublic void setNext(UserLoginHandler next) {this.next = next;}@Overridepublic void setParams(Object params) {this.params = params;}}

总结:遇到这类问题,就把获取request对象的代码放在主线程中,避免因为ThreadLocal的缺陷导致程序异常。


好了,文章就分享到这里了,看完如果对你有所帮助,不要忘了点赞+收藏哦~

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

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

相关文章

Docker提示某网络不存在如何解决,添加完网络之后如何删除?

Docker提示某网络不存在如何解决? 创建 Docker 网络 假设现在需要创建一个名为my-mysql-network的网络 docker network create my-mysql-network运行容器 创建网络之后,再运行 mysqld_exporter 容器。完整命令如下: docker run -d -p 9104…

认识K8s集群的声明式资源管理方法

前言 Kubernetes 集群的声明式资源管理方法是当今云原生领域中的核心概念之一,使得容器化应用程序的部署和管理变得更加高效和可靠。本文将认识了解 Kubernetes 中声明式管理的相关理念、实际应用以及优势。 目录 一、管理方法介绍 1. 概述 2. 语法格式 2.1 管…

Spring Boot Interceptor(拦截器使用及原理)

之前的博客中讲解了关于 Spring AOP的思想和原理,而实际开发中Spring Boot对于AOP的思想的具体实现就是Spring Boot Interceptor。在 Spring Boot 应用程序开发中,拦截器(Interceptor)是一个非常有用的工具。它允许我们在 HTTP 请…

Redis可视化工具:Another Redis Desktop Manager下载安装使用

1.Github下载 github下载地址: Releases qishibo/AnotherRedisDesktopManager GitHub 2. 安装 直接双击exe文件进行安装 3. 连接Redis服务 先启动Redis服务,具体启动过程可参考: Windows安装并启动Redis服务端(zip包&#xff09…

Golang | Leetcode Golang题解之第111题二叉树的最小深度

题目&#xff1a; 题解&#xff1a; func minDepth(root *TreeNode) int {if root nil {return 0}queue : []*TreeNode{}count : []int{}queue append(queue, root)count append(count, 1)for i : 0; i < len(queue); i {node : queue[i]depth : count[i]if node.Left …

FileZilla“服务器发回了不可路由的地址,使用服务器地址代替

问题&#xff1a;在宝塔创建的FTP无法使用&#xff0c;提示“服务器回应不可路由的地址。使用服务器地址代替 第一种解决办法&#xff1a;由于宝塔把FTP被动模式端口范围设置成了39000-40000&#xff0c;所以只需要把阿里云服务器上相应的端口范围开放即可。 第二种解决办法&am…

网络安全之安全协议浅谈

安全协议 安全协议概述安全协议分类IPSecIPSec安全协议IPSec架构IPSec封装模式AH协议ESP协议SET协议SET协议电子交易模型SET协议安全目标认证中心CA 安全协议概述 安全协议是信息交换安全的核心&#xff0c;它在网络不同层次上、针对不同应用&#xff0c;通过对各种密码学技术…

LiveGBS流媒体平台GB/T28181用户手册-云端录像:查看录像、列表视图、时间轴视图、下载、删除

LiveGBS流媒体平台GB/T28181用户手册-云端录像:查看录像、列表视图、时间轴视图、下载、删除 1、云端录像1.1、查看录像1.1.1、时间轴视图1.1.2、列表视图1.1.3、日期切换1.1.4、删除当天 1.2、录像计划1.2.1、录像计划列表1.2.2、编辑录像计划1.2.3、关联通道1.2.4、删除录像计…

解决在cmd里下载的库,但IDLE还是显示不存在的问题

原因一&#xff1a; 环境变量配置 首先&#xff0c;你需要确认你安装库的时候使用的Python环境是否和IDLE使用的Python环境是同一个。如果cmd中你使用的是系统路径下的Python&#xff0c;而IDLE使用的是另一个路径下的Python&#xff0c;那么你在cmd中下载的库&#xff0c;IDL…

存在重复元素 II[简单]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给你一个整数数组nums和一个整数k&#xff0c;判断数组中是否存在两个不同的索引i和j&#xff0c;满足nums[i] nums[j]且abs(i - j) < k。如果存在&#xff0c;返回true&#xff1b;否则&#xff0c;返回false。 示例 1&#…

OpenAI撤回有争议的决定:终止永久性非贬损协议

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

[windows系统安装/重装系统][step-4][番外篇-2]N卡驱动重装 |解决:开机几小时后电脑卡顿 | 后台自动运行了上千个Rundll32进程问题

现象 开机几小时后&#xff0c;电脑变卡&#xff0c;打开后台管理器都卡&#xff0c;后台管理去转圈圈一小会儿后看到后台进程上千个&#xff0c;好多个Rundll32进程 重启下运行会稍快 重启后运行快&#xff0c;后台管理器反应也快 打开后台管理器不卡&#xff08;几小时后打…

力扣刷题---2215. 找出两数组的不同【简单】

题目描述 给你两个下标从 0 开始的整数数组 nums1 和 nums2 &#xff0c;请你返回一个长度为 2 的列表 answer &#xff0c;其中&#xff1a; answer[0] 是 nums1 中所有 不 存在于 nums2 中的 不同 整数组成的列表。 answer[1] 是 nums2 中所有 不 存在于 nums1 中的 不同 整…

营销短信XML接口对接发送示例

在现代社会中&#xff0c;通信技术日新月异&#xff0c;其中&#xff0c;短信作为一种快速、简便的通信方式&#xff0c;仍然在日常生活中占据着重要的地位。为了满足各种应用场景的需求&#xff0c;短信接口应运而生&#xff0c;成为了实现高能有效通信的关键。 短信接口是一种…

L01_JVM 高频知识图谱

这些知识点你都掌握了吗&#xff1f;大家可以对着问题看下自己掌握程度如何&#xff1f;对于没掌握的知识点&#xff0c;大家自行网上搜索&#xff0c;都会有对应答案&#xff0c;本文不做知识点详细说明&#xff0c;只做简要文字或图示引导。 类的生命周期 类加载器 JVM 的内存…

KVM热迁移虚拟机+KSM内存页合并

KVM高级功能部署 文章目录 KVM高级功能部署资源列表基础环境一、静态迁移1.1.在源宿主机上准备虚拟机1.1.1、调试VNC1.1.2、创建虚拟机test011.1.3、console登录test01虚拟机1.1.4、标记虚拟机test01当前IP地址 2.1、提取磁盘和配置文件2.2.1、查看虚拟机test01当前状态2.2.2、…

Gradle的settings.gradle.kts你真的理解吗?

你还在用.gradle文件吗&#xff1f;例如build.gradle、settings.gradle&#xff0c;那么你就out了。现在我们有必要了解一下kts脚本了。在Android项目中&#xff0c;默认有3个文件可以替换成kts脚本&#xff0c;即project的build.gradle、app模块的build.gradle和project的sett…

DDR5—新手入门学习(一)【1-5】

目录 1、DDR背景 &#xff08;1&#xff09;SDR SDRAM时代 &#xff1a; &#xff08;2&#xff09;DDR SDRAM的创新 &#xff1a; &#xff08;3&#xff09;DDR技术的演进 &#xff1a; &#xff08;4&#xff09;需求推动&#xff1a; 2、了解内存 &#xff08;1&…

go学习笔记-从圣经中抄录的接口值的思考

接口值 接口值&#xff0c;由两个部分组成&#xff0c;一个具体的类型和那个类型的值 下面4个语句中&#xff0c;变量w得到了3个不同的值。&#xff08; 开始和最后的值是相同的&#xff09; var w io.Writer w os.Stdout w new(bytes.Buffer) w nil var w io.Writer var…

Python中的数据类型与函数之美

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、Python中的数据类型初探 代码案例&#xff1a; 二、Python内置函数的魅力 代码案例&a…