精通struts技术

第一章: Jakarta Struts 项目的介绍和它的支持组件

 

我们所有的章节的Web服务器都是基于Jakarta Tomcat容器。在本章结束的时候,通过运行你建立的Struts应用程序,你可以对Struts的框架机制有个大致的了解

 

The Jakarta Struts项目

The Jakarta Struts项目是由Apache Software Foundation发起的开源项目,它在java服务器端实现了MVCModel-View-Controller)设计模式。

The Jakarta Struts项目最初是由Craig McClanahan2000年五月创建的,但后来被开源组织所接收。

The Jakarta Struts作为一个开源框架的主要意图是为了在创建WEB应用时能比较容易的分离表示层和业务数据层。自从它诞生以来收到大量开发人员的支持,并很快的成为开源社区中一个重要的成员。

 

理解MVC设计模式

为了更深刻的理解Struts框架,你必须先理解MVC设计模式,Struts技术的就是基于MVC设计模式的。MVC设计模式起源于Smalltalk语言,它由以下三个部分组成:模型(model,视图(view),控制器(Controller.1.1定义了这些组件。

 

组件

描述

模型(model

封装数据对象。模型用来封装和显示数据对象。

视图(view

作为模型的显示,它表示数据对象的当前状态

控制器(Controller

定义对用户的输入执行相应操作的接口,它用来操作模型(model)和数据对象

 

使用MVC的好处包括如下:

可靠性:表示层和业务层别分离,这样就允许你更改你的表示层代码而不用重新编译你的模型(model)和控制器(Controller)代码

高重用和可适应性: MVC模式允许你使用各种不同样式的视图来访问同一个服务器端的代码。它包括任何WEBHTTP)浏览器或则无线浏览器(WAP)

较低的生命周期成本:MVC使降低开发和维护用户接口的技术含量成为可能。

快速的部署:开发时间会得到相当大的缩减,它使程序员(java开发人员)集中精力于业务逻辑,界面程序员(HTMLJSP开发人员)集中精力于表现形式上。

可维护性: 分离表示层和业务逻辑层也使得基于StrutsWeb应用更易于维护和修改。

 

The Struts架构图

在这章节,我们简要的画出一幅和MVC模式对应的STRUTS框架图1.1

 

 

 

 

 

 

 

 

1.1Struts框架下应用程序请求流通过的路径。这个处理过程由5个基本的步骤组成。

下面是处理步骤的描述。

1 由显示视图产生一个请求。

2  请求被ActionServlet(控制器)接收,它在struts-config.xml文件中寻找请求的URI,找到对应的Action类后,Action类执行相应的业务逻辑。

3  Action类执行建立在模型组件基础上的业务逻辑,模型组件是和应用程序关联的。

4  一旦Action类处理完业务逻辑,它把控制权返回给ActionServlet。,Action类提供一个键值作为返回的一部分,它指明了处理的结果。ActionServlet使用这个键值来决定在什么视图中显示Action的类处理结果。

5  ActionServletAction类的处理结果传送到指定的视图中,请求的过程也就完成了。

 

 

模型(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应用的根目录,所有的JSPHTML文件都在这个目录下。

/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应用服务器,我们的例子都以TomcatWEB应用服务器。在开始我们的学习前你需要下载

Tomcat4 地址:http://jakarta.apache.org/builds/jakarta-tomcat-4.0/release/v 4.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.jarjar;root/lib/tools.jarroot/jre/rt.jar;

6  系统变量中PATH下添加 root/bin

注意:root为你的安装目录

启动<CATALINA_HOME>/bin/startup.bat,在浏览器中输入http://localhost:8080

你若是能看到缺省的Tomcat 主页面,表明你的配置成功了。如果未成功请查看你的JDK是否已经安装,或者JDK路径是否设置正确。

下一章将大致讲述JSPservlets,若你对于这方面的技术已经了解,你可以跳过下一章节。

作者:James Goodwill   翻译:凤鸣高岗

本文的版权属于笔者本人,但欢迎转载,前提是注明出处和原作者

 

 

 

 

第二章:ServletJSP结构

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

 

Java Servlet 结构

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

 

servlet结构有两个包组成:javax.servlet javax.servlet.http

javax.servlet包含了被用来实现和扩展的通用接口和类。

javax. servlet.http是被用于特定的HTTP协议的。

Servlet接口被定义了五个方法。其中比较重要的有三个:

1init()方法,用于初始化一个Servlet;

2service方法,用于接受和响应客户端的请求。

3destroy()方法,执行清除占用资源的工作。

这些是servlet生命周期方法。我们会在后面的章节解说这些方法。所有的servlet都必须实现javax.servlet.Servlet接口,不管是直接或者是间接的。图2.2是对象图,给出了servlet的层次框架图

 

 

GenericServletHttpServlet

HttpServletGenericServlet扩展而来,GenericServlet实现了Servlet接口。当开发你的servlets时,你通常需要扩展GenericServlet的子类。你必须实现service()方法。GenericServlet.service()方法已经被定义为抽象方法,定义的原型如下:

public abstract void service(ServletRequest request,

ServletResponse response) throws ServletException, IOException;

ServletRequestServletResponse这两个参数通过service()方法来传递。ServletRequest对象用来把得到的信息传送到servletServletResponse对象用来把servlet产生的数据传送回到客户端。

对比GenericServletHttpServletHttpServlet不需要实现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请求时被执行。两个方法的传入参数是HttpServletRequestHttpServletResponse对象。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协议下的客户端的信息。如果你想更深入的了解HttpServletRequestHttpServletResponse对象,可以访问SUN公司的网站:http://java.sun.com/products/servlet/

 

创建和部署Servlet

我们需要创建一个WEB应用来存放Servlet,并且编译和部署ServletWEB应用中去。步骤描述如下:

1.创建名称为wileyappWEB应用,如我们在第一章中所说的那样。.

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 127001

注意:在地址中包含了“/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 ) {

// Dont try to add it just, say that you cant 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()方法,它将返回一个字符串数组或返回nullgetParameterNames()返回请求的参数名称的集合或者空集合。

为了了解如何使用这些方法查找数据,让我们来看servletPost方法,它是如何查找参数的,并把取得的值返回到客户端。

列表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通过requestgetParameterNames()方法取得所有的参数名。一旦取得参数集合后,它执行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>&nbsp;</td>

<td>&nbsp; </td>

<td>&nbsp; </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就是由HTMLJAVA代码组成的。因此它们可获得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代码时,它生成servletservice()方法。下面的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.jsperrorpage.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.HttpServletResponseresponse对象用于把取得的数据返回到客户端。这个隐含对象可以实现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,在本章的前面已讨论过ServletContextApplication对象用于访问存储在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>,将去寻找是否存在相同IDscope,如果实例不存在,它会创建一个,把命名空间和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.11Counter 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;

}

}

----------------------------------------------------------

让我们来看访问JavaBeanJSP页面:

列表 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 beans 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对象,idcounter,范围为session

现在我们可以在JSP中引用名称为counter的实例。下面的代码实例化Counter

<jsp:useBean id="counter" scope="session" class="chapter2.Counter" />

有两个种方法指明如何获取当前bean属性的值。第一种是在JSP脚本中使用一个方法访问bean属性。它是通过访问beanID并调用getCount()得到的。脚本代码如下:

<%

// write the current value of the property count

out.println("Count from scriptlet code : "

+ counter.getCount() + "<BR>");

%>

第二种是通过<jsp:getProperty>取得当前bean属性的值。

访问对应的属性,绑定它的属性值并输出到HTML中。

<!-- Get the beans 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引擎重定向当前请求到另外可用的资源上,包括静态资源,servletsJSP等。<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>

导致下载指定的appletJavaBeans组件,并同步执行业务。

. <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技术的两个基础:servletJSP。我们试验了它们的结构和组件。了解了JSPservlet 技术是如何在WEB应用中被装配使用的。下一章,我们将真正开始讲述Strutst技术。

 

第三章:开始学习Struts

 

在这一章,我们将开始学习Struts。在开始之前,我们必须先安装和配置Struts应用。我们将创建一个简单的应用来显示Struts是如何工作的。

这一章我们将提供一个Struts应用来让你快速入门。

 

获取和安装Jakarta Struts项目

在开始你的Struts开发前,我们需要获取最新版本的Struts包。目前struts包为1.1

.地址如下:http://cvs.apache.org/builds/jakarta-struts/nightly/jakarta-struts-20031010.zip

一旦你获取了版本后,你在部署Struts应用前需要完成下面的预备工作。

1  创建一个应用目录<CATALINA_HOME>/webapps/wileystruts

2  复制strutsJAR文件到<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.xmlStruts应用的部署描述文件。它用来把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, HTMLLogic。在第5章我们会集中关注在这几个标签库上,但这章我们在视图中主要关注于HTML标签库。在开始我们的应用时,我们首先要需要描述视图接口。在下面的应用中有两个视图:index.jspquote.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>&nbsp;</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>&nbsp;</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 />来替换。

 

 三章:开始学习Struts2

 

ActionForm

ActionForm用来保存视图中表单输入参数的实际数值。如我们在前面章节提到的,当一个<html:form />标签被提交,Struts框架把对应的数据组装到ActionForm实例中。Struts框架通过JavaBean影射,因此ActionForm中的成员变量必须遵守JavaBean的命名规则。举例如下:

private String symbol;

public void setSymbol(String symbol);

public String getSymbol();

在这个例子中有一个简单成员变量symbol。在获取或设置成员变量的数值时必须带有前缀setget,在setget后面的成员变量的第一个字符必须为大写。列表3-2ActionForm的源代码

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类我们暂时可以忽略,将在第45章中有详细的描述。

编译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>&nbsp;</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>&nbsp;</td>

</tr>

<tr>

<td>&nbsp;</td>

</tr>

<tr>

<td>&nbsp;</td>

</tr>

<tr>

<td>

Current Price : <%= request.getAttribute("PRICE") %>

</td>

</tr>

<tr>

<td>&nbsp;</td>

</tr>

</table>

</body>

</html>

-----------------------------------------------

上面的JSP中包含简单一个简单的代码行,它用HttpServletRequest获取特定的股票的价格。这个价格数据通过Action对象中的HttpServletRequest实例来设置。

 

创建控制组件

Struts应用中,控制器由两个组件组成。这两个组件是org.apache.struts.action.ActionServletorg.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;

import org.apache.struts.action.Action;

import org.apache.struts.action.ActionForm;

import org.apache.struts.action.ActionForward;

import org.apache.struts.action.ActionMapping;

public class LookupAction extends Action {

protected Double getQuote(String symbol) {

if ( symbol.equalsIgnoreCase("SUNW") ) {

return new Double(25.00);

}

return null;

}

public ActionForward execute(ActionMapping mapping,

ActionForm form,

HttpServletRequest request,

HttpServletResponse response)

throws IOException, ServletException

{

Double price = null;

// Default target to success

String target = new String("success");

if ( form != null ) {

// Use the LookupForm to get the request parameters

LookupForm lookupForm = (LookupForm)form;

String symbol = lookupForm.getSymbol();

price = getQuote(symbol);

}

// Set the target to failure

if ( price == null ) {

target = new String("failure");

}

else {

request.setAttribute("PRICE", price);

}

// Forward to the appropriate View

return (mapping.findForward(target));

}

}

-----------------------------------------------------------------

我们注意到LookupAction类有两个方法:getQuote() and execute()getQuote()方法会返回一个价格(如果提交的股票代码为“SUNW”)。execute() 方法是LookupAction的主函数,在所有的Action类中必须被实现(原文可能有误,在strut1.1上不是必须实现,可以使用perform()方法替代)。

 

 

 

 



 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值