RequestDispatcher可以让客户端请求在服务端server中的各个servlet间转发处理。这里结合源码对RequestDispatcher进行介绍。
RequestDispatcher接收客户端请求,并将它们发送到server中的其它资源(如servlet、html文件、JSP文件)。RequestDispatcher当作对指定路径或名称的服务资源的包装。
RequestDispatcher是通过HttpServletRequest.getRequestDispatcher方法获取的,参数为指定的资源路径,如果路径是相对路径,则相对目录是当前servlet的。HttpServletRequest.getRequestDispatcher方法定义源码如下:
public RequestDispatcher getRequestDispatcher(String path);
RequestDispatcher的核心方法是forward和include,这里把RequestDispatcher中定义的常量也列出来,源码如下:
package javax.servlet;
import java.io.IOException;
public interface RequestDispatcher {
//forward方式下,来源URI名称(值在目标request中attribute中获取)
static final String FORWARD_REQUEST_URI = "javax.servlet.forward.request_uri";
//forward方式下,来源context路径名称(值在目标request中attribute中获取)
static final String FORWARD_CONTEXT_PATH = "javax.servlet.forward.context_path";
//forward方式下,来源路径信息名称(值在目标request中attribute中获取)
static final String FORWARD_PATH_INFO = "javax.servlet.forward.path_info";
//forward方式下,来源servlet的servlet路径名称(值在目标request中attribute中获取)
static final String FORWARD_SERVLET_PATH = "javax.servlet.forward.servlet_path";
//forward方式下,来源请求查询串名称(值在目标request中attribute中获取)
static final String FORWARD_QUERY_STRING = "javax.servlet.forward.query_string";
//include方式下,目标请求的URI名称(值在目标request中attribute中获取)
static final String INCLUDE_REQUEST_URI = "javax.servlet.include.request_uri";
//include方式下,目标context路径名称(值在目标request中attribute中获取)
static final String INCLUDE_CONTEXT_PATH = "javax.servlet.include.context_path";
//include方式下,目标路径信息名称(值在目标request中attribute中获取)
static final String INCLUDE_PATH_INFO = "javax.servlet.include.path_info";
//include方式下,目标servlet路径名称(值在目标request中attribute中获取)
static final String INCLUDE_SERVLET_PATH = "javax.servlet.include.servlet_path";
//include方式下,目标查询串名称(值在目标request中attribute中获取)
static final String INCLUDE_QUERY_STRING = "javax.servlet.include.query_string";
//error方式下,传递的异常对象名称(值在目标request中attribute中获取)
public static final String ERROR_EXCEPTION = "javax.servlet.error.exception";
//error方式下,传递的异常类型名称(值在目标request中attribute中获取)
public static final String ERROR_EXCEPTION_TYPE = "javax.servlet.error.exception_type";
//error方式下,传递的异常信息名称(值在目标request中attribute中获取)
public static final String ERROR_MESSAGE = "javax.servlet.error.message";
//error方式下,导致传递异常的请求URI名称(值在目标request中attribute中获取)
public static final String ERROR_REQUEST_URI = "javax.servlet.error.request_uri";
//error方式下,传递的发生错误的servlet名称(值在目标request中attribute中获取)
public static final String ERROR_SERVLET_NAME = "javax.servlet.error.servlet_name";
//error方式下,传递的响应code名称(值在目标request中attribute中获取)
public static final String ERROR_STATUS_CODE = "javax.servlet.error.status_code";
//在内部(浏览器地址不会改变)将请求从一个serlvet转发到另一个资源(servlet、jsp、html)处理
public void forward(ServletRequest request, ServletResponse response)
throws ServletException, IOException;
//在响应请求中添加指定资源(servlet、jsp、html)
public void include(ServletRequest request, ServletResponse response)
throws ServletException, IOException;
}
关联的Dispatcher类型源,DispatcherType源码如下:
package javax.servlet;
public enum DispatcherType {
//通过RequestDispatcher.forward方法请求
FORWARD,
//通过RequestDispatcher.include方法请求
INCLUDE,
//正常请求
REQUEST,
//异步请求
ASYNC,
//错误响应
ERROR
}
如前源码所示,转发的方法主要有forward和include,为了全面,这里也将HttpServletResponse.sendRedirect方法一并介绍。
forward用于将客户端请求转发给其它server资源(servlet、jsp、html)处理,响应由指定server资源产生,浏览器地址不会改变。流程示意如下:
include是在处理客户端请求时,同时添加其它server资源(servlet、jsp、html)的响应,浏览器地址不会改变。流程示意如下:
sendRedirect是位于HttpServletResponse中的方法,是直接将用户请求重置,由浏览器再次发起请求,浏览器地址会改变。流程示意图如下:
请求1的OneServlet.java定义如下:
package requestDispatcher;
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.util.Objects;
@WebServlet(name="oneServlet", urlPatterns = "/oneServlet")
public class OneServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("this is oneServlet. ");
String type = Objects.toString(req.getParameter("type"), "redirect");
RequestDispatcher requestDispatcher = req.getRequestDispatcher(req.getContextPath()+"/twoServlet");
if("forward".equals(type)){
//走RequestDispatcher的forward内部转发
requestDispatcher.forward(req, resp);
}else if("include".equals(type)){
//走RequestDispatcher的include内部转发
requestDispatcher.include(req, resp);
}else {
//走HttpServletResponse的sendRedirect转发
resp.sendRedirect(req.getContextPath()+"/twoServlet");
}
}
}
请求2的TwoServlet.java定义如下:
package requestDispatcher;
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;
@WebServlet(name="twoServlet", urlPatterns = "/twoServlet")
public class TwoServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取来源servlet的servlet路径
Object originServletPath = req.getAttribute(RequestDispatcher.FORWARD_PATH_INFO);
System.out.println("originServletPath:"+originServletPath);
resp.getWriter().write("this is towServlet.");
}
}
操作结果:
请求:http://localhost:8080/oneServlet?type=forward
响应:this is towServlet.
请求:http://localhost:8080/oneServlet?type=include
响应:this is oneServlet. this is towServlet.
请求:http://localhost:8080/oneServlet?type=redirect
响应:his is towServlet.
同时:浏览器地址变为 http://localhost:8080/twoServlet