文章目录

  • 前言
  • 一、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 …