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

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

 更新時間:2024年07月08日 11:56:14   作者:沐雨橙風(fēng)ιε  
這篇文章主要介紹了解決子線程中獲取不到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對象,都能獲取到,覺得很是奇怪。

點進(jìn)去RequestContextHolder這個類的代碼里看了一下,好像找到問題了~

這是基于ThreadLocal實現(xiàn)的,可能與子線程無法訪問父線程中設(shè)置的數(shù)據(jù)的問題有關(guān)。

為了驗證自己的猜測,點開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+鼠標(biāo)點擊,發(fā)現(xiàn)實際調(diào)用的是這個方法
     * 所以默認(rèn)是通過ThreadLocal保存的變量
	 */
    public static void setRequestAttributes(@Nullable RequestAttributes attributes) {
		setRequestAttributes(attributes, false);
	}
 
    /**
	 * 獲取ThreadLocal中設(shè)置的RequestAttributes對象 
	 */
	@Nullable
	public static RequestAttributes getRequestAttributes() {
        // 因為默認(rèn)是通過ThreadLocal而不是InheritableThreadLocal保存,
        // 在子線程訪問不到在父線程中通過set()方法設(shè)置的變量
		RequestAttributes attributes = requestAttributesHolder.get();
 
        // 所以在子線程中,會走這個分支
		if (attributes == null) {
            // 然后從InheritableThreadLocal中獲取RequestAttributes對象
            // 因為調(diào)用上面第一個setRequestAttributes(RequestAttributes, boolean)方法時傳的參數(shù)是false,所以InheritableThreadLocal中沒有設(shè)置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;
    }
 
}

總結(jié)

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

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

相關(guān)文章

  • Java之SSM中bean相關(guān)知識匯總案例講解

    Java之SSM中bean相關(guān)知識匯總案例講解

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

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

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

    Java應(yīng)用打包成Docker鏡像

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

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

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

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

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

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

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

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

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

    SpringCloud微服務(wù)的調(diào)用與遠(yuǎn)程調(diào)用測試示例

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

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

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

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

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

最新評論

林西县| 德令哈市| 兖州市| 蓝山县| 石阡县| 英吉沙县| 天长市| 布拖县| 衡南县| 道孚县| 南阳市| 郴州市| 永平县| 旬邑县| 麟游县| 日喀则市| 霍城县| 区。| 宜良县| 青川县| 青岛市| 盖州市| 盱眙县| 龙胜| 明溪县| 新野县| 凉城县| 澄迈县| 顺义区| 六枝特区| 蓬莱市| 大名县| 永州市| 博白县| 丁青县| 岢岚县| 成武县| 石门县| 阳春市| 镇巴县| 彭阳县|