请求包含(Include)和请求转发(Forward)
定义
请求包含是指将另一个Servlet的请求处理流程包含进来。
请求转发是指将请求转发给别的Servlet处理。
实现
实现请求包含和请求转发,可以使用HttpServletRequest的getRequestDispatcher()方法取得RequestDispatcher接口的实现对象实例,调用时传入请求、响应对象即可。
取得RequestDispatcher还有两个方式,通过ServletContext的getRequestDispatcher()或getNamedDispatcher()。
demo
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.test; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; @WebServlet({"/some.controller", "/world"}) public class Some extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.println("Some do one..."); RequestDispatcher dispatcher = request.getRequestDispatcher("other.view"); // 请求包含 dispatcher.include(request, response); // 请求转发 // dispatcher.forward(request, response); out.println("Some do two..."); } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.test; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Arrays; @WebServlet({"/other.view", "/view"}) public class Other extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().println("Other do one..."); } }
请求转发 forward 的响应结果是:
Other do one...
请求包含 include 的响应结果是:
Some do one...
Other do one...
Some do two...
区别
forward:目前的Servlet不能有任何响应确认,如果在目前的Servlet中通过响应对象设置了一些响应但未确认(响应缓冲区未满或未调用任何清除方法),则所有响应设置会被忽略,如果已经有响应确认且调用了forward()方法,则会抛出IllegalStateException。
include:被包含的Servlet中任何对请求标头的设置都会被忽略。但被包含的Servlet中可以使用getSession()方法取得HttpSession对象。
相同点
1、在取得RequestDispatcher时,也可以包括查询字符串。
例如:req.getRequestDispatcher("other.view?data=123456").include(req, resp);
这样在被包含或转发的Servlet中就可以使用getParameter("data")取得请求参数值。
2.查询字符串的方式,仅适用于传递字符串值给另一个Servlet;如果有必须共享的“对象”,可以设置给请求对象成为属性。
HttpServletRequest上与请求范围属性有关的几个方法如下。
setAttribute():指定名称与对象设置属性。
getAttribute():指定名称取得属性。
getAttributeNames():取得所有属性名称。
removeAttribute():指定名称移除属性。
example:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.test; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; @WebServlet({"/some.controller", "/world"}) public class Some extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setAttribute("setAttr", new int[]{1, 2, 3}); PrintWriter out = response.getWriter(); out.println("Some do one..."); RequestDispatcher dispatcher = request.getRequestDispatcher("other.view?data=123456"); // 请求包含 // dispatcher.include(request, response); // 请求转发 dispatcher.forward(request, response); out.println("Some do two..."); } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.test; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Arrays; @WebServlet({"/other.view", "/view"}) public class Other extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String data = request.getParameter("data"); int[] getAttr = (int[])request.getAttribute("setAttr"); response.getWriter().println("Other do one..." + " | " + "include or forward parameter: " + data + " | " // 请求或转发时携带的查询参数 + "setAttrbute object: " + Arrays.toString(getAttr)); // 共享对象 } }
请求转发 forward 的响应结果是:
Other do one... | include or forward parameter: 123456 | setAttrbute object: [1, 2, 3]
请求包含 include 的响应结果是:
Some do one...
Other do one... | include or forward parameter: 123456 | setAttrbute object: [1, 2, 3]
Some do two...
相似点
请 求 包 含 |
javax.servlet. include.request_uri |
javax.servlet. include.context_path |
javax.servlet. include.servlet_path |
javax.servlet. include.path_info |
javax.servlet. include.query_string |
请 求 转 发 |
javax.servlet. forward.request_uri |
javax.servlet. forward.context_path |
javax.servlet. forward.servlet_path |
javax.servlet. forward.path_info |
javax.servlet. forward.query_string |
表 示 上 一 个 Servlet 的 |
Request URI | Context path | Servlet path | Path info |
取得RequestDispatcher时 给定的查询参数 |
如果被包含或转发的Servlet还包含或转发其他的Servlet,则这些属性名称的对应值也会被代换。
example:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.test; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; @WebServlet({"/some.controller", "/world"}) public class Some extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.println("Some do one..."); RequestDispatcher dispatcher = request.getRequestDispatcher("other.view?data=123456"); // 请求包含 dispatcher.include(request, response); // 请求转发 // dispatcher.forward(request, response); out.println("Some do two..."); } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.test; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet({"/other.view", "/view"}) public class Other extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String request_uri, context_path, servlet_path, path_info, query_string; // 默认的请求包含时的参数 /*request_uri = (String)request.getAttribute("javax.servlet.include.request_uri"); context_path = (String)request.getAttribute("javax.servlet.include.context_path"); servlet_path = (String)request.getAttribute("javax.servlet.include.servlet_path"); path_info = (String)request.getAttribute("javax.servlet.include.path_info"); query_string = (String)request.getAttribute("javax.servlet.include.query_string");*/ // 默认的请求转发时的参数 request_uri = (String)request.getAttribute("javax.servlet.forward.request_uri"); context_path = (String)request.getAttribute("javax.servlet.forward.context_path"); servlet_path = (String)request.getAttribute("javax.servlet.forward.servlet_path"); path_info = (String)request.getAttribute("javax.servlet.forward.path_info"); query_string = (String)request.getAttribute("javax.servlet.forward.query_string"); response.getWriter().println("Other do one..." + " | " + "request_uri: " + request_uri + " | " + "context_path: " + context_path + " | " + "servlet_path: " + servlet_path + " | " + "path_info: " + path_info + " | " + "query_string: " + query_string ); } }
请求转发 forward 的响应结果是:
Other do one... | request_uri: /hello/some.controller | context_path: /hello | servlet_path: /some.controller | path_info: null | query_string: null
请求包含 include 的响应结果是:
Some do one...
Other do one... | request_uri: /hello/other.view | context_path: /hello | servlet_path: /other.view | path_info: null | query_string: data=123456
Some do two...