Topic: 精通Struts技术第二章

  Print this page

1.精通Struts技术第二章 Copy to clipboard
Posted by: zhouhaifang
Posted on: 2003-09-08 11:06

精通Struts技术第一章

第二章:Servlet和JSP结构
在这章我们讨论两个问题JSP和servlets技术,它们是Struts框架的基础。我们描述的servlet结构包括它的生命周期,上下文环境(ServletContext)及WEB应用之间的关系。一旦你对Servlet有了比较透彻的了解,我们将集中讨论Struts框架中的视图即JSP页面。本章的目的是让你对JSP和Servlet技术有个大致的了解。在本章结束的时候你会清楚的知道为何Servlet和JSP技术适合于WEB开发。

Java Servlet 结构
Java servlet是平台独立的WEB应用组件,Servlets和客户端协作是通过request/response来进行处理的。图2.1为处理图

servlet结构有两个包组成:javax.servlet 和 javax.servlet.http。
javax.servlet包含了被用来实现和扩展的通用接口和类。
javax. servlet.http是被用于特定的HTTP协议的。
Servlet接口被定义了五个方法。其中比较重要的有三个:
1.init()方法,用于初始化一个Servlet;
2.service方法,用于接受和响应客户端的请求。
3.destroy()方法,执行清除占用资源的工作。
这些是servlet生命周期方法。我们会在后面的章节解说这些方法。所有的servlet都必须实现javax.servlet.Servlet接口,不管是直接或者是间接的。图2.2是对象图,给出了servlet的层次框架图


GenericServlet和HttpServlet类
HttpServlet从GenericServlet扩展而来,GenericServlet实现了Servlet接口。当开发你的servlets时,你通常需要扩展GenericServlet的子类。你必须实现service()方法。GenericServlet.service()方法已经被定义为抽象方法,定义的原型如下:
public abstract void service(ServletRequest request,
ServletResponse response) throws ServletException, IOException;
ServletRequest,ServletResponse这两个参数通过service()方法来传递。ServletRequest对象用来把得到的信息传送到servlet,ServletResponse对象用来把servlet产生的数据传送回到客户端。
对比GenericServlet和HttpServlet,HttpServlet不需要实现service()方法,HttpServlet类已经为你实现了service()方法。方法原型如下:
protected void service(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException;
当HttpServlet.service()方法被执行,它读取存储在request中的方法类型的值来决定哪个方法被执行。这里是你想重载的方法:如果方法类型为GET,就调用doGet()方法。如果为POST就调用doPost()方法。主要使用的就是这两个方法。另外的五个方法不是经常使用。因此我们比较关注的也就是这两个方法。

Servlet生命周期
Servlet生命周期有一个合理的逻辑顺序。javax.servlet.Servlet接口声明了周期方法。
这些方法就是init(), service(),destroy()。执行顺序分为三个处理步骤:
1.  init()方法用来把servlet导入和初始化。这个方法在servlet被预加载或在第一次请求时执行。
2.  Servlet处理0个或多个请求。Servlet对每个请求都用service()方法来处理。
3.  当WEB应用声明Servlet被关闭,Servlet被销毁,垃圾收集器对资源进行收集。用destory方法来关闭Servlet。

init() 方法
init()方法是servlet生命周期的开始。这个方法在servlet被实例化后立即执行,它只被调用一次,用来创建和初始化请求中用到的资源。
init() 方法的显示如下:
public void init(ServletConfig config) throws ServletException;
ServletConfig参数对象是成员变量,它在后面会被用到。一个比较通用的做法是调用超类的init()方法super.init()。如果因为一些原因servlet不能初始化请求所要求的资源就会抛出ServletException

service() 方法
service()方法 处理来自客户端的所有请求。
service()方法表示如下:
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
service()方法有两个参数:
ServletRequest:封装来自客户端的请求信息
ServletResponse:返回客户端的信息
通常情况下你不会实现这个方法,除非你扩展GenericServlet抽象类。
经常实现service()这个方法的是HttpServlet类。HttpServlet通过扩展GenericServlet来实现Servlet接口。HttpServlet支持HTTP/1.1。

destroy()方法
这个方法用于结束servlet生命周期。当一个WEB应用被关闭,destroy()方法被执行,
这时在init()方法中被创建的资源被释放。下面是destroy()方法的代码片段:
public void destroy();

创建一个Servlet
现在我们已经基本了解servlet是如何工作了,我们将创建一个非常简单的servlet应用。
它的主要功能是为了处理客户端请求,并在客户端输出客户地址。
在完成代码后我们将编译代码并部署它。下面为SimpleServlet.java类的源代码:

package chapter2;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
public class SimpleServlet extends HttpServlet {
public void init(ServletConfig config)
throws ServletException {
// Always pass the ServletConfig object to the super class
super.init(config);
}
//Process the HTTP Get request
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
//Process the HTTP Post request
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head><title>Simple Servlet</title></head>");
out.println("<body>");
// Outputs the address of the calling client
out.println("Your address is " + request.getRemoteAddr()
+ "\n");
out.println("</body></html>");
out.close();
}
}

现在我们可以查看SimpleServlet代码的细节部分了。我们来看它的三个覆盖方法:
init() 
doGet() 
doPost() 
每个方法的细节:
init()方法
SimpleServlet类首先定义了init()方法,它以ServletConfig对象为参数调用父类的init()方法:super.init(config)
注意:由SimpleServlet的父类GenericServlet来实际处理ServletConfig 对象,你可能也注意到了init()方法并没有创建任何资源,这也是为什么SimpleServlet中不执行destroy()方法的原因了。

doGet() 和 doPost() 方法
所有的业务逻辑都在这两个方法中执行。在这个例子中doGet()方法只是简单的调用doPost()方法。doGet()方法只在GET请求时被执行,doPost()方法也一样,只在Post请求时被执行。两个方法的传入参数是HttpServletRequest和HttpServletResponse对象。HttpServletRequest对象包含的是来自客户端的信息,HttpServletResponse包含的是返回客户端的信息。在doPost()方法中第一步是设置返回的内容类型:代码片段如下:
response.setContentType("text/html");
在输出流中它必须被最先设置,在例子中我们设置为text/html.
下一步获取PrintWriter对象,这是通过ServletResponse对象的getWriter()方法得到的。PrintWriter对象可以让我们写入输出流后发送到客户端显示,这个步骤代码片段如下:
PrintWriter out = response.getWriter();
一旦你获取了PrintWriter对象后,我们将往客户端输出信息,信息包含HTML标记,这是输出到客户端的格式,下面的几行代码显示了如何处理输出:
out.println("<html>");
out.println("<head><title>Simple Servlet</title></head>");
out.println("<body>");
// Outputs the address of the calling client
out.println("Your address is " + request.getRemoteAddr()
+ "\n");
前面部分代码说明你的输出格式为HTML,下面这段代码你可能会有些疑问:
// Outputs the address of the calling client
out.println("Your address is " + request.getRemoteAddr() + "\n");
这段代码调用了HttpServletRequest对象的getRemoteAddr()方法来获取客户端的IP地址,并将它发送到客户端。HttpServletRequest对象可以获取许多HTTP协议下的客户端的信息。如果你想更深入的了解HttpServletRequest和HttpServletResponse对象,可以访问SUN公司的网站:http://java.sun.com/products/servlet/

创建和部署Servlet
我们需要创建一个WEB应用来存放Servlet,并且编译和部署Servlet到WEB应用中去。步骤描述如下:
1.创建名称为wileyapp的WEB应用,如我们在第一章中所说的那样。.
2.编译SimpleServlet.java文件,拷贝SimpleServlet.class文件到<CATALINA_HOME>/webapps/wileyapp/WEB-INF/classes/chapter2/目录
4.你可以启动你的WEB Server,执行SimpleServlet并查看结果。在浏览器中输入如下地址http://localhost:8080/wileyapp/servlet/chapter2.SimpleServlet
你可以看到输出:Your address is 127。0。0。1
注意:在地址中包含了“/servlet”是为了告诉webServer你要执行的是一个servlet

ServletContext
ServletContext是定义在javax.servlet包中的对象。它定义了用于WEB应用中的服务器端组件关联servlet容器的方法集合。
ServletContext经常被用于存储对象的区域,这些对象在WEB应用中的所有的服务器端组件中使用。你可以把ServletContext当作在WEB应用中共享的存储区域。把一个对象放置到ServletContext中时,它存在于WEB应用的整个生命周期中,除非它被明确的删除或替换。在ServletContext中定义了四个方法来实现存储区的共享功能。
表2.1描述了四个方法:
方法名  描述
setAttribute(String name,Object obj)  通过名称绑定一个对象并存储对象到当前ServletContext。如果指定的名称已经被使用过,这个方法会删除旧对象绑定为新对象。
getAttribute(String name)  返回指定名称的对象,如果名称不存在返回null。
removeAttribute(String name)  从ServletContext中删除指定名称的对象
getAttributeNames()  返回在ServletContext中的指定名称的对象集合

Web 应用和ServletContext的关系:
ServletContext 在WEB应用中充当容器的角色。在WEB应用中只有一个ServletContext 实例,Java Servlet规范指定ServletContext作为所有servlet 的容器。The ServletContext acts
为了了解它在WEB组件中的关系,我们将使用一个Servlet和一个JSP来说明。
在这个Servlet中。我们可以看到在ServletContext中存储的一个对象,这个对象在所有的服务端组件中都可使用。
列表2.2显示了servlet的源代码:
Listing 2.2 ContextServlet.java.
----------------------------------------------------------------------------------
package chapter2;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
public class ContextServlet extends HttpServlet {
private static final String CONTENT_TYPE = "text/html";
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Get a reference to the ServletContext
ServletContext context = getServletContext();
// Get the userName attribute from the ServletContext
String userName = (String)context.getAttribute("USERNAME");
// If there was no attribute USERNAME, then create
// one and add it to the ServletContext
if ( userName == null ) {
userName = new String("Bob Roberts");
context.setAttribute("USERNAME", userName);
}
response.setContentType(CONTENT_TYPE);
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head><title>Context Servlet</title></head>");
out.println("<body>");
// Output the current value of the attribute USERNAME
out.println("<p>The current User is : " + userName +

".</p>");
out.println("</body></html>");
}
public void destroy() {
}
}
如你看到的ContextServlet,你注意到它执行了下面的步骤:
1.首先通过getServletContext()方法得到ServletContext的一个引用。
ServletContext context = getServletContext();
2.一旦你得到了ServletContext的引用,它将通过getAttribute()方法去获取绑定的名称的对象。绑定名称为USERNAME:.
String userName =(String)context.getAttribute("USERNAME");
3.检验返回的对象是否正确,如果getAttribute()方法返回null,说明没有对象绑定到名称USERNAME上。如果对象没有找到,它将创建一个,并添加到ServletContext中。绑定名称USERNAME,使用setAttribute()方法
// If there was no attribute USERNAME, then create
// one and add it to the ServletContext
if ( userName == null ) {
userName = new String("Bob Roberts");
context.setAttribute("USERNAME", userName);
}
4.通过PrintWriter.println(),传送获取的数据到输出流中。
// Output the current value of the attribute USERNAME
out.println("<p>The current User is : " +
userName + ".</p>");
编译你的servlet,并把编译后的class文件放到<CATALINA_HOME>/webapps/wileyapp/WEB-INF/classes/chapter2/目录下,这样servlet被部署到WEB应用中了。
在我们即将写的JSP中会和上面的servlet有很多相似之处,但是有两个不同的地方:ServletContext是在JSP脚本中本访问(这个问题我们将在本章稍后讨论)。
如果JSP中没有发现USERNAME属性,它不能添加一个新的。
代码实现的功能在本质上是一样的,只不过在JSP中。你可以查看源代码:

列表 2.3: Context.jsp.

<HTML>
<HEAD>
<TITLE>
Context
</TITLE>
</HEAD>
<BODY>
<%
// Try to get the USERNAME attribute from the ServletContext
String userName = (String)application.getAttribute("USERNAME");
// If there was no attribute USERNAME, then create
// one and add it to the ServletContext
if ( userName == null ) {
// Don’t try to add it just, say that you can’t find it
out.println("<b>Attribute USERNAME not found");
}
else {
out.println("<b>The current User is : " + userName +
"</b>");
}
%>
</BODY>
</HTML>
注意:Context.jsp中,我们使用了两个固有对象,application(用于引用ServletContext),out(用于输出流到客户端)。在这章的后面我们将讨论这两个对象。现在复制Context.jsp文件到<CATALINA_HOME>/webapps/wileyapp/,重新启动Tomcat;在浏览器中输入地址:
http://localhost:8080/wileyapp/Context.jsp
你会看到输出:Attribute USERNAME not found
Context.jsp没有发现USERNAME属性。如果你输入如下地址:
http://localhost:8080/wileyapp/servlet/chapter2.ContextServlet
会输出:The current User is Bob Roberts
运行servlet后,一个对象被绑定到ServletContext 中的属性USERNAME上,查看WEB应用的变化,打开前面的Context.jsp文件,地址为:http://localhost:8080/wileyapp/Context.jsp
USERNAME已经不为空。
注意:从ServletContext中删除一个对象的方法:重起JSP/Servlet容器或者使用ServletContext.removeAttribute()方法。

Using Servlets to Retrieve HTTP Data

在这一节,我们将实现servlet如何查找从客户端传送过来的信息。
有三个方法被用来查找:getParameter(), getParameterValues(), 和 getParameterNames()。每个方法的定义如下:
public String ServletRequest.getParameter(String name);
public String[] ServletRequest.getParameterValues(String name);
public Enumeration ServletRequest.getParameterNames ();
getParameter()方法返回单个字符串或者null(如果参数不存在),使用这个方法你确保只返回单个值。如果返回多个值,你必须使用getParameterValues()方法,它将返回一个字符串数组或返回null。getParameterNames()返回请求的参数名称的集合或者空集合。
为了了解如何使用这些方法查找数据,让我们来看servlet的Post方法,它是如何查找参数的,并把取得的值返回到客户端。
列表2.4: ParameterServlet.java.
-----------------------------------------------------------------
package chapter2;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
public class ParameterServlet extends HttpServlet {
public void init(ServletConfig config)
throws ServletException {
// Always pass the ServletConfig object to the super class
super.init(config);
}
// Process the HTTP GET request
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
// Process the HTTP POST request
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Parameter Servlet</title>");
out.println("</head>");
out.println("<body>");
// Get an enumeration of the parameter names
Enumeration parameters = request.getParameterNames();
String param = null;
// Iterate over the paramater names,
// getting the parameters values
while ( parameters.hasMoreElements() ) {
param = (String)parameters.nextElement();
out.println(param + " : " +
request.getParameter(param) +
"<BR>");
}
out.println("</body></html>");
out.close();
}
}
首先要注意的是servlet通过request的getParameterNames()方法取得所有的参数名。一旦取得参数集合后,它执行while循环来取得参数名和通过getParameter()来取得参数名对应的参数值,并打印。
创建一个HTML页面访问来ParameterServlet,如下:

列表 2.5: Form.html.
-------------------------------------------------------------
<HTML>
<HEAD>
<TITLE>
Parameter Servlet Form
</TITLE>
</HEAD>
<BODY>
<form
action="servlet/chapter2.ParameterServlet"
method=POST>
<table width="400" border="0" cellspacing="0">
<tr>
<td>Name: </td>
<td>
<input type="text"
name="name"
size="20"
maxlength="20">
</td>
<td>SSN:</td>
<td>
<input type="text" name="ssn" size="11" maxlength="11">
</td>
</tr>
<tr>
<td>Age:</td>
<td>
<input type="text" name="age" size="3" maxlength="3">
</td>
<td>email:</td>
<td>
<input type="text"
name="email"
size="30"
maxlength="30">
</td>
</tr>
<tr>
<td> </td>
<td>  </td>
<td>  </td>
<td>
<input type="submit" name="Submit" value="Submit">
<input type="reset" name="Reset" value="Reset">
</td>
</tr>
</table>
</FORM>
</BODY>
</HTML>
这个HTML文件包含了一个简单的HTML form,它用来递交到ParameterServlet的请求。
编译servlet,复制class文件到:
<CATALINA_HOME>/webapps/ wileyapp/WEB-INF/classes/chapter2目录下
把HTML文件放到:
<CATALINA_HOME>/webapps/wileyapp/ 目录下。
现在打开浏览器,输入如下地址:http://localhost:8080/wileyapp/Form.html
输入数据,点击提交按钮,输出结果。

JavaServer Pages
JavaServer Pages能产生强大的动态HTML页面。JSPs是直接从Java servlets扩展的,这可以让开发人员在JSP中嵌入JAVA逻辑代码。JSP文件必须以后缀.jsp结尾。下面的代码是一个简单的JSP文件,如下:
<HTML>
<BODY>
<% out.println("HELLO JSP READER"); %>
</BODY>
</HTML>
看起来和HTML文件差不多,只是添加了标记来包含.JAVA代码。源代码的文件为hello.jsp,把文件复制到WEB应用中进行部署。当请求一个JSP文件时,JSP引擎会进行处理。当JSP文件第一次被请求时,它被解析成servlet,被编译后驻留于内存。用这个生成的servlet来处理客户端的请求,并返回结果到客户端。对于以后的请求,服务器会检验JSP文件是否被改变。如果没有改变,服务器调用已经生成的servlet对象。如果JSP文件被修改,JSP引擎会重新编译JSP文件以生成新的Servlet。


注意:实质上JSP就是由HTML和JAVA代码组成的。因此它们可获得servlet一样的资源和功能。

JavaServer Page的组成
这节我们讨论JSP的组成,包括:标签,脚本,隐含对象和标准活动。
(directives, scripting, implicit objects, and standardactions.)
JSP标签(Directives)
JSP标签是JSP页面中提供全局信息的元素。标签的一个例子导入JAVA类列表到JSP中。JSP标签的语法如下:
<%@ directive {attribute="value"} %>

page 指令
表示如下:
<%@ page {attribute="value"} %>
表2.2定义了page指令的属性。
Table 2.2 defines the attributes for the page directive.
属性  说明
language=”scriptingLanguage”  告诉服务器什么语言会被编译,目前只支持JAVA
extends=”className”  当你扩展JSP时,指明JSP的父类。这么做会限制JSP/Servlet的自由度,因此不推荐。
import=”importList”  定义导入到JSP中的JAVA类包,用分号来分隔不同的类包。
session=”true|false”  定义是否在JSP中使用session。缺省值为true。
buffer=”none|size in kb”  是否对输出流进行缓冲。缺省值为8KB.
autoFlush=”true|false”  定义输出流是否会被自动输出,不管缓冲是否已满。缺省值为true。
isThreadSafe=”true|false”  告诉JSP引擎这个页面同时可为多个请求服务。缺省值为true。如果设置为false,只能被用于单线程。
info=”text”  通过调用Servlet.getServletInfo()方法访问JSP页面的表示信息
errorPage=”error_url”  表示相应地址的JSP页面来处理抛出的JSP异常。
isErrorPage=”true|false”  表明JSP页面是否有一个错误处理页面,缺省值为false。
contentType=”ctinfo”  表示发送到客户端的网际协议和字符集。

下面的代码片段包含了page指令,导入了java.util包
<%@ page import="java.util.*" %>

include指令
include指令被用来插入文本或者JSP文件。语法如下:
<%@ include file="relativeURLspec" %>
这个file属性通常为HTML文件或者JSP文件。被引用的文件必须为本WEB应用中的。例子如下:
<%@ include file="header.jsp" %>
注意:因为include指令在载入时只转换一次。因此,如果包含的资源改变,这个改变不会体现出来。即如果例子中header.jsp文件改变,当前页(包含header.jsp的页面)显示时并不会改变。
.
taglib指令
taglib指令用来包含自定义标签库,通过URI和关联的前缀来唯一的区分自定义标签。
注意:如果不熟悉JSP自定义标签,你可以学习作者的另一本书“Mastering JSP Custom Tags and Tag Libraries”。
taglib指令显示如下:
<%@ taglib uri="tagLibraryURI" prefix="tagPrefix" %>
taglib在表2.3中描述:

属性  定义
uri  URI是自定义标签的唯一名
prefix  前缀被用来区分自定义标签的实例

下面是taglib的例子:
<%@ taglib uri="http://jakarta.apache.org/taglibs/random-1.0" prefix="rand"%>

JSP脚本
JSP中的脚本是直接绑定到HTML中的JAVA代码片段。
在JSP中有三种脚本语言组件可被调用,每种组件出现于相应的位置。

声明
声明用于定义JAVA变量和方法。JSP声明必须有声明语句。当JSP页第一次被载入时,JSP声明被初始化。初始化后,它们被用于同一JSP页面中的声明,表达式,脚本。语法如下:
<%! declaration %>
一个简单的变量声明:
<%! String name = new String("BOB"); %>
一个简单的方法声明:
<%! public String getName() { return name; } %>
为了更好的理解声明,让我们把声明放到JSP文件中。这个简单的文件代码如下:
<HTML>
<BODY>
<%! String name = new String("BOB"); %>
</BODY>
</HTML>
当文件被载入时,JSP被转换成servlet代码,声明放在servlet的声明区域内。
它在所有的JSP组件中均可使用,相当于类的成员变量。
注意:所有的JSP声明定义为类水平的,因此JSP的所有表达式和脚本中均有效。

表达式
JSP表达式在容器中计算。它在请求时进行计算,计算结果插入到JSP文件的表达式位置上。如果表达式结果不能被转换成字符串,translation-time错误会产生。
表达式语法如下:
<%= expression %>
表达式代码片段:
Hello <B><%= getName() %></B>
JPS文件中的表达式:
<HTML>
<BODY>
<%! public String getName() { return "Bob"; } %>
Hello <B><%= getName() %></B>
</BODY>
</HTML>

脚本
脚本用来把所有的JSP元素放在一起,它们在请求时被执行。他们在所有的JSP组件中使用。脚本语法如下:Scriptlets are the JSP components that bring all the JSP elements together.
<% scriptlet source %>
当JSP脚本代码被转换成servlet代码时,它生成servlet的service()方法。下面的JSP代码片段用来向客户端打印出“Hello Bob”。

<HTML>
<BODY>
<% out.println("Hello Bob"); %>
</BODY>
</HTML>
你会注意到JSP脚本功能非常强大,在JSP中使用脚本来实现你的逻辑会使你的WEB应用很难管理。因为这个原因,导致了我们要创建定义的标签库。

JSP错误处理
象所有的开发方法一样,JSP需要一种比较完善的错误处理机制。JSP体系结构中提供了一种错误处理解决方案,它通过在JSP中专门指明处理错误的JSP文件来实现。
JSP错误出现最多的是运行时错误,它通常由JSP页面或则是被JSP页面调用的一些对象所引起的。请求时错误(Request-time errors)是因为异常抛出的,它可以在被调用的JSP页面中捕获和处理。异常若未被处理会被传送到客户端。

创建 JSP错误页面
下面创建的JSP错误页面只进行很简单的处理:创建简单的JSP页,告诉JSP引擎这是一个错误处理页面,你需要设置属性isErrorPage=true。代码如下:

列表2.6 errorpage.jsp.
----------------------------------------------------------------------------------
<html>
<%@ page isErrorPage="true" %>
Error: <%= exception.getMessage() %> has been reported.
</body>
</html>
第一行JSP代码告诉编译器,这个JSP页面是一个错误处理页面。
代码片段如下:
<%@ page isErrorPage="true" %>
第二段JSP代码使用了隐含异常对象来输出未在JSP页面中被捕获异常消息,这个隐含的异常对象在所有的JSP错误处理页面都可以使用。

使用JSP错误处理页面
为了查看错误处理页面是如何工作的,让我们来创建JSP页面,它包含一个未捕获的异常。JSP页面如下:
列表2.7: testerror.jsp.
------------------------------------------------------------------------------------
<%@ page errorPage="errorpage.jsp" %>
<%
if ( true ) {
// Just throw an exception
throw new Exception("An uncaught Exception");
}
%>
-----------------------------------------------------
注意:第一行代码设置isErrorPage=”errorpage.jsp”,是为了指明如果JSP页面出现异常,将由errorpage.jsp来处理异常。本例中JSP抛出Exception,将由errorpage.jsp来处理。
把testerror.jsp和errorpage.jsp复制到:
<CATALINA_HOME>/webapps/wileyapp/ 目录下, and open the testerror.jsp
在浏览器中打开,你可以看到浏览器中显示了异常。

隐含对象(Implicit Objects)
作为JSP开发人员,你经常会隐含的访问那些在所有的JSP文件中都可以使用的对象。
如果你使用了这些对象,它们会被JSP引擎分析出,并在生成servlet时插入到对应的位置。

Out对象
Out隐含对象来源于java.io.Writer类,它用于发送输出流到客户端。
最通用的时out.println()方法,它来打印文本信息到客户端浏览器。
列表2.8显示了使用out隐含对象的例子:
--------------------------------------------------------------------------
<%@ page errorPage="errorpage.jsp" %>
<html>
<head>
<title>Use Out</title>
</head>
<body>
<%
// Print a simple message using the implicit out object.
out.println("<center><b>Hello Wiley" +
" Reader!</b></center>");
%>
</body>
</html>
--------------------------------------------------------------------
为了执行这个例子,复制文件到
<CATALINA_HOME>/webapps/ wileyapp/ 目录下,在浏览器中输入如下地址:
http://localhost:8080/wileyapp/out.jsp
你会看到:Hello Wiley Reader!

Request对象
这个隐含对象来源于javax.servlet.http.HttpServletRequest接口。它被关联到每一个HTTP请求。常用它来访问请求参数。你可以调用request对象的带参数名称的getParameter()方法,它将返回一个和参数名称匹配的字符串。
Request对象的使用例子如下
列表2.9: request.jsp.
-----------------------------------------------------------------------
<%@ page errorPage="errorpage.jsp" %>
<html>
<head>
<title>UseRequest</title>
</head>
<body>
<%
out.println("<b>Welcome: " +
request.getParameter("user") + "</b>");
%>
</body>
</html>
----------------------------------------------------
JSP通过参数user调用request.getParameter()方法。这个方法寻找参数列表中的键值user来返回数据。在浏览器中输入如下:
http://localhost:8080/wileyapp/request.jsp?user=Robert
可以看到输出:Welcome:Robert。

Response对象
response隐含对象来源于javax.servlet.http.HttpServletResponse。response对象用于把取得的数据返回到客户端。这个隐含对象可以实现HttpServletRequest所有的功能,和你在servlet处理没有什么区别。Response对象经常用于向客户端输出信息。然而JSP API已经提供了一个流对象out来输出信息到客户端。

PageContext对象
PageContext对象提供访问JSP页面的命名空间。它也提供用来访问其他的JSP隐含对象。比较常用的是使用setAttribute() 和getAttribute()方法设置和寻找对象。

Session对象
Session对象来源于javax.servlet.http.HttpSession。它用于存储客户端请求的信息,因此它是有状态交互式的。
Session对象列表如下:

列表2.10: session.jsp.
-------------------------------------------------------------------------------------
<%@ page errorPage="errorpage.jsp" %>
<html>
<head>
<title>Session Example</title>
</head>
<body>
<%
// get a reference to the current count from the session
Integer count = (Integer)session.getAttribute("COUNT");
if ( count == null ) {
// If the count was not found create one
count = new Integer(1);
// and add it to the HttpSession
session.setAttribute("COUNT", count);
}
else {
// Otherwise increment the value
count = new Integer(count.intValue() + 1);
session.setAttribute("COUNT", count);
}
out.println("<b>You have accessed this page: "
+ count + " times.</b>");
%>
</body>
</html>

复制文件到
<CATALINA_HOME>/wileyapp/ 目录,在浏览器中输入地址:
http://localhost:8080/wileyapp/session.jsp
如果你刷新页面访问次数会增加。

Application对象
Application对象来源于javax.servlet.ServletContext,在本章的前面已讨论过ServletContext。Application对象用于访问存储在ServletContext中的全局范围的对象。Application对象的使用方法可以在本章前面部分看到,在次不做叙述。

Config对象
Config对象来源于ServletConfig,它包含了当前JSP/Servlet所在的WEB应用的配置信息。

Page对象
Page对象来源于当前被访问JSP页面的实例化。它实际使用的是JSP转换成的Servlet。

Exception对象
Exception对象用于捕获JSP抛出的异常。它只有在JSP页面属性isErrorPage=true时才可用。

标准Actions
JSP标准Actions是预先定义的标签。这标签很容易用来封装action。
在JSP中有两种类型的标准action。第一种:JavaBean,第二种:由另外的标准action组成。
JavaBeans有三种相应的标签设置:<useBean>, <setProperty>和<getProperty>.。
在定义三个标签后,我们会创建一个例子:

<jsp:useBean>
<jsp:useBean>是 JavaBean的标准行为。它通过ID号和范围来实例化一个JavaBean 。
表2.4对<jsp:useBean>的属性进行说明,表2.5定义了行为的范围。<jsp:useBean>行为非常灵活如果执行到<useBean>,将去寻找是否存在相同ID和scope,如果实例不存在,它会创建一个,把命名空间和ID号关联并存储起来。语法如下:
<jsp:useBean id="name"
scope="page|request|session|application" tpeSpec>
body
</jsp:useBean>
typeSpec ::=class="className" |
class="className" type="typeName" |
type="typeName" class="className" |
beanName="beanName" type="typeName" |
type="typeName" beanName="beanName" |
type="typeName"

表2.4<jsp:useBean>属性:
属性  定义
id  这个键关联指定范围的实例化对象。这个键大小写敏感。这个id属性的键和page.getAttribute方法取得的是一样。
Scope  对象的生命周期。范围选项page, request, session, and application.在表2.5中定义。

表 2.5: <jsp:useBean>的范围值:
值  定义
page  只能在被创建的页面中使用。当前页面完成工作时,引用的对象会被释放掉。
request  只为同一个请求服务。只在请求中实例化,也包括转向请求。所有引用的对象在请求完成时被释放。
session  只处理有相同session的请求,引用的对象也是在session中创建的。当session终止时引用对象被释放。
Application  在相同的WEB应用中被使用。当JSP/Servlet容器关闭,引用对象被释放。

<jsp:setProperty>
用于设置bean属性的值。它要设置的属性所在的对象必须已经存在。
<jsp:setProperty>语法如下:
<jsp:setProperty name="beanName" propexpr />
name属性时bean的实例化名称。
property="*" |
property="propertyName" |
property="propertyName" param="parameterName" |
property="propertyName" value="propertyValue"

表2.6<jsp:setProperty>的属性列表:
属性  说明
name  是通过<jsp:useBean>实例化的bean
property  设置一个属性的值。如果你对propertyName设置“*“,会取出ServletRequest中所有的参数集合。匹配参数名值类型属性名和设置方法类型。并设置每一个匹配的属性的值。如果参数值为空,相关的属性是左未更改的。.
param  你要设置值的属性名称。
value  对bean的属性赋值
.
<jsp:getProperty>
用来获取实例化的bean的属性值,转换成java.lang.String类型并产生输出。
在使用前bean必须被实例化。语法如下:
<jsp:getProperty name="name" property="propertyName" />
表2.7介绍了<jsp:getProperty>的属性:
属性  说明
name  获取实例化的bean的名称,在<jsp:useBean>中定义
Property  从实例化的bean中获取值的属性的名称

一个JavaBean例子
为了学习如何使用JavaBean,让我们创建一个例子。这个例子实现一个简单的计数器JavaBean。这个计数器有简单的int类型的count属性。它用来统计当前bean属性被访问的次数。另外它也包含了相应的设置获取属性的方法。
表2.11为Counter bean代码:Counter.java.
----------------------------------------------------------------
package chapter2;
public class Counter {
int count = 0;
39

public Counter() {
}
public int getCount() {
count++;
return count;
}
public void setCount(int count) {
this.count = count;
}
}
----------------------------------------------------------
让我们来看访问JavaBean的JSP页面:
列表 2.12 counter.jsp.
-------------------------------------------------------------
<!-- Set the scripting language to java -->
<%@ page language="java" %>
<HTML>
<HEAD>
<TITLE>Bean Example</TITLE>
</HEAD>
<BODY>
<!-- Instantiate the Counter bean with an id of "counter" -->
<jsp:useBean id="counter" scope="session"
class="chapter2.Counter" />
<%
// write the current value of the property count
out.println("Count from scriptlet code : "
+ counter.getCount() + "<BR>");
%>
<!-- Get the the bean’s count property, -->
<!-- using the jsp:getProperty action. -->
Count from jsp:getProperty :
<jsp:getProperty name="counter" property="count" /><BR>
</BODY>
</HTML>
----------------------------------------------------------------------------------------------
Counter.jsp有四个JSP组件。第一个:告诉JSP容器脚本语言为:java
<%@ page language="java" %>
第二步:用<jsp:useBean>实例化一个Counter对象,id为counter,范围为session。
现在我们可以在JSP中引用名称为counter的实例。下面的代码实例化Counter:
<jsp:useBean id="counter" scope="session" class="chapter2.Counter" />
有两个种方法指明如何获取当前bean属性的值。第一种是在JSP脚本中使用一个方法访问bean属性。它是通过访问bean的ID并调用getCount()得到的。脚本代码如下:
<%
// write the current value of the property count
out.println("Count from scriptlet code : "
+ counter.getCount() + "<BR>");
%>
第二种是通过<jsp:getProperty>取得当前bean属性的值。
访问对应的属性,绑定它的属性值并输出到HTML中。
<!-- Get the bean’s count property, -->
<!-- using the jsp:getProperty action. -->
Count from jsp:getProperty :
<jsp:getProperty name="counter" property="count" /><BR>

当你运行Counter.jsp,你会发现下一次的结果值大于前一次的。这是因为每次访问count属性都会调用getCount()方法,所以每次count的值都会增加。
编译Counter.java,把类文件复制到:
<CATALINA_HOME>/wileyapp/WEB-INF/classes/chapter2/目录下,复制Counter.jsp到
<CATALINA_HOME>/wileyapp/ 目录。在浏览器中输入地址:http://localhost:8080/wileyapp/counter.jsp

<jsp:param>
提供参数和值。
<jsp:include>,
<jsp:forward>, and <jsp:plugin>
<jsp:param name="name" value="value"/>

表2.8说明了<jsp:param>的属性:
属性  说明
name  引用的参数名称
value  对应参数名称的值

<jsp:include>
用于在JSP中包含静态或动态的WEB组件。语法如下:
<jsp:include page="urlSpec" flush="true">
<jsp:param ... />
</jsp:include>

表2.9描述了<jsp:include>的属性:
属性  说明
page  要包含的资源的地址,基于URL
flush  指明是否缓冲。

通过一个例子来对include进行说明:

列表 2.13 include.jsp.
----------------------------------------------------------------
<html>
<head>
<title>Include Example</title>
</head>
<body>
<table width="100%" cellspacing="0">
<tr>
<td align="left">
<jsp:include page="header.jsp" flush="true">
<jsp:param name="user"
value=’<%= request.getParameter("user") %>’ />
</jsp:include>
</td>
</tr>
</table>
</body>
</html>
------------------------------------------------------------
include.jsp文件包含了一个简单的JSP文件header.jsp,文件显示如下:

列表 2.14. header.jsp.
------------------------------------------
<%
out.println("<b>Welcome: </b>" +
request.getParameter("user"));
%>
------------------------------------
header.jsp寻找名称为user的参数并输出“welcome……”字符串。复制JSP文件到:
<CATALINA_HOME>/webapps/wileyapp/ 目录,在浏览器中输入地址.:
http://localhost:8080/wileyapp/include.jsp?user=Bob

<jsp:forward>
在当前的WEB应用中告诉JSP引擎重定向当前请求到另外可用的资源上,包括静态资源,servlets,JSP等。<jsp:forward>能有效的终止当前执行的JSP。
注意:<jsp:forward>能包含<jsp:param>子属性,这个子属性作为从定向的目标资源。
语法如下:
<jsp:forward page="relativeURL">
<jsp:param .../>
</jsp:forward>

表2.10对<jsp:forward>的属性进行描述:
属性  说明
page  重定向的目标

列表:2.15使用<jsp:forward>的例子:检验请求参数并且重定向请求到包含对应参数的JSP页面。
列表2.15 forward.jsp.
-----------------------------------------------------------------
<html>
<head>
<title>JSP Forward Example</title>
</head>
<body>
<%
if ( (request.getParameter("role")).equals("manager") ) {
%>
<jsp:forward page="management.jsp" />
<%
}
else {
%>
<jsp:forward page="welcome.jsp">
<jsp:param name="user"
value=’<%=request.getParameter("user") %>’ />
</jsp:forward>
<%
}
%>
</body>
</html>
-------------------------------------------
forward.jsp简单的检验请求参数的角色类型,然后重定向请求到相应的页面。
目标资源文件之一:welcome.jsp.
------------------------------------------------
<html>
<!-- Set the scripting language to java -->
<%@ page language="java" %>
<HTML>
<HEAD>
<TITLE>Welcome Home</TITLE>
</HEAD>
<BODY>
<table>
<tr>
<td>
Welcome User: <%= request.getParameter("user") %>
</td>
</tr>
</table>
</body>
</HTML>
----------------------------------------------------------
目标资源文件之二:management.jsp
------------------------------------------------------
<html>
<!-- Set the scripting language to java -->
<%@ page language="java" %>
<HTML>
<HEAD>
<TITLE>Management Console</TITLE>
</HEAD>
<BODY>
<table>
<tr>
<td>
Welcome Manager: <%= request.getParameter("user") %>
</td>
</tr>
</table>
</BODY>
</HTML>
复制三个JSP文件到<CATALINA_HOME>/webapps/ wileyapp/目录下,在浏览器中输入:
http://localhost:8080/wileyapp/forward.jsp?role=user&user=Bob
你可以通过修改输入的角色来重定向到不同的页面。

<jsp:plugin>
导致下载指定的applet和JavaBeans组件,并同步执行业务。
. <jsp:plugin>语法如下:
<jsp:plugin type="pluginType"
code="classFile"
codebase="relativeURLpath">
<jsp:params>
</jsp:params>
</jsp:plugin>
表2.11说明了<jsp:plugin>的属性:
属性  说明
type  说明plug-in包含的类型(比如applet)
code  被plug-in执行的类名称
Codebase  寻找代码的绝对或相对路径

小结:
在这一章我们讲述了Struts技术的两个基础:servlet和JSP。我们试验了它们的结构和组件。了解了JSP和servlet 技术是如何在WEB应用中被装配使用的。下一章,我们将真正开始讲述Strutst技术。

作者:James Goodwill 翻译:周海方
欢迎转载,请注明出处和译者

2.Re:精通Strut技术第二章 [Re: zhouhaifang] Copy to clipboard
Posted by: davidself
Posted on: 2003-09-08 11:23

终于又来了。支持一下。

3.Re:精通Strut技术第二章 [Re: zhouhaifang] Copy to clipboard
Posted by: j1j2
Posted on: 2003-09-21 15:36

整篇的jsp,servlet,下次是否讲讲java,面向对象什么的。

4.Re:精通Strut技术第二章 [Re: zhouhaifang] Copy to clipboard
Posted by: struggle
Posted on: 2003-09-24 15:53

好象这篇文章和STRUTS一点都不沾边啊。不过还是帮忙顶!

5.Re:精通Strut技术第二章 [Re: struggle] Copy to clipboard
Posted by: helloworld
Posted on: 2003-09-24 16:18

呵呵,人家原书就是那么写的嘛 ..由基础说起.

6.Re:精通Struts技术第二章 [Re: zhouhaifang] Copy to clipboard
Posted by: bbbaby
Posted on: 2003-10-13 09:05

^_^~~一步一个脚印

7.Re:精通Struts技术第二章 [Re: zhouhaifang] Copy to clipboard
Posted by: altonpeng
Posted on: 2003-10-13 19:00

整理在word文档中提供下载,可能更容易读


   Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent
Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1
客服电话 18559299278    客服信箱 714923@qq.com    客服QQ 714923