湖南城市学院教师备课纸
第 8 次课
题 JAVA服务器小程序(ServLet)之Servlet链、编程应用
目的要求 掌握Servlet链的含义及编程应用 教学重点 ServLet链的构建与Shtml的使用 教学难点 ServLet链的构建 教学课时 4(含2课时上机)
教学方法 讲解、示例与启发式教学相结合
教学内容和步骤 8.1 Servlet链
8.1.1 什么是servlet链
Servlet链,它是JvavServer体系结构的高级特征之一, 与UNIX和DOS命令中的管道类似,你也可以将多个servlet以特定顺序链接起来。在servlet链中,一个servlet的输出被当作下一个servlet的输入,而链中最后一个servlet的输出被返回到浏览器。 8.1.2表过滤器(Table Filter) 我们以表过滤器看看如何编写一个可以被用于链接的servlet,这个表过滤器servlet将分析另一个servlet的输出,查找含有特殊表格式指令的HTML注释,这些指令包括表有多少列、是否显示表头等等。在该表格式指令之后的所有行将会被格式化成一个HTML表格。这样,链中的前一个servlet只要简单地将数据用逗号分割,数据就可以一行一行地直接输出了,而无须将这些数据格式化成HTML表格。同样,当你决定修改这个表格的格式时,你就不必修改产生数据的servlet,而直接修改这个表过滤器servlet就可以了。
这个表过滤器servlet实现了HTTP服务的方法。首先,它必须重复(echo)上一个servlet中设置的头信息。这些信息包括内容类型、调用的URL、远程主机等等。TableFilter.java显示了设置这些头信息的必要代码。
例1:TableFilter.java
package javaservlets.samples;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public cla TableFilter extends HttpServlet
{
/**
*
Performs an HTTP service request
* @param req The request from the client
* @param resp The response from the servlet
*/
public void service(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, java.io.IOException
{
// Get all headers set by the previous servlet and echo them
java.util.Enumeration e = req.getHeaderNames();
while (e.hasMoreElements()) {
String header = (String)e.nextElement();
String value = req.getHeader(header);
resp.setHeader(header, value);
} // 如下述代码所示,接下来的步骤是取得一个可以从前一个servlet的输出流中讲读取数据的输入流,如果该输入流的内容类型是某种我们可以分析的类型(如HTML),我们就继续下一步骤;否则,我们就从输入流中读出所有字节并毫不修改地把它们写回浏览器。
// Get the input and output streams
ServletInputStream in = req.getInputStream();
ServletOutputStream out = resp.getOutputStream();
// Only proce if this is a recognized MIME type
String type = req.getContentType();
if (type.equals(\"text/html\") ||
type.equals(\"text/table\") ||
type.equals(\"application/x-www-form-urlencoded\")) {
resp.setContentType(\"text/html\");
// Create a buffered reader that we can use to read
// a single line at a time
BufferedReader br =
new BufferedReader(new InputStreamReader(in));
boolean inTable = false;
int tableCols = 0;
boolean headerRow = false;
// Read until no more data exists
while (true) {
String s = br.readLine();
// null indicates end of file
if (s == null) {
break;
}
// If we are in the middle of a table command, proce
// the line
if (inTable) {
// Search for the end of the table
if (s.startsWith(\"
out.println(\"\");
inTable = false;
}
else {
// We\'ve got a row of a table\" +
\"Periodic Elements\");
out.println(\"\");
out.println(\"\");
out.println(\"The Periodic Elements\");
out.println(\"\");
// Output special table formatting instructions for
// the TableFilter servlet
out.println(\"\");
// Output the table
out.println(\"Symbol,Element\");
out.println(\"Ac,Actinium\");
out.println(\"Ag,Silver\");
out.println(\"Al,Aluminum\");
//Etc...
out.println(\"Y,Yttrium\");
out.println(\"Yb,Ytterbium\");
out.println(\"Zn,Zinc\");
out.println(\"Zr,Zirconium\");
out.println(\"\");
// Wrap up
out.println(\"\");
out.flush();
out.close();
}
在你浏览器的URL中输出“/Elements”调用我们在Jrun中配置的servlet映射。 在刷新时,浏览器向Web服务器发出URL请求,Web服务器找到与这个URL信息对应的servlet映射,然后调用Elemetns Servlet。Elements Servlet处理GET请求并返回未格式化的元素周期表数据给Web服务器。之后,Web服务器发现存在servlet链接,于是将Elements Servlet的输出重定向为servlet链接中下一个servlet,也就是表过滤器的输入。表过滤器重新设置所有HTTP首部,以适应表过滤器的需要,然后读入所有元素周期表数据,表过滤器使用指定的表格格式信息来分析和处理这些数据,最后生成一个格式化的元素周期表。
⑶ Mime类型
触发servlet链接的另外一种方法是将一个servlet与特定Mime类型联系起来。当这种Mime类型的应答产生时,输出就会被发送给与之相联系的servlet。由于MIME类型是在servlet向输出流中写入时才确定的,所以用这种方法你可以轻易地将servlet的输出重定向到其他servlet。
① Java Web Server
如前所述,在所有的工作之前,你必须确认servlet链接功能已经启用(见图4.4)。截止到本书发稿,还没有可以管理MIME类型和servlet映射的图形用户接口(GUI),所以你不得不手工编辑“mimeservlets.properties”文件。这个文件位于目录“//properties/server/javawebserver/webpageservice”。下述代码给出了基本的内容。值得注意的是,MIME类型所映射的servlet名字实际上是该servlet的别名。
# This file maps mime-types to the servlets which proce them
# This is used by the filter manager to set up chains of servlets
# where the ouput of one servlet gets piped to the input of
# another servlet based on the mime-type that the servlet specifies
# with setContentType(\"mime-type\")
#
# The default servlet for all mime-types is file.Do not set this
# explicitly.
#
# Entries in this file should be of the form
# mime-type/servletname
# ie.
# foo/bar=fooServlet
# where fooServlet is defined in servlets.properties
java-internal/parsed-html=i
java-internal/template-content=template
② Jrun
在JRun中,你可以通过系统管理应用程序设置MIME类型映射。如图4.10所示,你可以把一个servlet和特定的MIME类型联系起来。
MIME类型链接的例子:Indy 500
为了说明如何通过MIME类型来触发servlet链接,让我们编写一个列出Indianapolis 500自1911年起的所有优胜者。就像Elements Servlet一样,我们直接将输入用逗号分隔的各行数据,并用表过滤器将其格式化成HTML表格形式输出。惟一的不同在于我们设置了一个不同的MIME类型,通过这个MIME类型,Web服务器将Indy 500 Servlet的输出重定向为表过滤器servlet的输入(见例3)。
例3 Indy500.java
package javaservlets.samples;
import javax.servlet.*;
import javax.servlet.http.*;
/**
This is a simple servlet that will return a list of
* past Indianapolis 500 winners
*/
public cla Indy500 extends HttpServlet
{
/**
*
Performs the HTTP GET operation
* @param req The request from the client
* @param resp The response from the servlet
*/
public void doGet(HttpServletRequest req,HttpServletResponse resp)
throws ServletException, java.io.IOException{
// Create a PrintWriter to write the response
java.io.PrintWriter out =
new java.io.PrintWriter(resp.getOutputStream());
// Set the content type of the response
resp.setContentType(\"text/table\");
// Print the HTML header
out.println(\"\");
out.println(\"\");
out.println(\"Java Servlets Sample\" + \"Planets In Our Solar System\"); out.println(\"\"); out.println(\"\"); out.println(\"Planets In Our Solar System\"); out.println(\"\"); // Output special table formatting instructions for // the TableFilter servlet out.println(\"\"); out.println(\"Planet,Avg.Distance from Sun,\" + \"Time to orbit,Time to spin,Moons\"); out.println(\"Mercury,58 million km,88 days,58.6 days,0\"); out.println(\"Venus,108 million km,225 days,243 days,0\"); out.println(\"Earth,150 million km,365.25 days,24 hours,1\"); out.println(\"Mars,228 million km,687 days,24.62 hours,2\"); out.println(\"Jupiter,778 million km,11.9 years,9.83 hours,16\"); out.println(\"Saturn,1427 million km,29.5 years,10.65 hours,19\"); out.println(\"Uranus,2870 million km,84 years,17.23 hours,15\"); out.println(\"Neptune,4497 million km,164.8 years,16 hours,8\"); out.println(\"Pluto,5913 million km,248 years,6.375 days,1\"); out.println(\"\"); // Wrap up out.println(\"\"); out.flush(); out.close();
} /** *
Initialize the servlet.This is called once when the * servlet is loaded.It is guaranteed to complete before any * requests are made to the servlet * * @param cfg Servlet configuration information */
public void init(ServletConfig cfg)
throws ServletException{
super.init(cfg);
}
/**
*
Destroy the servlet.This is called once when the servlet
* is unloaded.
*/
public void destroy()
super.destroy();
}
}
和前面的servlet一样,Solar System Servlet将直接输出无格式的数据而将格式化的工作交由表过滤器servlet来完成。由于Java Web Server不支持用HTTP请求触发servlet链接,我们将使用JRun。图4.14显示了Solar System Servlet和表过滤器servelt链接起来以后的输出结果。 请注意调用servlet时使用的URL,在这种情况下,URL中包含了一个链接在一起的servlet名字,它们之间用逗号来间隔。 8.2 Java Servlet 编程及应用 8.2.1服务器端包含
服务器端包含 (Server-Side Includes) 是Web 页面设计中的一种常用技术,在一个输出很多网页的系统中,经常会有一些网页的组成部分在多个网页中同时出现。Server-Side Includes 是Java Server 体系结构的一个高级特征,它可以在HTML 文档中嵌入servlet,这样就可以利用一个或多个servlet 来组成最终的HTML 文档,这种特殊的包含了Servlet 输出和HTML 标记的文件用扩展名.shtml 表示。
Servlet 标记的语法:
<servlet name=Servlet_name code=Servlet.cla codebase=类路径
名称 1 = 参数值 1
名称 2 = 参数值 2
........
名称 n = 参数值 n >
<param name =名称 1 value = 参数值 1 param name =名称 2 value = 参数值 2 ........ param name =名称 n value = 参数值 n > </servlet>
编程思路及技巧:下面是一个完整的简单的服务器包含(SSI)的实例,整个shtml 页面由2个Servlet 组成,第1个Servlet是Header.java,代表页头,主要功能是显示标题信息;第2个Servlet 是Footer.java,代表页脚,主要功能是显示页脚的版权信息;Together.shtml 是将2个Servlet 组合在一起显示的服务器包含,它应当从文档根目录(如root)中加载。
例5: Header.java
import javax.servlet.*; import java.io.*; public cla Header extends GenericServlet { public void service(ServletRequest req,ServletResponse resp) throws ServletException, IOException
{ res.setContentType(\"text/html;charset=gb2312\");
PrintWriter out =res.getWriter();
// Get the title of the page.Set to empty string if
// no title parameter was given
String titles[] = req.getParameterValues(\"title\");
String title = \"\";
if (titles != null) {
if (titles.length > 0) {
title = titles[0];
}
}
Footer.java import javax.servlet.*; import java.io.*; public cla Footer extends GenericServlet{ public void service(ServletRequest req,ServletResponse resp) throws ServletException, IOException
{ res.setContentType(\"text/html;charset=gb2312\");
PrintWriter out =res.getWriter();
// Format the standard header
out.println(\"<hr>\"=;
out.println(\"<p align=\'center\'><i> 版权所有,信息公司</i></p>\"=;
// Wrap up
out.flush();
out.close();
}
/** * <p>Returns information about this servlet */ public String getServletInfo() {
return \"Footer \";
} public void init(ServletConfig cfg) throws ServletException
{
super.init(cfg); } public void destroy() {
super.destroy();
} } 8.2.2使用Java Servlet API 进行会话管理
javax.servlet.http.HttpSeion 接口封装了HTTP 会话的细节,该会话与一段时间内特定的Web 客户对Web 服务器的多个请求相关。管理会话数据主要涉及到3个方面:会话交换、会话重定位和会话持久性,只有实现了java.io.Serializable 接口的数据对象才能够被交换、重定位和保持。这个接口主要是让对象具有序列化的能力,它可以将对象的状态信息写入任意的输出流中如:文件、网络连接等。
编程思路:下面是实现一个简单在商场购物的例子,当用户选购商品(糖果、收音机和练习簿)放入购物袋中,保存选购的商品信息。 编程技巧说明:
在Servlet 中进行会话管理时,首先要获得会话对象。HttpServletRequest.getSeion()对象返回与请求相关的当前HttpSeion 对象,并且当该对象不存在时就新创建一个对象;HttpServletRequest.getSeion(true)实现相同的功能。如果参数是false,当不存在会话对象时,将返回一个null 值。
8.3 小结
在本讲中,我们讨论了servlet链及编程应用,这是JavaServer体系结构的高级特征之一。servlet链接提供了将一个servlet的输出重定向为另一个servlet的输入的能力。这样,你就可以划分工作,从而使用一系列servlet来实现它。另外,你还可以将servlet组织在一起以提供新的功能。
作
业
①:用ServLet编程完成向浏览器输出一个九九乘法表的表格 ②:在TOMCAT环境下配置shtml页面的运行环境并完成教案上的例5。 教学总结:
上机实验八:ServLet链与Shtml的使用(2课时)
一、实验目的及要求
1.掌握ServLet链在各种WEB服务器中的配置
2.掌握触发ServLet链的各种方法及如何编写ServLet链 3.掌握shtml的使用
二、实验环境
Myeclipse、Tomcat、JDK
三、实验内容
1.上机完成教案上所有的示例
2.编写shtml页面嵌入如下二个servlet并分析运行结果 Header.java
import javax.servlet.*; import java.io.*; public cla Header extends GenericServlet { public void service(ServletRequest req,ServletResponse resp) throws ServletException, IOException
{ res.setContentType(\"text/html;charset=gb2312\");
PrintWriter out =res.getWriter();
// Get the title of the page.Set to empty string if
// no title parameter was given
String titles[] = req.getParameterValues(\"title\");
String title = \"\";
if (titles != null) {
if (titles.length > 0) {
title = titles[0];
}
}
Footer.java import javax.servlet.*; import java.io.*; public cla Footer extends GenericServlet{ public void service(ServletRequest req,ServletResponse resp) throws ServletException, IOException
{ res.setContentType(\"text/html;charset=gb2312\");
PrintWriter out =res.getWriter();
// Format the standard header
out.println(\"<hr>\"=;
out.println(\"<p align=\'center\'><i> 版权所有,信息公司</i></p>\"=;
// Wrap up
out.flush();
out.close();
}
/** * <p>Returns information about this servlet */ public String getServletInfo() {
return \"Footer \";
} public void init(ServletConfig cfg) throws ServletException
{
super.init(cfg); } public void destroy() {
super.destroy();
} } 3.在Myeclipse环境下完成教材P143页中习题6-1与6-2
四、实验步骤
略
五、实验思考
1.怎样利用Servlet实现页面重定向?
2.比较在TOMCAT与JRUN下配置Servlet链的异同