【Java.Web】Servlet —— 请求的转发和包含

请求的转发和包含

Servlet的service()方法是由Servlet容器来调用的,用户不能在一个Servlet对象中直接调用另一个Servlet对象的servie()方法,因为一个Servlet对象无法得到另一个Servlet对象的引用


但是web应用在响应客户端的一个请求时,有可能响应过程很复杂,需要多个web组件共同协作(参见上一节——动态生成图像)。尽管Servlet对象无法直接调用另一个Servlet对象的service()方法,但Servlet规范为Web组件之间的协作提供了两种途径:

  • 请求转发

Servlet(源组件)先对客户请求做一些预处理操作,然后把请求转发给其他Web组件(目标组件)来完成包括生成响应结果在内的后续操作;

  • 请求包含

Servlet(源组件)把其他Web组件(目标组件)生成的响应结果包含到自身的响应结果中;

  • 请求转发 V.S. 请求包含
    • 对于转发和包含,源组件和目标组件处理的都是同一个客户请求;源组件和目标组件共享同一个ServletRequest和ServletResponse对象
    • 对于转发和包含,目标组件都可以为Servlet,JSP或HTML文档
    • 对于转发和包含,都依赖与javax.servlet.RequestDispatcher接口

javax.servlet.RequestDispatcher接口

该接口表示请求分发器,

Methods  
Modifier and Type Method and Description
void forward(ServletRequest request, ServletResponse response)
Forwards a request from a servlet to another resource (servlet, JSP file, or HTML file) on the server.
void include(ServletRequest request, ServletResponse response)
Includes the content of a resource (servlet, JSP page, HTML file) in the response.

  • forward()方法
    • forward()方法的处理流程如下:(1)清空用于存放响应正文数据的缓冲区;(2)如果目标组件为Servlet或JSP,就调用它们的service()方法,把该方法产生的响应结果发送到客户端,如果目标组件为文件系统中的静态html文档,就读去文档中的数据并把它发送到客户端。
    • 由于forward()方法先清空用于存放响应正文数据的缓冲区,因此servlet源组件生成的响应结果不会被发送到客户端,只有目标组件生成的结果才会被发送到客户端;
    • 如果源组件在进行请求转发之前,已经提交了响应结果(例如调用了flushBuffer方法,或者close()方法),那么forward()方法会抛出IllegalStateException。为了避免该异常,不应该在源组件中提交响应结果。

  • include()方法
    • 包含与转发相比,源组件与被包含的目标组件的输出数据都会被添加到响应结果中
    • 在目标组件中对响应状态代码或者响应头所做的修改都会被忽略


当Servlet源组件调用RequestDispatcher的forward或include方法时,都要把当前的ServletRequest对象和ServletResponse对象作为参数传给forward或include方法,这使得源组件和目标组件共享同一个ServletRequest对象和ServletResponse对象。

Servlet可以通过两个两种方式得到RequestDispatcher对象:

  • 调用ServletContext的getRequestDispatcher(String path)方法,path参数指定目标组件的路径
    • path参数必须为绝对路径;绝对路径,就是以符号“/”开头的路径,“/”表示当前Web应用的URL路口
  • 调用ServletRequest的getRequestDispatcher(String path)方法,path参数指定目标组件的路径
    • path参数既可以为绝对路径,也可以为相对路径;相对路径,就是相对于当前Servlet组件的路径,不以“/”开头


请求转发

如下实例:源servlet —— ForwardSourceServlet;目标servlet —— ForwardDestinationServlet;

package com.gof.test.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletContext;
import javax.servlet.RequestDispatcher;

public class ForwardSourceServlet extends HttpServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = 7412912720309987937L;

	@Override
	public void service(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		String username = req.getParameter("username");
        String message = null;
        if (username == null){
        	message = "Please input username.";
        }else{
        	message = "Hello " + username;
        }
        
        // add attribute to request
        req.setAttribute("msg", message);
        
        // forward the request to ForwardDestinationServlet
        ServletContext context = getServletContext();
        RequestDispatcher dispatcher = context.getRequestDispatcher("/forwarddest");
        
        // try to output something into response
        PrintWriter out = res.getWriter();
        out.println("Output from ForwardSourceServlet before forwarding request");
        
        if (dispatcher != null){
        	dispatcher.forward(req, res);
        }
        
        out.println("Output from ForwardSourceServlet after forwarding request");
        out.close();
	}

}

package com.gof.test.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.GenericServlet;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ForwardDestinationServlet extends HttpServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = 7412912720309987937L;

	@Override
	public void service(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		String message = (String)req.getAttribute("msg");
        
        PrintWriter out = res.getWriter();
        out.println(message);
        out.close();
	}

}


在web.xml中注册:

<!-- Forward request -->
  <!-- test url = http://localhost:8080/base-webapp/forwardsrc?username=New User -->
  <servlet>
  	 <servlet-name>forwardsrc</servlet-name>
  	 <servlet-class>com.gof.test.servlet.ForwardSourceServlet</servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>forwardsrc</servlet-name>
      <url-pattern>/forwardsrc</url-pattern>
   </servlet-mapping>
   <servlet>
  	 <servlet-name>forwarddest</servlet-name>
  	 <servlet-class>com.gof.test.servlet.ForwardDestinationServlet</servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>forwarddest</servlet-name>
      <url-pattern>/forwarddest</url-pattern>
   </servlet-mapping>

访问如下URL:

http://localhost:8080/base-webapp/forwardsrc?username=New User


修改1:

在调用forward方法之前调用flush()/close()方法,将会抛出一个IllegalStateException异常;同时,目标组件中的内容不会输出:只会输出源组件前面输出的内容:


修改2:

将获取RequestDispatcher的方法参数path改为“forwarddest”,抛出IllegalArgumentException,提示参数没有以“/”开头。


修改3:

将获取RequestDispatcher的方法改为:

RequestDispatcher dispatcher = req.getRequestDispatcher("forwarddest");

可以正常运行。


请求包含

如下示例:源组件 —— IncludeSourceServlet;目标组件 —— includeheader.html,IncludeDestinationServlet,includefooter.html:

【Java.Web】Servlet —— 请求的转发和包含_第1张图片

package com.gof.test.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletContext;
import javax.servlet.RequestDispatcher;

public class IncludeSourceServlet extends HttpServlet {
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException{
		resp.setContentType("text/html");
		
		PrintWriter out = resp.getWriter();
		
		out.println("<html><header><title>Include Test</title></header>");
		out.println("<body>");
		
		ServletContext context = getServletContext();
		RequestDispatcher headDispatcher = context.getRequestDispatcher("/includeheader.html");
		RequestDispatcher bodyDispatcher = context.getRequestDispatcher("/includedest");
		RequestDispatcher footDispatcher = context.getRequestDispatcher("/includefooter.html");
		
		headDispatcher.include(req, resp);
		bodyDispatcher.include(req, resp);
		footDispatcher.include(req, resp);
		
		out.println("</body></html>");
		
		out.close();
	}
}

includeheader.html

<br/>
This is from includeheader.html
<br/>


package com.gof.test.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletContext;
import javax.servlet.RequestDispatcher;

public class IncludeDestinationServlet extends HttpServlet {
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException{
		PrintWriter out = resp.getWriter();
		
		out.println("<br/>This is from IncludeDestinationServlet<br/>");
	}
}

includefooter.html

<br/>
This is from includefooter.html
<br/>

在web.xml中注册:

<!-- Include request -->
  <!-- test url = http://localhost:8080/base-webapp/includesrc -->
  <servlet>
  	 <servlet-name>includesrc</servlet-name>
  	 <servlet-class>com.gof.test.servlet.IncludeSourceServlet</servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>includesrc</servlet-name>
      <url-pattern>/includesrc</url-pattern>
   </servlet-mapping>
   <servlet>
  	 <servlet-name>includedest</servlet-name>
  	 <servlet-class>com.gof.test.servlet.IncludeDestinationServlet</servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>includedest</servlet-name>
      <url-pattern>/includedest</url-pattern>
   </servlet-mapping>


在浏览器中访问如下的URL:

http://localhost:8080/base-webapp/includesrc

结果如下:

【Java.Web】Servlet —— 请求的转发和包含_第2张图片








你可能感兴趣的:(java,Web)