一、簡介
二、RequestDispatcher
RequestDispatcher接收客戶端請求,並將它們傳送到server中的其它資源(如servlet、html檔案、JSP檔案)。RequestDispatcher當作對指定路徑或名稱的服務資源的包裝。
2.1 RequestDispatcher獲取
RequestDispatcher是透過HttpServletRequest.getRequestDispatcher方法獲取的,引數為指定的資源路徑,如果路徑是相對路徑,則相對目錄是當前servlet的。HttpServletRequest.getRequestDispatcher方法定義原始碼如下:
public RequestDispatcher getRequestDispatcher(String path);
2.2 原始碼
RequestDispatcher的核心方法是forward和include,這裡把RequestDispatcher中定義的常量也列出來,原始碼如下:
package javax.servlet;
import java.io.IOException;
public interface RequestDispatcher {
static final String FORWARD_REQUEST_URI = "javax.servlet.forward.request_uri";
static final String FORWARD_CONTEXT_PATH = "javax.servlet.forward.context_path";
static final String FORWARD_PATH_INFO = "javax.servlet.forward.path_info";
static final String FORWARD_SERVLET_PATH = "javax.servlet.forward.servlet_path";
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";
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
}
2.3.1 forward
graph LR
browser --1請求--> oneServlet
twoServlet --3響應--> browser
2.3.2 include
include是在處理客戶端請求時,同時新增其它server資源(servlet、jsp、html)的響應,瀏覽器地址不會改變。流程示意如下:
graph LR
browser --1請求--> oneServlet
twoServlet --3響應--> oneServlet
oneServlet --4響應--> browser
2.3.3 sendRedirect
sendRedirect是位於HttpServletResponse中的方法,是直接將使用者請求重置,由瀏覽器再次發起請求,瀏覽器地址會改變。流程示意圖如下:
graph LR
browser --1請求--> oneServlet
oneServlet --2響應--> browser
browser --3再次主動--> twoServlet
twoServlet --4再次響應--> browser
三、示例
請求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(req, resp);
}else if("include".equals(type)){
requestDispatcher.include(req, resp);
}else {
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 {
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