一、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对象就结束生命周期。