最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解決子線程中獲取不到HttpServletRequest對象的問題

 更新時間:2024年07月08日 11:56:14   作者:沐雨橙風ιε  
這篇文章主要介紹了解決子線程中獲取不到HttpServletRequest對象的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

子線程中獲取不到HttpServletRequest對象

本文主要分享一下項目里遇到的獲取request對象為null的問題,具體是在登錄的時候觸發(fā)的郵箱提醒,獲取客戶端ip地址,然后通過ip地址定位獲取定位信息,從而提示賬號在哪里登錄。

但是登錄卻發(fā)現(xiàn)獲取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實現(xiàn)的,可能與子線程無法訪問父線程中設置的數(shù)據(jù)的問題有關。

為了驗證自己的猜測,點開RequestContextHolder的源代碼~

public abstract class RequestContextHolder  {    
    private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
			new NamedThreadLocal<>("Request attributes");
 
	private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
			new NamedInheritableThreadLocal<>("Request context");
 
	/**
	 * 根據(jù)inheritable的值決定通過ThreadLocal或InhertitableThreadLocal保存RequestAttributes對象 
	 */
	public static void setRequestAttributes(@Nullable RequestAttributes attributes, boolean inheritable) {
		if (attributes == null) {
			resetRequestAttributes();
		} else {
			if (inheritable) {
				inheritableRequestAttributesHolder.set(attributes);
 
				requestAttributesHolder.remove();
			} else {
				requestAttributesHolder.set(attributes);
 
				inheritableRequestAttributesHolder.remove();
			}
		}
	}
 
    /**
	 * 通過Ctrl+鼠標點擊,發(fā)現(xiàn)實際調(diào)用的是這個方法
     * 所以默認是通過ThreadLocal保存的變量
	 */
    public static void setRequestAttributes(@Nullable RequestAttributes attributes) {
		setRequestAttributes(attributes, false);
	}
 
    /**
	 * 獲取ThreadLocal中設置的RequestAttributes對象 
	 */
	@Nullable
	public static RequestAttributes getRequestAttributes() {
        // 因為默認是通過ThreadLocal而不是InheritableThreadLocal保存,
        // 在子線程訪問不到在父線程中通過set()方法設置的變量
		RequestAttributes attributes = requestAttributesHolder.get();
 
        // 所以在子線程中,會走這個分支
		if (attributes == null) {
            // 然后從InheritableThreadLocal中獲取RequestAttributes對象
            // 因為調(diào)用上面第一個setRequestAttributes(RequestAttributes, boolean)方法時傳的參數(shù)是false,所以InheritableThreadLocal中沒有設置RequestAttributes對象,因此,這里get()還是null,最后attributes的值為null
			attributes = inheritableRequestAttributesHolder.get();
		}
 
		return attributes;
	}
 
}

于是,把涉及獲取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;
 
    @Autowired
    public EmailSendHandler(
            EmailUtils emailUtils,
            EmailProperties emailProperties,
            SystemSettingsProperties systemSettingsProperties) {
        this.emailUtils = emailUtils;
        this.emailProperties = emailProperties;
        this.systemSettingsProperties = systemSettingsProperties;
    }
 
    @Override
    public 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();
        }
    }
 
    @Override
    public void setNext(UserLoginHandler next) {
        this.next = next;
    }
 
    @Override
    public void setParams(Object params) {
        this.params = params;
    }
 
}

總結

遇到這類問題,就把獲取request對象的代碼放在主線程中,避免因為ThreadLocal的問題導致程序異常。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • Java之SSM中bean相關知識匯總案例講解

    Java之SSM中bean相關知識匯總案例講解

    這篇文章主要介紹了Java之SSM中bean相關知識匯總案例講解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • Java8使用Stream流實現(xiàn)List列表查詢、統(tǒng)計、排序以及分組

    Java8使用Stream流實現(xiàn)List列表查詢、統(tǒng)計、排序以及分組

    List的Stream流操作可以簡化我們的代碼,減少程序運行的壓力,應對上面的問題,下面這篇文章主要給大家介紹了關于Java8使用Stream流實現(xiàn)List列表查詢、統(tǒng)計、排序以及分組的相關資料,需要的朋友可以參考下
    2023-06-06
  • Java應用打包成Docker鏡像

    Java應用打包成Docker鏡像

    這篇文章主要為大家介紹了Java應用打包成Docker鏡像的過程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • SpringBoot統(tǒng)一接口返回及全局異常處理高級用法

    SpringBoot統(tǒng)一接口返回及全局異常處理高級用法

    這篇文章主要為大家介紹了SpringBoot統(tǒng)一接口返回及全局異常處理高級用法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • 一文學會使用sa-token解決網(wǎng)站權限驗證

    一文學會使用sa-token解決網(wǎng)站權限驗證

    這篇文章主要為大家介紹了使用sa-token解決網(wǎng)站權限驗證方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-07-07
  • Java 3D入門之基本圖形功能 附源碼

    Java 3D入門之基本圖形功能 附源碼

    Java3D API是Sun定義的用于實現(xiàn)3D顯示的接口。3D技術是底層的顯示技術,Java3D提供了基于Java的上層接口。Java3D把OpenGL和DirectX這些底層技術包裝在Java接口中。這種全新的設計使3D技術變得不再繁瑣且可以加入到J2SE、J2EE的整套架構,故保證了Java3D技術強大的擴展性
    2021-10-10
  • mybatis報錯元素內(nèi)容必須由格式正確的字符數(shù)據(jù)或標記組成異常的解決辦法

    mybatis報錯元素內(nèi)容必須由格式正確的字符數(shù)據(jù)或標記組成異常的解決辦法

    今天小編就為大家分享一篇關于mybatis查詢出錯解決辦法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • SpringCloud微服務的調(diào)用與遠程調(diào)用測試示例

    SpringCloud微服務的調(diào)用與遠程調(diào)用測試示例

    這篇文章主要介紹了SpringCloud微服務的調(diào)用與遠程調(diào)用測試示例,服務調(diào)用者-可以暫時認為是與用戶交互的角色(因為存在微服務之間的調(diào)用),可以根據(jù)該用戶的類型將其賦予不同的服務調(diào)用權限,通過一次http請求訪問調(diào)用對應的微服務獲取想要的數(shù)據(jù)
    2023-04-04
  • 一文詳解如何更改電腦使用的JDK版本

    一文詳解如何更改電腦使用的JDK版本

    我們在日常學習或者工作中,難免會遇到需要使用不同的jdk版本進行開發(fā),這篇文章主要給大家介紹了關于如何更改電腦使用的JDK版本的相關資料,需要的朋友可以參考下
    2024-01-01
  • Spring Boot集成教程之異步調(diào)用Async

    Spring Boot集成教程之異步調(diào)用Async

    在項目中,當訪問其他人的接口較慢或者做耗時任務時,不想程序一直卡在耗時任務上,想程序能夠并行執(zhí)行,我們可以使用多線程來并行的處理任務,也可以使用spring提供的異步處理方式@Async。需要的朋友們下面來一起看看吧。
    2018-03-03

最新評論

公主岭市| 忻城县| 通化县| 久治县| 广宁县| 河北区| 罗甸县| 东丰县| 固阳县| 万全县| 河津市| 亳州市| 溧水县| 勐海县| 罗江县| 霍山县| 平和县| 阿拉善右旗| 井冈山市| 安丘市| 米泉市| 庐江县| 平舆县| 池州市| 铅山县| 水城县| 万载县| 广水市| 江北区| 云和县| 宣威市| 安陆市| 横山县| 祁阳县| 太仓市| 武定县| 丹凤县| 兰坪| 新沂市| 株洲市| 浦城县|