SpringTask 引起的錯誤

SpringTask 引起的錯誤

1. 場景

在使用 SpringBoot 編寫后臺程序時,當在瀏覽器頁面中發起請求時,MP 自動填充來完成一些字段的填充,例如創建時間、創建人、更新時間、更新人等。但是當編寫微信小程序時,由于一些字段無法進行自動填充,例如創建人、更新人等,這時需要進行處理,來區分是否為微信端的請求

private final HttpServletRequest request;// 是否排除路徑,排除微信端的路徑,不自動填充用戶id
private boolean isExclude() {String path = request.getRequestURI();return !path.startsWith("/member");
}// 插入數據時自動填充
@Override
public void insertFill(MetaObject metaObject) {if (isExclude()) {this.strictInsertFill(metaObject, "createBy", String.class, String.valueOf(getLoginUserId()));}this.strictInsertFill(metaObject, "createTime", Date.class, DateUtils.getNowDate());
}// 修改數據時自動填充
@Override
public void updateFill(MetaObject metaObject) {if (isExclude()) {this.setFieldValByName("updateBy", String.valueOf(getLoginUserId()), metaObject);}this.setFieldValByName("updateTime", DateUtils.getNowDate(), metaObject);
}

但是此時,就會產生一個問題:當在瀏覽器端(后臺管理端)使用定時任務時(這里以 SpringTask 舉例),就會出現異常


提示 “當前請求并未為 Web 請求”,后來經過層層排查,發現是自動填充處使用了 HttpServletRequest 來獲取當前請求詳情。

在場景中,isExclude 方法依賴于 HttpServletRequest 對象來獲取請求路徑。然而,定時任務并不屬于 Web 請求的一部分,因此在定時任務執行時,HttpServletRequest 對象不可用,這會導致遇到的 IllegalStateException 異常。

2. 解決方案

為了解決這個問題,可以考慮以下幾種方法:

  1. 檢查請求是否存在:在 isExclude 方法中添加一個檢查,判斷 HttpServletRequest 是否為空,如果為空則直接返回 truefalse,具體根據你的業務需求來決定。但這只是避免了異常,并沒有真正解決問題,因為定時任務確實不需要根據請求路徑來判斷是否填充用戶信息。
  2. 使用不同的條件來判斷是否排除:如果定時任務和微信端請求可以通過其他方式區分開來(比如特定的線程池、特定的任務標識等),你可以考慮使用這些方式來判斷,而不是依賴請求路徑。
  3. 將用戶ID作為參數傳遞:對于定時任務,你可以在任務觸發時直接傳遞用戶ID,而不是在任務內部去獲取。這樣可以避免對 HttpServletRequest 的依賴。
  4. 使用不同的 MetaObjectHandler 實現:為定時任務創建一個獨立的 MetaObjectHandler 實現,這個實現不需要考慮 HttpServletRequest,也不需要調用 isExclude 方法。
  5. 修改定時任務邏輯:在定時任務中,手動填充創建人或更新人字段,而不是依賴 MetaObjectHandler 來自動填充。這樣可以確保定時任務在執行時不會調用 isExclude 方法。
  6. 基于任務類型進行判斷:在 MetaObjectHandler 類中增加一個字段,用于標識當前操作的類型(比如是定時任務還是 Web 請求),在 insertFillupdateFill 方法中根據這個字段來決定是否執行 isExclude 方法的判斷。

3. 修改

這里使用一種很簡單的方法,使用 RequestContextHolder.getRequestAttributes() 方法來判斷當前線程是否綁定了一個 Web 請求的上下文,這是一種常見的方法來區分 Web 請求和其他非 Web 請求(例如定時任務)的線程上下文。這種方法在 Spring 框架中被廣泛用于獲取當前請求的相關信息,而不會拋出 No thread-bound request found 這樣的異常。

具體來說,在的 isExclude 方法中,通過檢查 RequestContextHolder.getRequestAttributes() 返回的結果是否為 null,可以判斷當前線程是否在一個 Web 請求的上下文中。如果返回的是 null,說明當前線程不是在一個 Web 請求中,因此可以決定不執行某些依賴于 Web 請求的操作,比如填充 createByupdateBy 字段。

private boolean isExclude() {// 校驗是否為 Web 請求,避免非 Web 請求導致 IllegalStateException 異常ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if (attributes != null) {HttpServletRequest request = attributes.getRequest();String path = request.getRequestURI();return !path.startsWith("/member");}return false;
}

以下是一些關鍵點,幫助更好地理解這種方法:

  1. RequestContextHolder: 這個類提供了對當前請求的訪問。通過 getRequestAttributes() 方法,可以獲取到當前線程的請求屬性。
  2. ServletRequestAttributes: 這是 RequestContextHolder.getRequestAttributes() 返回的對象類型之一,包含了當前請求的相關信息。
  3. 判斷是否為 web 請求: 通過檢查 RequestContextHolder.getRequestAttributes() 是否返回 null,可以判斷當前線程是否在一個 web 請求的上下文中。如果不是 null,則可以安全地獲取 HttpServletRequest 并進行相關操作。
  4. ThreadLocal 使用: 盡管在 MyMetaObjectHandler 中沒有直接使用 ThreadLocal 來判斷是否為 web 請求,但 Spring 框架本身在處理 web 請求時會使用 ThreadLocal 來存儲請求的上下文信息。因此,RequestContextHolder.getRequestAttributes() 能夠正確地識別當前線程是否為 web 請求線程。

這種方法不僅能夠有效地區分 Web 請求和其他請求,還能避免出現 No thread-bound request found 的異常,是一個比較優雅的解決方案。如果有其他特定的需求或場景,也可以考慮自定義 ThreadLocal 變量來標識不同的請求類型,但通常情況下,使用 Spring 提供的 RequestContextHolder 就可以滿足大多數需求。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/72574.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/72574.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/72574.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

FPGA學習篇——Verilog學習4

1.1 結構語句 結構語句主要是initial語句和always語句,initial 語句它在模塊中只執行一次,而always語句則不斷重復執行,以下是一個比較好解釋的圖: (圖片來源于知乎博主羅成,畫的很好很直觀!) 1.1.1 initial語句 ini…

【Linux】【網絡】UDP打洞-->不同子網下的客戶端和服務器通信(未成功版)

【Linux】【網絡】UDP打洞–>不同子網下的客戶端和服務器通信(未成功版) 上次說基于UDP的打洞程序改了五版一直沒有成功,要寫一下問題所在,但是我后續又查詢了一些資料,成功實現了,這次先寫一下未成功的…

【Python編程】高性能Python Web服務部署架構解析

一、FastAPI 與 Uvicorn/Gunicorn 的協同 1. 開發環境:Uvicorn 直接驅動 作用:Uvicorn 作為 ASGI 服務器,原生支持 FastAPI 的異步特性,提供熱重載(--reload)和高效異步請求處理。 啟動命令: u…

前端權限流程(基于rbac實現思想)

1. 權限控制 1.1. 實現思想 基于rbac權限控制思想實現,給用戶分配角色,給角色分配權限 給用戶分配角色業務 注意:上方圖片是個示例圖,代表給用戶分配職位(角色),頁面中使用了Element-plus的el- checkbox組件…

軟件高級架構師 - 軟件工程

補充中 測試 測試類型 靜態測試 動態測試 測試階段 單元測試中,包含性能測試,如下: 集成測試中,包含以下: 維護 遺留系統處置 高水平低價值:采取集成 對于這類系統,采取 集成 的方式&…

python3.13安裝教程【2025】python3.13超詳細圖文教程(包含安裝包)

文章目錄 前言一、python3.13安裝包下載二、Python 3.13安裝步驟三、Python3.13驗證 前言 本教程將為你詳細介紹 Python 3.13 python3.13安裝教程,幫助你順利搭建起 Python 3.13 開發環境,快速投身于 Python 編程的精彩實踐中。 一、python3.13安裝包下…

【極客時間】瀏覽器工作原理與實踐-2 宏觀視角下的瀏覽器 (6講) - 2.5 渲染流程(上):HTML、CSS和JavaScript,是如何變成頁面的?

https://time.geekbang.org/column/article/118205 2.5 渲染流程(上):HTML、CSS和JavaScript,是如何變成頁面的? 2.4講了導航相關的流程,那導航被提交后又會怎么樣呢? 就進入了渲染階段。 這…

小模型和小數據可以實現AGI嗎

小模型和小數據很難實現真正的 通用人工智能(AGI, Artificial General Intelligence),但在特定任務或受限環境下,可以通過高效的算法和優化方法實現“近似 AGI” 的能力。 1. 為什么小模型小數據難以實現 AGI? AGI 需…

Android14 OTA差分包升級報kPayloadTimestampError (51)

由于VF 架構, 所以鏡像的打包時間可能存在偏差, 如 boot.img 和 客制化的一些鏡像打包 可能會在 vendor 側進行打包。 而 與system 側進行merge 時,時間戳比較亂,為了解決這個問題,讓時間戳進行統一。 使用adb方式驗證…

CMake學習筆記(一):工程的新建和如何將源文件生成二進制文件

cmake是我們在工作過程中比較常見的一個工具,該系列文章是自己用來學習的筆記。目前只是記錄下自己學習cmake的過程中的一些重要的知識點,其是以項目需求為導向并非完整的cmake的學習路線和系統,同樣也并非適合所有的人。 1.生成一個可執行文…

重定位(1)

一、重定位 1、對于有強大ROM的板子,他們會將上電后的程序放到指定RAM內存 2、無強大片內ROM的板子,自己編程序讓他知道RAM內存指定位置 指定位置:就是鏈接地址,指定哪里,哪里就被編譯好一塊內存用來存放上電的程序 …

自由學習記錄(41)

代理服務器的核心功能是在客戶端(用戶設備)和目標服務器(網站/資源服務器)之間充當“中介”,具體過程如下: 代理服務器的工作流程 當客戶端希望訪問某個網站(比如 example.com)時&…

Jadx Gui 的詳細介紹、安裝指南、使用方法及配置說明

Jadx Gui:安卓應用逆向分析神器 一、Jadx Gui 簡介 Jadx 是一款開源的 Android 反編譯工具,支持將 .apk、.aab、.dex 等文件反編譯為可讀的 Java/Kotlin 源代碼和資源文件(如 XML、PNG)。其特點包括: 圖形化界面&am…

Linux+apache之 瀏覽器訪問云服務器磁盤的圖片,通過tomcat

https://javab.blog.csdn.net/article/details/80580520 安裝tomcact 修改添加 <Context docBase"/home/wyp/images" path"/img" debug"0" reloadable"true" />修改完成后保存重啟tomcat服務。 測試訪問方式&#xff1a;http…

軟件工程與實踐(第4版 新形態) 練習與實踐1

軟件工程與實踐&#xff08;第4版 新形態&#xff09; 練習與實踐1 1.填空題 (1)程序&#xff0c;文檔 (2)系統軟件&#xff0c;支撐軟件&#xff0c;應用軟件 (3)系統方法 (4)軟件開發和維護 (5)工程的概念、原理、技術和方法 (6)實現軟件的優質高產 (7)軟件開發技術和…

基于遺傳算法的無人機三維路徑規劃仿真步驟詳解

基于遺傳算法的無人機三維路徑規劃仿真步驟詳解 一、問題定義 目標:在三維空間內,尋找從起點到終點的最優路徑,需滿足: 避障:避開所有障礙物。路徑最短:總飛行距離盡可能短。平滑性:轉折角度不宜過大,降低機動能耗。輸入: 三維地圖(含障礙物,如立方體、圓柱體)。起…

LIUNX學習-線程

線程概念 一個進程需要訪的大部分資源&#xff0c;諸如自身的代碼、數據、new\malloc的空間數據、命令行參數和環境變量、動態庫、甚至是系統調用訪問內核代碼…都是通過虛擬地址空間來訪問的。換而言之&#xff0c;進程地址空間是進程的資源窗口&#xff01;&#xff01; ? …

1.Big-endian/ little endian大端對齊、小端對齊

一、大端模式、小端模式的介紹 Little endian&#xff1a;是低位字節排放在內存的低地址端、高位字節排放在內存的高地址端。 Big-endian&#xff1a;是高位字節排放在內存的低地址端、低位字節排放在內存的高地址端。 西門子是大端模式&#xff0c;因為比如 MW100 MB100(高位…

[mybatis]resultMap詳解

resultMap Mybatis中提供了resultMap功能&#xff0c;可以將數據庫查詢結果映射到Java對象&#xff0c;用于解決 字段名與屬性名不一致 或 復雜關系&#xff08;如一對多&#xff09;的映射問題。 比如一個User類&#xff0c;在它的屬性里還有另一個子對象&#xff08;或者多…

SpringBoot Actuator

SpringBoot Actuator 一、簡介二、入門1、依賴2、默認監控指標3、查詢監控指標4、全量監控指標 三、Spring Boot Admin1、主要功能2、Admin3、Client4、應用墻5、其他 四、定制化1、定制Health端點2、定制Info端點3、定制Metrics端點4、定制Endpoint端點 一、簡介 SpringBoot自…