一、Web組件協作的兩種方式
Servlet對象由Servlet容器創建,並且Servlet對象的service()方法也由容器調用。一個Servlet對象可否直接調用另一個Servlet對象的service()方法呢?答案是否定的,因爲一個Servlet對象無法獲得另一個Servlet對象的引用。
Web應用在響應客戶端的一個 請求時,有可能響應過程很複雜,需要多個Web組件共同協作,才能響應結果。儘管一個Servlet對象無法直接調用另一個Servlet對象的service()方法,但是Servlet規範爲Web組件之間的協作提供了兩種途徑。
1、請求轉發
Servlet(源組件)先對客戶請求做一些預處理操作,然後把請求轉發給其它Web組件(目標組件)來完成包括生成響應結果在內的後續操作。
2、包含
Servlet(源組件)把其它Web組件(目標組件)生成的響應結果包含到自身的響應結果中。
3.請求轉發與包含的共同點:
(1)源組件和目標組件處理的都是同一個客戶請求,源組件和目標組件共享同一個ServletRequest對象和ServletResponse對象
(2)目標組件都可以爲Servlet、jsp、HTML文檔
(3)都依賴javax.servlet.RequestDispatcher接口
二、javax.servlet.RequestDispatcher接口
它表示請求分發器。存在兩個方法
1.forward()方法:把請求轉發給目標組件,聲明如下:
Public void forward(ServletRequest request,ServletResponse response)
throws ServletException,java.io.IOException
2.include()方法:包含目標組件的響應結果,聲明如下:
Public void include(ServletRequet request,ServletResponse response)
throws ServletException,java.io.IOException
說明:
1.當Servlet源組件調用RequestDispatcher時,都要把當前的ServletRequest對象和ServletResponse對象作爲參數傳給它的forward()或Include()方法。這時的源組件和目標組件共享同一個ServletRequest對象和ServletResponse對象。
2.Servlet可通過兩種方式得到ResquestDispatcher對象
(1)調用ServletContext的getRequestDispatcher(String path)方法,path參數指定目標組件的絕對路徑。
(2)調用ServletRequest的getRequestDispather(String path)方法,path參數指定目標組件的路徑。
三、實例
1.請求轉發
Public class CheckServlet extends GenericServlet{
/**響應客戶請求
Public void service(ServletRequest request,ServletResponse response)
throws ServletException,IOException{
//讀取用戶名
String username = request.getParameter("username");
String message = null;
If(username == null){
Message="Please input username.";
}else{
Message="Hello," + username;
}
//在request對象中添加msg屬性
request.setAttribute("msg",message);
//把請求轉發給OutputServlet
//使用ServletContext,path路徑爲絕對路徑
ServletContext context = getServletContext();
RequestDispatcher dispatcher = context.getRequestDispatcher("/output");
//使用ServletRequest,path路徑可以爲絕對路徑,也可以爲相對路徑
//RequestDispatcher dispatcher = request.getRequestDispatcher("output");
PrintWrite out = response.getWriter();
out.println("Output from CheckServlet before fowrwarding request.");
System.out.println("Output from CheckServlet before forwarding request.");
Dispatcher.forward(request,response);
out.println("Output from CheckServlet after forwarding request.");
System.out.println("Output from CheckServlet after forwarding request.");
}
}
Public class OutputServlet extends GenericServlet{
Public void service(ServletRequest request,ServletResponse response)
Throws ServletException,IOException{
//讀取CheckServlet存放在請求範圍內的消息
String message = (String)requet.getAttribute("msg");
PrintWriter out = response.getWriter();
out.println(message);
out.close();
}
}
2.包含
Public class MainServlet extends HttpServlet{
Public void doGet(HttpServletRequest request,HttpServletResponse response)
throws ServletException,IOException{
//設置HTTP響應的正文的數據類型
Response.setContentType("text/html");
//輸出HTML文檔
PrintWriter out = response.getWriter();
out.println("<html></head><title>MainServlet</title></head>");
out.println("<body>");
ServletContext context = getServletContext();
RequestDispatcher headDispatcher = context.getRequestDispatcher("/header.htm");
RequestDispatcher greetDispatcher = context.getRequestDispatcher("/greet");
RequestDispatcher footerDispacher = context.getRequestDispatcher("footer.htm");
//包含header.htm
headerDispatcher.include(request,response);
//包含GreetServlet輸出的HTML文檔
greetDispatcher.include(request,response);
//包含footer.htm
footerDispatcher.include(request,response);
out.println("</body></html>");
//關閉輸出流
out.close();
}
}
說明:MainServlet類把header.htm的內容、GreetServlet生成的響應正文,以及foot.htm的內容都包含到自己的響應結果中,也就是說,MainServlet返回給客戶的HTML文檔是有MainServlet本身、header.htm、GreetServlet,以及foot.htm共同產生的。
總結:
Web組件的協作中不論轉發、包含都是藉助分發器ResquestDispatcher來實現,涉及到的目標組件,可以是HTML、JSP或者Servlet。Servlet容器每次接收到一個客戶的請求,都會創建一個針對於ServletRequest、ServletResponse對象,然後把這兩個對象作爲參數傳給響應的Servlet的服務方法。當容器把本次響應結果返回給客戶,ServletRequest對象和ServeltResponse對象就結束生命週期。