欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

解決子線程中獲取不到HttpServletRequest對(duì)象的問(wèn)題

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

子線程中獲取不到HttpServletRequest對(duì)象

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

但是登錄卻發(fā)現(xiàn)獲取request對(duì)象的時(shí)候報(bào)錯(cuò)了。

具體的代碼

如下:這個(gè)異常是自己手動(dòng)拋出的。

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工具類(lèi)
 * @author heyunlin
 * @version 1.0
 */
public class HttpUtils {
 
    /**
     * 獲取HttpServletRequest對(duì)象
     * @return HttpServletRequest
     */
    public static HttpServletRequest getRequest() {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
 
        if (attributes != null ) {
            return ((ServletRequestAttributes) attributes).getRequest();
        }
 
        throw new GlobalException(ResponseCode.ERROR, "獲取request對(duì)象失敗");
    }
 
}

在項(xiàng)目其他地方也有用這個(gè)工具了獲取HttpServletRequest對(duì)象,都能獲取到,覺(jué)得很是奇怪。

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

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

為了驗(yàn)證自己的猜測(cè),點(diǎn)開(kāi)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的值決定通過(guò)ThreadLocal或InhertitableThreadLocal保存RequestAttributes對(duì)象 
	 */
	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();
			}
		}
	}
 
    /**
	 * 通過(guò)Ctrl+鼠標(biāo)點(diǎn)擊,發(fā)現(xiàn)實(shí)際調(diào)用的是這個(gè)方法
     * 所以默認(rèn)是通過(guò)ThreadLocal保存的變量
	 */
    public static void setRequestAttributes(@Nullable RequestAttributes attributes) {
		setRequestAttributes(attributes, false);
	}
 
    /**
	 * 獲取ThreadLocal中設(shè)置的RequestAttributes對(duì)象 
	 */
	@Nullable
	public static RequestAttributes getRequestAttributes() {
        // 因?yàn)槟J(rèn)是通過(guò)ThreadLocal而不是InheritableThreadLocal保存,
        // 在子線程訪問(wèn)不到在父線程中通過(guò)set()方法設(shè)置的變量
		RequestAttributes attributes = requestAttributesHolder.get();
 
        // 所以在子線程中,會(huì)走這個(gè)分支
		if (attributes == null) {
            // 然后從InheritableThreadLocal中獲取RequestAttributes對(duì)象
            // 因?yàn)檎{(diào)用上面第一個(gè)setRequestAttributes(RequestAttributes, boolean)方法時(shí)傳的參數(shù)是false,所以InheritableThreadLocal中沒(méi)有設(shè)置RequestAttributes對(duì)象,因此,這里get()還是null,最后attributes的值為null
			attributes = inheritableRequestAttributesHolder.get();
		}
 
		return attributes;
	}
 
}

于是,把涉及獲取request對(duì)象ip地址獲取的代碼放在線程外面,這樣就避免了空指針問(wèn)題了~

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 = "您的賬號(hào)" + 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é)

遇到這類(lèi)問(wèn)題,就把獲取request對(duì)象的代碼放在主線程中,避免因?yàn)門(mén)hreadLocal的問(wèn)題導(dǎo)致程序異常。

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

相關(guān)文章

  • springboot項(xiàng)目獲取請(qǐng)求頭當(dāng)中的token的方法

    springboot項(xiàng)目獲取請(qǐng)求頭當(dāng)中的token的方法

    本文主要介紹了springboot項(xiàng)目獲取請(qǐng)求頭當(dāng)中的token的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-11-11
  • 淺談java面向?qū)ο蟮臄?shù)組化信息處理

    淺談java面向?qū)ο蟮臄?shù)組化信息處理

    下面小編就為大家?guī)?lái)一篇淺談java面向?qū)ο蟮臄?shù)組化信息處理。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06
  • Java編寫(xiě)的24點(diǎn)紙牌游戲

    Java編寫(xiě)的24點(diǎn)紙牌游戲

    這篇文章主要介紹了Java編寫(xiě)的24點(diǎn)紙牌游戲的相關(guān)資料,需要的朋友可以參考下
    2015-03-03
  • Java字符串替換的三種方法實(shí)際應(yīng)用

    Java字符串替換的三種方法實(shí)際應(yīng)用

    這篇文章主要給大家介紹了關(guān)于Java字符串替換的三種方法,replace和replaceAll是JAVA中常用的替換字符的方法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11
  • idea 訪問(wèn)html頁(yè)面端口號(hào)顯示的是63342而不是8080

    idea 訪問(wèn)html頁(yè)面端口號(hào)顯示的是63342而不是8080

    這篇文章主要介紹了idea 訪問(wèn)html頁(yè)面端口號(hào)顯示的是63342而不是8080,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • 淺談?dòng)胘ava實(shí)現(xiàn)事件驅(qū)動(dòng)機(jī)制

    淺談?dòng)胘ava實(shí)現(xiàn)事件驅(qū)動(dòng)機(jī)制

    這篇文章主要介紹了淺談?dòng)胘ava實(shí)現(xiàn)事件驅(qū)動(dòng)機(jī)制,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09
  • Java?hutool?List集合對(duì)象拷貝示例代碼

    Java?hutool?List集合對(duì)象拷貝示例代碼

    這篇文章主要介紹了Java?hutool?List集合對(duì)象拷貝的相關(guān)資料,文章還分享了在實(shí)現(xiàn)過(guò)程中遇到的一些問(wèn)題,并強(qiáng)調(diào)了閱讀源碼和正確配置CopyOptions的重要性,需要的朋友可以參考下
    2024-12-12
  • Java之String、StringBuffer、StringBuilder的區(qū)別分析

    Java之String、StringBuffer、StringBuilder的區(qū)別分析

    今天搞安卓在看書(shū)的時(shí)候遇到了StringBuilder這個(gè)類(lèi)型的東東,有點(diǎn)小迷,不知道它跟string、stringbuffer的關(guān)系式怎么樣的,趕快查閱相關(guān)資料,了解了個(gè)大概,拿出來(lái)分享一下
    2012-11-11
  • Java實(shí)現(xiàn)自定義LinkedList類(lèi)的示例代碼

    Java實(shí)現(xiàn)自定義LinkedList類(lèi)的示例代碼

    LinkedList類(lèi)跟ArrayList類(lèi)不同,它通過(guò)指針以及結(jié)點(diǎn)的操作對(duì)鏈表進(jìn)行增刪改查。本文就來(lái)和大家分享下Java如何為實(shí)現(xiàn)自定義LinkedList類(lèi),需要的可以參考一下
    2022-08-08
  • spring cloud oauth2 實(shí)現(xiàn)用戶認(rèn)證登錄的示例代碼

    spring cloud oauth2 實(shí)現(xiàn)用戶認(rèn)證登錄的示例代碼

    這篇文章主要介紹了spring cloud oauth2 實(shí)現(xiàn)用戶認(rèn)證登錄的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10

最新評(píng)論