【Servlet資源轉發介紹】

文章目錄

  • 前言
  • 一、Servlet 資源轉發是什么?
    • 1. 為什么要資源轉發?
  • 二、資源轉發 vs 重定向
  • 三、如何使用 RequestDispatcher 進行資源轉發
    • 1. 引入依賴
    • 2. 獲取 RequestDispatcher
    • 3. forward 示例
    • 4. include 示例
      • JSP 中 include 指令或動作
      • Servlet 中 include
  • 四、注意事項與常見陷阱
  • 五、基于注解與 web.xml 配置
  • 六、在現代框架中的類比


前言

在 Java Web 開發中,Servlet 作為服務端處理請求的重要組件,通常會在業務邏輯處理完成后,將請求或數據“轉發”到另一個資源(如 JSP、另一個 Servlet、靜態資源等)進行展示或后續處理。


一、Servlet 資源轉發是什么?

Servlet 資源轉發是指在服務器端,將當前 HTTP 請求(及其附帶的請求屬性、參數等)由一個資源(Servlet、JSP、HTML 等)內部傳遞到另一個資源處理或展示,而不再讓客戶端發起新的請求。典型方式是通過 javax.servlet.RequestDispatcher(或 Jakarta EE 中的同等接口)完成 forwardinclude 操作。

  • forward:將請求“完全”轉給目標資源處理,目標資源處理完成后,返回響應給客戶端;客戶端看到的 URL 不會改變,仍然是最初的請求 URL。
  • include:在當前響應中“嵌入”另一個資源的輸出,通常用于頁面片段(如頭部、尾部、側邊欄等)的復用。

1. 為什么要資源轉發?

  • 隱藏真實資源路徑:客戶端只看到請求 URL,內部可以組織不同資源處理和渲染。
  • 共享請求數據:可以在轉發前通過 request.setAttribute(...) 設置數據,目標資源直接通過 request.getAttribute(...) 獲取,無需重新請求或重定向傳參。
  • 性能與體驗:服務器端無需額外與客戶端交互,只做內部轉發,減少一次 HTTP 往返。
  • 職責分離:將業務邏輯與視圖渲染分離。Servlet 處理業務、準備數據后,通過轉發到 JSP/模板渲染頁面。

二、資源轉發 vs 重定向

特性資源轉發(forward)重定向(redirect)
機制類型服務器端內部轉發服務器向客戶端發送 302 狀態碼,客戶端再發起新請求
URL 變化不改變:瀏覽器地址欄仍顯示原始 URL改變:地址欄顯示重定向后的新 URL
請求/響應完整性保留同一次請求:request、response 對象同一實例新請求:無法保留原 request 的屬性;需要通過參數或 Session 傳遞
性能較好:一次請求、服務器內部跳轉較差:多一次 HTTP 往返
適用場景同一站內資源、內部分發、MVC 中轉發到視圖跨站、登錄后重定向到新頁面、避免表單重復提交(POST-Redirect-GET)
瀏覽器可見性不可見:瀏覽器地址欄不知內部轉發可見:地址欄顯示真實新的 URL

例如:登錄表單提交后,如果想在同一請求中校驗并展示錯誤信息,通常用 forward;如果登錄成功后,想讓瀏覽器地址欄跳轉到首頁且避免刷新時重復提交,一般用 redirect。


三、如何使用 RequestDispatcher 進行資源轉發

以下以傳統 Servlet API(Java EE/Servlet 規范)為主。

1. 引入依賴

如果使用 Maven + Servlet 容器(如 Tomcat),通常在項目中引入如下依賴(在 Servlet 規范已由容器提供時,這里可僅在編譯時作用):

<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope>
</dependency>

或 Jakarta EE:

<dependency><groupId>jakarta.servlet</groupId><artifactId>jakarta.servlet-api</artifactId><version>5.0.0</version><scope>provided</scope>
</dependency>

2. 獲取 RequestDispatcher

在 Servlet 的 doGetdoPost 中,可以通過以下方式獲取:

// 相對路徑,基于當前 Servlet 的 context 路徑
RequestDispatcher rd1 = request.getRequestDispatcher("/WEB-INF/views/result.jsp");// 也可通過 ServletContext 獲取,路徑以 “/” 開頭,代表相對于 webapp 根
RequestDispatcher rd2 = getServletContext().getRequestDispatcher("/WEB-INF/views/result.jsp");
  • request.getRequestDispatcher(path):路徑若以 / 開頭,表示相對于當前 web 應用根;若不以 / 開頭,表示相對于調用 Servlet 的路徑,需要注意常見誤區,建議始終以 / 開頭。
  • getServletContext().getRequestDispatcher(path):路徑必須以 / 開頭,相對于 web 應用根。

3. forward 示例

下面示例為:用戶提交表單后,Servlet 處理邏輯,根據條件轉發到不同 JSP。

@WebServlet("/login")
public class LoginServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 1. 處理請求字符編碼(若 POST 表單)request.setCharacterEncoding("UTF-8");String username = request.getParameter("username");String password = request.getParameter("password");// 簡單校驗示例(真實應用要調用服務或 DAO 層)if ("admin".equals(username) && "password".equals(password)) {// 登錄成功:準備用戶信息User user = new User(username);request.getSession().setAttribute("currentUser", user);// 轉發到歡迎頁面RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/welcome.jsp");rd.forward(request, response);} else {// 登錄失敗:設置錯誤信息并轉發回登錄頁面request.setAttribute("errorMessage", "用戶名或密碼錯誤");RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/login.jsp");rd.forward(request, response);}}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 直接跳轉到登錄頁面RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/login.jsp");rd.forward(request, response);}
}
  • 注意:forward 之前不能執行 response.getWriter().write(...) 等會提交響應體或 commit response 的操作,否則會拋 IllegalStateException。
  • 路徑:通常將 JSP 放在 WEB-INF 目錄下,以防用戶直接通過 URL 訪問,只能通過轉發訪問。

4. include 示例

當想在某頁面中復用一些公共片段(如頁頭、導航、頁腳),可以在 JSP/Servlet 中使用 include:

JSP 中 include 指令或動作

<%@ include file="/WEB-INF/views/common/header.jsp" %>  <%-- 編譯時包含,靜態包含 --%>
<jsp:include page="/WEB-INF/views/common/navbar.jsp" />  <%-- 運行時包含 --%><!-- 頁面內容主體 --><jsp:include page="/WEB-INF/views/common/footer.jsp" />

Servlet 中 include

@WebServlet("/report")
public class ReportServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {// 先在響應中輸出一些信息,或通過 include 嵌入其他資源RequestDispatcher header = req.getRequestDispatcher("/WEB-INF/views/common/header.jsp");header.include(req, resp);// 處理主體邏輯List<Item> data = fetchData();req.setAttribute("items", data);RequestDispatcher body = req.getRequestDispatcher("/WEB-INF/views/reportBody.jsp");body.include(req, resp);// 頁腳RequestDispatcher footer = req.getRequestDispatcher("/WEB-INF/views/common/footer.jsp");footer.include(req, resp);}
}
  • include 不會改變請求的處理流,執行完 include 后,控制權回到原 Servlet,可繼續輸出內容。
  • 注意響應緩沖區和字符編碼:在 include 之前應設置好 response.setContentType("text/html;charset=UTF-8") 等。

四、注意事項與常見陷阱

  1. response 已提交后不能 forward/include

    • 如果輸出已 flush 到客戶端(如調用 response.getWriter() 并寫入大量內容后 flush),再調用 forward 會拋 IllegalStateException
    • 建議:在 forward 前設置好全部屬性、編碼,不要提前輸出內容。
  2. 路徑書寫要正確

    • 推薦用以 / 開頭的絕對路徑,基于 Web 應用根目錄,如 /WEB-INF/views/...
    • 切勿使用相對路徑(不以 / 開頭),可能導致尋找不到資源。
  3. 字符編碼

    • 在接收 POST 請求參數前確保設置 request.setCharacterEncoding("UTF-8")
    • JSP 頁面應有 <%@ page contentType="text/html;charset=UTF-8" %>,且容器配置匹配。
  4. JSP 放置位置

    • 通常將 JSP 放在 WEB-INF 目錄,避免用戶直接通過 URL 訪問,必須通過 Servlet forward 訪問,以控制流程和權限。
    • 若靜態資源(CSS、JS、圖片等)需直接訪問,則放在 webapp 根或靜態目錄。
  5. 在 Filter 中使用 forward

    • 過濾器可在 doFilter 中通過 chain.doFilter(request, response) 繼續執行或在某條件下 request.getRequestDispatcher(...).forward(...)。注意,一旦 forward,需要 return,否則后續代碼及 chain 可能出現邏輯混亂。
  6. 跨 Context 轉發(不同 Web 應用之間)

    • 標準 Servlet API 不支持跨 Context 直接 forward;可通過 ServletContext.getContext("/otherApp") 獲取另一個 context 的 RequestDispatcher,但大多數容器默認禁用或安全限制較多,需謹慎。
    • 一般建議通過外部重定向或共享服務層實現跨應用調用。
  7. 并發和線程安全

    • forward 本身線程安全,但若在請求作用域或 session 作用域中存儲可變共享對象,需注意并發訪問。
    • Servlet 實例通常為單例,多線程并發執行 doGet/doPost,請避免在 Servlet 成員變量中存儲與請求相關狀態。
  8. 調試技巧

    • 容易遇到 404 Not Found(找不到 JSP),先檢查路徑是否正確,是否已編譯到目標目錄。
    • 瀏覽器地址欄不變:在測試時注意 URL 不變特性,方便判斷是否發生了 forward。

五、基于注解與 web.xml 配置

  • 注解方式(Servlet 3.0+ 推薦):在 Servlet 類上使用 @WebServlet("/path"),無需在 web.xml 再額外配置。
  • web.xml 方式:老項目或精細配置時,可在 WEB-INF/web.xml 中配置 <servlet><servlet-mapping>。兩者對 forward 使用無影響,關鍵在于 Dispatcher 的路徑。

示例(web.xml):

<servlet><servlet-name>UserListServlet</servlet-name><servlet-class>com.example.servlet.UserListServlet</servlet-class>
</servlet>
<servlet-mapping><servlet-name>UserListServlet</servlet-name><url-pattern>/users</url-pattern>
</servlet-mapping>

六、在現代框架中的類比

雖然本文聚焦原生 Servlet,但在常見 MVC 框架中(如 Spring MVC),也存在“轉發”概念。例如在 Spring MVC Controller 中,返回視圖名時,框架默認會將請求轉發到相應的視圖渲染器;若要重定向,可以使用 redirect: 前綴。理解 Servlet 原理有助于深入掌握框架行為。

@GetMapping("/hello")
public String hello(Model model) {model.addAttribute("msg", "Hello");// 返回視圖名,最終內部類似 forward 到 /WEB-INF/views/hello.jspreturn "hello";
}@GetMapping("/goRedirect")
public String goRedirect() {// 重定向示例:客戶端會看到 URL 變化return "redirect:/otherPage";
}

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

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

相關文章

牛客周賽 Round 99題解

Round 99 思路&#xff1a;我們之間去用字符串去統計即可&#xff0c;輸入一個字符串&#xff0c;看相鄰有沒有99即可 #include<bits/stdc.h> using namespace std; #define int long long string s; signed main() {cin>>s;int ns.size();for(int i1;i<n;i){i…

AR 如何改變我們構建網站的方式

想坐在沙發上試鞋子&#xff1f;歡迎來到 Web AR 的世界。還記得你在網頁上逛商城時&#xff0c;點擊一副墨鏡&#xff0c;然后鏡頭打開&#xff0c;它就自動出現在你臉上的那一瞬間嗎&#xff1f;不需要下載 App&#xff0c;不需要跳轉&#xff0c;只需一個瀏覽器。這不是科幻…

華為OD機試 2025B卷 - 貨幣單位轉換(C++PythonJAVAJSC語言)

2025B卷目錄點擊查看: 華為OD機試2025B卷真題題庫目錄|機考題庫 + 算法考點詳解 2025B卷 100分題型 題目描述 記賬本上記錄了若干條多國貨幣金額,需要轉換成人民幣分(fen),匯總后輸出。 每行記錄一條金額,金額帶有貨幣單位,格式為數字+單位,可能是單獨元,或者單獨分…

php協程

開發需求:在一套老項目中&#xff08;fastadmin&#xff09;實現一個定時任務&#xff0c;每分鐘訪問幾十個接口&#xff0c;拿到數據。 使用的swoole&#xff0c;在thinkphp5中實現協程。啟動命令php swoole.php <?php //chdir(__DIR__); define(APP_PATH, __DIR__ . /app…

【教程】強制關閉Windows防火墻的自啟動

轉載請注明出處&#xff1a;小鋒學長生活大爆炸[xfxuezhagn.cn] 如果本文幫助到了你&#xff0c;歡迎[點贊、收藏、關注]哦~ 背景說明 字節云的Windows server真是有點問題&#xff0c;忽然就開始自動開啟防火墻&#xff0c;手動關閉了過幾個小時又重新開啟了&#xff0c;導致…

【Qt】QSignalMapper

QSignalMapper 是 Qt 提供的一個用于信號映射的類&#xff0c;它允許將多個信號源&#xff08;例如按鈕點擊&#xff09;映射到一個單一的槽函數&#xff0c;并傳遞自定義參數。這在需要根據不同的觸發對象執行相似邏輯時非常有用。 用法說明 創建 QSignalMapper 實例&#xf…

Android Binder與AIDL與Service使用案例及分析

水一篇以前寫的文章?? Binder是Android內置的一種比較高效的跨進程機制,它很復雜,也很好用,可以讓我們像調用普通方法那樣完成跨進程式方法調用和數據傳遞。我們現在只需要知道它比較復雜以及怎么使用即可。 ALDL全名Android interface Definition Language, 是Android…

基于ConvLSTM的行人檢測與跟蹤預測算法研究

基于ConvLSTM的行人檢測與跟蹤預測算法研究 摘要 本文詳細探討了基于ConvLSTM(卷積長短期記憶網絡)的行人檢測與跟蹤預測算法的設計與實現。該算法結合了卷積神經網絡(CNN)的空間特征提取能力和長短期記憶網絡(LSTM)的時間序列建模優勢,能夠有效處理視頻序列中的行人檢測與…

深度學習基礎2

5.張量索引操作 &#xff08;1&#xff09;索引操作 行列索引列表索引 print(data[[0, 2], [1, 2]]) #返回(0, 1)&#xff0c;(2, 2)兩個位置的元素print(data[[[0], [1]], [1, 2]]) # 返回0&#xff0c;1行的1&#xff0c;2列共4個元素范圍索引 print(data[:3, :2]) # 前3行前…

Web安全:CSRF的攻擊原理與防御措施

什么是 CSRF&#xff1f; CSRF&#xff08;Cross-Site Request Forgery&#xff0c;跨站請求偽造&#xff09;是一種利用 瀏覽器自動攜帶 Cookie 的機制&#xff0c;誘騙用戶在已登錄目標網站的情況下&#xff0c;執行惡意操作的攻擊方式。 攻擊核心特點&#xff1a; 攻擊者 不…

學習記錄2025

1、Cmake相關 cmake -S . -B build -S . 表示CMakeLists.txt在哪個目錄 -B build CMake生成結果在哪個路徑 build就是路徑名 簡短 cmake -B build 或進入build 文件夾下 cmake cmake --build build 在build文件夾下編譯 常量&#xff1a;CMAKE_CURRENT_LIST_DIR CMAKE…

GIT操作 學習

登錄gitee登錄方式&#xff1a;通過網站登錄&#xff0c;使用注冊時的賬號&#xff08;通常是手機號&#xff09;和密碼進行認證創建倉庫 &#xfeff;新建倉庫步驟命名規范&#xff1a;倉庫名稱應盡量符合規范&#xff0c;避免與已有倉庫沖突&#xff0c;建議使用有意義的命名…

[論文精讀]StruQ: Defending Against Prompt Injection with Structured Queries

StruQ: Defending Against Prompt Injection with Structured Queries [2402.06363] StruQ: Defending Against Prompt Injection with Structured Queries usenix security 2025 提示注入攻擊是一個重要的威脅&#xff1a;它們誘使模型偏離原始應用程序的指令&#xff0c;轉…

磁懸浮軸承的反饋線性化:非線性控制的智能解耦之道

摘要:磁懸浮軸承憑借無摩擦、高速度、長壽命等優勢,成為高速旋轉機械的理想支撐方案。然而,其本質非線性與強耦合特性使得傳統線性控制方法難以滿足高性能要求。本文深入解析反饋線性化技術如何精確解除磁懸浮系統的非線性耦合,揭示其從微分幾何理論到工程實現的核心路徑,…

探尋《答案之書》:在隨機中尋找生活的指引

我強烈推薦4本可以改變命運的經典著作&#xff1a; 《壽康寶鑒》在線閱讀白話文《欲海回狂》在線閱讀白話文《陰律無情》在線閱讀白話文《了凡四訓》在線閱讀白話文 在快節奏的現代生活中&#xff0c;人們常常面臨各種困惑與抉擇。當常規的思考與決策方式無法帶來清晰答案時&am…

【PTA數據結構 | C語言版】計算1~n平方的和加上1~n的和

本專欄持續輸出數據結構題目集&#xff0c;歡迎訂閱。 文章目錄 題目代碼 題目 給定正整數 n&#xff0c;請編寫程序&#xff0c;求 (12?n^2 )(12?n) 的值。 輸入格式&#xff1a; 輸入在一行中給出正整數 n&#xff08;≤100&#xff09;。 輸出格式&#xff1a; 在一行中…

Assistant API的原理及應用

&#x1f9e0; 什么是 Assistants API&#xff1f; &#x1f4c5; **發布日期&#xff1a;**2023年11月6日&#xff0c;OpenAI在開發者大會上發布了 Assistants API —— 一款面向開發者的工具&#xff0c;用于在應用中構建 AI 助手。 ? 它可以做什么&#xff1f; Assistants …

《北京市加快推動“人工智能+醫藥健康“創新發展行動計劃(2025-2027年)》深度解讀

引言 隨著新一輪科技革命和產業變革的深入推進,人工智能技術與醫藥健康的深度融合已成為全球科技創新的重要方向。北京市于2025年7月正式發布《北京市加快推動"人工智能+醫藥健康"創新發展行動計劃(2025-2027年)》,旨在充分發揮北京在人工智能技術策源、頭部醫療…

DPDK 關于 IOMMU 設置

一、IOMMU 基礎概念 定義:IOMMU(Input/Output Memory Management Unit)即輸入 / 輸出內存管理單元,它是一種硬件機制,用于將設備發出的內存訪問請求進行地址轉換。在現代計算機系統中,它在設備與內存之間起到橋梁作用,提供內存保護和設備隔離功能。作用: 內存保護:防止…

pg_class 系統表信息

SELECT c.relname, c.relkind, CASE WHEN c.relkind r THEN 普通表 WHEN c.relkind p THEN 分區表 WHEN c.relkind f THEN 外表 WHEN c.relkind v THEN 視圖 WHEN c.relkind m THEN 物化視圖 ELSE 其他 END as table_type_desc FROM pg_class c JOIN pg_namespace …