江苏省网站建设与管理历年自考试题,商城网站 价格,网站开发工具的,wordpress page title文章目录 前言一、Servlet 资源转发是什么#xff1f;1. 为什么要资源转发#xff1f; 二、资源转发 vs 重定向三、如何使用 RequestDispatcher 进行资源转发1. 引入依赖2. 获取 RequestDispatcher3. forward 示例4. include 示例JSP 中 include 指令或动作Servlet 中 includ… 文章目录 前言一、Servlet 资源转发是什么1. 为什么要资源转发 二、资源转发 vs 重定向三、如何使用 RequestDispatcher 进行资源转发1. 引入依赖2. 获取 RequestDispatcher3. 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 中的同等接口完成 forward 或 include 操作。
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 APIJava EE/Servlet 规范为主。
1. 引入依赖
如果使用 Maven Servlet 容器如 Tomcat通常在项目中引入如下依赖在 Servlet 规范已由容器提供时这里可仅在编译时作用
dependencygroupIdjavax.servlet/groupIdartifactIdjavax.servlet-api/artifactIdversion4.0.1/versionscopeprovided/scope
/dependency或 Jakarta EE
dependencygroupIdjakarta.servlet/groupIdartifactIdjakarta.servlet-api/artifactIdversion5.0.0/versionscopeprovided/scope
/dependency2. 获取 RequestDispatcher
在 Servlet 的 doGet 或 doPost 中可以通过以下方式获取
// 相对路径基于当前 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);// 处理主体逻辑ListItem 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;charsetUTF-8) 等。 四、注意事项与常见陷阱 response 已提交后不能 forward/include 如果输出已 flush 到客户端如调用 response.getWriter() 并写入大量内容后 flush再调用 forward 会抛 IllegalStateException。建议在 forward 前设置好全部属性、编码不要提前输出内容。 路径书写要正确 推荐用以 / 开头的绝对路径基于 Web 应用根目录如 /WEB-INF/views/...。切勿使用相对路径不以 / 开头可能导致寻找不到资源。 字符编码 在接收 POST 请求参数前确保设置 request.setCharacterEncoding(UTF-8)。JSP 页面应有 % page contentTypetext/html;charsetUTF-8 %且容器配置匹配。 JSP 放置位置 通常将 JSP 放在 WEB-INF 目录避免用户直接通过 URL 访问必须通过 Servlet forward 访问以控制流程和权限。若静态资源CSS、JS、图片等需直接访问则放在 webapp 根或静态目录。 在 Filter 中使用 forward 过滤器可在 doFilter 中通过 chain.doFilter(request, response) 继续执行或在某条件下 request.getRequestDispatcher(...).forward(...)。注意一旦 forward需要 return否则后续代码及 chain 可能出现逻辑混乱。 跨 Context 转发不同 Web 应用之间 标准 Servlet API 不支持跨 Context 直接 forward可通过 ServletContext.getContext(/otherApp) 获取另一个 context 的 RequestDispatcher但大多数容器默认禁用或安全限制较多需谨慎。一般建议通过外部重定向或共享服务层实现跨应用调用。 并发和线程安全 forward 本身线程安全但若在请求作用域或 session 作用域中存储可变共享对象需注意并发访问。Servlet 实例通常为单例多线程并发执行 doGet/doPost请避免在 Servlet 成员变量中存储与请求相关状态。 调试技巧 容易遇到 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
servletservlet-nameUserListServlet/servlet-nameservlet-classcom.example.servlet.UserListServlet/servlet-class
/servlet
servlet-mappingservlet-nameUserListServlet/servlet-nameurl-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;
}