5.2.8 用forward方法请求转发网络资源

优质
小牛编辑
130浏览
2023-12-01

forward方法和include方法类似。只是forward方法的作用是转发网络资源(HTML、JSP、Servlet、图象等)。下面的例子演示了如何使用forward方法转发网络资源。

例子 : 用forward方法请求转发网络资源

1. 实例说明

本例使用了一个ForwardingServlet类分别转入IncludedServlet、IncludedHtml.html和图像文件。

2. 编写ForwardingServlet类

ForwardingServlet类负责转入由forward请求参数指定的网络资源。该类的实现代码如下:

package chapter5;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class ForwardingServlet extends HttpServlet
{
    public void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        // PrintWriter out = response.getWriter();   
        String forward = request.getParameter("forward");
        if (forward != null)
        {
            RequestDispatcher rd = getServletContext().getRequestDispatcher(forward);
            rd.forward(request, response);
            // rd.forward(request, response);  // 多次调用forward方法也会抛出异常   
        }
    }
}

3. 配置ForwardingServlet类

ForwardingServlet类的配置代码如下:

<servlet>
    <servlet-name>ForwardingServlet</servlet-name>
    <servlet-class>chapter5.ForwardingServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ForwardingServlet</servlet-name>
    <url-pattern>/ForwardingServlet</url-pattern>
</servlet-mapping>

4. 转入IncludedServlet

在浏览器地址栏中输入如下的URL:

http://localhost:8080/demo/ForwardingServlet?forward=/IncludedServlet

浏览器中显示的结果如图5.12所示。

12

图5.12 转入IncludedServlet

5. 转发图象文件

假设<Web根目录>\images目录中有一个abc.jpg文件。在浏览器地址栏中输入如下的URL:

http://localhost:8080/demo/ForwardingServlet?forward=/images/abc.jpg

浏览器将显示abc.jpg文件的内容。

现在将PrintWriter out = response.getWriter()前面的注释去掉,然后再次访问上面的URL。这时在浏览器中没有将图象显示出来,而是抛出一个java.lang.IllegalStateException异常(如果在浏览器中仍然显示出abc.jpg的内容,是因为浏览器缓存的原因,读者可以将浏览器的缓存清空,再次访问上面的URL)。抛出这个异常的原因是当forward转发的是二进制网络资源时(如图象文件),会使用ServletOutputStream对象直接将字节流输出到客户端,而在ForwardingServlet类的service方法中已经使用了getWriter方法来获得PrintWriter对象,因此,在调用forward方法时,就无法再使用ServletOutputStream对象了,所以就会抛出异常。

6. 多次调用forward

将第二条rd.forward(request, response)语句的注释去掉,然后在浏览器地址栏中再次输入如下的URL:

http://localhost:8080/demo/ForwardingServlet?forward=/IncludedServlet

浏览器将抛出一个java.lang.IllegalStateException异常,这说明无法多次调用forward方法,也就是说forward方法只能调用一次。

7. 程序总结

从图5.12所示的信息可以看出,虽然在浏览器地址栏中仍然是刚才输入的URL,但是所显示的内容却是IncludedServlet类所输出的内容,而且所输出的URL是IncludedServlet的访问路径,而不是ForwardingServlet的访问路径,并且正常输出了中文信息。因此可以断定。在IncludedServlet类中修改HTTP响应消息头的字段值起作用了(成功使用setContentType方法将服务端编码设为了UTF-8),并且在被调用者(IncludedServlet)中获得的URL就是自身。这一点是forward和include的区别之一。

在使用forward方法转发网络资源时应注意以下六点:

(1)在调用forward方法之前,输出缓冲区中的信息会被清空。也就是说,使用forward方法进行请求转发时,只可能输出被调用者的信息。读者可以在调用forward方法之前使用PrintWriter对象输出一些信息,看看会发生什么情况。

(2)如果在调用forward方法之前,已经将缓冲区中的数据发送到客户端,在调用forward方法时会抛出IllegalStateException异常。这个异常消息会在启动Tomcat的控制台中显示,而在浏览器中仍然会输出已经发送到客户端浏览器的消息。如下面的代码将在浏览器中正常显示“abcd”,但是会在控制台显示抛出的异常:

 PrintWriter out = response.getPrintWriter();

out.println("abcd");

out.flush();

RequestDispatcher rd =

     getServletContext().getRequestDispatcher("/servlet/IncludedServlet");

rd.forward(request, response);

(3)在调用者和被调用者中设置响应消息头都不会被忽略。而调用include方法时,只有在调用者中设置的响应消息头才会生效。

(4)Servlet引擎会根据RequestDispatcher对象所包含的网络资源对HttpServletRequest对象中的请求消息进行调整。而使用include方法时Servlet引擎并不调整这些消息。

(5)forward方法只能使用一次,否则会抛出IllegalStateException异常,而include方法可以多次使用。

(6)除了使用HttpRequestServlet接口的getRequestDispatcher方法获得RequestDispatcher对象外,还可以通过ServletContext接口的getNamedDispatcher方法获得RequestDispatcher对象,可以向该方法传递一个Servlet的名称。如在service方法中可以使用如下的代码来获得RequestDispatcher对象:

RequestDispatcher rd =

 this.getServletContext().getNamedDispatcher("IncludedServlet");

其中IncludedSevlet是Servlet类的名称。