Topic: mastering struts |
Print this page |
1.mastering struts | Copy to clipboard |
Posted by: zhouhaifang Posted on: 2004-03-07 12:22 第一章: Jakarta Struts 项目的介绍和它的支持组件 作者:James Goodwill 翻译:周海方 详细资料请访问 http://softtrade.vicp.net 我们所有的章节的Web服务器都是基于Jakarta Tomcat容器。在本章结束的时候,通过运行你建立的Struts应用程序,你可以对Struts的框架机制有个大致的了解 The Jakarta Struts项目 The Jakarta Struts项目是由Apache Software Foundation发起的开源项目,它在java服务器端实现了MVC(Model-View-Controller)设计模式。 The Jakarta Struts项目最初是由Craig McClanahan在2000年五月创建的,但后来被开源组织所接收。 The Jakarta Struts作为一个开源框架的主要意图是为了在创建WEB应用时能比较容易的分离表示层和业务数据层。自从它诞生以来收到大量开发人员的支持,并很快的成为开源社区中一个重要的成员。 理解MVC设计模式 为了更深刻的理解Struts框架,你必须先理解MVC设计模式,Struts技术的就是基于MVC设计模式的。MVC设计模式起源于Smalltalk语言,它由以下三个部分组成:模型(model),视图(view),控制器(Controller).表1.1定义了这些组件。 组件 描述 模型(model) 封装数据对象。模型用来封装和显示数据对象。 视图(view) 作为模型的显示,它表示数据对象的当前状态 控制器(Controller) 定义对用户的输入执行相应操作的接口,它用来操作模型(model)和数据对象 使用MVC的好处包括如下: 可靠性:表示层和业务层别分离,这样就允许你更改你的表示层代码而不用重新编译你的模型(model)和控制器(Controller)代码 高重用和可适应性: MVC模式允许你使用各种不同样式的视图来访问同一个服务器端的代码。它包括任何WEB(HTTP)浏览器或则无线浏览器(WAP)。 较低的生命周期成本:MVC使降低开发和维护用户接口的技术含量成为可能。 快速的部署:开发时间会得到相当大的缩减,它使程序员(java开发人员)集中精力于业务逻辑,界面程序员(HTML和JSP开发人员)集中精力于表现形式上。 可维护性: 分离表示层和业务逻辑层也使得基于Struts的Web应用更易于维护和修改。 The Struts架构图 在这章节,我们简要的画出一幅和MVC模式对应的STRUTS框架图1.1: 图1.1是Struts框架下应用程序请求流通过的路径。这个处理过程由5个基本的步骤组成。 下面是处理步骤的描述。 1. 由显示视图产生一个请求。 2. 请求被ActionServlet(控制器)接收,它在struts-config.xml文件中寻找请求的URI,找到对应的Action类后,Action类执行相应的业务逻辑。 3. Action类执行建立在模型组件基础上的业务逻辑,模型组件是和应用程序关联的。 4. 一旦Action类处理完业务逻辑,它把控制权返回给ActionServlet,Action类提供一个键值作为返回的一部分,它指明了处理结果回传的路径(视图路径)。ActionServlet使用这个键值来决定在什么视图中显示Action的类处理结果。 5. 当ActionServlet把Action类的处理结果传送到指定的视图中,请求的过程也就完成了。 模型(The Model) Struts框架没有提供特定的模型组件,因此我们不会整章介绍模型组件,但我们会把它使用到我们的例子中去。 视图(The View) Struts框架中视图组件对应于一个简单的JSP文件,这个JSP文件包含了Struts定义的标签,下面的代码片段是一个简单的Struts视图: <%@page language="java"> <%@taglib uri="/WEB-INF/struts-html.tld" prefix="html"> <html:form action="loginAction.do" name="loginForm" type="com.wiley.loginForm" > User Id: <html:text property="username"><br/> Password: <html:password property="password"><br/> <html:submit /> </html:form> 如你看到的那样,几个JSP的标签是JSP文件中的重点。这些标签在Struts框架中定义,它使struts应用项目和控制器之间实现松耦合。在第三章我们会建立一个真正可运行的struts视图,第五章中会对视图进行更详细的介绍。 控制器(The Controller) 控制器是Struts框架中的中枢,它由org.apache.struts.action.ActionServlet这个servlet来贯彻和执行的。这个org.apache.struts.action.ActionServlet接收所有客户端的请求,并把请求委派到指定的Action类(用户扩展自org.apache.struts.action)。ActionServlet委派请求是基于客户端传入的URI。一旦Action类完成处理,ActionServlet根据Action返回的键值来决定在什么视图中显示Action的类处理结果。ActionServlet类似于一个创建Action对象的工厂,由Action对象去执行应用中实际的业务逻辑。控制器是Struts框架中最重要的部分。我们会在第三章和第四章对控制器进行更详细的探讨。 Web应用 (WebApplications) 所有的Web应用被包含在一个目录结构中,首先你要在Web服务器下建立如下目录: 目录 内容 wileyapp 这是Web应用的根目录,所有的JSP和HTML文件都在这个目录下。 /wileyapp/WEB-INF 这个目录包含了所有除根目录外需要的资源, 包括WEB应用部署信息。注意:WEB-INF目录下的不是公共文件,无法直接服务于客户端。 / wileyapp/WEB-INF/classes 存放了所有的servlet类或实用类。 / wileyapp/WEB-INF/lib 包含所有WEB应用中要用到的后缀为JAR的包文件 图1.2 如果你实用的是Tomcat服务器,你的缺省根目录为<CATALINA_HOME>/webapps/,在<CATALINA_HOME>/webapps/下建立图1.2所示目录 注意:WEB服务器允许你编译你的类并存放到/WEB-INF/classes或/WEB-INF/lib下,但/WEB-INF/classes的类将被优先载入,即若你编译的类在两个目录下都存在,起作用的只有/WEB-INF/classes目录下的类。 Web应用的部署描述 Web应用的核心是部署描述。部署描述存放在/<SERVER_ROOT>/applicationname/WEB-INF/下的web.xml文件中,它描述了所有Web应用要使用的组件。如果你使用图1.2的目录结构,那么你的部署描述位于/<SERVER_ROOT>/wileyapp /WEB-INF/web.xml文件中。 部署描述中包括如下元素: •ServletContext init parameters •Localized content •Session configuration •Servlet/JSP definitions •Servlet/JSP mappings •Tag library references •MIME type mappings •Welcome file list •Error pages •Security information 下面的代码片段是部署描述的一个例子,它定义了一个简单的servlet。 <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <servlet> <servlet-name>SimpleServlet</servlet-name> <servlet-class>com.wiley.SimpleServlet</servlet-class> </servlet> </web-app> 打包Web应用 标准的Web应用都被打包成后缀为war的文件,你可以使用Java打包命令来创建WAR文件:jar cvf wileyapp.war 现在你就可以用wileyapp.war文件发布你WEB应用了。 Tomcat容器 Tomcat是是基于JAVA的开源WEB应用服务器,我们的例子都以Tomcat为WEB应用服务器。在开始我们的学习前你需要下载 Tomcat4 地址:http://jakarta.apache.org/builds/jakarta-tomcat-4.0/release/v4.0.6/src/jakarta-tomcat-4.0.6-src.zip JDK1.4地址:http://java.sun.com/webapps/download/Redirect/68949517/5847479377282807053505607246086069333228071972022813600060132859339008063305596058473206-3865/j2sdk-1_4_1_02-s1studio_ce-4u1-bin-windows.exe 操作系统为Win2000 2.在系统变量中设置JAVA_HOME = root 3.在系统变量中设置CATALINA_HOME> = root 4.在系统变量中设置CLASSPATH= root/lib/dt.jar;jar;root/lib/tools.jar;root/jre/rt.jar; 6. 在系统变量中PATH下添加 root\bin; 注意:root为你的安装目录 启动<CATALINA_HOME>\bin\startup.bat,在浏览器中输入http://localhost:8080, 你若是能看到缺省的Tomcat 主页面,表明你的配置成功了。如果未成功请查看你的JDK是否已经安装,或者JDK路径是否设置正确。 下一章将大致讲述JSP和servlets,若你对于这方面的技术已经了解,你可以跳过下一章节。 作者:James Goodwill 翻译:凤鸣高岗 欢迎转载,请注明出处和译者 第二章: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 翻译:周海方 欢迎转载,请注明出处和译者 第三章:开始学习Struts 在这一章,我们将开始学习Struts。在开始之前,我们必须先安装和配置Struts应用。我们将创建一个简单的应用来显示Struts是如何工作的。 这一章我们将提供一个Struts应用来让你快速入门。 获取和安装Jakarta Struts项目 在开始你的Struts开发前,我们需要获取最新版本的Struts包。 .地址如下: 一旦你获取了版本后,你在部署Struts应用前需要完成下面的预备工作。 1. 创建一个应用目录<CATALINA_HOME>/webapps/wileystruts 2. 复制struts的JAR文件到<CATALINA_HOME>/webapps/wileystruts/WEB-INF/lib目录下,jar文件列表如下: struts.jar • commons-beanutils.jar • commons-collections.jar • commons-dbcp.jar • commons-digester.jar • commons-logging.jar • commons-pool.jar • commons-services.jar • commons-validator.jar • 3.在<CATALINA_HOME>/webapps/wileystruts/WEB-INF/下创建web.xml,在文件中添加如下代码: <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd"> <web-app> </web-app> 4.创建一个strut-config.xml文件,复制到 <CATALINA_HOME>/webapps/wileystruts/WEB-INF/ 目录下。 struts-config.xml是Struts应用的部署描述文件。它用来把MVC组件组合在一起。 它通常被放置在 <CATALINA_HOME>/webapps/ webappname/WEB-INF/目录下,我们将会频繁的使用到它。空的struts-config.xml如下: <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"> <struts-config> <message-resources parameter="wiley.ApplicationResources"/> </struts-config> 注意:如果你使用Struts 1.1 b1版本,在struts-config.xml文件中你需要添加<message-resources />元素。现在我们只是简单的创建struts-config.xml文件,对于每个元素的详细介绍我们将放在第六章“国际化你的struts应用”。在这章我们将创建struts应用中所有必须的组件。当你开始设计和开发你的Struts应用时,你必须安装和培植你的struts组件。在下一节,我们将会说明那些步骤是必须完成的。 创建你的第一个Struts应用 你已经完成了struts包的下载和安装,现在可以开发Struts应用了。我们的应用由查询股票号码的简单的JSP页面来完成,它将返回被查询股票的价格。我们会通过这个例子来说明在创建Struts应用中必须执行哪些步骤。因为Struts技术来源于MVC设计模式,所以在所有基于Struts的开发中,你可以遵循MVC模式这种标准来进行处理。处理方式为:从视图开始,控制器对象操纵模型组件来为视图服务。这个处理过程通过下面步骤来实现: 1.定义并创建实现某一功能的相关视图,它们是应用中的用户接口。在struts-config.xml这个struts配置文件中所有的ActionForm 就是我们要创建的视图。 2.创建控制器组件。 3.在struts-config.xm文件中定义视图,控制器之间的关系。 4.在web.xml文件中配置启动struts的一些必要信息。 5.启动应用。 上述步骤只是对Struts开发做了概要描述,在接下来的章节我们将会对这些步骤进行比较细致的描述。 创建视图 在创建struts应用的视图时,我们会先创建一个包含Struts标签的JSP文件。 当前有三个主要的struts标签,Bean, HTML和Logic。在第5章我们会集中关注在这几个标签库上,但这章我们在视图中主要关注于HTML标签库。在开始我们的应用时,我们首先要需要描述视图接口。在下面的应用中有两个视图:index.jsp和quote.jsp。 Index视图 Index视图有index.jsp文件来表现,是我们第一个看到的视图。它用来查询股票和提交 请求到相应的Action中。Index.jsp源文件如下: ------------------------------------------------------------ Listing 3.1: index.jsp. <%@ page language="java" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <html> <head> <title>Wiley Struts Application</title> </head> <body> <table width="500" border="0" cellspacing="0" cellpadding="0"> <tr> <td> </td> </tr> <tr bgcolor="#36566E"> <td height="68" width="48%"> <div align="left"> <img src="images/hp_logo_wiley.gif" width="220" height="74"> </div> </td> </tr> <tr> <td> </td> </tr> </table> <html:form action="Lookup" name="lookupForm" type="wiley.LookupForm" > <table width="45%" border="0"> <tr> <td>Symbol:</td> <td><html:text property="symbol" /></td> </tr> <tr> <td colspan="2" align="center"><html:submit /></td> </tr> </table> </html:form> </body> </html> 如你看到的index视图,除了form标签外,它就象一个包含数据集合的HTML页面。在HTML页面中我们把FORM标签改为用Struts标签<html:form />来替换。 这个标签和它的子标签封装了struts form的处理。Form标签的属性列表如下: 属性 描述 action Form被提交到的URL地址。这个属性用来在struts-config.xml配置文件中查找对应的action。 这个属性在我们的例子中是“Lookup”。 file, which we will describe later in this section. The value used in our example is Lookup, which will map to an ActionMapping with a path attribute equal to name ActionForm的识别键。在这个例子中的值为LookupForm。 ActionForm是Struts中用来封装客户端数据的JavaBean对象。它的主要目的是审查视图到控制器组件的数据。我们会在本章的后面讨论LookupForm。 Type 请求的类名的全称,这个例子中的值为wiley.LookupForm。它封装了客户端输入的数据。 <html:form />标签是另外两个标签的父类。第一个是<html:text /> tag.。这个标签和HTML中的<input type=”text”..>意义是一样的。只有一点不同的地方那就是property属性。它的值是唯一的,和ActionForm类中对应的成员变量是对应的。 第二个标签是<html:submit />,它只是简单仿效HTML的submit按钮的功能。 ActionForm 类通过使用<html:form />标签来创建一个实例,并把<html:text />标签的值存储到实例中。实例最后被存储到一个session对象当中。 一旦ActionForm实例被存储了相应的数值之后,action通过<html:form />来调用和审核存储在ActionForm上的数据。 1.为了使用前面提到的标签,你必须在 wiley这个应用的Web.xml文件中添加对应的标签引用。下面的代码段就是添加在web.xml中的标签元素: <taglib> <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri> <taglib-location>/WEB-INF/struts-html.tld</taglib-location> </taglib> 2.你必须复制struts-html.tld文件到<CATALINA_HOME>/webapps/wileystruts/ WEB_INF/目录下。 注意:上面的这两个步骤在部署所有struts应用中都会用到,唯一的不同就是部署时TLD文件的不同(表示不同的标签库)。另外的标签库我们会在第五章进行讨论。 ActionForm ActionForm用来保存视图中表单输入参数的实际数值。如我们在前面章节提到的,当一个<html:form />标签被提交,Struts框架把对应的数据组装到ActionForm实例中。Struts框架通过JavaBean影射,因此ActionForm中的成员变量必须遵守JavaBean的命名规则。举例如下: private String symbol; public void setSymbol(String symbol); public String getSymbol(); 在这个例子中有一个简单成员变量symbol。在获取或设置成员变量的数值时必须带有前缀set和get,在set和get后面的成员变量的第一个字符必须为大写。列表3-2是ActionForm的源代码 LookupForm.java. -------------------------------------------------------------------------------- package wiley; import javax.servlet.http.HttpServletRequest; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionMapping; public class LookupForm extends ActionForm { private String symbol = null; public String getSymbol() { return (symbol); } public void setSymbol(String symbol) { this.symbol = symbol; } public void reset(ActionMapping mapping, HttpServletRequest request) { this.symbol = null; } } --------------------------------------------------------- 在这个类中没有特殊的东西,它只是简单的继承org.apache.struts.action.ActionForm,以及每个ActionForm实例对每个成员变量必须实现的get,set方法。在这个ActionForm bean中有一个特殊的reset()方法。每一个使用LookupForm的请求都会执行reset()方法。这个方法的目的是为了重置LookupForm的成员变量,以便下一个应用使用。 注意:reset()方法ActionMapping类来被引用。关于ActionMapping类我们暂时可以忽略,将在第4,5章中有详细的描述。 编译LookupForm类,移到<CATALINA_HOME>/webapps/wileystruts/WEB-INF/classes/wiley目录下,在<CATALINA_HOME>/webapps/wileystruts/WEB-INF/struts-config.xml文件中添加<form-bean name="lookupForm" type="wiley.LookupForm"/> 这是为了让Struts应用知道LookupForm如何被引用。 Quote 视图 我们最后的视图是quote.jsp。视图在用户成功的寻找到股票后显示。它是没有特殊struts功能的非常简单的JSP页面。列表3-3 quote.jsp. ---------------------------------------------------- <html> <head> <title>Wiley Struts Application</title> </head> <body> <table width="500" border="0" cellspacing="0" cellpadding="0"> <tr> <td> </td> </tr> <tr bgcolor="#36566E"> <td height="68" width="48%"> <div align="left"> <img src="images/hp_logo_wiley.gif" width="220" height="74"> </div> </td> </tr> <tr> <td> </td> </tr> <tr> <td> </td> </tr> <tr> <td> </td> </tr> <tr> <td> Current Price : <%= request.getAttribute("PRICE") %> </td> </tr> <tr> <td> </td> </tr> </table> </body> </html> ----------------------------------------------- 上面的JSP中包含简单一个简单的代码行,它用HttpServletRequest获取特定的股票的价格。这个价格数据通过Action对象中的HttpServletRequest实例来设置。 创建控制组件 在Struts应用中,控制器由两个组件组成。这两个组件是org.apache.struts.action.ActionServlet和org.apache. struts.action.Action类。在大多数的Struts应用只存在一个org. apache.struts.action.ActionServlet实现(实例),但存在多个org.apache.struts.action.Action实现(多个继承实例)。org.apache.struts.action.ActionServlet用来控制客户端请求和决定哪个org.apache.struts.action.Action实例来处理请求。在我们创建的简单应用中,缺省的ActionServlet已经足以满足我们的应用需求了,你不需要再实现特定的org.apache.struts.action.ActionServlet。即使需要扩展ActionServlet也很容易。我们会在第四章中详细介绍。 控制器的第二个组件是org.apache.struts. action.Action,和ActionServlet不同的是Action类在你的应用中必须扩展。这个类是你业务逻辑的开始部分。 例如我们寻找指定的股票的价格。我们会创建一个从org.apache.struts.action.Action扩展的LookupAction。代码如下: LookupAction.java ------------------------------------------------------------ package wiley; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; impo |
2.Re:mastering struts [Re: zhouhaifang] | Copy to clipboard |
Posted by: dearmeiw Posted on: 2004-03-11 21:54 好,不错,支持!!! |
3.Re:mastering struts [Re: zhouhaifang] | Copy to clipboard |
Posted by: Wendy0007 Posted on: 2004-04-05 19:17 已经收藏^_^ 谢谢! 学习…… |
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 |