5.2.7 用include方法包含网络资源
通过在RequestDispatcher接口中定义的include方法,可以在一个Servlet类中包含另外一个网络资源(包括HTML、JSP、Servlet等)。在Servlet类中可以使用如下的代码获得RequestDispatcher对象:
RequestDispatcher rd =
getServletContext().getRequestDispatcher("/servlet/IncludedServlet");
其中getRequestDispatcher方法的参数值是一个相对于Web根目录的Web资源路径。该Web路径必须以“/”开头,表示Web根目录。
在下面的例子中演示了如何使用include方法包含Web资源。
例子 : 用include方法包含网络资源
1. 实例说明
这个例子由三个Web资源组成,其中有两个Servlet:IncludingServlet和IncludedServlet,一个HTML页:IncludedHtml.html。在IncludingServlet类的service方法中包含另外两个Web资源。IncludingServlet类使用了一个charset请求参数,通过该请求参数,可以指定IncludingServlet类输出信息的字符集编码。并可以观察在用include方法包含的资源中修改字符集编码后产生的效果。
2. 编写IncludedServlet类
IncludedServlet类是被包含的Servlet类,该类的实现代码如下:
package chapter5;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class IncludedServlet extends HttpServlet
{
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<b>UTF-8编码格式</b><br/>");
out.println("IncludedServlet URI:" + request.getRequestURI() + "<p/>");
}
}
3. 配置IncludedServlet类
IncludedServlet类的配置代码如下:
<servlet>
<servlet-name>IncludedServlet</servlet-name>
<servlet-class>chapter5.IncludedServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>IncludedServlet</servlet-name>
<url-pattern>/IncludedServlet</url-pattern>
</servlet-mapping>
4. 编写IncludedHtml.html
IncludedHtml.html是被包含的HTML页面,实现代码如下:
<html>
<head>
<title>IncludedHtml</title>
</head>
<body>
<table border="1">
<tr>
<td>
书名
</td>
<td>
出版日期
</td>
</tr>
<tr>
<td>
Java基础
</td>
<td>
2006年12月
</td>
</tr>
</table>
</body>
</html>
5. 编写IncludingServlet类
IncludingServlet类包含了IncludedHtml.html和IncludedServlet,该类的实现代码如下:
package chapter5;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class IncludingServlet extends HttpServlet
{
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String charset = request.getParameter("charset");// 获得charset请求参数
// 如果指定了charset参数,则设置Content-Type字段的字符集编码部分
if(charset != null)
response.setContentType("text/html; charset=" + charset);
else
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<b>" + ((charset == null)?"ISO-8859-1":charset) + "编码格式</b><br/>");
out.println("IncludingServlet URI:" + request.getRequestURI() + "<p/>");
RequestDispatcher rd = getServletContext().getRequestDispatcher(
"/IncludedServlet");
// 包含IncludedServlet
rd.include(request, response);
rd = getServletContext().getRequestDispatcher(
"/chapter5/IncludedHtml.html");
// 包含IncludedHtml.html
rd.include(request, response);
}
}
6. 配置IncludingServlet类
IncludingServlet类的配置代码如下:
<servlet>
<servlet-name>IncludingServlet</servlet-name>
<servlet-class>chapter5.IncludingServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>IncludingServlet</servlet-name>
<url-pattern>/IncludingServlet</url-pattern>
</servlet-mapping>
7. 测试默认编码
在浏览器的地址栏中输入如下的URL:
http://localhost:8080/demo/IncludingServlet
浏览器中显示的结果如图5.10所示。
图5.10 测试默认编码
8. 测试UTF-8编码
在浏览器地址栏中输入如下的URL:
http://localhost:8080/demo/IncludingServlet?charset=utf-8
浏览器中显示的结果如图5.11所示。
图5.11 测试UTF-8编码
9. 程序总结
从图5.10可以看出,所有中文字符都显示成了“?”,这个问题在上面曾经讲过。是由于服务端的编码问题所致,但在IncludedServlet中已经通过setContentType方法设置了编码格式。而且通过http://localhost:8080/demo/IncludedServlet可以正常输出中文。那么为什么IncludedServlet的输出都是“?”呢?答案只有一个,就是在IncludedServlet中的setContentType方法并未起作用。因此,可以得出一个结论:在使用include方法包含Web资源时,在被包含资源中无法修改Content-Type字段的值,既然无法修改Content-Type字段的值,那么HTTP响应消息头的其他字段值应该也无法修改(读者可以自己去做实验)。所以还可以有一个推论,就是在被包含资源中无法修改HTTP响应消息头的字段值(包括调用addHeader、setHeader等方法都不起作用)。
在使用include方法时应注意以下四点:
(1)include方法的参数值必须是Web资源的相对路径,而且这个Web路径是相对于当前Web应用程序根目录的,而且路径前必须加“/”。
(2)在被包含资源中无法改变HTTP响应消息头的字段值。
(3)在被包含资源中并不会改变HTTP请求路径,如在IncludedServlet中输出的URL仍然是/demo/servlet/IncludingServlet(见图3.14和图3.15)。
(4)如果在IncludingServlet中使用的是PrintWriter对象输出的信息,那么在被包含资源(IncludedServlet)中也会使用PrintWriter对象来输出信息,这是因为PrintWriter对象已经在IncludingServlet对象中获得了,而且PrintWriter和ServletOutputStream对象不能同时使用,所以IncludedServlet和IncludingServlet类使用的是同一个PrintWriter对象(读者可以通过hashcode方法来证明这一点),而且在IncludedServlet中不能使用getOutputStream方法来获得ServletOutputStream对象,否则将抛出异常。当然,如果在IncludingServlet类中使用ServletOutputStream对象来输出信息,那么在IncludedServlet类中也不能使用PrintWriter对象来输出信息。