Struts2 是目前较为普及和成熟的基于MVC设计模式的web应用程序框架,它不仅仅是Struts1 的升级版本,更是一个全新的Struts架构。最初,是以WebWork框架和Struts框架为基础,通过提供增强和改进的Struts框架,进而实现简化web技术人员开发工作的目标。不久之后,Webwork框架和Struts社区联合创造了现在流行的Struts2框架。

Struts2 框架的优点

了解了这几个主要的优点,会促使你考虑使用Struts2 :
  • POJO表单及POJO操作 - Struts2 去除掉了Struts框架中的Action Forms部分。在Struts2框架下,你可以用任何一POJO来接收表单输入,同样的,你可以把任一POJO视为一个Action类。
  • 标签支持 - Struts2 改进了标签表单,而新的标签可让开发人员减少代码编写量。
  • AJAX支持 - Struts2 被认可接收进Web 2.0技术,并创建了功能非常类似于标准的Struts2 标签的AJAX标签,把AJAX支持整合进其结果中。
  • 易于整合 - Struts有多种整合方式可使用,现在与其他类型的框架,如Spring、Tiles、SiteMesh之类的,整合更为容易了。
  • 模板支持 - 支持使用模板生成视图。
  • 插件支持 - 有大量的插件可用于Struts2,而使用插件可以增强和扩大Struts2 核心行为。
  • 性能分析 - Struts2 为调试和配置应用程序提供综合的性能分析,此外,Struts也以嵌入调试工具的形式提供集成调试。
  • 易于修改标签 - 在Struts2 中,可使用Freemarker的模板对标签标记进行调整,而修改标签不需要JSP或是Java知识,基本的HTML、XML和CSS知识就足够了。
  • 促进减少配置 - Struts2 使用各种设置的默认值促进减少配置,而你不需要再配置什么除非是偏离了Struts2 设定的默认设置。
  • 视图技术 - Struts2 为多种视图选项(JSP、Freemarker、Velocity、XSLT等)提供支持。
以上是使Struts2 成为准企业框架的十大优点。

Struts2 框架的缺点

尽管Struts2 有一大列的优点,但我们还是要提到关于它的一些仍需不断改进的缺点:
  • 更大的学习曲线 - 使用Struts MVC,你必须要熟悉JSP、Servlet APIs标准以及一个大型、复杂的框架。
  • 文档缺乏 - 相比于Servlet和JSP APIs标准,Struts的在线资源较少,许多初学者会发现Apache在线文档混乱并缺乏整理。
  • 不够透明 - 相比于使用正常的基于Java的Web应用程序,使用Struts的应用程序有许多是进行在后台,这使得框架不易于理解。
最后说明一点,一个好的框架应该提供各种类型的应用程序都可以使用的通用行为,Struts2 是最好的Web框架之一,并频繁用于RIA(Rich Internet Applications)的发展。

模型(Model)-视图(View)-控制器(Controller),通常简称MVC,是一种开发web应用程序的软件设计模式。该软件设计模式由以下三部分组成:  

  • 模型——属于软件设计模式的底层基础,主要负责数据维护。  
  • 视图——这部分是负责向用户呈现全部或部分数据。 
  • 控制器——通过软件代码控制模型和视图之间的交互。
MVC普及的原因在于它区分了应用程序的逻辑层和用户界面层,并支持开发关注点的分离。在MVC模式下,控制器接收了所有来自应用程序的请求后,调用模型去准备视图所需要的数据,然后视图使用由控制器提供的数据最终生成一个可视的响应。MVC的抽象概念可通过以下图形进行表述:

Struts MVC

模型

模型主要负责管理应用程序的数据,它通过响应视图的请求和控制器的指令来更新自身的数据。

视图

通过控制器的指令触发所展现的一种特殊的数据格式。它们是基于像JSP、ASP、PHP之类模板系统的脚本,较易与AJAX技术进行整合。

控制器

控制器负责响应用户输入并执行数据模型对象的交互。控制器在接收、确认输入后执行修改数据模型状态的业务操作。
  
Struts2是一个以MVC为基础的框架。在接下来的章节,让我们看看如何在Struts2中使用MVC。

我们的第一个任务是运行一个最小的Struts2 应用程序。本章将指导你如何搭建Struts2 开发环境进行工作。我们假设你的电脑已经安装了JDK(5+)、Tomcat以及Eclipse,如果你没有安装这些组件那就按照下面列出快捷方式安装:

步骤1 - 安装Java开发工具包(JDK):

你可以在甲骨文网站的Java页面下载最新版本的SDK:Java SE下载链接。在下载文件中你可以看到安装JDK的说明,按照说明安装及配置设置。最后,设置路径和JAVA_HOME环境变量到引用的包含Java和Javac的目录,通常分别是 java_install_dir/bin 和 java_install_dir 。

如果你是在Windows系统下把SDK安装到C:jdk1.5.0_20,你需要把以下代码放到你的C:autoexec.bat文件里。

set PATH=C:jdk1.5.0_20in;%PATH%set JAVA_HOME=C:jdk1.5.0_20
此外,在Windows NT/2000/XP系统中,你也可以右键点击“我的电脑”,选择“属性”→“高级”→“环境变量”,然后将路径值更新并按下“确定”按钮。

在Unix(或Solaris,Linux等)系统中,如果SDK是安装在C盘的 /usr/local/jdk1.5.0_20 ,你可以把以下代码放到 .cshrc 文件中。

setenv PATH /usr/local/jdk1.5.0_20/bin:$PATHsetenv JAVA_HOME /usr/local/jdk1.5.0_20

另外,如果你使用的是像Borland JBuilder、Eclipse、IntelliJ IDEA或是Sun ONE Studio之类的集成开发环境(IDE),编译运行一个简单的程序来确认IDE找寻到了你安装的Java的位置,否则的话就按照IDE给出的文档做正确的设置。

步骤2 - 安装Apache Tomcat:

你可以从这个地址下载Tomcat的最新版本:http://tomcat.apache.org/。一旦你下载了安装程序,解压二进制发布包到一个便捷的位置,例如Windows的 C:apache-tomcat-6.0.33 ,Linux或Unix的 /usr/local/apache-tomcat-6.0.33 ,并创建CATALINA_HOME环境变量指向这些位置。
在Windows环境下,可以通过执行以下指令启动Tomcat,或者你可以直接双击 startup.bat 。
%CATALINA_HOME%instartup.bat  or  C:apache-tomcat-6.0.33instartup.bat
在Unix(或Solaris、Linux等)环境下,可以通过执行以下指令启动Tomcat:
$CATALINA_HOME/bin/startup.shor /usr/local/apache-tomcat-6.0.33/bin/startup.sh
启动成功后,包含Tomcat的默认web程序就可以通过 http://localhost:8080/ 进行访问了。如果一切正常,那么会显示以下结果:

Tomcat主页

在这里可发现更多关于配置和运行Tomcat的信息的文档,同样也可登陆Tomcat网站进行查找:http://tomcat.apache.org 。
在Windows环境下,可以通过执行以下指令停止Tomcat:
%CATALINA_HOME%inshutdownorC:apache-tomcat-5.5.29inshutdown
在Unix(或Solaris、Linux等)环境下,可以通过执行以下指令停止Tomcat:
$CATALINA_HOME/bin/shutdown.shor/usr/local/apache-tomcat-5.5.29/bin/shutdown.sh

步骤3 - 安装Eclipse(IDE)

本教程中的所有示例都是使用Eclipse IDE,因此我们建议你在电脑上安装最新版本的Eclipse。可在这个地址下载安装最新的Eclipse: http://www.eclipse.org/downloads/ 。一旦你下载了安装程序,解压二进制发布包到一个便捷的位置,例如Windows的 C:eclipse ,Linux或Unix的 /usr/local/eclipse ,并设置适当的路径变量。
在Windows环境下,可以通过执行以下指令启动Eclipse,或者你可以直接双击 eclipse.exe 。
 %C:eclipseeclipse.exe
在Unix(或Solaris、Linux等)环境下,可以通过执行以下指令启动Eclipse:
$/usr/local/eclipse/eclipse
启动成功后,如果一切正常,那么会显示以下结果:

Eclipse主页

步骤4 - 安装Struts2 文件库

如果一切顺利,那么现在你可以继续安装你的Struts2 框架,以下是在电脑上下载和安装Struts2 的简单步骤:
  • 选择是否想要在Windows或者Unix上安装Struts2 ,然后继续下一步,下载适用于Windows或者Unix的压缩文件。
  • 在这个地址下载最新版本的Struts2 二进制文件: http://struts.apache.org/download.cgi 。
  • 在编写本教程时我们下载的是 struts-2.0.14-all.zip ,当你解压下载的文件时,它会在 C:struts-2.2.3 里显示以下目录结构:
Sturts目录

接下来是在任意位置解压zip文件,我们是在Windows 7电脑的C:文件夹里下载并解压 struts-2.2.3-all.zip ,这样我们可以把所有jar文件放在 C:struts-2.2.3lib 里。确保你已正确设置CLASSPATH变量,否则你运行应用程序的时候就会遇到问题。


从一个高水平角度看,Struts2 是一个MVC拉动的(或MVC2)框架,Struts2 的模型-视图-控制器模式是通过以下五个核心部分进行实现的:

  • 操作(Actions)
  • 拦截器(Interceptors)
  • 值栈(Value Stack)/OGNL
  • 结果(Result)/结果类型
  • 视图技术
而Struts2 与传统的MVC框架略有不同,因为它由Action扮演模型的角色,而不是控制器,虽然这样会有一些重叠。

Struts 2的架构

上图描述了Struts2 高级系统架构下的模型、视图及控制器。控制器是通过Struts2 分派servlet过滤器以及拦截器进行实现,模型是通过Actions进行实现,而视图则是结果类型和结果的结合。值栈和OGNL提供共同的路线、链接以及与其他组件之间的集成。
除了上述部分,还有许多组件相关的信息。web应用程序组件、Actions组件、拦截器组件、结果组件等等。
这些是Struts2 MVC模式的体系结构概述,在随后的章节中,我们将详细了解各个部分。

请求生命周期

通过上述图片的描述,我们可以依照下面几点解释在Struts2 中用户的请求生命周期:
  • 用户发送一个资源需求的请求到服务器(例如:页面)。
  • 核心控制器查看请求后确定适当的动作。
  • 使用验证、文件上传等配置拦截器功能
  • 执行选择的动作来完成请求的操作。
  • 另外,如果需要的话,配置的拦截器可做任何后期处理。
  • 最后,由视图显示结果并返回给用户。

通过学习Struts2 框架可以了解到,当你在Struts2 的web应用程序里点击一个超链接或提交一个HTML表单时,会由控制器收集输入并发送一个叫Actions的Java类。Action被执行后,Result会选择一个资源给予响应。这个资源通常是一个JSP,也可以是一个PDF文件,一个Excel表格,或者是一个Java小程序窗口。

假设你已经建好了你的开发环境,那么现在让我们继续构建第一个Struts2 项目:Hello World 。这个项目的目标是构建一个收集用户名并在用户名后跟随显示“Hello World”的web应用程序。我们需要为每个Struts2 项目构建以下四个组件:

序号名称及描述
1Action(操作)
创建一个动作类,包含完整的业务逻辑并控制用户、模型以及视图间的交互。
2Interceptors(拦截器)
这是控制器的一部分,可依据需求创建拦截器,或使用现有的拦截器。
3View(视图)
创建一个JSP与用户进行交互,获取输入并呈现最终信息。
4Configuration Files(配置文件)
创建配置文件来连接动作、视图以及控制器,这些文件分别是struts.xml、web.xml以及struts.properties。

我们如果打算使用Eclipse IDE,那么所有必需的组件都要在动态Web项目(Dynamic Web Project)下创建。因此我们就先从创建动态Web项目开始

创建一个动态Web项目:

启动你的Eclipse,然后打开“File”>“New”>“Dynamic Web Project”,输入“HelloWorldStruts2”的项目名称,参照下图设置其他选项:

按照下图选择所有默认选项,最后检查 Generate Web.xml deployment descriptor 选项。这个将在Eclipse为你创建一个动态web项目。现在点击“Windows”>“Show”>“View”>“Project Explorer”,你就可以看到你的项目窗口,如下图:

你好世界Sturts2
现在从Struts2 的lib文件夹 C:struts-2.2.3lib 中拷贝以下文件到项目的 WEB-INFlib 文件夹里。你可以直接拖拽以下所有文件到 WEB-INFlib 文件夹。
  • commons-fileupload-x.y.z.jar
  • commons-io-x.y.z.jar
  • commons-lang-x.y.jar
  • commons-logging-x.y.z.jar
  • commons-logging-api-x.y.jar
  • freemarker-x.y.z.jar
  • javassist-x.y.z.GA
  • ognl-x.y.z.jar
  • struts2-core-x.y.z.jar
  • xwork-core.x.y.z.jar

创建Aciton类

Action类是Struts2 应用程序的关键,我们通过它实现大部分的业务逻辑。那么让我们在“Java Resources”>“src”的类目下创建一个名称为“HelloWorldAction.java”的java文件夹,使用一个命名为“cn.51coolma.struts2”并包含以下内容的资源包。
当用户点击一个URL时,由Action类来响应用户操作。一个或多个Action类的方法被执行,并返回一个字符串结果。基于结果的值,会呈现一个特定的JSP页面。
package cn.51coolma.struts2;public class HelloWorldAction{   private String name;   public String execute() throws Exception {      return "success";   }      public String getName() {      return name;   }   public void setName(String name) {      this.name = name;   }}
这是一个非常简单的具有“name”属性的类。对于“name”属性,我们用标准的getter和setter方法,以及一个返回“success”字符串的执行方法。
Struts2 框架将创建一个“HelloWorldAction”类的对象,并调用execute方法来响应用户的动作。你把你的业务逻辑放进execute方法里,最后会返回字符串常量。简单的描述每个URL,你需要实现一个Action类,你也可以用类名直接作为你的动作名,或者如下面内容所示使用 struts.xml 文件映射到其他name上。

创建视图

我们需要一个JSP来呈现最终的信息,当一个预定义动作发生时这个页面将被Struts2 框架调用,并且这个映像会定义到 struts.xml 文件里。那么让我们在你的Eclipse项目的WebContent文件夹里创建以下JSP文件 HelloWorld.jsp 。在project explorer中右键点击WebContent文件夹并选择“New”>“JSP File”
<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>Hello World</title></head><body>   Hello World, <s:property value="name"/></body></html>
Taglib指令告知Servlet容器这个页面将使用Struts2 标签,并且这些标签会被s放在前面。s:property 标签显示Action类“name”属性的值,这个值是使用HelloWorldAction类的 getName() 方法返回的。

创建主页

在WebContent文件夹里,我们还需要创建 index.jsp 文件,这个文件是用作初始的action URL。用户可以通过点击它命令Struts2框架去调用HelloWorldAction类的定义方法并呈现HelloWorld.jsp视图。
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%>   <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Hello World</title></head><body>   <h1>Hello World From Struts2</h1>   <form action="hello">      <label for="name">Please enter your name</label><br/>      <input type="text" name="name"/>      <input type="submit" value="Say Hello"/>   </form></body></html>
上面视图文件里定义的hello action将通过struts.xml文件影射到HelloWorldAction类及其execute方法。当用户点击提交按钮时,将使得Struts2框架运行HelloWorldAction类中的execute方法,并基于该方法的返回值,选择一个适当的视图作为响应进行呈现。

配置文件

我们需要一个映像把URL、HelloWorldAction类(模型)以及 HelloWorld.jsp(视图)联系在一起。映像告知Struts2 框架哪个类将响应用户的动作(URL),类里的哪个方法将要执行,以及基于方法所返回的字符串结果,会呈现怎样的视图。
那么接下来让我们创建一个名为 struts.xml 的文件。因为Struts2 要求 strust.xml 文件显示在classes的文件夹里,所以我们要在WebContent/WEB-INF/classes 的文件夹下创建 struts.xml 文件。Eclipse并没有默认创建“classes”文件夹,因此你需要自己创建。在project explorer里右键点击WEB-INF文件夹并选择“New”>“Folder”,你的 struts.xml 文件应该如下:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts><constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">           <action name="hello"             class="cn.51coolma.struts2.HelloWorldAction"             method="execute">            <result name="success">/HelloWorld.jsp</result>      </action>   </package></struts>
这里说几句关于上述的配置文件。这里我们设定常数struts.devMode的值为,因为我们是在开发环境下工作,需要查看一些有用的日志消息。然后,我们定义一个名为helloworld的数据包。当你想要把你的Actions集合在一起时,创建一个数据包是非常有用的。在我们的示例中,我们命名我们的动作为“hello”,与URL /hello.action保持一致,由HelloWorldAction.class进行备份。HelloWorldAction.classexecute方法就是当URL /hello.action被调用时运行。如果execute方法返回的结果为“success”,那么我们带用户进入HelloWorld.jsp
下一步是创建一个web.xml文件,这是一个适用于Struts2 任何请求的接入点。在部署描述符(web.xml)中,Struts2 应用程序的接入点将会定义为一个过滤器。因此我们将在web.xml里定义一个org.apache.struts2.dispatcher.FilterDispatcher 类的接入点,而web.xml文件需要在WebContent的WEB-INF文件夹下创建。Eclipse已经创建了一个基础的web.xml文件,你在创建项目的时候可以使用。那么,让我们参照以下内容做修改:
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">      <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>
我们指定了index.jsp作为我们的欢迎文件,那么我们已经配置好了在所有的URL(列如:所有匹配/*模式的URL)上运行Struts2 过滤器。

注意:

如果它是struts2-core-2.5.jar,那么将web.xml中的过滤器类标记值更改为

<filter-class>

     org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter

</filter-class>

如果它是struts2-core-2.1.3.jar,那么将web.xml中的过滤器类标记值更改为

<filter-class>

     org.apache.struts2.dispatcher.FilterDispatcher

</filter-class>

自Struts 2.1.3以来,FilterDispatcher就不推荐使用了。如果您使用的是较旧的版本,则用户高于解决方案。

如果它是struts2-core-2.3.X.jar,那么将web.xml中的过滤器类标记值更改为

<filter-class> 

     org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

</filter-class>

启用详细日志

通过在WEB-INF/classes文件夹下创建logging.properties文件,可以实现在使用Struts 2时启用完整的日志记录功能。 属性文件中需保留以下两行::
org.apache.catalina.core.ContainerBase.[Catalina].level = INFOorg.apache.catalina.core.ContainerBase.[Catalina].handlers =                               java.util.logging.ConsoleHandler

默认由logging.properties指定一个ConsoleHandler将日志记录按指定路线发送给stdout和FileHandler。程序运行日志的级别阈值可以使用SEVERE,WARNING,INFO,CONFIG,FINE,FINER,FINEST或者ALL。

这样,我们就准备好使用Struts 2运行我们的Hello World程序了。

执行应用程序

右键点击项目名称,接着点击“Export”>“WAR File”创建WAR文件,然后将WAR部署到Tomcat的webapps目录中。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp ,将会呈现如下图所示的结果:

你好世界Struts4

输入一个“Struts2”值并提交页面,你可以看到以下页面

你好世界Struts5

注意,你可以在struts.xml文件中定义一个索引作为操作,这样你可以调用索引页面 http://localhost:8080/HelloWorldStruts2/index.action 。查看下面是怎样定义索引作为操作:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts><constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="index">            <result >/index.jsp</result>      </action>      <action name="hello"             class="cn.51coolma.struts2.HelloWorldAction"             method="execute">            <result name="success">/HelloWorld.jsp</result>      </action>   </package></struts>


本章节将带你学习Struts2 应用程序所需的基本配置。在这里可以看到哪些将被配置到一些重要的配置文件中:web.xmlstruts.xmlstruts-config.xml以及struts.properties

实际上,你可以继续依赖于使用web.xml和struts.xml配置文件,并且你已经在前面的章节中了解到,我们的示例是使用这两个文件运作的,不过为了让你了解更多,我们还是再来说明一下其他的文件。

web.xml文件

web.xml配置文件是一种J2EE配置文件,决定servlet容器的HTTP元素需求如何进行处理。它严格来说不是一个Struts2 配置文件,但它是Struts2 运作所需要进行配置的文件。

正如前面所讨论的,这个文件为每个web应用程序提供接入点。在部署描述符(web.xml)中,Struts2 应用程序的接入点将会定义为一个过滤器。因此我们将在web.xml里定义一个FilterDispatcher类的接入点,而这个web.xml文件需要在WebContent/WEB-INF文件夹下创建。

如果你开始时没有模板或工具(比如Eclipse或Maven2)的辅助来生成,那这就是第一个你需要配置的文件。下面是我们在上一个例子中用到的web.xml的内容。

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">      <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>      <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

注意,我们将Struts2 过滤器映射到 /* ,而不是 /*.action ,这意味着所有的url都会被Struts过滤器解析。当我们学到关于注解的章节时会对这个进行讨论。

注意:自2.1.3版本开始,ActionContextCleanUp和FilterDispatcher都由StrutsPrepareAndExecuteFilter代替。

struts.xml文件

struts.xml文件包含有随着Actions的开发你将要修改的配置信息。它可用于覆盖应用程序的默认设置,例如:struts.devMode=false 以及其他定义为属性文件的设置。这个文件可在WEB-INF/classes文件夹下创建。
让我们来看一下在前一章节中阐述的Hello World示例里创建的struts.xml文件。

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">           <action name="hello"             class="cn.51coolma.struts2.HelloWorldAction"             method="execute">            <result name="success">/HelloWorld.jsp</result>      </action>      <-- more actions can be listed here -->   </package>   <-- more packages can be listed here --></struts>

首先要注意的是DOCTYPE(文档类型)。如我们的示例所示,所有的Struts配置文件都需要有正确的doctype。<struts>是根标记元素,在其下,我们使用<package>标签声明不同的包。 这里的<package>标签允许配置的分离和模块化。这在你进行一个大的项目并且项目分为多个不同的模块时,是非常有用的。

如果您的项目有三个域:business_applicaiton、customer_application和staff_application的话,你可以创建三个包,并将相关的Actions存储到相应的包中。 <package>标签具有以下属性:

属性描述
name(必需)为package的唯一标识
extends指定package继承另一package的所有配置。通常情况下,我们使用struts-default作为package的基础。
abstract定义package为抽象的。如果标记为true,则package不能被最终用户使用。
namespaceActions的唯一命名空间

<constant>标签以及name和value属性将用于覆盖default.properties中定义的任一属性,就像我们设置的struts.devMode属性一样。设置struts.devMode属性允许我们在日志文件中查看更多的调试消息。

我们定义<action>标签对应于我们想要访问的每个URL,并且使用execute()方法定义一个访问相应的URL时将要访问的类。

Results(结果)确定在执行操作后返回到浏览器的内容,而从操作返回的字符串应该是结果的名称。 Results按上述方式配置,或作为“全局”结果配置,可用于包中的每个操作。 Results有

name

type

属性可选,默认的name值是“success”。


Struts.xml文件可以随着时间的推移而增长,因此通过包打破它是使它模块化的一种方式,但struts提供了另一种模块化struts.xml文件的方法,你可以将文件拆分为多个xml文件,并用以下方式导入它们。

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"    "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>     <include file="my-struts1.xml"/>     <include file="my-struts2.xml"/></struts>

我们没有覆盖的另一个配置文件是struts-default.xml。此文件包含Struts的标准配置设置,你不必再为99.99%的项目重复这些设置。 因此,我们不会深入了解这个文件的太多细节。如果你有兴趣,可以查看在struts2-core-2.2.3.jar文件中可用的default.properties文件。

struts-config.xml文件

struts-config.xml配置文件是Web Client中View和Model组件之间的链接,但在你99.99%的项目里你不必使用这些设置。 struts-config.xml配置文件包含以下主要元素:

序号拦截器和说明
1struts-config

这是配置文件的根节点。

2form-beans

这是你将ActionForm子类映射到name的位置,你可以在struts-config.xml文件的其余部分,甚至在JSP页面上,将这个name用作ActionForm的别名。

3global forwards

此部分将你在webapp上的页面映射到name,你可以使用这个name来引用实际页面。这避免了对你网页上的URL进行硬编码。

4action-mappings

这是你声明表单处理程序的地方,也被称为操作映射(action mappings)

5controller

这部分是配置Struts的内部,在实际情况中很少使用。

6plug-in

这部分告诉Struts在哪里找到属性文件,它包含提示和错误消息。

下面是struts-config.xml文件的示例:

<?xml version="1.0" encoding="ISO-8859-1" ?><!DOCTYPE struts-config PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 1.0//EN""http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd"><struts-config>   <!-- ========== Form Bean Definitions ============ -->   <form-beans>      <form-bean name="login" type="test.struts.LoginForm" />   </form-beans>   <!-- ========== Global Forward Definitions ========= -->   <global-forwards>   </global-forwards>   <!-- ========== Action Mapping Definitions ======== -->   <action-mappings>      <action         path="/login"         type="test.struts.LoginAction" >         <forward name="valid" path="/jsp/MainMenu.jsp" />         <forward name="invalid" path="/jsp/LoginView.jsp" />      </action>   </action-mappings>   <!-- ========== Controller Definitions ======== -->   <controller       contentType="text/html;charset=UTF-8"      debug="3"      maxFileSize="1.618M"      locale="true"      nocache="true"/></struts-config>

有关struts-config.xml文件的更多详细内容,可查看Struts Documentation。

struts.properties文件

这个配置文件提供了一种机制来改变框架的默认行为。实际上,struts.properties配置文件中包含的所有属性也可以在web.xml中配置使用init-param,以及在struts.xml配置文件中使用constant标签。 但如果你想保持事件独立以及保留更多struts细节,那么你可以在WEB-INF/classes文件夹下创建这个文件。

struts.properties

文件中配置的值将覆盖

default.properties

中配置的默认值,这些值包含在struts2-core-x.y.z.jar分布中。有一些属性,你可以考虑改为使用

struts.properties

文件:

### When set to true, Struts will act much more friendly for developersstruts.devMode = true### Enables reloading of internationalization filesstruts.i18n.reload = true### Enables reloading of XML configuration filesstruts.configuration.xml.reload = true### Sets the port that the server is run onstruts.url.http.port = 8080

这里任何以#(hash)开头的行都将被假定为注释,并且它会被Struts 2默认忽略。


Actions是Struts2框架的核心,因为它们适用于任何MVC(Model View Controller)框架。 每个URL映射到特定的action,其提供处理来自用户的请求所需的处理逻辑。
但action还有另外两个重要的功能。 首先,action在将数据从请求传递到视图(无论是JSP还是其他类型的结果)方面起着重要作用。 第二,action必须协助框架确定哪个结果应该呈现在响应请求的视图中。

创建Action

Struts2中actions的唯一要求是必须有一个无参数方法返回String或Result对象,并且必须是POJO。如果没有指定no-argument方法,则默认是使用execute()方法。
你还可以扩展ActionSupport类,该类可实现六个接口,包括Action接口。Action的接口如下:

public interface Action {   public static final String SUCCESS = "success";   public static final String NONE = "none";   public static final String ERROR = "error";   public static final String INPUT = "input";   public static final String LOGIN = "login";   public String execute() throws Exception;}

让我们来看看在Hello World示例中的action方法:

package cn.51coolma.struts2;public class HelloWorldAction{   private String name;   public String execute() throws Exception {      return "success";   }      public String getName() {      return name;   }   public void setName(String name) {      this.name = name;   }}

为了说明action方法控制视图的要点,让我们对execute方法进行以下更改,并扩展ActionSupport类如下:

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class HelloWorldAction extends ActionSupport{   private String name;   public String execute() throws Exception {      if ("SECRET".equals(name))      {         return SUCCESS;      }else{         return ERROR;        }   }      public String getName() {      return name;   }   public void setName(String name) {      this.name = name;   }}

在这个例子中,我们在execute方法中使用一些逻辑来查看name属性。如果属性等于字符串“SECRET”,我们返回SUCCESS作为结果,否则我们返回ERROR作为结果。因为我们已经扩展了ActionSupport,所以我们可以使用String常量、SUCCESS和ERROR。 现在,让我们修改struts.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd">   <struts>      <constant name="struts.devMode" value="true" />      <package name="helloworld" extends="struts-default">         <action name="hello"             class="cn.51coolma.struts2.HelloWorldAction"            method="execute">            <result name="success">/HelloWorld.jsp</result>            <result name="error">/AccessDenied.jsp</result>         </action>      </package></struts>

创建视图

让我们在你的eclipse项目的WebContent文件夹中创建下面的jsp文件HelloWorld.jsp。右键单击项目资源管理器中的WebContent文件夹,然后选择“New”> “JSP File”。如果返回结果是SUCCESS将调用此文件(这个字符串常量“success”是在Action接口中定义的):

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>Hello World</title></head><body>   Hello World, <s:property value="name"/></body></html>

如果action的结果是ERROR,即字符串常量为“error”,下面的文件将被框架调用。 以下是AccessDenied.jsp的内容:

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>Access Denied</title></head><body>   You are not authorized to view this page.</body></html>

我们还需要在WebContent文件夹中创建index.jsp文件。此文件将用作初始的action URL,用户可以单击它以命令Struts 2框架调用HelloWorldAction类的execute方法并呈现HelloWorld.jsp视图。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%>   <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Hello World</title></head><body>   <h1>Hello World From Struts2</h1>   <form action="hello">      <label for="name">Please enter your name</label><br/>      <input type="text" name="name"/>      <input type="submit" value="Say Hello"/>   </form></body></html>

这样,没有改变web.xml文件的需求,所以我们可以使用前面在Hello World示例章节中创建的的web.xml文件。现在,我们准备好使用Struts 2框架运行我们的Hello World应用程序了。

执行应用程序

右键单击项目名称,然后单击“Export”>“WAR File”创建WAR文件。 然后在Tomcat的webapps目录中部署这个WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp。显示的图示如下:

输入

让我们输入一个单词为“SECRET”,你会看到如下页面:

secret成功

现在输入除“SECRET”之外的任何词,你会看到如下页面:

错误

创建多个Actions

你会需要频繁定义多个action来处理不同的请求,并为用户提供不同的URL,因此你将如下定义的不同类:

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;   class MyAction extends ActionSupport{      public static String GOOD = SUCCESS;      public static String BAD = ERROR;   }   public class HelloWorld extends ActionSupport{      ...      public String execute()      {         if ("SECRET".equals(name)) return MyAction.GOOD;         return MyAction.BAD;      }      ...   }   public class SomeOtherClass extends ActionSupport{      ...      public String execute()      {         return MyAction.GOOD;      }      ...   }

你将如下在struts.xml文件中的配置这些action:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"    "http://struts.apache.org/dtds/struts-2.0.dtd">struts> <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="hello"          class="cn.51coolma.struts2.HelloWorld"          method="execute">         <result name="success">/HelloWorld.jsp</result>         <result name="error">/AccessDenied.jsp</result>      </action>      <action name="something"          class="cn.51coolma.struts2.SomeOtherClass"          method="execute">         <result name="success">/Something.jsp</result>         <result name="error">/AccessDenied.jsp</result>      </action>   </package></struts>

正如你在上面的例子中看到的,action的结果SUCCESS和ERROR是重复的。为了解决这个问题,建议您创建一个包含结果的类。


拦截器在概念上与servlet过滤器或JDK代理类相同。拦截器允许横切功能,把action以及框架分开实现。你可以使用拦截器实现以下操作:

  • 在调用action之前提供预处理逻辑。

  • 在调用action后提供后处理逻辑。

  • 捕获异常,以便可以执行备用处理。

Struts2框架中提供的许多功能都是使用拦截器实现的,包括异常处理,文件上传,生命周期回调和验证等。事实上,由于Struts2将其大部分功能基于拦截器,因此不太可能为每个action分配7个或8个拦截器。

Struts2框架拦截器

Struts 2框架提供了一个良好的开箱即用的拦截器列表,这些拦截器预先配置好并可以使用。 下面列出了几个重要的拦截器:

序号拦截器和说明
1alias

允许参数在请求之间使用不同的别名。

2checkbox

通过为未检查的复选框添加参数值false,以辅助管理复选框。

3conversionError

将字符串转换为参数类型的错误信息放置到action的错误字段中。

4createSession

自动创建HTTP会话(如果尚不存在)。

5debugging

为开发人员提供一些不同的调试屏幕。

6execAndWait

当action在后台执行时,将用户发送到中间的等待页面。

7exception

映射从action到结果抛出的异常,允许通过重定向自动处理异常。

8fileUpload

便于文件上传。

9

i18n

在用户会话期间跟踪选定的区域。

10logger

通过输出正在执行的action的名称提供简单的日志记录。

11params

设置action上的请求参数。

12prepare

这通常用于执行预处理工作,例如设置数据库连接。

13profile

允许记录action的简单分析信息。

14scope

在会话或应用程序范围内存储和检索action的状态。

15ServletConfig

提供可访问各种基于servlet信息的action。

16timer

以action执行时间的形式提供简单的分析信息。

17token

检查action的有效性,以防止重复提交表单。

18validation

提供action的验证支持。

你可以阅读Struts 2文档,了解上述拦截器的完整信息。接下来我们会告诉你如何在Struts应用程序中使用拦截器。

如何使用拦截器?

让我们看看如何在我们的“Hello World”程序中使用一个已经存在的拦截器。我们将首先使用timer拦截器,目的是测量执行action方法所需的时间。同时我们使用params拦截器,目的是将请求参数发送给action。你可以尝试不在你的例子中使用这个拦截器,然后你会发现name属性没有被设置,因为参数无法发送给action。
我们可以保留HelloWorldAction.java,web.xml,HelloWorld.jsp和index.jsp文件,因为它们已在Hellow World示例一章中创建过了,然后让我们参照下面修改struts.xml文件给它添加拦截器:

 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="hello"          class="cn.51coolma.struts2.HelloWorldAction"         method="execute">         <interceptor-ref name="params"/>         <interceptor-ref name="timer" />         <result name="success">/HelloWorld.jsp</result>      </action>   </package></struts>

右键单击项目名称,然后单击“Export”>“WAR File”创建WAR文件。然后在Tomcat的webapps目录中部署这个WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp。结果如下图所示:

输入

现在,在给定文本框中输入任意单词,然后单击Say Hello按钮执行定义的action。如果你去查看生成的日志,会看到以下文本:

INFO: Server startup in 3539 ms27/08/2011 8:40:53 PM com.opensymphony.xwork2.util.logging.commons.CommonsLogger infoINFO: Executed action [//hello!execute] took 109 ms.

这里的最后一行是由timer拦截器生成的,是表示ation总共需要109ms来执行。

创建自定义拦截器

在你的应用程序中使用自定义拦截器是提供跨切割应用程序功能的简洁方式。创建自定义拦截器很容易,需要扩展的是以下Interceptor接口:

 public interface Interceptor extends Serializable{   void destroy();   void init();   String intercept(ActionInvocation invocation)   throws Exception;}

正如name所指出的,init()方法提供了一种初始化拦截器的方法,而destroy()方法为拦截器清理提供了一个工具。与action不同,拦截器在请求之间重复使用,需要线程安全,特别是intercept()方法。
ActionInvocation对象可访问运行时的环境。它允许访问action本身以及方法来调用action,并确定action是否已被调用。
如果你不需要初始化或清理代码,可以扩展AbstractInterceptor类,以实现init()和destroy()的默认的无操作指令。

创建拦截器类

我们接下来在Java Resources>src文件夹中创建以下MyInterceptor.java文件:

 package cn.51coolma.struts2;import java.util.*;import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.interceptor.AbstractInterceptor;public class MyInterceptor extends AbstractInterceptor {   public String intercept(ActionInvocation invocation)throws Exception{      /* let us do some pre-processing */      String output = "Pre-Processing";       System.out.println(output);      /* let us call action or next interceptor */      String result = invocation.invoke();      /* let us do some post-processing */      output = "Post-Processing";       System.out.println(output);      return result;   }}

你可以发现,实际中action将通过拦截器使用invocation.invoke()调用执行,所以你可以根据你的需求做一些预处理和一些后处理。
框架本身通过第一次调用ActionInvocation对象的invoke()来启动进程。每次调用invoke()时,ActionInvocation都会查询其状态,并执行下一个拦截器。当所有配置的拦截器都被调用时,invoke()将使得action本身被执行。以下图表通过请求流显示了所说的概念:

ActionInvocation

创建Action类

我们在Java Resources>src文件夹下创建一个java文件HelloWorldAction.java,其中包名为cn.51coolma.struts2,内容如下:

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class HelloWorldAction extends ActionSupport{   private String name;   public String execute() throws Exception {      System.out.println("Inside action....");      return "success";   }     public String getName() {      return name;   }   public void setName(String name) {      this.name = name;   }}

这是我们在前面的例子中看到的同一个类,我们有“name”属性标准的getters和setter方法,以及返回字符串“success”的execute方法。

创建视图

让我们在你的eclipse项目的WebContent文件夹中创建下面的jsp文件HelloWorld.jsp

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>Hello World</title></head><body>   Hello World, <s:property value="name"/></body></html>

创建主页

我们还需要在WebContent文件夹中创建index.jsp文件,此文件将用作初始的action URL,用户可以单击它以命令Struts 2框架调用HelloWorldAction类的定义方法并呈现HelloWorld.jsp视图。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%>   <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Hello World</title></head><body>   <h1>Hello World From Struts2</h1>   <form action="hello">      <label for="name">Please enter your name</label><br/>      <input type="text" name="name"/>      <input type="submit" value="Say Hello"/>   </form></body></html>

在上述视图文件中定义的hello action将使用struts.xml文件映射到HelloWorldAction类及其execute方法中。

配置文件

现在我们需要注册新的拦截器,然后调用它,因为我们在前面的例子中调用的是默认拦截器。要注册一个新的拦截器,把<interceptors> ... </ interceptors>标签直接放置在<package>标签下的struts.xml文件中即可。对于默认拦截器,你可以跳过此步骤,就像我们前面的示例中所做的那样。但现在让我们使用以下方法注册新的:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"    "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <interceptors>         <interceptor name="myinterceptor"            class="cn.51coolma.struts2.MyInterceptor" />      </interceptors>      <action name="hello"          class="cn.51coolma.struts2.HelloWorldAction"          method="execute">         <interceptor-ref name="params"/>         <interceptor-ref name="myinterceptor" />         <result name="success">/HelloWorld.jsp</result>      </action>   </package></struts>

需要注意的是,你可以在<package>标签内注册多个拦截器,同时可以在<action>标签内调用多个拦截器,也可以用不同的action调用同一个拦截器。

web.xml文件需要在WebContent下的WEB-INF文件夹下创建,如下所示:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">      <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

右键单击项目名称,然后单击“Export”>“WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp。将显示如下图片:

输入2

现在,在给的定文本框中输入任意单词,然后单击Say Hello按钮执行定义的action。如果你查看生成的日志,会在底部看到以下文本:

Pre-ProcessingInside action....Post-Processing

拦截器堆栈

你可以想象,为每个action配置的多个拦截器将很快变得极其难以管理。为此,拦截器使用拦截器堆栈进行管理。这里是直接从struts-default.xml文件展示的一个例子:

<interceptor-stack name="basicStack">   <interceptor-ref name="exception"/>   <interceptor-ref name="servlet-config"/>   <interceptor-ref name="prepare"/>   <interceptor-ref name="checkbox"/>   <interceptor-ref name="params"/>   <interceptor-ref name="conversionError"/></interceptor-stack>

上面的堆栈称为basicStack,可以如下所述在你的配置中使用,此配置节点放置在<package ... />节点下。<interceptor-ref ... />标签引用的是在当前拦截器堆栈之前配置的拦截器或拦截器堆栈。因此非常重要的是在配置初始拦截器和拦截器堆栈时,确保name在所有拦截器和拦截器堆栈配置中是唯一的。
我们已经学习了如何将拦截器应用到action中,而拦截器堆栈的应用也是类似的。事实上,使用的标签也是一样的:

 <action name="hello" class="com.tutorialspoint.struts2.MyAction">   <interceptor-ref name="basicStack"/>   <result>view.jsp</result></action

上述的“basicStack”注册将完整注册hello action的所使用的六个拦截器。要注意的是,拦截器按照它们被配置的顺序执行。例如,在上面的例子中,exception将首先执行,第二个将是servlet-config等。


如前面所述,<results>标签在Struts2 MVC框架中扮演视图的角色。Action负责执行业务逻辑,下一步就是使用<results>标签显示视图。
通常有一些导航规则附加的结果。例如,如果action是进行验证用户,则有三种可能的结果:(a)成功登录(b)登录失败:用户名或密码不正确(c)帐户锁定。
在这种情况下,action将配置三个可能的结果字符串和三个不同的视图来渲染结果,这在我们前面的例子中已经看到过了。
但是,Struts2不绑定使用JSP作为视图技术。毕竟,MVC范例的目的是保持图层分离和高度可配置。例如,对于Web2.0客户端,你可能希望返回XML或JSON作为输出。在这种情况下,你可以为XML或JSON创建一个新的结果类型并实现这一点。
Struts提供了许多预定义的结果类型,我们已经看到的是默认的结果类型dispatcher,它用于分发到JSP页面。Struts允许你使用其他标记语言为视图技术呈现结果,较常选用的包括VelocityFreemakerXSLTTiles

dispatcher结果类型

dispatcher结果类型是默认的类型,如果未指定其他结果类型,则使用此类型。它用于转发到服务器上的servlet,JSP,HTML等页面。它使用RequestDispatcher.forward()方法。
我们在前面的示例中看到了“简写”版本,里面我们用一个JSP路径作为结果标签的主体。

<result name="success">   /HelloWorld.jsp</result>

我们还可以使用<result ...>元素中的<param name="location">标签来指定JSP文件,如下所示:

<result name="success" type="dispatcher">   <param name="location">      /HelloWorld.jsp   </param ></result>

我们还可以使用一个parse参数,默认情况下为true。parse参数确定是否将为OGNL表达式解析位置参数。

FreeMaker结果类型

在这个例子中,我们将介绍如何使用FreeMaker作为视图技术。Freemaker是一个流行的模板引擎,使用预定义的模板生成输出。让我们创建一个包含以下内容的名为hello.fm的Freemaker模板文件:

Hello World ${name}

上面的文件是一个模板,其中name是一个参数,将使用定义的action从外部传递。你可以在CLASSPATH中保留此文件。接下来,让我们参考下面修改struts.xml以指定结果:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN""http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="hello"          class="cn.51coolma.struts2.HelloWorldAction"         method="execute">         <result name="success" type="freemarker">            <param name="location">/hello.fm</param>         </result>      </action>         </package></struts>

我们继续保留之前在HelloWorld示例一章中创建的HelloWorldAction.java,HelloWorldAction.jsp和index.jsp文件。现在右键单击项目名称,然后单击“Export”>“WAR File”创建WAR文件。然后在Tomcat的webapps目录中部署这个WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp。将显示如下页面:

输入

输入值“Struts2”并提交,你可以看到以下页面

成功

这个例子中我们使用了Freemaker,可以看到,这与JSP视图完全相同,只是我们不绑定使用JSP作为视图技术。

redirect结果类型

redirect结果类型调用标准的response.sendRedirect()方法,使得浏览器向给定的位置创建一个新请求。
我们可以在<result...>元素的主体中或作为<param name="location">的元素中给定位置。redirect也支持parse参数,以下是使用XML配置的示例:

<action name="hello"    class="com.tutorialspoint.struts2.HelloWorldAction"   method="execute">   <result name="success" type="redirect">       <param name="location">         /NewWorld.jsp      </param >   </result></action>

所以只需修改你的struts.xml文件来定义上面提到的redirect结果类型,并创建一个新的文件NewWorld.jpg,那么当你的hello action返回“success”时就会产生redirect结果。你可以检查Struts 2的Redirect Action示例,以便更详细地了解。

值栈是一组对象,按照提供的顺序存储以下这些对象:

序号对象和说明
1Temporary对象

实际中存在各种在页面执行期间创建的temporary对象。例如,JSP标签循环集合的当前迭代值。

2Model对象

如果在struts应用程序中使用Model对象,则当前Model对象放在值堆栈上的action之前。

3Action对象

这是指正在执行的当前action对象。

4命名对象

这些对象包括#application,#session,#request,#attr和#parameters以及所引用的相应的servlet作用域。

值栈可以通过为JSP,Velocity或Freemarker提供的标签进行访问。我们将在单独的章节中学习到用于获取和设置struts2 值栈的各种标签。你可以在action中获取值栈对象,如下所示:

ActionContext.getContext().getValueStack()

一旦你有一个值栈对象,你可以使用以下方法来操纵该对象:

序号值栈方法和说明
1Object findValue(String expr)

通过在默认搜索顺序中对值栈评估所给定的表达式来查找值。

2CompoundRoot getRoot()

获取将对象推入值栈的CompoundRoot。

3Object peek()

获取值栈顶部的对象而不改变值栈。

4Object pop()

获取值栈顶部的对象,并将其从值栈中删除。

5void push(Object o)

将对象放在值栈的顶部。

6void set(String key,Object o)

使用给定的key在值栈上设置一个对象,使其可通过findValue(key,...)检索。

7void setDefaultType(Class defaultType)

设置在获取值时要转换的默认类型。

8void setValue(String expr,Object value)

尝试使用由默认搜索顺序给定的表达式在值栈的bean上设置属性。

9int size()

获取值栈中的对象数。

OGNL

OGNL(Object-Graph Navigation Language,对象图导航语言)是一种强大的表达式语言,用于引用和操作值栈上的数据,还可用于数据传输和类型转换。
OGNL非常类似于JSP表达式语言。OGNL基于上下文中存有根对象或默认对象的理念,使用标记符号(即#号)来引用默认或根对象的属性。
如前面所述,OGNL是基于上下文的,而Struts构建了一个ActionContext映射以供OGNL使用。 ActionContext映射包含以下内容:

  • 应用程序 - 应用程序作用域变量

  • 会话 - 会话作用域变量

  • 根/值栈 - 所有的action变量都存储在这里

  • 请求 - 请求作用域变量

  • 参数 - 请求参数

  • 属性 - 存储在页面,请求,会话和应用程序作用域中的属性

有必要了解的是,Action对象在值栈中总是可用的,因此如果你的Action对象有x和y属性,你可以随时使用。
ActionContext中的对象使用#号引用,但是,值栈中的对象可以直接引用,例如,如果employee是action类的属性,则可以按如下方式引用:

  <s:property value="name"/>

替代

  <s:property value="#name"/>

如果你在会话中有一个名为“login”的属性,你可以按如下方式检索:

  <s:property value="#session.login"/>

OGNL还支持处理集合 - 即Map,List和Set。例如,要显示颜色的下拉列表,你可以执行以下操作:

  <s:select name="color" list="{'red','yellow','green'}" />

OGNL表达式很智能地将“红色”,“黄色”,“绿色”解释为颜色,并基于此构建了列表。
在下一章我们学习各种的标签时,OGNL表达式将会广泛的用到。因此,不要用孤立的方式去了解OGNL,让我们结合Form标签/Control标签/Data标签和Ajax标签部分中的一些示例来了解它。

值栈/ OGNL示例

创建Action:

让我们参考下面用于访问值栈的action类,然后在ie.JSP视图页面设置使用OGNL进行访问的几个key。

package cn.51coolma.struts2;import java.util.*; import com.opensymphony.xwork2.util.ValueStack;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionSupport;public class HelloWorldAction extends ActionSupport{   private String name;   public String execute() throws Exception {      ValueStack stack = ActionContext.getContext().getValueStack();      Map<String, Object> context = new HashMap<String, Object>();      context.put("key1", new String("This is key1"));       context.put("key2", new String("This is key2"));      stack.push(context);      System.out.println("Size of the valueStack: " + stack.size());      return "success";   }     public String getName() {      return name;   }   public void setName(String name) {      this.name = name;   }}

实际上,Struts 2在执行时会将action添加到值栈的顶部。所以,通常放置东西在值栈的方法是添加getters/setters的值到Action类,然后使用<s:property>标签访问值。我们前面已展示了ActionContext和值栈在struts中的工作原理。

创建视图

在你的eclipse项目的WebContent文件夹中创建下面的jsp文件HelloWorld.jsp,如果action返回为success将显示视图:

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>Hello World</title></head><body>   Entered value : <s:property value="name"/><br/>   Value of key 1 : <s:property value="key1" /><br/>   Value of key 2 : <s:property value="key2" /> <br/></body></html>

我们还需要在WebContent文件夹中创建index.jsp文件,其内容如下:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%>   <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Hello World</title></head><body>   <h1>Hello World From Struts2</h1>   <form action="hello">      <label for="name">Please enter your name</label><br/>      <input type="text" name="name"/>      <input type="submit" value="Say Hello"/>   </form></body></html>

配置文件

以下是struts.xml文件的内容:

 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"    "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="hello"          class="cn.51coolma.struts2.HelloWorldAction"          method="execute">         <result name="success">/HelloWorld.jsp</result>      </action>   </package></struts>

以下是web.xml文件的内容:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">      <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

右键单击项目名称,然后单击“Export”>“WAR File”创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp。将显示如下界面:

输入

现在,在给定的文本框中输入任意单词,然后单击“Say Hello”按钮执行定义的action。如果你查看生成的日志,可以在底部看到以下文本:

 Size of the valueStack: 3

这意味着它将显示你输入的任何值和我们放在值栈上的key1和key2的值。

Struts2 框架为依据“基于表单的HTML文件上传”所进行的文件处理上传提供了内置支持。当文件上传时,它通常会存储在临时目录中,然后Action类应对其进行处理或移动到固定目录中,以确保数据不会丢失。
注意:服务器可能有适当的安全策略,禁止你写入临时目录以外的目录以及属于Web应用程序的目录。
通过一个名为FileUpload的预定义拦截器可以在Struts中上传文件,该拦截器可通过org.apache.struts2.interceptor.FileUploadInterceptor类获得,并作为defaultStack的一部分包含在内。你也将在接下来的内容中看到如何使用它在struts.xml文件中设置各种参数。

创建视图文件

创建视图时需要浏览和上传选定的文件。因此,让我们先使用HTML上传表单,创建一个允许用户上传文件的index.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>File Upload</title></head><body>   <form action="upload" method="post" enctype="multipart/form-data">      <label for="myFile">Upload your file</label>      <input type="file" name="myFile" />      <input type="submit" value="Upload"/>   </form></body></html>

在上面的例子中有几点值得注意。首先,表单的enctype设置为multipart/form-data,要使得文件上传拦截器成功处理文件上传,这个就必须设置。然后要注意的是表单的action方法上传和文件上传字段的名称(即myFile)。我们需要这些信息来创建action方法和struts配置。
接下来让我们创建一个简单的jsp文件success.jsp来显示我们文件上传成功后的结果。

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>File Upload Success</title></head><body>You have successfully uploaded <s:property value="myFileFileName"/></body></html>

以下是结果文件error.jsp,一旦上传文件出错时会使用:

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>File Upload Error</title></head><body>There has been an error in uploading the file.</body></html>

创建Action类

接下来,让我们创建一个名为uploadFile.java的Java类,它将负责上传文件并将文件存储在安全的位置:

package cn.51coolma.struts2;import java.io.File;import org.apache.commons.io.FileUtils;import java.io.IOException; import com.opensymphony.xwork2.ActionSupport;public class uploadFile extends ActionSupport{   private File myFile;   private String myFileContentType;   private String myFileFileName;   private String destPath;   public String execute()   {      /* Copy file to a safe location */      destPath = "C:/apache-tomcat-6.0.33/work/";      try{     	 System.out.println("Src File name: " + myFile);     	 System.out.println("Dst File name: " + myFileFileName);     	    	      	 File destFile  = new File(destPath, myFileFileName);    	 FileUtils.copyFile(myFile, destFile);        }catch(IOException e){         e.printStackTrace();         return ERROR;      }      return SUCCESS;   }   public File getMyFile() {      return myFile;   }   public void setMyFile(File myFile) {      this.myFile = myFile;   }   public String getMyFileContentType() {      return myFileContentType;   }   public void setMyFileContentType(String myFileContentType) {      this.myFileContentType = myFileContentType;   }   public String getMyFileFileName() {      return myFileFileName;   }   public void setMyFileFileName(String myFileFileName) {      this.myFileFileName = myFileFileName;   }}

uploadFile.java是一个非常简单的类。要注意的重点是,FileUpload拦截器和Parameters拦截器为我们承担了所有的重工作量。默认情况下,FileUpload拦截器为你提供三个参数,它们分别按以下方式命名:

  • [文件名参数] - 这是用户已上传的实际文件。在这个例子中它将是“myFile”

  • [文件名参数]ContentType - 这是上传的文件的内容类型。在这个例子中,它将是“myFileContentType”

  • [文件名参数]FileName - 这是上传的文件的名称。在这个例子中,它将是“myFileFileName”

得益于Struts拦截器这三个参数均可供我们使用。我们要做的是在Action类中创建三个带有正确名称的参数,并使这些变量可以自动连接。所以,在上面的例子中,我们有三个参数和一个action方法。如果一切正常,则返回“success”,否则返回“error”。

配置文件

以下是控制文件上传过程的Struts2 配置属性:

序号属性和说明
1struts.multipart.maxSize

可接受的上传文件的最大值(以字节为单位),默认值为250M。

2struts.multipart.parser

用于上传多部分表单的库,默认为jakarta

3struts.multipart.saveDir

存储临时文件的位置,默认是javax.servlet.context.tempdir。

你可以在应用程序的struts.xml文件中使用constant标签更改任意一个这些设置,我们可以看以下struts.xml的示例:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN""http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <constant name="struts.multipart.maxSize" value="1000000" />   <package name="helloworld" extends="struts-default">   <action name="upload" class="cn.51coolma.struts2.uploadFile">       <result name="success">/success.jsp</result>       <result name="error">/error.jsp</result>   </action>   </package></struts>

因为FileUpload拦截器是defaultStack拦截器的一部分,我们不需要准确的配置它,但你可以在<action>中添加<interceptor-ref>标签。fileUpload拦截器有两个参数:maximumSizeallowedTypes。 maximumSize参数是设置所允许的文件大小的最大值(默认约为2MB)。allowedTypes参数是所允许的内容(MIME)类型的用逗号分隔的列表,如下所示:

   <action name="upload" class="cn.51coolma.struts2.uploadFile">       <interceptor-ref name="basicStack">       <interceptor-ref name="fileUpload">           <param name="allowedTypes">image/jpeg,image/gif</param>       </interceptor-ref>       <result name="success">/success.jsp</result>       <result name="error">/error.jsp</result>   </action>

以下是web.xml文件的内容:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">      <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

现在右键单击项目名称,然后单击“Export”>“WAR File”创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/upload.jsp,将显示如下界面:

输入

现在使用浏览按钮选择一个文件“Contacts.txt”,然后点击上传按钮,上传文件到服务器,你将看到如下页面。你上传的文件应该保存在C:apache-tomcat-6.0.33work下。

成功

注意:FileUpload拦截器会自动删除上传的文件,因此你必须在上传的文件被删除之前将其以编程方式保存在某个位置。

错误信息

fileUplaod拦截器使用几个默认的错误信息key:

序号错误信息key和说明
1struts.messages.error.uploading

无法上传文件时发生的常规错误。

2struts.messages.error.file.too.large

当上传的文件过大(由maximumSize指定)时发生。

3struts.messages.error.content.type.not.allowed

当上传的文件与指定的预期内容类型不匹配时发生。

你可以在WebContent/WEB-INF/classes/messages.properties资源文件中覆盖这些消息文本。

本章内容将告诉你如何使用Struts2 的简单步骤访问数据库。Struts是一个MVC框架,而不是一个数据库框架,但它提供了对JPA/Hibernate集成的出色支持。我们会在后面的章节中讨论hibernate集成,但在本章中,我们将使用旧的JDBC来访问数据库。
首先第一步是设置和初始化数据库,这个例子中我们使用MySQL作为数据库。如果有在机器上安装MySQL,那么就创建一个名为“struts_tutorial”的新数据库。然后创建一个名为login的表,并用一些值填充它。下面是用来创建和填充表的脚本。
MYSQL数据库有默认用户名“root”和“root123”密码

CREATE TABLE `struts_tutorial`.`login` (   `user` VARCHAR( 10 ) NOT NULL ,   `password` VARCHAR( 10 ) NOT NULL ,   `name` VARCHAR( 20 ) NOT NULL ,   PRIMARY KEY ( `user` )) ENGINE = InnoDB;INSERT INTO `struts_tutorial`.`login` (`user`, `password`, `name`) VALUES ('scott', 'navy', 'Scott Burgemott');

下一步是下载MySQL Connector 的jar文件,并将此文件放在项目的WEB-INFlib文件夹中。做好这个后,我们开始准备创建action类。

创建Action

Action类具有与数据库表中的列对应的属性。我们有userpasswordname作为String属性。在action方法中,我们使用user和password参数来检查用户是否存在,如果存在,则在下一个界面中显示用户名。如果用户输入错误的信息,则会再次将其发送到登录界面。以下是LoginAction.java文件的内容:

package cn.51coolma.struts2;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import com.opensymphony.xwork2.ActionSupport;public class LoginAction extends ActionSupport {   private String user;   private String password;   private String name;   public String execute() {      String ret = ERROR;      Connection conn = null;      try {         String URL = "jdbc:mysql://localhost/struts_tutorial";         Class.forName("com.mysql.jdbc.Driver");         conn = DriverManager.getConnection(URL, "root", "root123");         String sql = "SELECT name FROM login WHERE";         sql+=" user = ? AND password = ?";         PreparedStatement ps = conn.prepareStatement(sql);         ps.setString(1, user);         ps.setString(2, password);         ResultSet rs = ps.executeQuery();         while (rs.next()) {            name = rs.getString(1);            ret = SUCCESS;         }      } catch (Exception e) {         ret = ERROR;      } finally {         if (conn != null) {            try {               conn.close();            } catch (Exception e) {            }         }      }      return ret;   }   public String getUser() {      return user;   }   public void setUser(String user) {      this.user = user;   }   public String getPassword() {      return password;   }   public void setPassword(String password) {      this.password = password;   }   public String getName() {      return name;   }   public void setName(String name) {      this.name = name;   }}

创建主页

现在,让我们创建一个JSP文件index.jsp来收集用户名和密码,将针对数据库检查这些用户名和密码。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Login</title></head><body>   <form action="loginaction" method="post">      User:<br/><input type="text" name="user"/><br/>      Password:<br/><input type="password" name="password"/><br/>      <input type="submit" value="Login"/>		   </form></body></html>

创建视图:

现在先创建success.jsp文件,这在action返回SUCCESS结果的情况下会被调用,但如果从action返回ERROR结果,我们将用另一个视图文件。

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>Successful Login</title></head><body>   Hello World, <s:property value="name"/></body></html>

以下将是在action返回ERROR的情况下调用的视图文件error.jsp

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>Invalid User Name or Password</title></head><body>   Wrong user name or password provided.</body></html>

配置文件

最后,让我们使用struts.xml配置文件将所有内容放在一起,如下所示:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN""http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">         <action name="loginaction"          class="cn.51coolma.struts2.LoginAction"         method="execute">         <result name="success">/success.jsp</result>         <result name="error">/error.jsp</result>      </action>      </package></struts>

以下是web.xml文件的内容:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">      <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp,将显示以下界面:

Hello World的Struts

输入错误的用户名和密码,你看到以下页面:

错误

现在输入scott作为用户名,navy作为密码,可以应该看到以下页面:

成功

本章内容将教你如何使用Struts2 应用程序发送电子邮件。学习前,你需要从JavaMail API 1.4.4下载并安装mail.jar,并将mail.jar文件放在WEB-INFlib文件夹中,然后继续按照以下标准步骤创建action,视图和配置文件。

创建Action

首先是创建一个Action方法来处理电子邮件发送。让我们创建一个包含以下内容的名为Emailer.java的新类:

package cn.51coolma.struts2;import java.util.Properties;import javax.mail.Message;import javax.mail.PasswordAuthentication;import javax.mail.Session;import javax.mail.Transport;import javax.mail.internet.InternetAddress;import javax.mail.internet.MimeMessage;import com.opensymphony.xwork2.ActionSupport;public class Emailer extends ActionSupport {   private String from;   private String password;   private String to;   private String subject;   private String body;   static Properties properties = new Properties();   static   {      properties.put("mail.smtp.host", "smtp.gmail.com");      properties.put("mail.smtp.socketFactory.port", "465");      properties.put("mail.smtp.socketFactory.class",                     "javax.net.ssl.SSLSocketFactory");      properties.put("mail.smtp.auth", "true");      properties.put("mail.smtp.port", "465");   }   public String execute()    {      String ret = SUCCESS;      try      {         Session session = Session.getDefaultInstance(properties,              new javax.mail.Authenticator() {            protected PasswordAuthentication             getPasswordAuthentication() {            return new             PasswordAuthentication(from, password);            }});         Message message = new MimeMessage(session);         message.setFrom(new InternetAddress(from));         message.setRecipients(Message.RecipientType.TO,             InternetAddress.parse(to));         message.setSubject(subject);         message.setText(body);         Transport.send(message);      }      catch(Exception e)      {         ret = ERROR;         e.printStackTrace();      }      return ret;   }   public String getFrom() {      return from;   }   public void setFrom(String from) {      this.from = from;   }   public String getPassword() {      return password;   }   public void setPassword(String password) {      this.password = password;   }   public String getTo() {      return to;   }   public void setTo(String to) {      this.to = to;   }   public String getSubject() {      return subject;   }   public void setSubject(String subject) {      this.subject = subject;   }   public String getBody() {      return body;   }   public void setBody(String body) {      this.body = body;   }   public static Properties getProperties() {      return properties;   }   public static void setProperties(Properties properties) {      Emailer.properties = properties;   }}

如上面的源代码所示,Emailer.java具有与下面给出的email.jsp页面中的表单属性相对应的属,这些属性分别是:

  • from - 发件人的电子邮件地址。由于我们使用Google的SMTP,因此我们需要有效的gtalk ID。

  • password - 上述帐户的密码

  • to - 发送电子邮件给谁?

  • Subject - 电子邮件的主题

  • body - 实际的电子邮件内容

我们没有考虑对上述字段的任何验证,验证将在下一章添加。让我们看看execute()方法, execute()方法使用javax Mail库提供的参数发送电子邮件。如果邮件成功发送,action返回SUCCESS,否则返回ERROR。

创建主页

现行编写主页的JSP文件index.jsp,这将用于收集上面提到的电子邮件相关信息:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Email Form</title></head><body>   <em>The form below uses Google's SMTP server.    So you need to enter a gmail username and password   </em>   <form action="emailer" method="post">   <label for="from">From</label><br/>   <input type="text" name="from"/><br/>   <label for="password">Password</label><br/>   <input type="password" name="password"/><br/>   <label for="to">To</label><br/>   <input type="text" name="to"/><br/>   <label for="subject">Subject</label><br/>   <input type="text" name="subject"/><br/>   <label for="body">Body</label><br/>   <input type="text" name="body"/><br/>   <input type="submit" value="Send Email"/>   </form></body></html>

创建视图

现在创建success.jsp文件,这在action返回SUCCESS结果的情况下会被调用,但如果从action返回ERROR结果,我们将用另一个视图文件。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"	pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Email Success</title></head><body>   Your email to <s:property value="to"/> was sent successfully.</body></html>

以下将是在action返回ERROR的情况下调用的视图文件error.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"	pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Email Error</title></head><body>   There is a problem sending your email to <s:property value="to"/>.</body></html>

配置文件

最后,让我们使用struts.xml配置文件将所有内容放在一起,如下所示:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="emailer"          class="cn.51coolma.struts2.Emailer"         method="execute">         <result name="success">/success.jsp</result>         <result name="error">/error.jsp</result>      </action>   </package></struts>

以下是web.xml文件的内容:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">      <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp,将显示以下界面:

电子邮件用户输入

输入所需的信息,然后单击Send Email按钮。如果一切正常,那么你可以看到以下页面:

电子邮件成功

这章我们将研究Struts的验证框架。Struts的核心中的验证框架,可在执行action方法之前,帮助应用程序运行规则执行验证。
客户端验证通常使用Javascript实现,但是不能仅仅依赖于客户端验证。实践表明,应该在应用程序框架的所有级别引入验证。接下来让我们看一下给Struts项目添加验证的两种方法。
我们举一个Employee的例子,employee的名字和年龄将使用一个简单的页面捕获,我们会进行两次验证,以确保用户始终输入一个名称,并且年龄是在28和65之间。那么让我们先从示例的JSP主页面开始。

创建主页

我们接下来编写用于收集employee的相关信息的JSP文件index.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Employee Form</title></head><body>   <s:form action="empinfo" method="post">      <s:textfield name="name" label="Name" size="20" />      <s:textfield name="age" label="Age" size="20" />      <s:submit name="submit" label="Submit" align="center" />   </s:form></body></html>

index.jsp使用Struts标签,目前我们还没有学习到,不过会在标签相关的章节中学习它们。现在,假设s:textfield标签印出一个输入框,并且s:submit印出一个提交按钮。我们为每个标签使用了label属性,即为每个标签创建label。

创建视图

我们将使用在action返回SUCCESS的情况下调用的JSP文件success.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"	pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Success</title></head><body>   Employee Information is captured successfully.</body></html>

创建Action

那么,让我们定义一个小的action类:Employee,然后添加一个名为validate()的方法,如下Employee.java文件所示。确保action类扩展了ActionSupport类,否则将不会执行validate方法。

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class Employee extends ActionSupport{   private String name;   private int age;      public String execute()    {       return SUCCESS;   }   public String getName() {       return name;   }   public void setName(String name) {       this.name = name;   }   public int getAge() {       return age;   }   public void setAge(int age) {       this.age = age;   }   public void validate()   {      if (name == null || name.trim().equals(""))      {         addFieldError("name","The name is required");      }      if (age < 28 || age > 65)      {         addFieldError("age","Age must be in between 28 and 65");      }   }}

如上例所示,验证方法首先检查“Name”字段是否具有值。如果没有任何值,则会为“Name”字段添加一个字段“错误”,并显示自定义的错误消息。其次,检查“年龄”字段的输入值是否在28和65之间,如果不符合这个条件,我们在验证字段之上添加一个错误。

配置文件

最后,让我们使用struts.xml配置文件将所有内容放在一起,如下所示:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="empinfo"          class="cn.51coolma.struts2.Employee"         method="execute">         <result name="input">/index.jsp</result>         <result name="success">/success.jsp</result>      </action>   </package></struts>

以下是web.xml文件的内容:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"   xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">   <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp,将显示以下界面:

电子邮件用户输入

现在不输入任何信息,只点击Submit按钮,将看到以下结果:

错误

输入所要求的信息而非错误类的字段,如名称为“text”,年龄为30,然后点击Submit按钮,可以看到以下界面:

成功

这个验证是如何进行的?

当用户按下提交按钮时,Struts2 将自动执行validate方法,如果方法中列出的任何if语句为真,Struts2 将调用addFieldError方法。如果添加了任何错误信息,Struts2 将不会调用execute方法。否则,Struts2 框架将返回input作为调用操作的结果。
因此,当验证失败并且Struts2 返回input时,Struts2 框架将重新显示index.jsp文件。由于我们使用Struts2 的form标签,Struts2 会自动在form字段上方添加错误信息。
这些错误信息是我们在addFieldError方法调用中指定的信息。addFieldError方法接受两个参数,第一个是出错时应用的form字段名称,第二个是在form字段上方显示的错误信息。

addFieldError("name","The name is required");

要处理input的返回值,我们需要将以下结果添加到struts.xml中的action节点。

<result name="input">/index.jsp</result>

XML验证

第二种进行验证的方法是在action类旁边放置一个xml文件。Struts2 基于XML的验证提供了更多的验证方式,如email验证、integer range验证、form验证、expression验证、regex验证、required验证、requiredstring验证、stringlength验证等。
xml文件需要命名为'[action-class]'-validation.xml。因此,在我们的示例中,创建了一个名为Employee-validation.xml的文件,其含以下内容:

<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN""http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"><validators>   <field name="name">      <field-validator type="required">         <message>            The name is required.         </message>      </field-validator>   </field>   <field name="age">     <field-validator type="int">         <param name="min">29</param>         <param name="max">64</param>         <message>            Age must be in between 28 and 65         </message>      </field-validator>   </field></validators>

上面的XML文件将保存在CLASSPATH中,理想情况下是与类文件一起保存。以下是没有validate()方法的Employee action类:

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class Employee extends ActionSupport{   private String name;   private int age;      public String execute()    {       return SUCCESS;   }   public String getName() {       return name;   }   public void setName(String name) {       this.name = name;   }   public int getAge() {       return age;   }   public void setAge(int age) {       this.age = age;   }}

其余的设置将保持,如同前面的例子一样。现在如果你运行应用程序,它将产生与我们前面例子相同的结果。

使用xml文件来存储配置的优点是允许验证与应用程序代码分离。你可以让开发人员编写代码,让测试人员来创建xml验证文件。另一个需要注意的是默认情况下可用的验证器。Struts有许多默认的验证器,常见的包括:Date验证器,Regex验证器和String Length验证器。点击以下链接可以了解更多“Struts2-XML验证器”的详细信息。

国际化(i18n)是规划和实施产品和服务以便更好地适应特定的当地语言和文化的过程,也就是本地化过程,而国际化过程有时也被称为翻译或本地化实现。国际化缩写为i18n,单词以i开头,以n结尾,是因为在第一个i和最后一个n之间有18个字符。
Struts2使用bundle资源束、拦截器和标签库提供本地化,即国际化(i18n)支持,主要用在以下几个地方:

  • UI标签

  • 信息和错误。

  • Action类。

资源束

Struts2使用资源束为Web应用程序的用户提供多种语言和区域的设置选项。你不必担心需要用不同的语言编写页面,你需要做的只是为每种你想要的语言创建一个资源束。资源束将包含用户语言中的标题,消息和其他文本,是包含应用程序默认语言的一对key/value的文件。
资源文件最简单的命名格式是:

bundlename_language_country.properties

这里的bundlename可以是ActionClass,Interface,SuperClass,Model,Package,Global资源属性。下一部分language_country表示国家区域设置,例如西班牙语(西班牙)区域设置由es_ES表示,英语(美国)区域设置由en_US表示等。这里先跳过可选国家的部分。
当你通过key引用消息元素时,Struts框架按以下顺序搜索相应的信息束:

  • ActionClass.properties

  • Interface.properties

  • SuperClass.properties

  • model.properties

  • package.properties

  • struts.properties

  • global.properties

要以多种语言开发应用程序,你必须维护与这些语言/区域设置对应的多个属性文件,并根据每对key/value定义所有内容。例如,如果你要开发美国英语(默认),西班牙语和法语的应用程序,必须创建三个属性文件。这里我们将使用global.properties文件,你也可以使用不同的属性文件来分离不同类型的信息。

  • global.properties:默认情况下使用英语(美国)

  • global_fr.properties:这将用于法语环境。

  • global_es.properties:这将用于西班牙语环境。

访问信息

有几种方法来访问信息资源,包括getText,text标签,UI标签的key属性和i18n标签。接下来让我们简要了解一下:

显示i18n文本,需在property标签或其他任何标签(如UI标签)中调用getText,如下所示:

<s:property value="getText('some.key')" />

text标签从默认资源束(即struts.properties)中检索信息:

<s:text name="some.key" />

i18n标签会将任意资源束推送到值栈,而i18n标签内的其他标签可以显示来自该资源束的信息:

<s:i18n name="some.package.bundle">     <s:text name="some.key" /></s:i18n>

大多数UI标签的key属性可用于从资源束检索信息:

<s:textfield key="some.key" name="textfieldName"/>

本地化示例

现在,让我们用多种语言创建前一章中的index.jsp文件,如下所示:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Employee Form with Multilingual Support</title></head><body>   <h1><s:text name="global.heading"/></h1>   <s:url id="indexEN" namespace="/" action="locale" >      <s:param name="request_locale" >en</s:param>   </s:url>   <s:url id="indexES" namespace="/" action="locale" >      <s:param name="request_locale" >es</s:param>   </s:url>   <s:url id="indexFR" namespace="/" action="locale" >      <s:param name="request_locale" >fr</s:param>   </s:url>   <s:a href="%{indexEN}" >English</s:a>   <s:a href="%{indexES}" >Spanish</s:a>   <s:a href="%{indexFR}" >France</s:a>   <s:form action="empinfo" method="post" namespace="/">      <s:textfield name="name" key="global.name" size="20" />      <s:textfield name="age" key="global.age" size="20" />      <s:submit name="submit" key="global.submit" />   </s:form></body></html>

现在创建success.jsp文件,这个文件在action返回SUCCESS结果的情况下会被调用。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"	pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Success</title></head><body>   <s:property value="getText('global.success')" /></body></html>

这里我们需要创建以下两个action。(a)第一个action处理区域设置并显示使用不同语言的同一个index.jsp文件;(b)另一个action是负责提交表单本身。这两个action都将返回SUCCESS,但我们将根据返回值采取不同的action,因为这两个action的目的是不同的:

区域设置Action

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class Locale extends ActionSupport{   public String execute()    {       return SUCCESS;   }}

提交表单Action

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class Employee extends ActionSupport{   private String name;   private int age;      public String execute()    {       return SUCCESS;   }      public String getName() {       return name;   }   public void setName(String name) {       this.name = name;   }   public int getAge() {       return age;   }   public void setAge(int age) {       this.age = age;   }}

现在,让我们创建以下三个global.properties文件并放入CLASSPATH:

global.properties

global.name = Nameglobal.age = Ageglobal.submit = Submitglobal.heading = Select Localeglobal.success = Successfully authenticated

global_fr.properties

global.name = Nom d'utilisateur global.age = l'âgeglobal.submit = Soumettre desglobal.heading = Sé lectionnez Localglobal.success = Authentifi	é  avec succès

global_es.properties

global.name = Nombre de usuarioglobal.age = Edadglobal.submit = Presentarglobal.heading = seleccionar la configuracion regionalglobal.success = Autenticado correctamente

我们接着创建包含两个action的struts.xml文件,如下所示:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <constant name="struts.custom.i18n.resources" value="global" />   <package name="helloworld" extends="struts-default" namespace="/">      <action name="empinfo"          class="cn.51coolma.struts2.Employee"         method="execute">         <result name="input">/index.jsp</result>         <result name="success">/success.jsp</result>      </action>            <action name="locale"          class="cn.51coolma.struts2.Locale"         method="execute">         <result name="success">/index.jsp</result>      </action>   </package></struts>

以下是web.xml文件的内容:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"   xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">   <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp,将显示以下界面:

英语输出

现在可选择任意语言,如果选择西班牙语,会显示以下结果:

西班牙输出

你也可以尝试用法语。最后,点击Submit按钮,当在西班牙语环境时,会显示以下界面:

成功

恭喜,你现在有了多语言的网页,可以在尝试在全球推送你的网站。

HTTP请求上的所有内容都按协议处理为字符串,包括数字,布尔值,整数,日期,小数和其他。对HTTP来说,每个事件都是一个字符串。但是,在Struts类中,你可以具有任意数据类型的属性。我们如何让Struts自动匹配属性呢?
Struts使用各种类型的转换器在幕后做了许多繁重的工作。例如,如果你的Action类中有一个integer属性,你不需要执行任何操作,Struts会自动将请求参数转换为integer属性。默认情况下,Struts提供了多个类型的转换器。其中一些列出如下,如果你使用其中一个,那你就不用担心什么了:

  • Integer,Float,Double,Decimal

  • Date,Datetime

  • Arrays,Collections

  • Enumerations

  • Boolean

  • BigDecimal

有时,当你使用自己的数据类型时,有必要添加自己的转换器,以使Struts知道如何在显示之前转换这些值。可以考虑使用下面的POJO类Environment.java

package cn.51coolma.struts2;public class Environment {   private String name;   public  Environment(String name)   {      this.name = name;   }   public String getName() {      return name;   }   public void setName(String name) {      this.name = name;   }}

这是一个非常简单的类,它有一个name属性,除此之外没有什么特别的。让我们接下来创建另一个包含系统信息的类:SystemDetails.java。 出于练习的目的,我们是将环境硬编码为“开发”,操作系统为“Windows XP SP3”。而在实际项目中,你会从系统配置中获取这些信息。那么让我们先创建以下action类:

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class SystemDetails extends ActionSupport {   private Environment environment = new Environment("Development");   private String operatingSystem = "Windows XP SP3";   public String execute()   {      return SUCCESS;   }   public Environment getEnvironment() {      return environment;   }   public void setEnvironment(Environment environment) {      this.environment = environment;   }   public String getOperatingSystem() {      return operatingSystem;   }   public void setOperatingSystem(String operatingSystem) {      this.operatingSystem = operatingSystem;   }}

接着让我们创建一个简单的JSP文件System.jsp来显示环境和操作系统信息。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>System Details</title></head><body>   Environment: <s:property value="environment"/><br/>   Operating System:<s:property value="operatingSystem"/></body></html>

让我们使用struts.xml连接system.jspSystemDetails.java类。 SystemDetails类有一个简单的可返回字符串“SUCCESS”的execute()方法。

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"    "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="system"             class="com.tutorialspoint.struts2.SystemDetails"             method="execute">         <result name="success">/System.jsp</result>      </action>   </package></struts>

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/system.action,将显示以下界面:

系统信息

上面的输出有什么问题? Struts知道如何显示和转换“Windows XP SP3”字符串和其他内置数据类型,但它不知道如何处理Environment类型的属性。所以,它只是简单地在类上调用了toString()方法。为了解决这个问题,让我们现在为Environment类创建和注册一个简单的TypeConverter。创建一个名为EnvironmentConverter.java的类,包含有以下内容:

package cn.51coolma.struts2;import java.util.Map;import org.apache.struts2.util.StrutsTypeConverter;   public class EnvironmentConverter extends StrutsTypeConverter {      @Override      public Object convertFromString(Map context, String[] values,                                       Class clazz) {      Environment env = new Environment(values[0]);      return env;   }   @Override   public String convertToString(Map context, Object value) {      Environment env  = (Environment) value;      return env == null ? null : env.getName();   }	}

EnvironmentConverter扩展了StrutsTypeConverter类,并告诉Struts如何通过覆盖convertFromString()convertToString()两个方法将Environment转换为String,反之亦然。 现在,让我们在使用前先在应用程序中注册这个转换器,有两种方式注册转换器。如果转换器将只在特定的操作中使用,那么你必须创建一个命名为'[action-class]'-conversion.properties的属性文件,所以,在我们的例子中,创建了一个包含以下注册表的名为SystemDetails-converstion.properties文件:

environment=cn.51coolma.struts2.EnvironmentConverter

在上面的例子中,“environment”是SystemDetails.java类中属性的名称,用以告诉Struts使用EnvironmentConverter来转换这个属性。但是,我们的做法将会相反,我们会全局注册这个转换器,以便它可以在整个应用程序中使用。因此,需要在WEB-INF/classes文件夹中创建一个名为xwork-conversion.properties的属性文件,使用以下内容:

cn.51coolma.struts2.Environment =             cn.51coolma.struts2.EnvironmentConverter

这简单地将转换器进行了全局注册,使得Struts可以在每次遇到类型为Environment的对象时自动执行转换。现在,如果你重新编译并重新运行程序,你会得到一个更好的输出结果,如下所示:

系统信息

显然,现在的结果是更好的,这意味着我们的Struts转换器工作正常。这就是如何根据你的要求创建多个转换器和注册使用它们。

开始本章的内容学习之前,让我们看看http://struts.apache.org给出的几个定义:

术语描述
tag(标签)从JSP,FreeMarker或Velocity内部执行的一小段代码。
template(模板)一些代码,通常是写在FreeMarker上的,可以由某些标签(HTML标签)呈现。
theme(主题)封装在一起以提供公共功能的模板集合。

我们建议再回顾一下Struts2本地化/国际化(i18n)章节,因为我们将再次使用同样的例子来进行练习。

当你在Web页面中使用Struts2 标签(如<s:submit...>,<s:textfield...>等)时,Struts2 框架会生成具有预配置样式和布局的HTML代码。Struts2 具有三个内置主题:

Theme(主题)描述
simple theme没有“bells and whistles”的最小主题。例如,textfield标签呈现HTML<input/>标签无标记、验证、错误报告或任何其他格式或功能。
xhtml theme这是Struts 2使用的默认主题,提供了simple theme具备的所有基础,并添加了几个功能,如HTML的标准两列表布局、每个HTML的标记、验证和错误报告等。
css_xhtml theme这个主题提供了simple theme具备的所有基础,并添加了几个功能,如基于CSS的标准两列布局,对HTML Struts标签使用<div>,HTML Struts每个标签的标记,根据CSS样式表放置等。

如上所述,如果你不指定一个主题,那么Struts2 将默认使用xhtml theme。例如这个Struts2选择标签:

<s:textfield name="name" label="Name" />

生成以下HTML标记:

<tr><td class="tdLabel">   <label for="empinfo_name" class="label">Name:</label></td><td>   <input type="text" name="name" value="" id="empinfo_name"/></td></tr>

这里empinfo是在struts.xml文件中定义的action名称。

选择主题

你可以在每个Struts2 标签的基础上指定主题,也可以使用以下方法之一指定Struts2 应使用的主题:

  • 特定标签上的theme属性

  • 标签的周边表单标签的theme属性

  • 名为“theme”的页面作用域属性

  • 名为“theme”的请求作用域属性

  • 名为“theme”的会话作用域属性

  • 名为“theme”的应用程序作用域属性

  • struts.properties中的struts.ui.theme属性(默认为xhtml)

以下是在标签级别指定它们的语法,如果你愿意为不同的标签使用不同的主题:

<s:textfield name="name" label="Name" theme="xhtml"/>

因为在每个标签的基础上使用主题并不是很实用,所以只需使用以下标签就可以在struts.properties文件中指定规则:

# Standard UI themestruts.ui.theme=xhtml# Directory where theme template residesstruts.ui.templateDir=template# Sets the default template type. Either ftl, vm, or jspstruts.ui.templateSuffix=ftl

下面是我们从本地化章节中选择的结果,我们在struts-default.properties文件中使用了默认主题,设置为struts.ui.theme=xhtml,该文件默认情况下位于struts2-core.xy.z.jar文件中。

输出

主题是如何工作的?

对于给定的主题,每个struts标签都有一个关联的模板,如s:textfield -> text.ftls:password -> password.ftl等。这些模板文件压缩在struts2-core.xy.z.jar文件中,它们为每个标签保留预定义的HTML布局。因此Struts2 框架使用Sturts标签和相关模板生成最终的HTML标记代码。

Struts 2 tags + Associated template file = Final HTML markup code.

默认模板已经写在FreeMarker中,它们有扩展名.ftl。你可以使用velocity或JSP设计你的模板,使用struts.ui.templateSuffixstruts.ui.templateDir在struts.properties中设置配置。

创建新主题

创建新主题的最简单方法是复制任何现有的theme/template文件,并进行必要的修改。那么,让我们在WebContent/WEB-INF/classes中创建一个名为template的文件夹,以及一个以新主题名称命名的子文件夹,例如WebContent/WEB-INF/classes/template/mytheme。从这里,你可以从头开始构建模板,或者你可以从Struts2 现有版本中复制模板,并根据需要修改它们。
出于学习的目的,我们将修改现有的默认模板xhtml。那么现在先将内容从struts2-core-x.y.z.jar/template/xhtml复制到我们的主题目录,并只修改WebContent/WEB-INF/classes/template/mytheme/control.ftl文件。当我们打开control.ftl时它会显示以下几行:

<table class="${parameters.cssClass?default('wwFormTable')?html}"<#rt/><#if parameters.cssStyle??> style="${parameters.cssStyle?html}"<#rt/></#if>>

让我们将以下内容修改到上面的control.ftl文件中:

<table style="border:1px solid black;">

如果你查看form.ftl,你会发现它正在使用这个control.ftl文件,但form.ftl是从xhtml主题中引用这个文件。那么让我们把它做如下修改:

<#include "/${parameters.templateDir}/xhtml/form-validate.ftl" /><#include "/${parameters.templateDir}/simple/form-common.ftl" /><#if (parameters.validate?default(false))>  onreset="${parameters.onreset?default('clearErrorMessages(this);  clearErrorLabels(this);')}"<#else>  <#if parameters.onreset??>  onreset="${parameters.onreset?html}"  </#if></#if>><#include "/${parameters.templateDir}/mytheme/control.ftl" />

我们假设你不太了解FreeMarker模板语言,不过你仍可以通过查看.ftl文件得到一个很好的想法。 不管怎样,让我们先保存以上更改,并返回到我们的本地化示例,创建具有以下内容的WebContent/WEB-INF/classes/struts.properties文件:

# Customized themstruts.ui.theme=mytheme# Directory where theme template residesstruts.ui.templateDir=template# Sets the template type to ftl.struts.ui.templateSuffix=ftl

现在在此更改后,右键单击项目名称,然后单击“Export”>“ WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2。将显示以下界面:

主题和模板

你可以看到窗体组件周围的边框,这是我们从xhtml主题复制之后在out主题中所做更改的结果。如果你稍微学习一下FreeMarker,那么就能够非常容易地创建或修改你的主题。至少现在,你一定对Sturts2 主题和模板有了基本的了解,是吗?

Struts提供了一种更简单的方法来处理未捕获的异常,并将用户重定向到专门的错误页面。你可以很轻松地配置Struts为不同的异常显示不同的错误页面。
Struts通过使用“exception”拦截器来使异常处理变得简单。“exception”拦截器被作为默认堆栈的一部分包含其中,所以你不必对它做任何额外的配置。它提供开箱即用的功能可供使用。让我们看一个简单的Hello World示例,在HelloWorldAction.java文件中进行一些修改。在这里我们有意的给HelloWorldAction操作代码中引入一个NullPointer异常。

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class HelloWorldAction extends ActionSupport{   private String name;   public String execute(){      String x = null;      x = x.substring(0);      return SUCCESS;   }      public String getName() {      return name;   }   public void setName(String name) {      this.name = name;   }}

让我们保持HelloWorld.jsp的内容如下:

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>Hello World</title></head><body>   Hello World, <s:property value="name"/></body></html>

以下是index.jsp的内容:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%>   <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Hello World</title></head><body>   <h1>Hello World From Struts2</h1>   <form action="hello">      <label for="name">Please enter your name</label><br/>      <input type="text" name="name"/>      <input type="submit" value="Say Hello"/>   </form></body></html>

你的struts.xml应该如下:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts><constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">           <action name="hello"          class="cn.51coolma.struts2.HelloWorldAction"          method="execute">         <result name="success">/HelloWorld.jsp</result>      </action>   </package></struts>

现在右键单击项目名称,然后单击“Export”>“WAR File”创建WAR文件。然后在Tomcat的webapps目录中部署这个WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp。将显示如下页面:

Hello World输入

输入值“Struts2”并提交页面。你应该看到以下页面:

输出异常

如上面的例子所示,默认exception拦截器处理异常的工作非常好。现在让我们为异常创建一个专门的错误页面,一个名为Error.jsp的文件,包含以下内容:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"	pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title></title></head><body>   This is my custom error page</body></html>

现在,让我们配置Struts在异常情况下使用此错误页面,修改struts.xml如下:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts><constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">         <action name="hello"          class="cn.51coolma.struts2.HelloWorldAction"          method="execute">         <exception-mapping exception="java.lang.NullPointerException"         result="error" />         <result name="success">/HelloWorld.jsp</result>         <result name="error">/Error.jsp</result>      </action>   </package></struts>

如上面的例子所示,现在我们已经配置Struts为NullPointerException使用专门的Error.jsp。如果现在重新运行程序,将看到以下输出页面:

Hello World输出

除此之外,Struts2框架还带有一个“logging”拦截器来记录异常。通过启用记录器记录未捕获的异常,我们可以轻松地查看堆栈跟踪记录,并找出哪里出错了。

全局异常映射

我们已经看到了如何处理特定于action的异常。现在,我们可以设置一个全局异常,这将应用于所有的action。例如,为了捕获相同的NullPointerException异常,我们可以在<package...>标签中添加<global-exception-mappings...>标签,并在struts.xml文件的<action...>标签中添加<result...>标签,如下:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts><constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <global-exception-mappings>         <exception-mapping exception="java.lang.NullPointerException"         result="error" />      </global-exception-mappings>      <action name="hello"          class="cn.51coolma.struts2.HelloWorldAction"          method="execute">         <result name="success">/HelloWorld.jsp</result>         <result name="error">/Error.jsp</result>      </action>   </package></struts>


如前章节中所讲到的,Struts提供了两种形式的配置。传统的方式是对所有配置使用struts.xml文件。到目前为止,我们在教程里已经看到了好些这样的例子。配置Struts的另一种方法是使用Java5 的注释功能。使用struts注释,我们可以实现零配置。
要在项目中开始使用注释,请确保WebContent/WEB-INF/lib文件夹中包含以下jar文件:

  • struts2-convention-plugin-x.y.z.jar

  • asm-x.y.jar

  • antlr-x.y.z.jar

  • commons-fileupload-x.y.z.jar

  • commons-io-x.y.z.jar

  • commons-lang-x.y.jar

  • commons-logging-x.y.z.jar

  • commons-logging-api-x.y.jar

  • freemarker-x.y.z.jar

  • javassist-.xy.z.GA

  • ognl-x.y.z.jar

  • struts2-core-x.y.z.jar

  • xwork-core.x.y.z.jar

现在让我们看看如何可以取消struts.xml文件中可用的配置,并将其替换为注释。
为了解释Struts2 中注释的概念,我们必须重新使用在Struts2 验证框架章节中所学习的验证示例。
这里我们将举一个Employee的例子,employee的名字和年龄使用一个简单的页面捕获,我们将进行两次验证,以确保用户始终输入一个名字,并且年龄应在28和65之间。那么,让我们从示例的JSP主页面开始。

创建主页

首先,先开始写用来收集上面提到的Employee相关信息的主页JSP文件index.jsp。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Employee Form</title></head><body>   <s:form action="empinfo" method="post">      <s:textfield name="name" label="Name" size="20" />      <s:textfield name="age" label="Age" size="20" />      <s:submit name="submit" label="Submit" align="center" />   </s:form></body></html>

index.jsp使用的Struts标签我们还没有涉及到,不过将在标签相关章节中学习它们。现在,假设s:textfield标签印出一个输入字段,并且s:submit印出一个提交按钮。我们为每个标签使用了label属性,即为每个标签创建标记。

创建视图

我们将使用JSP文件的success.jsp,在定义的action返回SUCCESS的情况下调用它。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"	pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Success</title></head><body>   Employee Information is captured successfully.</body></html>

创建Action

Action是使用注释的地方。让我们重新定义具有注释的action类Employee,然后如下所示在Employee.java文件中添加一个名为validate()的方法。需要确保action类扩展了ActionSupport类,否则将不会执行validate方法。

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;import org.apache.struts2.convention.annotation.Action;import org.apache.struts2.convention.annotation.Result;import org.apache.struts2.convention.annotation.Results;import com.opensymphony.xwork2.validator.annotations.*;@Results({   @Result(name="success", location="/success.jsp"),   @Result(name="input", location="/index.jsp")})public class Employee extends ActionSupport{   private String name;   private int age;   @Action(value="/empinfo")   public String execute()    {       return SUCCESS;   }   @RequiredFieldValidator( message = "The name is required" )   public String getName() {       return name;   }   public void setName(String name) {       this.name = name;   }   @IntRangeFieldValidator(message = "Age must be in between 28 and 65",                                      min = "29", max = "65")   public int getAge() {       return age;   }   public void setAge(int age) {       this.age = age;   }}

我们在这个例子中使用了一些注释,让我们逐个了解一下:

  • 首先是例子中包含的Results注释,Results注释是结果的集合。在这个注释集合下,有两个结果注释。它们包含对应于execute方法结果的名称,还包含对应于execute()的返回值所提的视图位置。

  • 下一个注释是Action注释,这可用于装饰execute()方法。Action方法还接收一个值,该值是调用action的URL。

  • 最后,我们使用了两个validation注释。我们已经配置了必填字段验证器上的name字段和整数范围验证器上的age字段,此外还为验证指定了自定义的信息。

配置文件

实际上我们真的不需要struts.xml配置文件,可以删除这个文件,直接来查看web.xml文件的内容:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"   xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">   <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>      <init-param>         <param-name>struts.devMode</param-name>         <param-value>true</param-value>      </init-param>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp,将显示以下界面:

电子邮件用户输入

先不要输入任何所需的信息,只点击“Submit”按钮。你将看到以下结果:

错误

输入所要求的信息而非错误类的字段,如名称为“text”,年龄为30,然后点击Submit按钮,可以看到以下界面:

成功

Struts2 注释类型

Struts2 应用程序可以使用Java5注释来替代XML和Java属性的配置。你可以查看与不同类别相关的最重要注释的列表:Struts2 注释类型

Struts2 标签有一组标签,可以方便地控制页面执行的流程。以下是主要的Struts2 控制标签:

if和else标签

这些标签执行在每种语言中找到的基本条件流。“If”标签可以单独使用,也可以与“Else If”标签,和单个或是多个“Else”标签一起使用,如下所示:

<s:if test="%{false}">    <div>Will Not Be Executed</div></s:if><s:elseif test="%{true}">    <div>Will Be Executed</div></s:elseif><s:else>    <div>Will Not Be Executed</div></s:else>

查看详细示例

iterator标签

这些iterator将迭代一个值。可迭代值可以是以下任一值:java.util.Collection,java.util.Iterator。在迭代一个iterator时,可以使用Sort标签对结果进行排序,或者使用SubSet标签来获取列表或数组的子集。
以下示例是检索值栈上当前对象的getDays()方法的值,并使用它迭代。<s:property/>标签印出迭代器的当前值。

<s:iterator value="days">  <p>day is: <s:property/></p></s:iterator>

查看详细示例

merge标签

这些merge标签采用两个或多个列表作为参数,并将它们合并在一起,如下所示:

<s:merge var="myMergedIterator">     <s:param value="%{myList1}" />     <s:param value="%{myList2}" />     <s:param value="%{myList3}" /></s:merge><s:iterator value="%{#myMergedIterator}">     <s:property /></s:iterator>

查看详细示例

append标签

这些append标签采用两个或多个列表作为参数,并将它们全部附加在一起,如下所示:

<s:append var="myAppendIterator">     <s:param value="%{myList1}" />     <s:param value="%{myList2}" />     <s:param value="%{myList3}" /></s:append><s:iterator value="%{#myAppendIterator}">     <s:property /></s:iterator>

查看详细示例

generator标签

这些generator标签基于提供的val属性生成迭代器。下面的generator标签生成一个迭代器并使用iterator标签打印出来。

<s:generator val="%{'aaa,bbb,ccc,ddd,eee'}"> <s:iterator>     <s:property /><br/> </s:iterator></s:generator>

查看详细示例


Struts2 的数据标签主要用于操作页面上显示的数据。下面列出了主要的数据标签:

action标签

此标签允许开发人员通过指定action名称和可选的命名空间直接从JSP页面调用action。标签的正文内容用于呈现action的结果。在struts.xml中为此action定义的任何结果处理程序将会被忽略,除非指定executeResult参数。

<div>Tag to execute the action</div><br /><s:action name="actionTagAction" executeResult="true" /><br /><div>To invokes special method  in action class</div><br /><s:action name="actionTagAction!specialMethod" executeResult="true" />

查看详细示例

include标签

这些include标签将用于在另一个JSP页面中包含一个JSP文件。

<-- First Syntax --><s:include value="myJsp.jsp" /><-- Second Syntax --><s:include value="myJsp.jsp">   <s:param name="param1" value="value2" />   <s:param name="param2" value="value2" /></s:include><-- Third Syntax --><s:include value="myJsp.jsp">   <s:param name="param1">value1</s:param>   <s:param name="param2">value2</s:param></s:include>

查看详细示例

bean标签

这些bean标签实例化一个符合JavaBeans规范的类。这个标签有一个主体,可以包含一些Param元素来设置任何mutator方法。如果在BeanTag上设置了var属性,它将把实例化的bean放入值栈的Context中。

<s:bean name="org.apache.struts2.util.Counter" var="counter">   <s:param name="first" value="20"/>   <s:param name="last" value="25" /></s:bean>

查看详细示例

date标签

data标签允许以快速简单的方式格式化日期。用户可以指定自定义日期格式(例如“dd/MM/yyyy hh:mm”),可以生成易读的符号(例如“在2小时14分钟内”),或者可以使用属性文件中的key:“struts.date.format”来回退到预定义的格式。

<s:date name="person.birthday" format="dd/MM/yyyy" /><s:date name="person.birthday" format="%{getText('some.i18n.key')}" /><s:date name="person.birthday" nice="true" /><s:date name="person.birthday" />

查看详细示例

param标签

这些param标签可用于参数化其他标签。此标签具有以下两个参数。

  • name(字符串) - 参数的名称

  • value(对象) - 参数的值

<pre><ui:component> <ui:param name="key"     value="[0]"/> <ui:param name="value"   value="[1]"/> <ui:param name="context" value="[2]"/></ui:component></pre>

查看详细示例

property标签

这些property标签用于获取一个值的属性,如果没有指定,它将默认为在值栈的顶部。

<s:push value="myBean">    <!-- Example 1: -->    <s:property value="myBeanProperty" />    <!-- Example 2: -->TextUtils    <s:property value="myBeanProperty" default="a default value" /></s:push>

查看详细示例

push标签:

这些push标签用于推送堆栈中的值,以简化使用。

<s:push value="user">    <s:propery value="firstName" />    <s:propery value="lastName" /></s:push>

查看详细示例

set标签

这些set标签为指定范围内的变量赋值。当你希望将变量分配给复杂表达式,然后仅仅引用该变量而不是复杂表达式时,它是很有用的。可应用的范围是应用程序,会话,请求,页面和action。

<s:set name="myenv" value="environment.name"/><s:property value="myenv"/>

查看详细示例

text标签

这些text标签用于呈现I18n文本消息。

<!-- First Example --><s:i18n name="struts.action.test.i18n.Shop">    <s:text name="main.title"/></s:i18n><!-- Second Example --><s:text name="main.title" /><!-- Third Examlpe --><s:text name="i18n.label.greetings">   <s:param >Mr Smith</s:param></s:text>

查看详细示例

url标签

这些url标签用于创建URL。

<-- Example 1 --><s:url value="editGadget.action">    <s:param name="id" value="%{selected}" /></s:url><-- Example 2 --><s:url action="editGadget">    <s:param name="id" value="%{selected}" /></s:url><-- Example 3--><s:url includeParams="get">    <s:param name="id" value="%{'22'}" /></s:url>

查看详细示例


表单标签列表是Struts UI标签的子集。这些标签有助于渲染Struts Web应用程序所需的用户界面,主要分为三类,本章将介绍这三种类型的UI标签:

简单UI标签

我们其实已经在前面的示例中使用了这些标签,接下来将在本章中重新回顾一下。以下是一个简单的视图页面email.jsp与几个简单的UI标签:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"	pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><s:head/><title>Hello World</title></head><body>   <s:div>Email Form</s:div>   <s:text name="Please fill in the form below:" />   <s:form action="hello" method="post" enctype="multipart/form-data">   <s:hidden name="secret" value="abracadabra"/>   <s:textfield key="email.from" name="from" />   <s:password key="email.password" name="password" />   <s:textfield key="email.to" name="to" />   <s:textfield key="email.subject" name="subject" />   <s:textarea key="email.body" name="email.body" />   <s:label for="attachment" value="Attachment"/>   <s:file name="attachment" accept="text/html,text/plain" />   <s:token />   <s:submit key="submit" />   </s:form></body></html>

如果你了解HTML,那么就知道所有使用的标签都是非常常见的HTML标签,每个标签带有一个额外的前缀“s:”以及不同的属性。当我们执行上面的程序时,将得出以下用户界面,只要你已经为所有的key设置了正确的映射。

Struts的简单的UI标签

如图所示,s:head生成Struts2 应用程序所需的javascript和stylesheet元素。
接下来,s:div和s:text元素。s:div用于呈现HTML Div元素。这对于不喜欢将HTML和Struts标签混合在一起的人很有用,他们可选择使用s:div来渲染div。
如图所示,s:text用于在屏幕上呈现文本。
接下来是相类似的s:form标签。s:form标签具有确定在何处提交表单的action属性。因为在表单中有一个文件上传元素,我们必须将enctype设置为multipart。否则,就留空。
在表单标签的末尾,有s:submit标签,这用于提交表单。提交表单时,所有表单值都将提交到s:form标签中指定的action。
在s:form标签中,我们有一个称为secret的隐藏属性,这将在HTML中呈现一个隐藏元素。在我们的例子中,“secret”元素的值为“abracadabra”。此元素对最终用户不可见,并用于将状态从一个视图传递到另一个视图。
接下来是s:label,s:textfield,s:password和s:textarea标签。这些分别用于渲染标签,输入字段,密码和文本区域。我们已经在“Struts2 发送电子邮件”章节示例中看到了这些。这里要注意的重要事情是使用“key”属性。“key”属性用于从属性文件中提取这些控件的标签。我们已经在Struts2本地化/国际化(i18n)一章中讨论了这个特性。
然后是s:file标签,它呈现输入文件上传的组件,此组件允许用户上传文件。在这个例子中,我们使用了s:file标签的“accept”参数来指定允许上传哪些文件类型。
最后,s:token标签。token标签生成唯一的token,用于查明表单是否已被两次提交。
呈现表单时,会将一个隐藏变量放置为token(令牌)值。例如令牌是“ABC”,提交此表单时,Struts Fitler将根据存储在会话中的令牌进行检查。如果匹配,则从会话中删除令牌。现在,如果表单意外被重新提交(通过刷新或通过点击浏览器后退按钮),表单将重新提交,用“ABC”作为令牌。在这种情况下,过滤器将对照存储在会话中的令牌再次进行检查。但是因为令牌“ABC”已经从会话中删除,它将不匹配,Struts过滤器将拒绝请求。

群组UI标签

群组UI标签用于创建单选按钮和复选框。让我们看一个简单的带有复选框和单选按钮标签的视图页面HelloWorld.jsp

<%@ page contentType="text/html; charset=UTF-8"%><%@ taglib prefix="s" uri="/struts-tags"%><html><head><title>Hello World</title><s:head /></head><body>   <s:form action="hello.action">   <s:radio label="Gender" name="gender" list="{'male','female'}" />   <s:checkboxlist label="Hobbies" name="hobbies"   list="{'sports','tv','shopping'}" />   </s:form></body></html>

当我们执行上面的程序时,我们的输出将类似于以下内容:

Struts群组UI标签

现在让我们看看这些例子。在第一个例子中,我们创建一个简单的radiobutton,标签为“Gender”。name属性对于radiobutton标签是必需的,那么我们指定一个名为“gender”的name。然后我们提供一个性别列表,该列表用值“male”和“female”填充。因此,在输出中我们得到一个带有两个值的radiobutton。
在第二个例子中,我们创建一个复选框列表。这是为了收集用户的爱好。用户可以有多个爱好,因此我们使用复选框而不是单选按钮。复选框用“sports”,“Tv”和“Shopping”填充列表,将这些爱好作为复选框列表。

选择UI标签

让我们来探讨Struts提供的Select标签的不同变化。让我们看一个简单的带select标签的视图页面HelloWorld.jsp

<%@ page contentType="text/html; charset=UTF-8"%><%@ taglib prefix="s" uri="/struts-tags"%><html><head><title>Hello World</title><s:head /></head><body>   <s:form action="login.action">      <s:select name="username" label="Username"         list="{'Mike','John','Smith'}" />      <s:select label="Company Office" name="mySelection"         value="%{'America'}"         list="%{#{'America':'America'}}">      <s:optgroup label="Asia"          list="%{#{'India':'India','China':'China'}}" />      <s:optgroup label="Europe"         list="%{#{'UK':'UK','Sweden':'Sweden','Italy':'Italy'}}" />      </s:select>      <s:combobox label="My Sign" name="mySign"         list="#{'aries':'aries','capricorn':'capricorn'}"         headerKey="-1"          headerValue="--- Please Select ---" emptyOption="true"         value="capricorn" />      <s:doubleselect label="Occupation" name="occupation"         list="{'Technical','Other'}" doubleName="occupations2"         doubleList="top == 'Technical' ?          {'I.T', 'Hardware'} : {'Accounting', 'H.R'}" />   </s:form></body></html>

当我们执行上面的程序时,输出的结果将类似于以下内容:

Struts的选择UI标签

现在,让我们逐一查看每个案例。
  • 首先,select标签呈现HTML选择框。在第一个例子中,我们创建一个名为“username”和标记“username”的简单选择框。选择框将填充包含姓名Mike,John和Smith的列表。
  • 在第二个例子中,公司在美国设有总部。它还在亚洲和欧洲设有全球办事处。我们想在一个选择框中显示办公点,但要按全球大陆的名称对全球办事处进行分组。这是optgroup的用武之地。我们使用s:optgroup标签创建一个新组,给组一个标记和一个单独的列表。
  • 在第三个示例中,使用组合框。组合框是输入字段和选择框的组合。用户可以从选择框中选择一个值,在这种情况下,输入字段将自动填入用户选择的值。如果用户直接输入值,则将不选择来自选择框的值。
  • 在我们的示例中,我们有组合框列出了星座。选择框只列出四个条目,允许用户输入他的星座,如果它不在列表中。我们还向选择框中添加一个标题条目。headerentry是显示在选择框顶部的。在示例中,我们要显示“Please Select”。如果用户没有选择任何东西,那么我们假设-1作为值。在某些情况下,我们不希望用户选择一个空值。那么,可以将“emptyOption”属性设置为false。最后,在我们的示例中,我们提供“capricorn”作为组合框的默认值。
  • 在第四个例子中,我们有一个双选框。当要显示两个选择框时,使用double select。在第一个选择框中选择的值确定在第二个选择框中显示的值。在示例中,第一个选择框显示“Technical”和“Other”。如果用户选择Technical,我们将在第二个选择框中显示IT和Hardware。否则,将显示Accounting和HR。这可以使用“list”和“doubleList”属性,如示例所示。
在上面的例子中,我们做一个比较,看看顶部的选择框是否等于Techical。如果是,那么我们显示IT和Hardware。我们还需要给顶部框(“name ='Occupations')和底部框(doubleName ='occupations2')命名。

Struts使用DOJO框架来实现AJAX标签。首先,执行示例前,你需要将struts2-dojo-plugin-2.2.3.jar添加到类路径。你可以从struts2 下载的lib文件夹中获取这个文件(C:struts-2.2.3-allstruts-2.2.3libstruts2-dojo-plugin-2.2.3.jar)。

对于这个示例,让我们参照以下内容修改HelloWorld.jsp

<%@ page contentType="text/html; charset=UTF-8"%><%@ taglib prefix="s" uri="/struts-tags"%><%@ taglib prefix="sx" uri="/struts-dojo-tags"%><html><head><title>Hello World</title><s:head /><sx:head /></head><body>   <s:form>      <sx:autocompleter label="Favourite Colour"         list="{'red','green','blue'}" />      <br />      <sx:datetimepicker name="deliverydate" label="Delivery Date"         displayFormat="dd/MM/yyyy" />      <br />      <s:url id="url" value="/hello.action" />      <sx:div href="%{#url}" delay="2000">           Initial Content      </sx:div>      <br/>      <sx:tabbedpanel id="tabContainer">         <sx:div label="Tab 1">Tab 1</sx:div>         <sx:div label="Tab 2">Tab 2</sx:div>      </sx:tabbedpanel>   </s:form></body></html>

当我们运行上面的例子,将得到以下的输出:

Struts的Ajax标签

现在,让我们一步一步地完成这个例子。

首先要注意的是添加一个带有前缀sx的新标签库。这个(struts-dojo-tags)是为ajax集成专门创建的标签库。

然后在HTML头部内,我们称之为sx:head。这将初始化dojo框架,并使其准备好在页面中被所有AJAX调用。这个步骤很重要,如果没有初始化sx:head,你的ajax调用将无法工作。

首先我们有autocompleter标签。autocompleter标签看起来非常像一个选择框。它使用红色,绿色和蓝色值填充。但选择框和autocompleter标签之间的不同是autocompleter标签自动完成。也就是说,如果你开始在gr中输入,它将填充“绿色”。除此之外,这个标签非常类似于我们前面介绍的s:select标签。

接下来,我们有一个日期时间选择器。此标标签创建一个旁边带有按钮的输入字段。当按下按钮时,显示弹出日期时间选择器。当用户选择日期时,日期以在tag属性中指定的格式填充到输入文本中。在我们的示例中,我们指定了dd/MM/yyyy作为日期的格式。

接下来,是我们在之前的示例中为system.action文件创建的一个url标签。它不必是system.action,它可以是之前创建的任何action文件。然后我们有一个div,超链接设置为url,延迟设置为2秒。当你运行时会发生什么,“Initial Content”将显示2秒,然后div的内容将替换为hello.action执行的内容。

最后,我们有一个简单的标签面板,有两个标签。选项卡将其标签标记为Tab1和Tab2。

值得注意的是,Struts中的AJAX标签集成仍然是一项进展,并且此集成的成熟度在每个版本中都在缓慢增长。

Spring是当下流行的Web框架,可提供带有许多常见Web任务的简易的集成。那么问题是,当我们有Struts2时,为什么我们需要Spring?因为Spring不仅仅是一个MVC框架,它提供了许多其他在Struts中不可用的好东西。例如:依赖注入可以对任何框架有用。在本章中,我们将通过一个简单的例子来了解如何将Spring和Struts2集成在一起。
首先,你需要将以下文件添加到Spring的项目的构建路径。你可以从http://www.springsource.org/download下载并安装最新版本的Spring框架。

  • org.springframework.asm-x.y.z.M(a).jar

  • org.springframework.beans-x.y.z.M(a).jar

  • org.springframework.context-x.y.z.M(a).jar

  • org.springframework.core-x.y.z.M(a).jar

  • org.springframework.expression-x.y.z.M(a).jar

  • org.springframework.web-x.y.z.M(a).jar

  • org.springframework.web.servlet-x.y.z.M(a).jar

最后从你的struts lib目录中添加struts2-spring-plugin-x.y.z.jar到你的WEB-INF/lib中。如果你使用Eclipse,那么你可能会遇到一个异常java.lang.ClassNotFoundException:org.springframework.web.context.ContextLoaderListener。要解决这个问题,你应该进到Marker选项卡中右键逐个点击类依赖关系,然后快速修复以发布/导出所有的依赖关系。最后,确保在Marker选项卡下没有可用的依赖冲突。

Struts和Spring集成

现在让我们为Struts-Spring集成设置web.xml,如下所示:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"	xmlns="http://java.sun.com/xml/ns/javaee" 	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 	http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"	id="WebApp_ID" version="3.0">	   <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <listener>      <listener-class>         org.springframework.web.context.ContextLoaderListener      </listener-class>   </listener>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

这里需要注意的重点是我们配置的监听器。加载spring上下文文件需要ContextLoaderListener。Spring的配置文件称为applicationContext.xml文件,它必须放置在与web.xml文件相同的级别。
让我们创建一个简单的action类User.java,它有两个属性 - firstName和lastName。

package cn.51coolma.struts2;public class User {   private String firstName;   private String lastName;   public String execute()   {      return "success";   }   public String getFirstName() {      return firstName;   }   public void setFirstName(String firstName) {      this.firstName = firstName;   }   public String getLastName() {      return lastName;   }   public void setLastName(String lastName) {      this.lastName = lastName;   }}

现在,创建spring配置文件applicationContext.xml并实例化User.java类。如前所述,此文件应在WEB-INF文件夹下:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">   <beans>      <bean id="userClass" class="cn.51coolma.struts2.User">      <property name="firstName" value="Michael" />      <property name="lastName" value="Jackson" />   </bean></beans>

如上所示,我们已经配置了用户bean,并且我们已经将值MichaelJackson注入到bean中。我们还给这个bean一个名称“userClass”,以便我们可以在别处重新使用它。接下来,让我们在WebContent文件夹中创建User.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"	pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Hello World</title></head><body>   <h1>Hello World From Struts2 - Spring integration</h1>   <s:form>      <s:textfield name="firstName" label="First Name"/><br/>      <s:textfield name="lastName" label="Last Name"/><br/>   </s:form>	</body></html>

User.jsp文件很简单。它仅用于一个目的:显示用户对象的firstname和lastname的值。最后,让我们使用struts.xml文件将所有实体放在一起。

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN""http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="user" class="userClass"          method="execute">         <result name="success">/User.jsp</result>      </action>   </package></struts>

重点需要注意的是,我们使用id userClass来引用类,这意味着我们使用spring为User类做依赖注入。

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/User.jsp,将显示以下界面:

Struts和Spring集成

我们现在已经看到如何将两个伟大的框架结合在一起,这就结束了Struts-Spring集成章节。

在本章中,我们会学习到将 Tiles 框架与 Struts2 集成所涉及的步骤。Apache Tiles是一个模板框架,用于简化 Web 应用程序用户界面的开发。
首先,我们需要从 Apache Tiles 网站下载tiles jar文件。你需要将以下 jar 文件添加到项目的类路径。

  • tiles-api-x.y.z.jar

  • tiles-compat-x.y.z.jar

  • tiles-core-x.y.z.jar

  • tiles-jsp-x.y.z.jar

  • tiles-servlet-x.y.z.jar

除了上面的,我们必须从WEB-INF/lib中复制以下jar文件。

  • commons-beanutils-x.y.z.jar

  • commons-digester-x.y.z.jar

  • struts2-tiles-plugin-x.y.z.jar

现在,让我们设置Struts-Tiles集成的 web.xml,如下所示。这里有两个要点要注意。首先,我们需要告诉tile,在哪里可以找到tiles的配置文件tiles.xml。在我们的例子中,它将在/WEB-INF文件夹下。然后,我们需要初始化 Struts2 下载附带的Tiles监听器。

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   id="WebApp_ID" version="2.5">   <display-name>Struts2Example15</display-name>	   <context-param>   <param-name>      org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG   </param-name>   <param-value>      /WEB-INF/tiles.xml   </param-value>   </context-param>   <listener>   <listener-class>      org.apache.struts2.tiles.StrutsTilesListener   </listener-class>   </listener>   <filter>   <filter-name>struts2</filter-name>   <filter-class>   org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter   </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list></web-app>

接下来在 /WEB-INF 文件夹下创建 tiles.xml,内容如下:

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE tiles-definitions PUBLIC   "-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"   "http://tiles.apache.org/dtds/tiles-config_2_0.dtd"><tiles-definitions>   <definition name="baseLayout" template="/baseLayout.jsp">      <put-attribute name="title"  value="Template"/>      <put-attribute name="banner" value="/banner.jsp"/>      <put-attribute name="menu"   value="/menu.jsp"/>      <put-attribute name="body"   value="/body.jsp"/>      <put-attribute name="footer"   value="/footer.jsp"/>   </definition>   <definition name="tiger" extends="baseLayout">      <put-attribute name="title"  value="Tiger"/>      <put-attribute name="body"   value="/tiger.jsp"/>         </definition>   <definition name="lion" extends="baseLayout">      <put-attribute name="title"  value="Lion"/>      <put-attribute name="body"   value="/lion.jsp"/>         </definition>  </tiles-definitions>

接下来,我们在 baseLayout.jsp 中定义一个基本的skeleton布局。它有五个可重用/可覆盖区域。即 titlebannermenubodyfooter。我们提供baseLayout的默认值,然后创建从默认布局扩展的两个自定义。tiger布局类似于基本布局,除了它使用 tiger.jsp 作为其body和文本“Tiger”作为title。类似地,lion布局也类似于基本布局,除了它使用 lion.jsp 作为其 body 和文本“Lion”作为 title。
让我们看看各个jsp文件。以下是 baseLayout.jsp 文件的内容:

<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title><tiles:insertAttribute name="title" ignore="true" /></title></head><body>   <tiles:insertAttribute name="banner" /><br/>   <hr/>   <tiles:insertAttribute name="menu" /><br/>   <hr/>   <tiles:insertAttribute name="body" /><br/>   <hr/>   <tiles:insertAttribute name="footer" /><br/></body></html>

这里我们只是把一个有 tiles 属性的基本的 HTML 页面放在一起。将tile属性插入到需要用到它的地方。接下来,让我们创建具有以下内容的banner.jsp文件:

<img src="//atts.51coolma.cn/attachments/tuploads/struts_2/tp-logo.gif"/>

menu.jsp文件将有以下内容,它们是TigerMenu.action和LionMenu.action的链接。

<%@taglib uri="/struts-tags" prefix="s"%><a href="<s:url action="tigerMenu"/>" Tiger</a><br><a href="<s:url action="lionMenu"/>" Lion</a><br>

lion.jsp 文件将具有以下内容:

<img src="//atts.51coolma.cn/attachments/tuploads/struts_2/Lion.jpg"/>The lion

tiger.jsp 文件将具有以下内容:

<img src="//atts.51coolma.cn/attachments/tuploads/struts_2/tiger.jpg"/>The tiger

接下来,创建一个action类文件 MenuAction.java,它包含以下内容:

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class MenuAction extends ActionSupport {   public String tiger() { return "tiger"; }   public String lion() { return "lion"; }	}

这是一个非常直接的类。我们声明了两种方法 tiger() 和 lion() ,它们分别返回 tiger 和 lion 作为结果。让我们把它们放在 struts.xml 文件中:

<!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN""http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <package name="default" extends="struts-default">      <result-types>         <result-type name="tiles"          class="org.apache.struts2.views.tiles.TilesResult" />      </result-types>      <action name="*Menu" method="{1}"          class="cn.51coolma.struts2.MenuAction">         <result name="tiger" type="tiles">tiger</result>         <result name="lion" type="tiles">lion</result>      </action>   </package></struts>

让我们回顾一下我们在上面的文件中做的。首先,我们声明了一种称为“tiles”的新结果类型,因为我们现在使用 tile 而不是普通的jsp作为视图技术。Struts2 支持Tiles View结果类型,因此我们创建了结果类型“tiles”作为“org.apache.struts2.view.tiles.TilesResult”类的结果类型。
接下来,我们要说的是,如果请求是 /tigerMenu.action,用户跳到tiger标题页面,如果请求是 /lionMenu.action,用户跳到lion标题页面。
我们使用一些正则表达式来实现这个。在action定义中,我们说任何匹配“*Menu”模式的东西都会被这个action处理。匹配方法将在MenuAction类中调用。也就是说,tigerMenu.action将调用tiger()和lionMenu.action将调用lion()。然后,我们需要将结果映射到适当的标题页面。

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在 Tomcat 的 webapps 目录中部署WAR文件。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/tigerMenu.jsp,将显示以下界面:

Struts和Tiles集成

同样,如果你转到 lionMenu.action 页面,你会看到 lion 页面使用相同的标题布局。

Hibernate是一个高性能的对象/关系留存和查询服务,它是根据开源GNU宽通用公共许可证(LGPL)许可的,可以免费下载。在这一章。 我们将学习如何实现Struts2 与Hibernate的集成。如果你不熟悉Hibernate,可以查看我们的Hibernate教程

数据库设置

对于本教程,我们将使用“struts2_tutorial”MySQL数据库,使用用户名“root”连接到机器上的这个数据库,不设密码。首先,你需要运行以下脚本。此脚本创建一个名为student的新表,并在此表中创建少量记录:

CREATE TABLE IF NOT EXISTS `student` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `first_name` varchar(40) NOT NULL,  `last_name` varchar(40) NOT NULL,  `marks` int(11) NOT NULL,  PRIMARY KEY (`id`));---- Dumping data for table `student`--INSERT INTO `student` (`id`, `first_name`, `last_name`, `marks`)   VALUES(1, 'George', 'Kane', 20);INSERT INTO `student` (`id`, `first_name`, `last_name`, `marks`)   VALUES(2, 'Melissa', 'Michael', 91);INSERT INTO `student` (`id`, `first_name`, `last_name`, `marks`)   VALUES(3, 'Jessica', 'Drake', 21);

Hibernate配置

接下来让我们创建hibernate.cfg.xml,它是hibernate配置文件。

<?xml version='1.0' encoding='utf-8'?><!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD//EN""http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"><hibernate-configuration><session-factory>   <property name="hibernate.connection.driver_class">c      om.mysql.jdbc.Driver   </property>   <property name="hibernate.connection.url">      jdbc:mysql://www.51coolma.cn/struts_tutorial   </property>   <property name="hibernate.connection.username">root</property>   <property name="hibernate.connection.password"></property>   <property name="hibernate.connection.pool_size">10</property>   <property name="show_sql">true</property>   <property name="dialect">      org.hibernate.dialect.MySQLDialect   </property>   <property name="hibernate.hbm2ddl.auto">update</property>   <mapping class="cn.51coolma.hibernate.Student" /></session-factory></hibernate-configuration> 

让我们过一下hibernate配置文件。首先,我们声明使用MySQL驱动程序。然后我们声明了jdbc url用于连接到数据库。接着我们声明连接的用户名,密码和池大小。我们还指出希望通过将“show_sql”打开为true来查看日志文件中的SQL。请通过Hibernate教程了解这些属性的含义。最后,我们将映射类设置为在本章中创建的cn.51coolma.hibernate.Student。

环境搭建

这个项目需要很多jar文件,以下的是所需的JAR文件的完整列表的屏幕截图:

Struts和Hibernate的jar

大多数JAR文件可以作为struts分发的一部分获取。如果你有安装一个应用程序服务器,如glassfish,websphere或jboss,那么你可以从appserver的lib文件夹中获取大多数剩余的jar文件。如果没有,你可以单独下载文件:

其余的文件,你应该能够从struts2 中分配。

Hibernate类

现在让我们为hibernate集成创建所需的java类。按照Student.java的内容:

package cn.51coolma.hibernate;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;import javax.persistence.Table;@Entity@Table(name="student")public class Student {	   @Id   @GeneratedValue   private int id;   @Column(name="last_name")   private String lastName;   @Column(name="first_name")   private String firstName;   private int marks;   public int getId() {    return id;   }   public void setId(int id) {    this.id = id;   }   public String getLastName() {      return lastName;   }   public void setLastName(String lastName) {      this.lastName = lastName;   }   public String getFirstName() {      return firstName;   }   public void setFirstName(String firstName) {      this.firstName = firstName;   }   public int getMarks() {      return marks;   }   public void setMarks(int marks) {      this.marks = marks;   }}

这是一个POJO类,根据Hibernate规范表示的student表。它具有对应于student表列名的属性id,firstName和lastName。接下来让我们创建StudentDAO.java文件,如下所示:

package cn.51coolma.hibernate;import java.util.ArrayList;import java.util.List;import org.hibernate.Session;import org.hibernate.Transaction;import com.googlecode.s2hibernate.struts2.plugin.                     annotations.SessionTarget;import com.googlecode.s2hibernate.struts2.plugin.                     annotations.TransactionTarget;public class StudentDAO {	   @SessionTarget   Session session;   @TransactionTarget   Transaction transaction;   @SuppressWarnings("unchecked")   public List<Student> getStudents()   {      List<Student> students = new ArrayList<Student>();      try      {         students = session.createQuery("from Student").list();      }      catch(Exception e)      {         e.printStackTrace();      }      return students;   }   public void addStudent(Student student)   {      session.save(student);   }}

StudentDAO类是Student类的数据访问层。它有方法来列出所有学生,然后保存一个新的学生记录。

Action类

下面的文件AddStudentAction.java定义了我们的action类。我们在这里有两个action方法:execute()和listStudents()。execute()方法用于添加新的学生记录。我们使用dao的save()方法来实现这一点。另一种listStudents()方法用于列出学生。我们使用dao的列表方法来获取所有学生的列表。

package cn.51coolma.struts2;import java.util.ArrayList;import java.util.List;import com.opensymphony.xwork2.ActionSupport;import com.opensymphony.xwork2.ModelDriven;import cn.51coolma.hibernate.Student;import cn.51coolma.hibernate.StudentDAO;public class AddStudentAction extends ActionSupport             implements ModelDriven<Student>{   Student student  = new Student();   List<Student> students = new ArrayList<Student>();   StudentDAO dao = new StudentDAO();   @Override   public Student getModel() {      return student;   }   public String execute()   {      dao.addStudent(student);      return "success";   }   public String listStudents()   {      students = dao.getStudents();      return "success";   }   public Student getStudent() {      return student;   }   public void setStudent(Student student) {      this.student = student;   }   public List<Student> getStudents() {      return students;   }   public void setStudents(List<Student> students) {      this.students = students;   }	}

你会注意到我们正在实现ModelDriven接口。这是在你的action类处理一个具体的模型类(如Student)而不是个别的属性(如firstName,lastName)时使用。ModelAware接口需要你实现一个方法来返回模型。在我们的例子中,我们返回“student”对象。

创建视图文件

现在创建包含以下内容的student.jsp视图文件:

<%@ page contentType="text/html; charset=UTF-8"%><%@ taglib prefix="s" uri="/struts-tags"%><html><head><title>Hello World</title><s:head /></head><body>   <s:form action="addStudent">   <s:textfield name="firstName" label="First Name"/>   <s:textfield name="lastName" label="Last Name"/>   <s:textfield name="marks" label="Marks"/>   <s:submit/>   <hr/>   <table>      <tr>         <td>First Name</td>         <td>Last Name</td>         <td>Marks</td>      </tr>      <s:iterator value="students">	         <tr>            <td><s:property value="firstName"/></td>            <td><s:property value="lastName"/></td>            <td><s:property value="marks"/></td>           </tr>      </s:iterator>	   </table>   </s:form></body></html>

student.jsp非常简单。在上面部分,我们有一个提交到“addStudent.action”的表单。它接受firstName,lastName和marks。因为addStudent action绑定到ModelAware的“AddSudentAction”,所以将自动创建一个学生bean,其值自动填充为firstName,lastName和marks。
在下面部分,我们浏览学生列表(参见AddStudentAction.java),并在表中显示firstname,lastname和marks的值。

Struts配置

让我们使用struts.xml

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="myhibernate" extends="hibernate-default">      <action name="addStudent" method="execute"         class="cn.51coolma.struts2.AddStudentAction">         <result name="success" type="redirect">               listStudents         </result>      </action>      <action name="listStudents" method="listStudents"         class="cn.51coolma.struts2.AddStudentAction">         <result name="success">/students.jsp</result>      </action></package></struts>

要注意的要点是,我们的包“myhibernate”扩展了名为“hibernate-default”的struts2默认包。然后我们声明两个action:addStudent和listStudents。addStudent调用AddStudentAction类的execute(),然后在成功时调用listStudents方法。listStudent方法调用AddStudentAction类上的listStudents(),并使用student.jsp作为视图。

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/student.jsp,将显示以下界面:
Struts和Hibernate的集成

在上面部分,我们得到一个表单,输入新学生记录的值,下面部分列出数据库中的学生。继续添加一个新的学生记录,然后按提交。屏幕将刷新,并在每次单击提交时向你显示更新了的列表。

Struts2 是目前较为普及和成熟的基于MVC设计模式的web应用程序框架,它不仅仅是Struts1 的升级版本,更是一个全新的Struts架构。最初,是以WebWork框架和Struts框架为基础,通过提供增强和改进的Struts框架,进而实现简化web技术人员开发工作的目标。不久之后,Webwork框架和Struts社区联合创造了现在流行的Struts2框架。

Struts2 框架的优点

了解了这几个主要的优点,会促使你考虑使用Struts2 :
  • POJO表单及POJO操作 - Struts2 去除掉了Struts框架中的Action Forms部分。在Struts2框架下,你可以用任何一POJO来接收表单输入,同样的,你可以把任一POJO视为一个Action类。
  • 标签支持 - Struts2 改进了标签表单,而新的标签可让开发人员减少代码编写量。
  • AJAX支持 - Struts2 被认可接收进Web 2.0技术,并创建了功能非常类似于标准的Struts2 标签的AJAX标签,把AJAX支持整合进其结果中。
  • 易于整合 - Struts有多种整合方式可使用,现在与其他类型的框架,如Spring、Tiles、SiteMesh之类的,整合更为容易了。
  • 模板支持 - 支持使用模板生成视图。
  • 插件支持 - 有大量的插件可用于Struts2,而使用插件可以增强和扩大Struts2 核心行为。
  • 性能分析 - Struts2 为调试和配置应用程序提供综合的性能分析,此外,Struts也以嵌入调试工具的形式提供集成调试。
  • 易于修改标签 - 在Struts2 中,可使用Freemarker的模板对标签标记进行调整,而修改标签不需要JSP或是Java知识,基本的HTML、XML和CSS知识就足够了。
  • 促进减少配置 - Struts2 使用各种设置的默认值促进减少配置,而你不需要再配置什么除非是偏离了Struts2 设定的默认设置。
  • 视图技术 - Struts2 为多种视图选项(JSP、Freemarker、Velocity、XSLT等)提供支持。
以上是使Struts2 成为准企业框架的十大优点。

Struts2 框架的缺点

尽管Struts2 有一大列的优点,但我们还是要提到关于它的一些仍需不断改进的缺点:
  • 更大的学习曲线 - 使用Struts MVC,你必须要熟悉JSP、Servlet APIs标准以及一个大型、复杂的框架。
  • 文档缺乏 - 相比于Servlet和JSP APIs标准,Struts的在线资源较少,许多初学者会发现Apache在线文档混乱并缺乏整理。
  • 不够透明 - 相比于使用正常的基于Java的Web应用程序,使用Struts的应用程序有许多是进行在后台,这使得框架不易于理解。
最后说明一点,一个好的框架应该提供各种类型的应用程序都可以使用的通用行为,Struts2 是最好的Web框架之一,并频繁用于RIA(Rich Internet Applications)的发展。

模型(Model)-视图(View)-控制器(Controller),通常简称MVC,是一种开发web应用程序的软件设计模式。该软件设计模式由以下三部分组成:  

  • 模型——属于软件设计模式的底层基础,主要负责数据维护。  
  • 视图——这部分是负责向用户呈现全部或部分数据。 
  • 控制器——通过软件代码控制模型和视图之间的交互。
MVC普及的原因在于它区分了应用程序的逻辑层和用户界面层,并支持开发关注点的分离。在MVC模式下,控制器接收了所有来自应用程序的请求后,调用模型去准备视图所需要的数据,然后视图使用由控制器提供的数据最终生成一个可视的响应。MVC的抽象概念可通过以下图形进行表述:

Struts MVC

模型

模型主要负责管理应用程序的数据,它通过响应视图的请求和控制器的指令来更新自身的数据。

视图

通过控制器的指令触发所展现的一种特殊的数据格式。它们是基于像JSP、ASP、PHP之类模板系统的脚本,较易与AJAX技术进行整合。

控制器

控制器负责响应用户输入并执行数据模型对象的交互。控制器在接收、确认输入后执行修改数据模型状态的业务操作。
  
Struts2是一个以MVC为基础的框架。在接下来的章节,让我们看看如何在Struts2中使用MVC。

我们的第一个任务是运行一个最小的Struts2 应用程序。本章将指导你如何搭建Struts2 开发环境进行工作。我们假设你的电脑已经安装了JDK(5+)、Tomcat以及Eclipse,如果你没有安装这些组件那就按照下面列出快捷方式安装:

步骤1 - 安装Java开发工具包(JDK):

你可以在甲骨文网站的Java页面下载最新版本的SDK:Java SE下载链接。在下载文件中你可以看到安装JDK的说明,按照说明安装及配置设置。最后,设置路径和JAVA_HOME环境变量到引用的包含Java和Javac的目录,通常分别是 java_install_dir/bin 和 java_install_dir 。

如果你是在Windows系统下把SDK安装到C:jdk1.5.0_20,你需要把以下代码放到你的C:autoexec.bat文件里。

set PATH=C:jdk1.5.0_20in;%PATH%set JAVA_HOME=C:jdk1.5.0_20
此外,在Windows NT/2000/XP系统中,你也可以右键点击“我的电脑”,选择“属性”→“高级”→“环境变量”,然后将路径值更新并按下“确定”按钮。

在Unix(或Solaris,Linux等)系统中,如果SDK是安装在C盘的 /usr/local/jdk1.5.0_20 ,你可以把以下代码放到 .cshrc 文件中。

setenv PATH /usr/local/jdk1.5.0_20/bin:$PATHsetenv JAVA_HOME /usr/local/jdk1.5.0_20

另外,如果你使用的是像Borland JBuilder、Eclipse、IntelliJ IDEA或是Sun ONE Studio之类的集成开发环境(IDE),编译运行一个简单的程序来确认IDE找寻到了你安装的Java的位置,否则的话就按照IDE给出的文档做正确的设置。

步骤2 - 安装Apache Tomcat:

你可以从这个地址下载Tomcat的最新版本:http://tomcat.apache.org/。一旦你下载了安装程序,解压二进制发布包到一个便捷的位置,例如Windows的 C:apache-tomcat-6.0.33 ,Linux或Unix的 /usr/local/apache-tomcat-6.0.33 ,并创建CATALINA_HOME环境变量指向这些位置。
在Windows环境下,可以通过执行以下指令启动Tomcat,或者你可以直接双击 startup.bat 。
%CATALINA_HOME%instartup.bat  or  C:apache-tomcat-6.0.33instartup.bat
在Unix(或Solaris、Linux等)环境下,可以通过执行以下指令启动Tomcat:
$CATALINA_HOME/bin/startup.shor /usr/local/apache-tomcat-6.0.33/bin/startup.sh
启动成功后,包含Tomcat的默认web程序就可以通过 http://localhost:8080/ 进行访问了。如果一切正常,那么会显示以下结果:

Tomcat主页

在这里可发现更多关于配置和运行Tomcat的信息的文档,同样也可登陆Tomcat网站进行查找:http://tomcat.apache.org 。
在Windows环境下,可以通过执行以下指令停止Tomcat:
%CATALINA_HOME%inshutdownorC:apache-tomcat-5.5.29inshutdown
在Unix(或Solaris、Linux等)环境下,可以通过执行以下指令停止Tomcat:
$CATALINA_HOME/bin/shutdown.shor/usr/local/apache-tomcat-5.5.29/bin/shutdown.sh

步骤3 - 安装Eclipse(IDE)

本教程中的所有示例都是使用Eclipse IDE,因此我们建议你在电脑上安装最新版本的Eclipse。可在这个地址下载安装最新的Eclipse: http://www.eclipse.org/downloads/ 。一旦你下载了安装程序,解压二进制发布包到一个便捷的位置,例如Windows的 C:eclipse ,Linux或Unix的 /usr/local/eclipse ,并设置适当的路径变量。
在Windows环境下,可以通过执行以下指令启动Eclipse,或者你可以直接双击 eclipse.exe 。
 %C:eclipseeclipse.exe
在Unix(或Solaris、Linux等)环境下,可以通过执行以下指令启动Eclipse:
$/usr/local/eclipse/eclipse
启动成功后,如果一切正常,那么会显示以下结果:

Eclipse主页

步骤4 - 安装Struts2 文件库

如果一切顺利,那么现在你可以继续安装你的Struts2 框架,以下是在电脑上下载和安装Struts2 的简单步骤:
  • 选择是否想要在Windows或者Unix上安装Struts2 ,然后继续下一步,下载适用于Windows或者Unix的压缩文件。
  • 在这个地址下载最新版本的Struts2 二进制文件: http://struts.apache.org/download.cgi 。
  • 在编写本教程时我们下载的是 struts-2.0.14-all.zip ,当你解压下载的文件时,它会在 C:struts-2.2.3 里显示以下目录结构:
Sturts目录

接下来是在任意位置解压zip文件,我们是在Windows 7电脑的C:文件夹里下载并解压 struts-2.2.3-all.zip ,这样我们可以把所有jar文件放在 C:struts-2.2.3lib 里。确保你已正确设置CLASSPATH变量,否则你运行应用程序的时候就会遇到问题。


从一个高水平角度看,Struts2 是一个MVC拉动的(或MVC2)框架,Struts2 的模型-视图-控制器模式是通过以下五个核心部分进行实现的:

  • 操作(Actions)
  • 拦截器(Interceptors)
  • 值栈(Value Stack)/OGNL
  • 结果(Result)/结果类型
  • 视图技术
而Struts2 与传统的MVC框架略有不同,因为它由Action扮演模型的角色,而不是控制器,虽然这样会有一些重叠。

Struts 2的架构

上图描述了Struts2 高级系统架构下的模型、视图及控制器。控制器是通过Struts2 分派servlet过滤器以及拦截器进行实现,模型是通过Actions进行实现,而视图则是结果类型和结果的结合。值栈和OGNL提供共同的路线、链接以及与其他组件之间的集成。
除了上述部分,还有许多组件相关的信息。web应用程序组件、Actions组件、拦截器组件、结果组件等等。
这些是Struts2 MVC模式的体系结构概述,在随后的章节中,我们将详细了解各个部分。

请求生命周期

通过上述图片的描述,我们可以依照下面几点解释在Struts2 中用户的请求生命周期:
  • 用户发送一个资源需求的请求到服务器(例如:页面)。
  • 核心控制器查看请求后确定适当的动作。
  • 使用验证、文件上传等配置拦截器功能
  • 执行选择的动作来完成请求的操作。
  • 另外,如果需要的话,配置的拦截器可做任何后期处理。
  • 最后,由视图显示结果并返回给用户。

通过学习Struts2 框架可以了解到,当你在Struts2 的web应用程序里点击一个超链接或提交一个HTML表单时,会由控制器收集输入并发送一个叫Actions的Java类。Action被执行后,Result会选择一个资源给予响应。这个资源通常是一个JSP,也可以是一个PDF文件,一个Excel表格,或者是一个Java小程序窗口。

假设你已经建好了你的开发环境,那么现在让我们继续构建第一个Struts2 项目:Hello World 。这个项目的目标是构建一个收集用户名并在用户名后跟随显示“Hello World”的web应用程序。我们需要为每个Struts2 项目构建以下四个组件:

序号名称及描述
1Action(操作)
创建一个动作类,包含完整的业务逻辑并控制用户、模型以及视图间的交互。
2Interceptors(拦截器)
这是控制器的一部分,可依据需求创建拦截器,或使用现有的拦截器。
3View(视图)
创建一个JSP与用户进行交互,获取输入并呈现最终信息。
4Configuration Files(配置文件)
创建配置文件来连接动作、视图以及控制器,这些文件分别是struts.xml、web.xml以及struts.properties。

我们如果打算使用Eclipse IDE,那么所有必需的组件都要在动态Web项目(Dynamic Web Project)下创建。因此我们就先从创建动态Web项目开始

创建一个动态Web项目:

启动你的Eclipse,然后打开“File”>“New”>“Dynamic Web Project”,输入“HelloWorldStruts2”的项目名称,参照下图设置其他选项:

按照下图选择所有默认选项,最后检查 Generate Web.xml deployment descriptor 选项。这个将在Eclipse为你创建一个动态web项目。现在点击“Windows”>“Show”>“View”>“Project Explorer”,你就可以看到你的项目窗口,如下图:

你好世界Sturts2
现在从Struts2 的lib文件夹 C:struts-2.2.3lib 中拷贝以下文件到项目的 WEB-INFlib 文件夹里。你可以直接拖拽以下所有文件到 WEB-INFlib 文件夹。
  • commons-fileupload-x.y.z.jar
  • commons-io-x.y.z.jar
  • commons-lang-x.y.jar
  • commons-logging-x.y.z.jar
  • commons-logging-api-x.y.jar
  • freemarker-x.y.z.jar
  • javassist-x.y.z.GA
  • ognl-x.y.z.jar
  • struts2-core-x.y.z.jar
  • xwork-core.x.y.z.jar

创建Aciton类

Action类是Struts2 应用程序的关键,我们通过它实现大部分的业务逻辑。那么让我们在“Java Resources”>“src”的类目下创建一个名称为“HelloWorldAction.java”的java文件夹,使用一个命名为“cn.51coolma.struts2”并包含以下内容的资源包。
当用户点击一个URL时,由Action类来响应用户操作。一个或多个Action类的方法被执行,并返回一个字符串结果。基于结果的值,会呈现一个特定的JSP页面。
package cn.51coolma.struts2;public class HelloWorldAction{   private String name;   public String execute() throws Exception {      return "success";   }      public String getName() {      return name;   }   public void setName(String name) {      this.name = name;   }}
这是一个非常简单的具有“name”属性的类。对于“name”属性,我们用标准的getter和setter方法,以及一个返回“success”字符串的执行方法。
Struts2 框架将创建一个“HelloWorldAction”类的对象,并调用execute方法来响应用户的动作。你把你的业务逻辑放进execute方法里,最后会返回字符串常量。简单的描述每个URL,你需要实现一个Action类,你也可以用类名直接作为你的动作名,或者如下面内容所示使用 struts.xml 文件映射到其他name上。

创建视图

我们需要一个JSP来呈现最终的信息,当一个预定义动作发生时这个页面将被Struts2 框架调用,并且这个映像会定义到 struts.xml 文件里。那么让我们在你的Eclipse项目的WebContent文件夹里创建以下JSP文件 HelloWorld.jsp 。在project explorer中右键点击WebContent文件夹并选择“New”>“JSP File”
<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>Hello World</title></head><body>   Hello World, <s:property value="name"/></body></html>
Taglib指令告知Servlet容器这个页面将使用Struts2 标签,并且这些标签会被s放在前面。s:property 标签显示Action类“name”属性的值,这个值是使用HelloWorldAction类的 getName() 方法返回的。

创建主页

在WebContent文件夹里,我们还需要创建 index.jsp 文件,这个文件是用作初始的action URL。用户可以通过点击它命令Struts2框架去调用HelloWorldAction类的定义方法并呈现HelloWorld.jsp视图。
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%>   <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Hello World</title></head><body>   <h1>Hello World From Struts2</h1>   <form action="hello">      <label for="name">Please enter your name</label><br/>      <input type="text" name="name"/>      <input type="submit" value="Say Hello"/>   </form></body></html>
上面视图文件里定义的hello action将通过struts.xml文件影射到HelloWorldAction类及其execute方法。当用户点击提交按钮时,将使得Struts2框架运行HelloWorldAction类中的execute方法,并基于该方法的返回值,选择一个适当的视图作为响应进行呈现。

配置文件

我们需要一个映像把URL、HelloWorldAction类(模型)以及 HelloWorld.jsp(视图)联系在一起。映像告知Struts2 框架哪个类将响应用户的动作(URL),类里的哪个方法将要执行,以及基于方法所返回的字符串结果,会呈现怎样的视图。
那么接下来让我们创建一个名为 struts.xml 的文件。因为Struts2 要求 strust.xml 文件显示在classes的文件夹里,所以我们要在WebContent/WEB-INF/classes 的文件夹下创建 struts.xml 文件。Eclipse并没有默认创建“classes”文件夹,因此你需要自己创建。在project explorer里右键点击WEB-INF文件夹并选择“New”>“Folder”,你的 struts.xml 文件应该如下:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts><constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">           <action name="hello"             class="cn.51coolma.struts2.HelloWorldAction"             method="execute">            <result name="success">/HelloWorld.jsp</result>      </action>   </package></struts>
这里说几句关于上述的配置文件。这里我们设定常数struts.devMode的值为,因为我们是在开发环境下工作,需要查看一些有用的日志消息。然后,我们定义一个名为helloworld的数据包。当你想要把你的Actions集合在一起时,创建一个数据包是非常有用的。在我们的示例中,我们命名我们的动作为“hello”,与URL /hello.action保持一致,由HelloWorldAction.class进行备份。HelloWorldAction.classexecute方法就是当URL /hello.action被调用时运行。如果execute方法返回的结果为“success”,那么我们带用户进入HelloWorld.jsp
下一步是创建一个web.xml文件,这是一个适用于Struts2 任何请求的接入点。在部署描述符(web.xml)中,Struts2 应用程序的接入点将会定义为一个过滤器。因此我们将在web.xml里定义一个org.apache.struts2.dispatcher.FilterDispatcher 类的接入点,而web.xml文件需要在WebContent的WEB-INF文件夹下创建。Eclipse已经创建了一个基础的web.xml文件,你在创建项目的时候可以使用。那么,让我们参照以下内容做修改:
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">      <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>
我们指定了index.jsp作为我们的欢迎文件,那么我们已经配置好了在所有的URL(列如:所有匹配/*模式的URL)上运行Struts2 过滤器。

注意:

如果它是struts2-core-2.5.jar,那么将web.xml中的过滤器类标记值更改为

<filter-class>

     org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter

</filter-class>

如果它是struts2-core-2.1.3.jar,那么将web.xml中的过滤器类标记值更改为

<filter-class>

     org.apache.struts2.dispatcher.FilterDispatcher

</filter-class>

自Struts 2.1.3以来,FilterDispatcher就不推荐使用了。如果您使用的是较旧的版本,则用户高于解决方案。

如果它是struts2-core-2.3.X.jar,那么将web.xml中的过滤器类标记值更改为

<filter-class> 

     org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

</filter-class>

启用详细日志

通过在WEB-INF/classes文件夹下创建logging.properties文件,可以实现在使用Struts 2时启用完整的日志记录功能。 属性文件中需保留以下两行::
org.apache.catalina.core.ContainerBase.[Catalina].level = INFOorg.apache.catalina.core.ContainerBase.[Catalina].handlers =                               java.util.logging.ConsoleHandler

默认由logging.properties指定一个ConsoleHandler将日志记录按指定路线发送给stdout和FileHandler。程序运行日志的级别阈值可以使用SEVERE,WARNING,INFO,CONFIG,FINE,FINER,FINEST或者ALL。

这样,我们就准备好使用Struts 2运行我们的Hello World程序了。

执行应用程序

右键点击项目名称,接着点击“Export”>“WAR File”创建WAR文件,然后将WAR部署到Tomcat的webapps目录中。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp ,将会呈现如下图所示的结果:

你好世界Struts4

输入一个“Struts2”值并提交页面,你可以看到以下页面

你好世界Struts5

注意,你可以在struts.xml文件中定义一个索引作为操作,这样你可以调用索引页面 http://localhost:8080/HelloWorldStruts2/index.action 。查看下面是怎样定义索引作为操作:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts><constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="index">            <result >/index.jsp</result>      </action>      <action name="hello"             class="cn.51coolma.struts2.HelloWorldAction"             method="execute">            <result name="success">/HelloWorld.jsp</result>      </action>   </package></struts>


本章节将带你学习Struts2 应用程序所需的基本配置。在这里可以看到哪些将被配置到一些重要的配置文件中:web.xmlstruts.xmlstruts-config.xml以及struts.properties

实际上,你可以继续依赖于使用web.xml和struts.xml配置文件,并且你已经在前面的章节中了解到,我们的示例是使用这两个文件运作的,不过为了让你了解更多,我们还是再来说明一下其他的文件。

web.xml文件

web.xml配置文件是一种J2EE配置文件,决定servlet容器的HTTP元素需求如何进行处理。它严格来说不是一个Struts2 配置文件,但它是Struts2 运作所需要进行配置的文件。

正如前面所讨论的,这个文件为每个web应用程序提供接入点。在部署描述符(web.xml)中,Struts2 应用程序的接入点将会定义为一个过滤器。因此我们将在web.xml里定义一个FilterDispatcher类的接入点,而这个web.xml文件需要在WebContent/WEB-INF文件夹下创建。

如果你开始时没有模板或工具(比如Eclipse或Maven2)的辅助来生成,那这就是第一个你需要配置的文件。下面是我们在上一个例子中用到的web.xml的内容。

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">      <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>      <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

注意,我们将Struts2 过滤器映射到 /* ,而不是 /*.action ,这意味着所有的url都会被Struts过滤器解析。当我们学到关于注解的章节时会对这个进行讨论。

注意:自2.1.3版本开始,ActionContextCleanUp和FilterDispatcher都由StrutsPrepareAndExecuteFilter代替。

struts.xml文件

struts.xml文件包含有随着Actions的开发你将要修改的配置信息。它可用于覆盖应用程序的默认设置,例如:struts.devMode=false 以及其他定义为属性文件的设置。这个文件可在WEB-INF/classes文件夹下创建。
让我们来看一下在前一章节中阐述的Hello World示例里创建的struts.xml文件。

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">           <action name="hello"             class="cn.51coolma.struts2.HelloWorldAction"             method="execute">            <result name="success">/HelloWorld.jsp</result>      </action>      <-- more actions can be listed here -->   </package>   <-- more packages can be listed here --></struts>

首先要注意的是DOCTYPE(文档类型)。如我们的示例所示,所有的Struts配置文件都需要有正确的doctype。<struts>是根标记元素,在其下,我们使用<package>标签声明不同的包。 这里的<package>标签允许配置的分离和模块化。这在你进行一个大的项目并且项目分为多个不同的模块时,是非常有用的。

如果您的项目有三个域:business_applicaiton、customer_application和staff_application的话,你可以创建三个包,并将相关的Actions存储到相应的包中。 <package>标签具有以下属性:

属性描述
name(必需)为package的唯一标识
extends指定package继承另一package的所有配置。通常情况下,我们使用struts-default作为package的基础。
abstract定义package为抽象的。如果标记为true,则package不能被最终用户使用。
namespaceActions的唯一命名空间

<constant>标签以及name和value属性将用于覆盖default.properties中定义的任一属性,就像我们设置的struts.devMode属性一样。设置struts.devMode属性允许我们在日志文件中查看更多的调试消息。

我们定义<action>标签对应于我们想要访问的每个URL,并且使用execute()方法定义一个访问相应的URL时将要访问的类。

Results(结果)确定在执行操作后返回到浏览器的内容,而从操作返回的字符串应该是结果的名称。 Results按上述方式配置,或作为“全局”结果配置,可用于包中的每个操作。 Results有

name

type

属性可选,默认的name值是“success”。


Struts.xml文件可以随着时间的推移而增长,因此通过包打破它是使它模块化的一种方式,但struts提供了另一种模块化struts.xml文件的方法,你可以将文件拆分为多个xml文件,并用以下方式导入它们。

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"    "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>     <include file="my-struts1.xml"/>     <include file="my-struts2.xml"/></struts>

我们没有覆盖的另一个配置文件是struts-default.xml。此文件包含Struts的标准配置设置,你不必再为99.99%的项目重复这些设置。 因此,我们不会深入了解这个文件的太多细节。如果你有兴趣,可以查看在struts2-core-2.2.3.jar文件中可用的default.properties文件。

struts-config.xml文件

struts-config.xml配置文件是Web Client中View和Model组件之间的链接,但在你99.99%的项目里你不必使用这些设置。 struts-config.xml配置文件包含以下主要元素:

序号拦截器和说明
1struts-config

这是配置文件的根节点。

2form-beans

这是你将ActionForm子类映射到name的位置,你可以在struts-config.xml文件的其余部分,甚至在JSP页面上,将这个name用作ActionForm的别名。

3global forwards

此部分将你在webapp上的页面映射到name,你可以使用这个name来引用实际页面。这避免了对你网页上的URL进行硬编码。

4action-mappings

这是你声明表单处理程序的地方,也被称为操作映射(action mappings)

5controller

这部分是配置Struts的内部,在实际情况中很少使用。

6plug-in

这部分告诉Struts在哪里找到属性文件,它包含提示和错误消息。

下面是struts-config.xml文件的示例:

<?xml version="1.0" encoding="ISO-8859-1" ?><!DOCTYPE struts-config PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 1.0//EN""http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd"><struts-config>   <!-- ========== Form Bean Definitions ============ -->   <form-beans>      <form-bean name="login" type="test.struts.LoginForm" />   </form-beans>   <!-- ========== Global Forward Definitions ========= -->   <global-forwards>   </global-forwards>   <!-- ========== Action Mapping Definitions ======== -->   <action-mappings>      <action         path="/login"         type="test.struts.LoginAction" >         <forward name="valid" path="/jsp/MainMenu.jsp" />         <forward name="invalid" path="/jsp/LoginView.jsp" />      </action>   </action-mappings>   <!-- ========== Controller Definitions ======== -->   <controller       contentType="text/html;charset=UTF-8"      debug="3"      maxFileSize="1.618M"      locale="true"      nocache="true"/></struts-config>

有关struts-config.xml文件的更多详细内容,可查看Struts Documentation。

struts.properties文件

这个配置文件提供了一种机制来改变框架的默认行为。实际上,struts.properties配置文件中包含的所有属性也可以在web.xml中配置使用init-param,以及在struts.xml配置文件中使用constant标签。 但如果你想保持事件独立以及保留更多struts细节,那么你可以在WEB-INF/classes文件夹下创建这个文件。

struts.properties

文件中配置的值将覆盖

default.properties

中配置的默认值,这些值包含在struts2-core-x.y.z.jar分布中。有一些属性,你可以考虑改为使用

struts.properties

文件:

### When set to true, Struts will act much more friendly for developersstruts.devMode = true### Enables reloading of internationalization filesstruts.i18n.reload = true### Enables reloading of XML configuration filesstruts.configuration.xml.reload = true### Sets the port that the server is run onstruts.url.http.port = 8080

这里任何以#(hash)开头的行都将被假定为注释,并且它会被Struts 2默认忽略。


Actions是Struts2框架的核心,因为它们适用于任何MVC(Model View Controller)框架。 每个URL映射到特定的action,其提供处理来自用户的请求所需的处理逻辑。
但action还有另外两个重要的功能。 首先,action在将数据从请求传递到视图(无论是JSP还是其他类型的结果)方面起着重要作用。 第二,action必须协助框架确定哪个结果应该呈现在响应请求的视图中。

创建Action

Struts2中actions的唯一要求是必须有一个无参数方法返回String或Result对象,并且必须是POJO。如果没有指定no-argument方法,则默认是使用execute()方法。
你还可以扩展ActionSupport类,该类可实现六个接口,包括Action接口。Action的接口如下:

public interface Action {   public static final String SUCCESS = "success";   public static final String NONE = "none";   public static final String ERROR = "error";   public static final String INPUT = "input";   public static final String LOGIN = "login";   public String execute() throws Exception;}

让我们来看看在Hello World示例中的action方法:

package cn.51coolma.struts2;public class HelloWorldAction{   private String name;   public String execute() throws Exception {      return "success";   }      public String getName() {      return name;   }   public void setName(String name) {      this.name = name;   }}

为了说明action方法控制视图的要点,让我们对execute方法进行以下更改,并扩展ActionSupport类如下:

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class HelloWorldAction extends ActionSupport{   private String name;   public String execute() throws Exception {      if ("SECRET".equals(name))      {         return SUCCESS;      }else{         return ERROR;        }   }      public String getName() {      return name;   }   public void setName(String name) {      this.name = name;   }}

在这个例子中,我们在execute方法中使用一些逻辑来查看name属性。如果属性等于字符串“SECRET”,我们返回SUCCESS作为结果,否则我们返回ERROR作为结果。因为我们已经扩展了ActionSupport,所以我们可以使用String常量、SUCCESS和ERROR。 现在,让我们修改struts.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd">   <struts>      <constant name="struts.devMode" value="true" />      <package name="helloworld" extends="struts-default">         <action name="hello"             class="cn.51coolma.struts2.HelloWorldAction"            method="execute">            <result name="success">/HelloWorld.jsp</result>            <result name="error">/AccessDenied.jsp</result>         </action>      </package></struts>

创建视图

让我们在你的eclipse项目的WebContent文件夹中创建下面的jsp文件HelloWorld.jsp。右键单击项目资源管理器中的WebContent文件夹,然后选择“New”> “JSP File”。如果返回结果是SUCCESS将调用此文件(这个字符串常量“success”是在Action接口中定义的):

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>Hello World</title></head><body>   Hello World, <s:property value="name"/></body></html>

如果action的结果是ERROR,即字符串常量为“error”,下面的文件将被框架调用。 以下是AccessDenied.jsp的内容:

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>Access Denied</title></head><body>   You are not authorized to view this page.</body></html>

我们还需要在WebContent文件夹中创建index.jsp文件。此文件将用作初始的action URL,用户可以单击它以命令Struts 2框架调用HelloWorldAction类的execute方法并呈现HelloWorld.jsp视图。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%>   <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Hello World</title></head><body>   <h1>Hello World From Struts2</h1>   <form action="hello">      <label for="name">Please enter your name</label><br/>      <input type="text" name="name"/>      <input type="submit" value="Say Hello"/>   </form></body></html>

这样,没有改变web.xml文件的需求,所以我们可以使用前面在Hello World示例章节中创建的的web.xml文件。现在,我们准备好使用Struts 2框架运行我们的Hello World应用程序了。

执行应用程序

右键单击项目名称,然后单击“Export”>“WAR File”创建WAR文件。 然后在Tomcat的webapps目录中部署这个WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp。显示的图示如下:

输入

让我们输入一个单词为“SECRET”,你会看到如下页面:

secret成功

现在输入除“SECRET”之外的任何词,你会看到如下页面:

错误

创建多个Actions

你会需要频繁定义多个action来处理不同的请求,并为用户提供不同的URL,因此你将如下定义的不同类:

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;   class MyAction extends ActionSupport{      public static String GOOD = SUCCESS;      public static String BAD = ERROR;   }   public class HelloWorld extends ActionSupport{      ...      public String execute()      {         if ("SECRET".equals(name)) return MyAction.GOOD;         return MyAction.BAD;      }      ...   }   public class SomeOtherClass extends ActionSupport{      ...      public String execute()      {         return MyAction.GOOD;      }      ...   }

你将如下在struts.xml文件中的配置这些action:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"    "http://struts.apache.org/dtds/struts-2.0.dtd">struts> <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="hello"          class="cn.51coolma.struts2.HelloWorld"          method="execute">         <result name="success">/HelloWorld.jsp</result>         <result name="error">/AccessDenied.jsp</result>      </action>      <action name="something"          class="cn.51coolma.struts2.SomeOtherClass"          method="execute">         <result name="success">/Something.jsp</result>         <result name="error">/AccessDenied.jsp</result>      </action>   </package></struts>

正如你在上面的例子中看到的,action的结果SUCCESS和ERROR是重复的。为了解决这个问题,建议您创建一个包含结果的类。


拦截器在概念上与servlet过滤器或JDK代理类相同。拦截器允许横切功能,把action以及框架分开实现。你可以使用拦截器实现以下操作:

  • 在调用action之前提供预处理逻辑。

  • 在调用action后提供后处理逻辑。

  • 捕获异常,以便可以执行备用处理。

Struts2框架中提供的许多功能都是使用拦截器实现的,包括异常处理,文件上传,生命周期回调和验证等。事实上,由于Struts2将其大部分功能基于拦截器,因此不太可能为每个action分配7个或8个拦截器。

Struts2框架拦截器

Struts 2框架提供了一个良好的开箱即用的拦截器列表,这些拦截器预先配置好并可以使用。 下面列出了几个重要的拦截器:

序号拦截器和说明
1alias

允许参数在请求之间使用不同的别名。

2checkbox

通过为未检查的复选框添加参数值false,以辅助管理复选框。

3conversionError

将字符串转换为参数类型的错误信息放置到action的错误字段中。

4createSession

自动创建HTTP会话(如果尚不存在)。

5debugging

为开发人员提供一些不同的调试屏幕。

6execAndWait

当action在后台执行时,将用户发送到中间的等待页面。

7exception

映射从action到结果抛出的异常,允许通过重定向自动处理异常。

8fileUpload

便于文件上传。

9

i18n

在用户会话期间跟踪选定的区域。

10logger

通过输出正在执行的action的名称提供简单的日志记录。

11params

设置action上的请求参数。

12prepare

这通常用于执行预处理工作,例如设置数据库连接。

13profile

允许记录action的简单分析信息。

14scope

在会话或应用程序范围内存储和检索action的状态。

15ServletConfig

提供可访问各种基于servlet信息的action。

16timer

以action执行时间的形式提供简单的分析信息。

17token

检查action的有效性,以防止重复提交表单。

18validation

提供action的验证支持。

你可以阅读Struts 2文档,了解上述拦截器的完整信息。接下来我们会告诉你如何在Struts应用程序中使用拦截器。

如何使用拦截器?

让我们看看如何在我们的“Hello World”程序中使用一个已经存在的拦截器。我们将首先使用timer拦截器,目的是测量执行action方法所需的时间。同时我们使用params拦截器,目的是将请求参数发送给action。你可以尝试不在你的例子中使用这个拦截器,然后你会发现name属性没有被设置,因为参数无法发送给action。
我们可以保留HelloWorldAction.java,web.xml,HelloWorld.jsp和index.jsp文件,因为它们已在Hellow World示例一章中创建过了,然后让我们参照下面修改struts.xml文件给它添加拦截器:

 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="hello"          class="cn.51coolma.struts2.HelloWorldAction"         method="execute">         <interceptor-ref name="params"/>         <interceptor-ref name="timer" />         <result name="success">/HelloWorld.jsp</result>      </action>   </package></struts>

右键单击项目名称,然后单击“Export”>“WAR File”创建WAR文件。然后在Tomcat的webapps目录中部署这个WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp。结果如下图所示:

输入

现在,在给定文本框中输入任意单词,然后单击Say Hello按钮执行定义的action。如果你去查看生成的日志,会看到以下文本:

INFO: Server startup in 3539 ms27/08/2011 8:40:53 PM com.opensymphony.xwork2.util.logging.commons.CommonsLogger infoINFO: Executed action [//hello!execute] took 109 ms.

这里的最后一行是由timer拦截器生成的,是表示ation总共需要109ms来执行。

创建自定义拦截器

在你的应用程序中使用自定义拦截器是提供跨切割应用程序功能的简洁方式。创建自定义拦截器很容易,需要扩展的是以下Interceptor接口:

 public interface Interceptor extends Serializable{   void destroy();   void init();   String intercept(ActionInvocation invocation)   throws Exception;}

正如name所指出的,init()方法提供了一种初始化拦截器的方法,而destroy()方法为拦截器清理提供了一个工具。与action不同,拦截器在请求之间重复使用,需要线程安全,特别是intercept()方法。
ActionInvocation对象可访问运行时的环境。它允许访问action本身以及方法来调用action,并确定action是否已被调用。
如果你不需要初始化或清理代码,可以扩展AbstractInterceptor类,以实现init()和destroy()的默认的无操作指令。

创建拦截器类

我们接下来在Java Resources>src文件夹中创建以下MyInterceptor.java文件:

 package cn.51coolma.struts2;import java.util.*;import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.interceptor.AbstractInterceptor;public class MyInterceptor extends AbstractInterceptor {   public String intercept(ActionInvocation invocation)throws Exception{      /* let us do some pre-processing */      String output = "Pre-Processing";       System.out.println(output);      /* let us call action or next interceptor */      String result = invocation.invoke();      /* let us do some post-processing */      output = "Post-Processing";       System.out.println(output);      return result;   }}

你可以发现,实际中action将通过拦截器使用invocation.invoke()调用执行,所以你可以根据你的需求做一些预处理和一些后处理。
框架本身通过第一次调用ActionInvocation对象的invoke()来启动进程。每次调用invoke()时,ActionInvocation都会查询其状态,并执行下一个拦截器。当所有配置的拦截器都被调用时,invoke()将使得action本身被执行。以下图表通过请求流显示了所说的概念:

ActionInvocation

创建Action类

我们在Java Resources>src文件夹下创建一个java文件HelloWorldAction.java,其中包名为cn.51coolma.struts2,内容如下:

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class HelloWorldAction extends ActionSupport{   private String name;   public String execute() throws Exception {      System.out.println("Inside action....");      return "success";   }     public String getName() {      return name;   }   public void setName(String name) {      this.name = name;   }}

这是我们在前面的例子中看到的同一个类,我们有“name”属性标准的getters和setter方法,以及返回字符串“success”的execute方法。

创建视图

让我们在你的eclipse项目的WebContent文件夹中创建下面的jsp文件HelloWorld.jsp

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>Hello World</title></head><body>   Hello World, <s:property value="name"/></body></html>

创建主页

我们还需要在WebContent文件夹中创建index.jsp文件,此文件将用作初始的action URL,用户可以单击它以命令Struts 2框架调用HelloWorldAction类的定义方法并呈现HelloWorld.jsp视图。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%>   <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Hello World</title></head><body>   <h1>Hello World From Struts2</h1>   <form action="hello">      <label for="name">Please enter your name</label><br/>      <input type="text" name="name"/>      <input type="submit" value="Say Hello"/>   </form></body></html>

在上述视图文件中定义的hello action将使用struts.xml文件映射到HelloWorldAction类及其execute方法中。

配置文件

现在我们需要注册新的拦截器,然后调用它,因为我们在前面的例子中调用的是默认拦截器。要注册一个新的拦截器,把<interceptors> ... </ interceptors>标签直接放置在<package>标签下的struts.xml文件中即可。对于默认拦截器,你可以跳过此步骤,就像我们前面的示例中所做的那样。但现在让我们使用以下方法注册新的:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"    "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <interceptors>         <interceptor name="myinterceptor"            class="cn.51coolma.struts2.MyInterceptor" />      </interceptors>      <action name="hello"          class="cn.51coolma.struts2.HelloWorldAction"          method="execute">         <interceptor-ref name="params"/>         <interceptor-ref name="myinterceptor" />         <result name="success">/HelloWorld.jsp</result>      </action>   </package></struts>

需要注意的是,你可以在<package>标签内注册多个拦截器,同时可以在<action>标签内调用多个拦截器,也可以用不同的action调用同一个拦截器。

web.xml文件需要在WebContent下的WEB-INF文件夹下创建,如下所示:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">      <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

右键单击项目名称,然后单击“Export”>“WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp。将显示如下图片:

输入2

现在,在给的定文本框中输入任意单词,然后单击Say Hello按钮执行定义的action。如果你查看生成的日志,会在底部看到以下文本:

Pre-ProcessingInside action....Post-Processing

拦截器堆栈

你可以想象,为每个action配置的多个拦截器将很快变得极其难以管理。为此,拦截器使用拦截器堆栈进行管理。这里是直接从struts-default.xml文件展示的一个例子:

<interceptor-stack name="basicStack">   <interceptor-ref name="exception"/>   <interceptor-ref name="servlet-config"/>   <interceptor-ref name="prepare"/>   <interceptor-ref name="checkbox"/>   <interceptor-ref name="params"/>   <interceptor-ref name="conversionError"/></interceptor-stack>

上面的堆栈称为basicStack,可以如下所述在你的配置中使用,此配置节点放置在<package ... />节点下。<interceptor-ref ... />标签引用的是在当前拦截器堆栈之前配置的拦截器或拦截器堆栈。因此非常重要的是在配置初始拦截器和拦截器堆栈时,确保name在所有拦截器和拦截器堆栈配置中是唯一的。
我们已经学习了如何将拦截器应用到action中,而拦截器堆栈的应用也是类似的。事实上,使用的标签也是一样的:

 <action name="hello" class="com.tutorialspoint.struts2.MyAction">   <interceptor-ref name="basicStack"/>   <result>view.jsp</result></action

上述的“basicStack”注册将完整注册hello action的所使用的六个拦截器。要注意的是,拦截器按照它们被配置的顺序执行。例如,在上面的例子中,exception将首先执行,第二个将是servlet-config等。


如前面所述,<results>标签在Struts2 MVC框架中扮演视图的角色。Action负责执行业务逻辑,下一步就是使用<results>标签显示视图。
通常有一些导航规则附加的结果。例如,如果action是进行验证用户,则有三种可能的结果:(a)成功登录(b)登录失败:用户名或密码不正确(c)帐户锁定。
在这种情况下,action将配置三个可能的结果字符串和三个不同的视图来渲染结果,这在我们前面的例子中已经看到过了。
但是,Struts2不绑定使用JSP作为视图技术。毕竟,MVC范例的目的是保持图层分离和高度可配置。例如,对于Web2.0客户端,你可能希望返回XML或JSON作为输出。在这种情况下,你可以为XML或JSON创建一个新的结果类型并实现这一点。
Struts提供了许多预定义的结果类型,我们已经看到的是默认的结果类型dispatcher,它用于分发到JSP页面。Struts允许你使用其他标记语言为视图技术呈现结果,较常选用的包括VelocityFreemakerXSLTTiles

dispatcher结果类型

dispatcher结果类型是默认的类型,如果未指定其他结果类型,则使用此类型。它用于转发到服务器上的servlet,JSP,HTML等页面。它使用RequestDispatcher.forward()方法。
我们在前面的示例中看到了“简写”版本,里面我们用一个JSP路径作为结果标签的主体。

<result name="success">   /HelloWorld.jsp</result>

我们还可以使用<result ...>元素中的<param name="location">标签来指定JSP文件,如下所示:

<result name="success" type="dispatcher">   <param name="location">      /HelloWorld.jsp   </param ></result>

我们还可以使用一个parse参数,默认情况下为true。parse参数确定是否将为OGNL表达式解析位置参数。

FreeMaker结果类型

在这个例子中,我们将介绍如何使用FreeMaker作为视图技术。Freemaker是一个流行的模板引擎,使用预定义的模板生成输出。让我们创建一个包含以下内容的名为hello.fm的Freemaker模板文件:

Hello World ${name}

上面的文件是一个模板,其中name是一个参数,将使用定义的action从外部传递。你可以在CLASSPATH中保留此文件。接下来,让我们参考下面修改struts.xml以指定结果:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN""http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="hello"          class="cn.51coolma.struts2.HelloWorldAction"         method="execute">         <result name="success" type="freemarker">            <param name="location">/hello.fm</param>         </result>      </action>         </package></struts>

我们继续保留之前在HelloWorld示例一章中创建的HelloWorldAction.java,HelloWorldAction.jsp和index.jsp文件。现在右键单击项目名称,然后单击“Export”>“WAR File”创建WAR文件。然后在Tomcat的webapps目录中部署这个WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp。将显示如下页面:

输入

输入值“Struts2”并提交,你可以看到以下页面

成功

这个例子中我们使用了Freemaker,可以看到,这与JSP视图完全相同,只是我们不绑定使用JSP作为视图技术。

redirect结果类型

redirect结果类型调用标准的response.sendRedirect()方法,使得浏览器向给定的位置创建一个新请求。
我们可以在<result...>元素的主体中或作为<param name="location">的元素中给定位置。redirect也支持parse参数,以下是使用XML配置的示例:

<action name="hello"    class="com.tutorialspoint.struts2.HelloWorldAction"   method="execute">   <result name="success" type="redirect">       <param name="location">         /NewWorld.jsp      </param >   </result></action>

所以只需修改你的struts.xml文件来定义上面提到的redirect结果类型,并创建一个新的文件NewWorld.jpg,那么当你的hello action返回“success”时就会产生redirect结果。你可以检查Struts 2的Redirect Action示例,以便更详细地了解。

值栈是一组对象,按照提供的顺序存储以下这些对象:

序号对象和说明
1Temporary对象

实际中存在各种在页面执行期间创建的temporary对象。例如,JSP标签循环集合的当前迭代值。

2Model对象

如果在struts应用程序中使用Model对象,则当前Model对象放在值堆栈上的action之前。

3Action对象

这是指正在执行的当前action对象。

4命名对象

这些对象包括#application,#session,#request,#attr和#parameters以及所引用的相应的servlet作用域。

值栈可以通过为JSP,Velocity或Freemarker提供的标签进行访问。我们将在单独的章节中学习到用于获取和设置struts2 值栈的各种标签。你可以在action中获取值栈对象,如下所示:

ActionContext.getContext().getValueStack()

一旦你有一个值栈对象,你可以使用以下方法来操纵该对象:

序号值栈方法和说明
1Object findValue(String expr)

通过在默认搜索顺序中对值栈评估所给定的表达式来查找值。

2CompoundRoot getRoot()

获取将对象推入值栈的CompoundRoot。

3Object peek()

获取值栈顶部的对象而不改变值栈。

4Object pop()

获取值栈顶部的对象,并将其从值栈中删除。

5void push(Object o)

将对象放在值栈的顶部。

6void set(String key,Object o)

使用给定的key在值栈上设置一个对象,使其可通过findValue(key,...)检索。

7void setDefaultType(Class defaultType)

设置在获取值时要转换的默认类型。

8void setValue(String expr,Object value)

尝试使用由默认搜索顺序给定的表达式在值栈的bean上设置属性。

9int size()

获取值栈中的对象数。

OGNL

OGNL(Object-Graph Navigation Language,对象图导航语言)是一种强大的表达式语言,用于引用和操作值栈上的数据,还可用于数据传输和类型转换。
OGNL非常类似于JSP表达式语言。OGNL基于上下文中存有根对象或默认对象的理念,使用标记符号(即#号)来引用默认或根对象的属性。
如前面所述,OGNL是基于上下文的,而Struts构建了一个ActionContext映射以供OGNL使用。 ActionContext映射包含以下内容:

  • 应用程序 - 应用程序作用域变量

  • 会话 - 会话作用域变量

  • 根/值栈 - 所有的action变量都存储在这里

  • 请求 - 请求作用域变量

  • 参数 - 请求参数

  • 属性 - 存储在页面,请求,会话和应用程序作用域中的属性

有必要了解的是,Action对象在值栈中总是可用的,因此如果你的Action对象有x和y属性,你可以随时使用。
ActionContext中的对象使用#号引用,但是,值栈中的对象可以直接引用,例如,如果employee是action类的属性,则可以按如下方式引用:

  <s:property value="name"/>

替代

  <s:property value="#name"/>

如果你在会话中有一个名为“login”的属性,你可以按如下方式检索:

  <s:property value="#session.login"/>

OGNL还支持处理集合 - 即Map,List和Set。例如,要显示颜色的下拉列表,你可以执行以下操作:

  <s:select name="color" list="{'red','yellow','green'}" />

OGNL表达式很智能地将“红色”,“黄色”,“绿色”解释为颜色,并基于此构建了列表。
在下一章我们学习各种的标签时,OGNL表达式将会广泛的用到。因此,不要用孤立的方式去了解OGNL,让我们结合Form标签/Control标签/Data标签和Ajax标签部分中的一些示例来了解它。

值栈/ OGNL示例

创建Action:

让我们参考下面用于访问值栈的action类,然后在ie.JSP视图页面设置使用OGNL进行访问的几个key。

package cn.51coolma.struts2;import java.util.*; import com.opensymphony.xwork2.util.ValueStack;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionSupport;public class HelloWorldAction extends ActionSupport{   private String name;   public String execute() throws Exception {      ValueStack stack = ActionContext.getContext().getValueStack();      Map<String, Object> context = new HashMap<String, Object>();      context.put("key1", new String("This is key1"));       context.put("key2", new String("This is key2"));      stack.push(context);      System.out.println("Size of the valueStack: " + stack.size());      return "success";   }     public String getName() {      return name;   }   public void setName(String name) {      this.name = name;   }}

实际上,Struts 2在执行时会将action添加到值栈的顶部。所以,通常放置东西在值栈的方法是添加getters/setters的值到Action类,然后使用<s:property>标签访问值。我们前面已展示了ActionContext和值栈在struts中的工作原理。

创建视图

在你的eclipse项目的WebContent文件夹中创建下面的jsp文件HelloWorld.jsp,如果action返回为success将显示视图:

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>Hello World</title></head><body>   Entered value : <s:property value="name"/><br/>   Value of key 1 : <s:property value="key1" /><br/>   Value of key 2 : <s:property value="key2" /> <br/></body></html>

我们还需要在WebContent文件夹中创建index.jsp文件,其内容如下:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%>   <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Hello World</title></head><body>   <h1>Hello World From Struts2</h1>   <form action="hello">      <label for="name">Please enter your name</label><br/>      <input type="text" name="name"/>      <input type="submit" value="Say Hello"/>   </form></body></html>

配置文件

以下是struts.xml文件的内容:

 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"    "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="hello"          class="cn.51coolma.struts2.HelloWorldAction"          method="execute">         <result name="success">/HelloWorld.jsp</result>      </action>   </package></struts>

以下是web.xml文件的内容:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">      <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

右键单击项目名称,然后单击“Export”>“WAR File”创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp。将显示如下界面:

输入

现在,在给定的文本框中输入任意单词,然后单击“Say Hello”按钮执行定义的action。如果你查看生成的日志,可以在底部看到以下文本:

 Size of the valueStack: 3

这意味着它将显示你输入的任何值和我们放在值栈上的key1和key2的值。

Struts2 框架为依据“基于表单的HTML文件上传”所进行的文件处理上传提供了内置支持。当文件上传时,它通常会存储在临时目录中,然后Action类应对其进行处理或移动到固定目录中,以确保数据不会丢失。
注意:服务器可能有适当的安全策略,禁止你写入临时目录以外的目录以及属于Web应用程序的目录。
通过一个名为FileUpload的预定义拦截器可以在Struts中上传文件,该拦截器可通过org.apache.struts2.interceptor.FileUploadInterceptor类获得,并作为defaultStack的一部分包含在内。你也将在接下来的内容中看到如何使用它在struts.xml文件中设置各种参数。

创建视图文件

创建视图时需要浏览和上传选定的文件。因此,让我们先使用HTML上传表单,创建一个允许用户上传文件的index.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>File Upload</title></head><body>   <form action="upload" method="post" enctype="multipart/form-data">      <label for="myFile">Upload your file</label>      <input type="file" name="myFile" />      <input type="submit" value="Upload"/>   </form></body></html>

在上面的例子中有几点值得注意。首先,表单的enctype设置为multipart/form-data,要使得文件上传拦截器成功处理文件上传,这个就必须设置。然后要注意的是表单的action方法上传和文件上传字段的名称(即myFile)。我们需要这些信息来创建action方法和struts配置。
接下来让我们创建一个简单的jsp文件success.jsp来显示我们文件上传成功后的结果。

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>File Upload Success</title></head><body>You have successfully uploaded <s:property value="myFileFileName"/></body></html>

以下是结果文件error.jsp,一旦上传文件出错时会使用:

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>File Upload Error</title></head><body>There has been an error in uploading the file.</body></html>

创建Action类

接下来,让我们创建一个名为uploadFile.java的Java类,它将负责上传文件并将文件存储在安全的位置:

package cn.51coolma.struts2;import java.io.File;import org.apache.commons.io.FileUtils;import java.io.IOException; import com.opensymphony.xwork2.ActionSupport;public class uploadFile extends ActionSupport{   private File myFile;   private String myFileContentType;   private String myFileFileName;   private String destPath;   public String execute()   {      /* Copy file to a safe location */      destPath = "C:/apache-tomcat-6.0.33/work/";      try{     	 System.out.println("Src File name: " + myFile);     	 System.out.println("Dst File name: " + myFileFileName);     	    	      	 File destFile  = new File(destPath, myFileFileName);    	 FileUtils.copyFile(myFile, destFile);        }catch(IOException e){         e.printStackTrace();         return ERROR;      }      return SUCCESS;   }   public File getMyFile() {      return myFile;   }   public void setMyFile(File myFile) {      this.myFile = myFile;   }   public String getMyFileContentType() {      return myFileContentType;   }   public void setMyFileContentType(String myFileContentType) {      this.myFileContentType = myFileContentType;   }   public String getMyFileFileName() {      return myFileFileName;   }   public void setMyFileFileName(String myFileFileName) {      this.myFileFileName = myFileFileName;   }}

uploadFile.java是一个非常简单的类。要注意的重点是,FileUpload拦截器和Parameters拦截器为我们承担了所有的重工作量。默认情况下,FileUpload拦截器为你提供三个参数,它们分别按以下方式命名:

  • [文件名参数] - 这是用户已上传的实际文件。在这个例子中它将是“myFile”

  • [文件名参数]ContentType - 这是上传的文件的内容类型。在这个例子中,它将是“myFileContentType”

  • [文件名参数]FileName - 这是上传的文件的名称。在这个例子中,它将是“myFileFileName”

得益于Struts拦截器这三个参数均可供我们使用。我们要做的是在Action类中创建三个带有正确名称的参数,并使这些变量可以自动连接。所以,在上面的例子中,我们有三个参数和一个action方法。如果一切正常,则返回“success”,否则返回“error”。

配置文件

以下是控制文件上传过程的Struts2 配置属性:

序号属性和说明
1struts.multipart.maxSize

可接受的上传文件的最大值(以字节为单位),默认值为250M。

2struts.multipart.parser

用于上传多部分表单的库,默认为jakarta

3struts.multipart.saveDir

存储临时文件的位置,默认是javax.servlet.context.tempdir。

你可以在应用程序的struts.xml文件中使用constant标签更改任意一个这些设置,我们可以看以下struts.xml的示例:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN""http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <constant name="struts.multipart.maxSize" value="1000000" />   <package name="helloworld" extends="struts-default">   <action name="upload" class="cn.51coolma.struts2.uploadFile">       <result name="success">/success.jsp</result>       <result name="error">/error.jsp</result>   </action>   </package></struts>

因为FileUpload拦截器是defaultStack拦截器的一部分,我们不需要准确的配置它,但你可以在<action>中添加<interceptor-ref>标签。fileUpload拦截器有两个参数:maximumSizeallowedTypes。 maximumSize参数是设置所允许的文件大小的最大值(默认约为2MB)。allowedTypes参数是所允许的内容(MIME)类型的用逗号分隔的列表,如下所示:

   <action name="upload" class="cn.51coolma.struts2.uploadFile">       <interceptor-ref name="basicStack">       <interceptor-ref name="fileUpload">           <param name="allowedTypes">image/jpeg,image/gif</param>       </interceptor-ref>       <result name="success">/success.jsp</result>       <result name="error">/error.jsp</result>   </action>

以下是web.xml文件的内容:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">      <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

现在右键单击项目名称,然后单击“Export”>“WAR File”创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/upload.jsp,将显示如下界面:

输入

现在使用浏览按钮选择一个文件“Contacts.txt”,然后点击上传按钮,上传文件到服务器,你将看到如下页面。你上传的文件应该保存在C:apache-tomcat-6.0.33work下。

成功

注意:FileUpload拦截器会自动删除上传的文件,因此你必须在上传的文件被删除之前将其以编程方式保存在某个位置。

错误信息

fileUplaod拦截器使用几个默认的错误信息key:

序号错误信息key和说明
1struts.messages.error.uploading

无法上传文件时发生的常规错误。

2struts.messages.error.file.too.large

当上传的文件过大(由maximumSize指定)时发生。

3struts.messages.error.content.type.not.allowed

当上传的文件与指定的预期内容类型不匹配时发生。

你可以在WebContent/WEB-INF/classes/messages.properties资源文件中覆盖这些消息文本。

本章内容将告诉你如何使用Struts2 的简单步骤访问数据库。Struts是一个MVC框架,而不是一个数据库框架,但它提供了对JPA/Hibernate集成的出色支持。我们会在后面的章节中讨论hibernate集成,但在本章中,我们将使用旧的JDBC来访问数据库。
首先第一步是设置和初始化数据库,这个例子中我们使用MySQL作为数据库。如果有在机器上安装MySQL,那么就创建一个名为“struts_tutorial”的新数据库。然后创建一个名为login的表,并用一些值填充它。下面是用来创建和填充表的脚本。
MYSQL数据库有默认用户名“root”和“root123”密码

CREATE TABLE `struts_tutorial`.`login` (   `user` VARCHAR( 10 ) NOT NULL ,   `password` VARCHAR( 10 ) NOT NULL ,   `name` VARCHAR( 20 ) NOT NULL ,   PRIMARY KEY ( `user` )) ENGINE = InnoDB;INSERT INTO `struts_tutorial`.`login` (`user`, `password`, `name`) VALUES ('scott', 'navy', 'Scott Burgemott');

下一步是下载MySQL Connector 的jar文件,并将此文件放在项目的WEB-INFlib文件夹中。做好这个后,我们开始准备创建action类。

创建Action

Action类具有与数据库表中的列对应的属性。我们有userpasswordname作为String属性。在action方法中,我们使用user和password参数来检查用户是否存在,如果存在,则在下一个界面中显示用户名。如果用户输入错误的信息,则会再次将其发送到登录界面。以下是LoginAction.java文件的内容:

package cn.51coolma.struts2;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import com.opensymphony.xwork2.ActionSupport;public class LoginAction extends ActionSupport {   private String user;   private String password;   private String name;   public String execute() {      String ret = ERROR;      Connection conn = null;      try {         String URL = "jdbc:mysql://localhost/struts_tutorial";         Class.forName("com.mysql.jdbc.Driver");         conn = DriverManager.getConnection(URL, "root", "root123");         String sql = "SELECT name FROM login WHERE";         sql+=" user = ? AND password = ?";         PreparedStatement ps = conn.prepareStatement(sql);         ps.setString(1, user);         ps.setString(2, password);         ResultSet rs = ps.executeQuery();         while (rs.next()) {            name = rs.getString(1);            ret = SUCCESS;         }      } catch (Exception e) {         ret = ERROR;      } finally {         if (conn != null) {            try {               conn.close();            } catch (Exception e) {            }         }      }      return ret;   }   public String getUser() {      return user;   }   public void setUser(String user) {      this.user = user;   }   public String getPassword() {      return password;   }   public void setPassword(String password) {      this.password = password;   }   public String getName() {      return name;   }   public void setName(String name) {      this.name = name;   }}

创建主页

现在,让我们创建一个JSP文件index.jsp来收集用户名和密码,将针对数据库检查这些用户名和密码。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Login</title></head><body>   <form action="loginaction" method="post">      User:<br/><input type="text" name="user"/><br/>      Password:<br/><input type="password" name="password"/><br/>      <input type="submit" value="Login"/>		   </form></body></html>

创建视图:

现在先创建success.jsp文件,这在action返回SUCCESS结果的情况下会被调用,但如果从action返回ERROR结果,我们将用另一个视图文件。

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>Successful Login</title></head><body>   Hello World, <s:property value="name"/></body></html>

以下将是在action返回ERROR的情况下调用的视图文件error.jsp

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>Invalid User Name or Password</title></head><body>   Wrong user name or password provided.</body></html>

配置文件

最后,让我们使用struts.xml配置文件将所有内容放在一起,如下所示:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN""http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">         <action name="loginaction"          class="cn.51coolma.struts2.LoginAction"         method="execute">         <result name="success">/success.jsp</result>         <result name="error">/error.jsp</result>      </action>      </package></struts>

以下是web.xml文件的内容:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">      <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp,将显示以下界面:

Hello World的Struts

输入错误的用户名和密码,你看到以下页面:

错误

现在输入scott作为用户名,navy作为密码,可以应该看到以下页面:

成功

本章内容将教你如何使用Struts2 应用程序发送电子邮件。学习前,你需要从JavaMail API 1.4.4下载并安装mail.jar,并将mail.jar文件放在WEB-INFlib文件夹中,然后继续按照以下标准步骤创建action,视图和配置文件。

创建Action

首先是创建一个Action方法来处理电子邮件发送。让我们创建一个包含以下内容的名为Emailer.java的新类:

package cn.51coolma.struts2;import java.util.Properties;import javax.mail.Message;import javax.mail.PasswordAuthentication;import javax.mail.Session;import javax.mail.Transport;import javax.mail.internet.InternetAddress;import javax.mail.internet.MimeMessage;import com.opensymphony.xwork2.ActionSupport;public class Emailer extends ActionSupport {   private String from;   private String password;   private String to;   private String subject;   private String body;   static Properties properties = new Properties();   static   {      properties.put("mail.smtp.host", "smtp.gmail.com");      properties.put("mail.smtp.socketFactory.port", "465");      properties.put("mail.smtp.socketFactory.class",                     "javax.net.ssl.SSLSocketFactory");      properties.put("mail.smtp.auth", "true");      properties.put("mail.smtp.port", "465");   }   public String execute()    {      String ret = SUCCESS;      try      {         Session session = Session.getDefaultInstance(properties,              new javax.mail.Authenticator() {            protected PasswordAuthentication             getPasswordAuthentication() {            return new             PasswordAuthentication(from, password);            }});         Message message = new MimeMessage(session);         message.setFrom(new InternetAddress(from));         message.setRecipients(Message.RecipientType.TO,             InternetAddress.parse(to));         message.setSubject(subject);         message.setText(body);         Transport.send(message);      }      catch(Exception e)      {         ret = ERROR;         e.printStackTrace();      }      return ret;   }   public String getFrom() {      return from;   }   public void setFrom(String from) {      this.from = from;   }   public String getPassword() {      return password;   }   public void setPassword(String password) {      this.password = password;   }   public String getTo() {      return to;   }   public void setTo(String to) {      this.to = to;   }   public String getSubject() {      return subject;   }   public void setSubject(String subject) {      this.subject = subject;   }   public String getBody() {      return body;   }   public void setBody(String body) {      this.body = body;   }   public static Properties getProperties() {      return properties;   }   public static void setProperties(Properties properties) {      Emailer.properties = properties;   }}

如上面的源代码所示,Emailer.java具有与下面给出的email.jsp页面中的表单属性相对应的属,这些属性分别是:

  • from - 发件人的电子邮件地址。由于我们使用Google的SMTP,因此我们需要有效的gtalk ID。

  • password - 上述帐户的密码

  • to - 发送电子邮件给谁?

  • Subject - 电子邮件的主题

  • body - 实际的电子邮件内容

我们没有考虑对上述字段的任何验证,验证将在下一章添加。让我们看看execute()方法, execute()方法使用javax Mail库提供的参数发送电子邮件。如果邮件成功发送,action返回SUCCESS,否则返回ERROR。

创建主页

现行编写主页的JSP文件index.jsp,这将用于收集上面提到的电子邮件相关信息:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Email Form</title></head><body>   <em>The form below uses Google's SMTP server.    So you need to enter a gmail username and password   </em>   <form action="emailer" method="post">   <label for="from">From</label><br/>   <input type="text" name="from"/><br/>   <label for="password">Password</label><br/>   <input type="password" name="password"/><br/>   <label for="to">To</label><br/>   <input type="text" name="to"/><br/>   <label for="subject">Subject</label><br/>   <input type="text" name="subject"/><br/>   <label for="body">Body</label><br/>   <input type="text" name="body"/><br/>   <input type="submit" value="Send Email"/>   </form></body></html>

创建视图

现在创建success.jsp文件,这在action返回SUCCESS结果的情况下会被调用,但如果从action返回ERROR结果,我们将用另一个视图文件。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"	pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Email Success</title></head><body>   Your email to <s:property value="to"/> was sent successfully.</body></html>

以下将是在action返回ERROR的情况下调用的视图文件error.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"	pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Email Error</title></head><body>   There is a problem sending your email to <s:property value="to"/>.</body></html>

配置文件

最后,让我们使用struts.xml配置文件将所有内容放在一起,如下所示:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="emailer"          class="cn.51coolma.struts2.Emailer"         method="execute">         <result name="success">/success.jsp</result>         <result name="error">/error.jsp</result>      </action>   </package></struts>

以下是web.xml文件的内容:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">      <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp,将显示以下界面:

电子邮件用户输入

输入所需的信息,然后单击Send Email按钮。如果一切正常,那么你可以看到以下页面:

电子邮件成功

这章我们将研究Struts的验证框架。Struts的核心中的验证框架,可在执行action方法之前,帮助应用程序运行规则执行验证。
客户端验证通常使用Javascript实现,但是不能仅仅依赖于客户端验证。实践表明,应该在应用程序框架的所有级别引入验证。接下来让我们看一下给Struts项目添加验证的两种方法。
我们举一个Employee的例子,employee的名字和年龄将使用一个简单的页面捕获,我们会进行两次验证,以确保用户始终输入一个名称,并且年龄是在28和65之间。那么让我们先从示例的JSP主页面开始。

创建主页

我们接下来编写用于收集employee的相关信息的JSP文件index.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Employee Form</title></head><body>   <s:form action="empinfo" method="post">      <s:textfield name="name" label="Name" size="20" />      <s:textfield name="age" label="Age" size="20" />      <s:submit name="submit" label="Submit" align="center" />   </s:form></body></html>

index.jsp使用Struts标签,目前我们还没有学习到,不过会在标签相关的章节中学习它们。现在,假设s:textfield标签印出一个输入框,并且s:submit印出一个提交按钮。我们为每个标签使用了label属性,即为每个标签创建label。

创建视图

我们将使用在action返回SUCCESS的情况下调用的JSP文件success.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"	pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Success</title></head><body>   Employee Information is captured successfully.</body></html>

创建Action

那么,让我们定义一个小的action类:Employee,然后添加一个名为validate()的方法,如下Employee.java文件所示。确保action类扩展了ActionSupport类,否则将不会执行validate方法。

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class Employee extends ActionSupport{   private String name;   private int age;      public String execute()    {       return SUCCESS;   }   public String getName() {       return name;   }   public void setName(String name) {       this.name = name;   }   public int getAge() {       return age;   }   public void setAge(int age) {       this.age = age;   }   public void validate()   {      if (name == null || name.trim().equals(""))      {         addFieldError("name","The name is required");      }      if (age < 28 || age > 65)      {         addFieldError("age","Age must be in between 28 and 65");      }   }}

如上例所示,验证方法首先检查“Name”字段是否具有值。如果没有任何值,则会为“Name”字段添加一个字段“错误”,并显示自定义的错误消息。其次,检查“年龄”字段的输入值是否在28和65之间,如果不符合这个条件,我们在验证字段之上添加一个错误。

配置文件

最后,让我们使用struts.xml配置文件将所有内容放在一起,如下所示:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="empinfo"          class="cn.51coolma.struts2.Employee"         method="execute">         <result name="input">/index.jsp</result>         <result name="success">/success.jsp</result>      </action>   </package></struts>

以下是web.xml文件的内容:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"   xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">   <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp,将显示以下界面:

电子邮件用户输入

现在不输入任何信息,只点击Submit按钮,将看到以下结果:

错误

输入所要求的信息而非错误类的字段,如名称为“text”,年龄为30,然后点击Submit按钮,可以看到以下界面:

成功

这个验证是如何进行的?

当用户按下提交按钮时,Struts2 将自动执行validate方法,如果方法中列出的任何if语句为真,Struts2 将调用addFieldError方法。如果添加了任何错误信息,Struts2 将不会调用execute方法。否则,Struts2 框架将返回input作为调用操作的结果。
因此,当验证失败并且Struts2 返回input时,Struts2 框架将重新显示index.jsp文件。由于我们使用Struts2 的form标签,Struts2 会自动在form字段上方添加错误信息。
这些错误信息是我们在addFieldError方法调用中指定的信息。addFieldError方法接受两个参数,第一个是出错时应用的form字段名称,第二个是在form字段上方显示的错误信息。

addFieldError("name","The name is required");

要处理input的返回值,我们需要将以下结果添加到struts.xml中的action节点。

<result name="input">/index.jsp</result>

XML验证

第二种进行验证的方法是在action类旁边放置一个xml文件。Struts2 基于XML的验证提供了更多的验证方式,如email验证、integer range验证、form验证、expression验证、regex验证、required验证、requiredstring验证、stringlength验证等。
xml文件需要命名为'[action-class]'-validation.xml。因此,在我们的示例中,创建了一个名为Employee-validation.xml的文件,其含以下内容:

<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN""http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"><validators>   <field name="name">      <field-validator type="required">         <message>            The name is required.         </message>      </field-validator>   </field>   <field name="age">     <field-validator type="int">         <param name="min">29</param>         <param name="max">64</param>         <message>            Age must be in between 28 and 65         </message>      </field-validator>   </field></validators>

上面的XML文件将保存在CLASSPATH中,理想情况下是与类文件一起保存。以下是没有validate()方法的Employee action类:

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class Employee extends ActionSupport{   private String name;   private int age;      public String execute()    {       return SUCCESS;   }   public String getName() {       return name;   }   public void setName(String name) {       this.name = name;   }   public int getAge() {       return age;   }   public void setAge(int age) {       this.age = age;   }}

其余的设置将保持,如同前面的例子一样。现在如果你运行应用程序,它将产生与我们前面例子相同的结果。

使用xml文件来存储配置的优点是允许验证与应用程序代码分离。你可以让开发人员编写代码,让测试人员来创建xml验证文件。另一个需要注意的是默认情况下可用的验证器。Struts有许多默认的验证器,常见的包括:Date验证器,Regex验证器和String Length验证器。点击以下链接可以了解更多“Struts2-XML验证器”的详细信息。

国际化(i18n)是规划和实施产品和服务以便更好地适应特定的当地语言和文化的过程,也就是本地化过程,而国际化过程有时也被称为翻译或本地化实现。国际化缩写为i18n,单词以i开头,以n结尾,是因为在第一个i和最后一个n之间有18个字符。
Struts2使用bundle资源束、拦截器和标签库提供本地化,即国际化(i18n)支持,主要用在以下几个地方:

  • UI标签

  • 信息和错误。

  • Action类。

资源束

Struts2使用资源束为Web应用程序的用户提供多种语言和区域的设置选项。你不必担心需要用不同的语言编写页面,你需要做的只是为每种你想要的语言创建一个资源束。资源束将包含用户语言中的标题,消息和其他文本,是包含应用程序默认语言的一对key/value的文件。
资源文件最简单的命名格式是:

bundlename_language_country.properties

这里的bundlename可以是ActionClass,Interface,SuperClass,Model,Package,Global资源属性。下一部分language_country表示国家区域设置,例如西班牙语(西班牙)区域设置由es_ES表示,英语(美国)区域设置由en_US表示等。这里先跳过可选国家的部分。
当你通过key引用消息元素时,Struts框架按以下顺序搜索相应的信息束:

  • ActionClass.properties

  • Interface.properties

  • SuperClass.properties

  • model.properties

  • package.properties

  • struts.properties

  • global.properties

要以多种语言开发应用程序,你必须维护与这些语言/区域设置对应的多个属性文件,并根据每对key/value定义所有内容。例如,如果你要开发美国英语(默认),西班牙语和法语的应用程序,必须创建三个属性文件。这里我们将使用global.properties文件,你也可以使用不同的属性文件来分离不同类型的信息。

  • global.properties:默认情况下使用英语(美国)

  • global_fr.properties:这将用于法语环境。

  • global_es.properties:这将用于西班牙语环境。

访问信息

有几种方法来访问信息资源,包括getText,text标签,UI标签的key属性和i18n标签。接下来让我们简要了解一下:

显示i18n文本,需在property标签或其他任何标签(如UI标签)中调用getText,如下所示:

<s:property value="getText('some.key')" />

text标签从默认资源束(即struts.properties)中检索信息:

<s:text name="some.key" />

i18n标签会将任意资源束推送到值栈,而i18n标签内的其他标签可以显示来自该资源束的信息:

<s:i18n name="some.package.bundle">     <s:text name="some.key" /></s:i18n>

大多数UI标签的key属性可用于从资源束检索信息:

<s:textfield key="some.key" name="textfieldName"/>

本地化示例

现在,让我们用多种语言创建前一章中的index.jsp文件,如下所示:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Employee Form with Multilingual Support</title></head><body>   <h1><s:text name="global.heading"/></h1>   <s:url id="indexEN" namespace="/" action="locale" >      <s:param name="request_locale" >en</s:param>   </s:url>   <s:url id="indexES" namespace="/" action="locale" >      <s:param name="request_locale" >es</s:param>   </s:url>   <s:url id="indexFR" namespace="/" action="locale" >      <s:param name="request_locale" >fr</s:param>   </s:url>   <s:a href="%{indexEN}" >English</s:a>   <s:a href="%{indexES}" >Spanish</s:a>   <s:a href="%{indexFR}" >France</s:a>   <s:form action="empinfo" method="post" namespace="/">      <s:textfield name="name" key="global.name" size="20" />      <s:textfield name="age" key="global.age" size="20" />      <s:submit name="submit" key="global.submit" />   </s:form></body></html>

现在创建success.jsp文件,这个文件在action返回SUCCESS结果的情况下会被调用。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"	pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Success</title></head><body>   <s:property value="getText('global.success')" /></body></html>

这里我们需要创建以下两个action。(a)第一个action处理区域设置并显示使用不同语言的同一个index.jsp文件;(b)另一个action是负责提交表单本身。这两个action都将返回SUCCESS,但我们将根据返回值采取不同的action,因为这两个action的目的是不同的:

区域设置Action

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class Locale extends ActionSupport{   public String execute()    {       return SUCCESS;   }}

提交表单Action

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class Employee extends ActionSupport{   private String name;   private int age;      public String execute()    {       return SUCCESS;   }      public String getName() {       return name;   }   public void setName(String name) {       this.name = name;   }   public int getAge() {       return age;   }   public void setAge(int age) {       this.age = age;   }}

现在,让我们创建以下三个global.properties文件并放入CLASSPATH:

global.properties

global.name = Nameglobal.age = Ageglobal.submit = Submitglobal.heading = Select Localeglobal.success = Successfully authenticated

global_fr.properties

global.name = Nom d'utilisateur global.age = l'âgeglobal.submit = Soumettre desglobal.heading = Sé lectionnez Localglobal.success = Authentifi	é  avec succès

global_es.properties

global.name = Nombre de usuarioglobal.age = Edadglobal.submit = Presentarglobal.heading = seleccionar la configuracion regionalglobal.success = Autenticado correctamente

我们接着创建包含两个action的struts.xml文件,如下所示:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <constant name="struts.custom.i18n.resources" value="global" />   <package name="helloworld" extends="struts-default" namespace="/">      <action name="empinfo"          class="cn.51coolma.struts2.Employee"         method="execute">         <result name="input">/index.jsp</result>         <result name="success">/success.jsp</result>      </action>            <action name="locale"          class="cn.51coolma.struts2.Locale"         method="execute">         <result name="success">/index.jsp</result>      </action>   </package></struts>

以下是web.xml文件的内容:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"   xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">   <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp,将显示以下界面:

英语输出

现在可选择任意语言,如果选择西班牙语,会显示以下结果:

西班牙输出

你也可以尝试用法语。最后,点击Submit按钮,当在西班牙语环境时,会显示以下界面:

成功

恭喜,你现在有了多语言的网页,可以在尝试在全球推送你的网站。

HTTP请求上的所有内容都按协议处理为字符串,包括数字,布尔值,整数,日期,小数和其他。对HTTP来说,每个事件都是一个字符串。但是,在Struts类中,你可以具有任意数据类型的属性。我们如何让Struts自动匹配属性呢?
Struts使用各种类型的转换器在幕后做了许多繁重的工作。例如,如果你的Action类中有一个integer属性,你不需要执行任何操作,Struts会自动将请求参数转换为integer属性。默认情况下,Struts提供了多个类型的转换器。其中一些列出如下,如果你使用其中一个,那你就不用担心什么了:

  • Integer,Float,Double,Decimal

  • Date,Datetime

  • Arrays,Collections

  • Enumerations

  • Boolean

  • BigDecimal

有时,当你使用自己的数据类型时,有必要添加自己的转换器,以使Struts知道如何在显示之前转换这些值。可以考虑使用下面的POJO类Environment.java

package cn.51coolma.struts2;public class Environment {   private String name;   public  Environment(String name)   {      this.name = name;   }   public String getName() {      return name;   }   public void setName(String name) {      this.name = name;   }}

这是一个非常简单的类,它有一个name属性,除此之外没有什么特别的。让我们接下来创建另一个包含系统信息的类:SystemDetails.java。 出于练习的目的,我们是将环境硬编码为“开发”,操作系统为“Windows XP SP3”。而在实际项目中,你会从系统配置中获取这些信息。那么让我们先创建以下action类:

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class SystemDetails extends ActionSupport {   private Environment environment = new Environment("Development");   private String operatingSystem = "Windows XP SP3";   public String execute()   {      return SUCCESS;   }   public Environment getEnvironment() {      return environment;   }   public void setEnvironment(Environment environment) {      this.environment = environment;   }   public String getOperatingSystem() {      return operatingSystem;   }   public void setOperatingSystem(String operatingSystem) {      this.operatingSystem = operatingSystem;   }}

接着让我们创建一个简单的JSP文件System.jsp来显示环境和操作系统信息。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>System Details</title></head><body>   Environment: <s:property value="environment"/><br/>   Operating System:<s:property value="operatingSystem"/></body></html>

让我们使用struts.xml连接system.jspSystemDetails.java类。 SystemDetails类有一个简单的可返回字符串“SUCCESS”的execute()方法。

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"    "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="system"             class="com.tutorialspoint.struts2.SystemDetails"             method="execute">         <result name="success">/System.jsp</result>      </action>   </package></struts>

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/system.action,将显示以下界面:

系统信息

上面的输出有什么问题? Struts知道如何显示和转换“Windows XP SP3”字符串和其他内置数据类型,但它不知道如何处理Environment类型的属性。所以,它只是简单地在类上调用了toString()方法。为了解决这个问题,让我们现在为Environment类创建和注册一个简单的TypeConverter。创建一个名为EnvironmentConverter.java的类,包含有以下内容:

package cn.51coolma.struts2;import java.util.Map;import org.apache.struts2.util.StrutsTypeConverter;   public class EnvironmentConverter extends StrutsTypeConverter {      @Override      public Object convertFromString(Map context, String[] values,                                       Class clazz) {      Environment env = new Environment(values[0]);      return env;   }   @Override   public String convertToString(Map context, Object value) {      Environment env  = (Environment) value;      return env == null ? null : env.getName();   }	}

EnvironmentConverter扩展了StrutsTypeConverter类,并告诉Struts如何通过覆盖convertFromString()convertToString()两个方法将Environment转换为String,反之亦然。 现在,让我们在使用前先在应用程序中注册这个转换器,有两种方式注册转换器。如果转换器将只在特定的操作中使用,那么你必须创建一个命名为'[action-class]'-conversion.properties的属性文件,所以,在我们的例子中,创建了一个包含以下注册表的名为SystemDetails-converstion.properties文件:

environment=cn.51coolma.struts2.EnvironmentConverter

在上面的例子中,“environment”是SystemDetails.java类中属性的名称,用以告诉Struts使用EnvironmentConverter来转换这个属性。但是,我们的做法将会相反,我们会全局注册这个转换器,以便它可以在整个应用程序中使用。因此,需要在WEB-INF/classes文件夹中创建一个名为xwork-conversion.properties的属性文件,使用以下内容:

cn.51coolma.struts2.Environment =             cn.51coolma.struts2.EnvironmentConverter

这简单地将转换器进行了全局注册,使得Struts可以在每次遇到类型为Environment的对象时自动执行转换。现在,如果你重新编译并重新运行程序,你会得到一个更好的输出结果,如下所示:

系统信息

显然,现在的结果是更好的,这意味着我们的Struts转换器工作正常。这就是如何根据你的要求创建多个转换器和注册使用它们。

开始本章的内容学习之前,让我们看看http://struts.apache.org给出的几个定义:

术语描述
tag(标签)从JSP,FreeMarker或Velocity内部执行的一小段代码。
template(模板)一些代码,通常是写在FreeMarker上的,可以由某些标签(HTML标签)呈现。
theme(主题)封装在一起以提供公共功能的模板集合。

我们建议再回顾一下Struts2本地化/国际化(i18n)章节,因为我们将再次使用同样的例子来进行练习。

当你在Web页面中使用Struts2 标签(如<s:submit...>,<s:textfield...>等)时,Struts2 框架会生成具有预配置样式和布局的HTML代码。Struts2 具有三个内置主题:

Theme(主题)描述
simple theme没有“bells and whistles”的最小主题。例如,textfield标签呈现HTML<input/>标签无标记、验证、错误报告或任何其他格式或功能。
xhtml theme这是Struts 2使用的默认主题,提供了simple theme具备的所有基础,并添加了几个功能,如HTML的标准两列表布局、每个HTML的标记、验证和错误报告等。
css_xhtml theme这个主题提供了simple theme具备的所有基础,并添加了几个功能,如基于CSS的标准两列布局,对HTML Struts标签使用<div>,HTML Struts每个标签的标记,根据CSS样式表放置等。

如上所述,如果你不指定一个主题,那么Struts2 将默认使用xhtml theme。例如这个Struts2选择标签:

<s:textfield name="name" label="Name" />

生成以下HTML标记:

<tr><td class="tdLabel">   <label for="empinfo_name" class="label">Name:</label></td><td>   <input type="text" name="name" value="" id="empinfo_name"/></td></tr>

这里empinfo是在struts.xml文件中定义的action名称。

选择主题

你可以在每个Struts2 标签的基础上指定主题,也可以使用以下方法之一指定Struts2 应使用的主题:

  • 特定标签上的theme属性

  • 标签的周边表单标签的theme属性

  • 名为“theme”的页面作用域属性

  • 名为“theme”的请求作用域属性

  • 名为“theme”的会话作用域属性

  • 名为“theme”的应用程序作用域属性

  • struts.properties中的struts.ui.theme属性(默认为xhtml)

以下是在标签级别指定它们的语法,如果你愿意为不同的标签使用不同的主题:

<s:textfield name="name" label="Name" theme="xhtml"/>

因为在每个标签的基础上使用主题并不是很实用,所以只需使用以下标签就可以在struts.properties文件中指定规则:

# Standard UI themestruts.ui.theme=xhtml# Directory where theme template residesstruts.ui.templateDir=template# Sets the default template type. Either ftl, vm, or jspstruts.ui.templateSuffix=ftl

下面是我们从本地化章节中选择的结果,我们在struts-default.properties文件中使用了默认主题,设置为struts.ui.theme=xhtml,该文件默认情况下位于struts2-core.xy.z.jar文件中。

输出

主题是如何工作的?

对于给定的主题,每个struts标签都有一个关联的模板,如s:textfield -> text.ftls:password -> password.ftl等。这些模板文件压缩在struts2-core.xy.z.jar文件中,它们为每个标签保留预定义的HTML布局。因此Struts2 框架使用Sturts标签和相关模板生成最终的HTML标记代码。

Struts 2 tags + Associated template file = Final HTML markup code.

默认模板已经写在FreeMarker中,它们有扩展名.ftl。你可以使用velocity或JSP设计你的模板,使用struts.ui.templateSuffixstruts.ui.templateDir在struts.properties中设置配置。

创建新主题

创建新主题的最简单方法是复制任何现有的theme/template文件,并进行必要的修改。那么,让我们在WebContent/WEB-INF/classes中创建一个名为template的文件夹,以及一个以新主题名称命名的子文件夹,例如WebContent/WEB-INF/classes/template/mytheme。从这里,你可以从头开始构建模板,或者你可以从Struts2 现有版本中复制模板,并根据需要修改它们。
出于学习的目的,我们将修改现有的默认模板xhtml。那么现在先将内容从struts2-core-x.y.z.jar/template/xhtml复制到我们的主题目录,并只修改WebContent/WEB-INF/classes/template/mytheme/control.ftl文件。当我们打开control.ftl时它会显示以下几行:

<table class="${parameters.cssClass?default('wwFormTable')?html}"<#rt/><#if parameters.cssStyle??> style="${parameters.cssStyle?html}"<#rt/></#if>>

让我们将以下内容修改到上面的control.ftl文件中:

<table style="border:1px solid black;">

如果你查看form.ftl,你会发现它正在使用这个control.ftl文件,但form.ftl是从xhtml主题中引用这个文件。那么让我们把它做如下修改:

<#include "/${parameters.templateDir}/xhtml/form-validate.ftl" /><#include "/${parameters.templateDir}/simple/form-common.ftl" /><#if (parameters.validate?default(false))>  onreset="${parameters.onreset?default('clearErrorMessages(this);  clearErrorLabels(this);')}"<#else>  <#if parameters.onreset??>  onreset="${parameters.onreset?html}"  </#if></#if>><#include "/${parameters.templateDir}/mytheme/control.ftl" />

我们假设你不太了解FreeMarker模板语言,不过你仍可以通过查看.ftl文件得到一个很好的想法。 不管怎样,让我们先保存以上更改,并返回到我们的本地化示例,创建具有以下内容的WebContent/WEB-INF/classes/struts.properties文件:

# Customized themstruts.ui.theme=mytheme# Directory where theme template residesstruts.ui.templateDir=template# Sets the template type to ftl.struts.ui.templateSuffix=ftl

现在在此更改后,右键单击项目名称,然后单击“Export”>“ WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2。将显示以下界面:

主题和模板

你可以看到窗体组件周围的边框,这是我们从xhtml主题复制之后在out主题中所做更改的结果。如果你稍微学习一下FreeMarker,那么就能够非常容易地创建或修改你的主题。至少现在,你一定对Sturts2 主题和模板有了基本的了解,是吗?

Struts提供了一种更简单的方法来处理未捕获的异常,并将用户重定向到专门的错误页面。你可以很轻松地配置Struts为不同的异常显示不同的错误页面。
Struts通过使用“exception”拦截器来使异常处理变得简单。“exception”拦截器被作为默认堆栈的一部分包含其中,所以你不必对它做任何额外的配置。它提供开箱即用的功能可供使用。让我们看一个简单的Hello World示例,在HelloWorldAction.java文件中进行一些修改。在这里我们有意的给HelloWorldAction操作代码中引入一个NullPointer异常。

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class HelloWorldAction extends ActionSupport{   private String name;   public String execute(){      String x = null;      x = x.substring(0);      return SUCCESS;   }      public String getName() {      return name;   }   public void setName(String name) {      this.name = name;   }}

让我们保持HelloWorld.jsp的内容如下:

<%@ page contentType="text/html; charset=UTF-8" %><%@ taglib prefix="s" uri="/struts-tags" %><html><head><title>Hello World</title></head><body>   Hello World, <s:property value="name"/></body></html>

以下是index.jsp的内容:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%>   <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Hello World</title></head><body>   <h1>Hello World From Struts2</h1>   <form action="hello">      <label for="name">Please enter your name</label><br/>      <input type="text" name="name"/>      <input type="submit" value="Say Hello"/>   </form></body></html>

你的struts.xml应该如下:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts><constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">           <action name="hello"          class="cn.51coolma.struts2.HelloWorldAction"          method="execute">         <result name="success">/HelloWorld.jsp</result>      </action>   </package></struts>

现在右键单击项目名称,然后单击“Export”>“WAR File”创建WAR文件。然后在Tomcat的webapps目录中部署这个WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp。将显示如下页面:

Hello World输入

输入值“Struts2”并提交页面。你应该看到以下页面:

输出异常

如上面的例子所示,默认exception拦截器处理异常的工作非常好。现在让我们为异常创建一个专门的错误页面,一个名为Error.jsp的文件,包含以下内容:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"	pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title></title></head><body>   This is my custom error page</body></html>

现在,让我们配置Struts在异常情况下使用此错误页面,修改struts.xml如下:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts><constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">         <action name="hello"          class="cn.51coolma.struts2.HelloWorldAction"          method="execute">         <exception-mapping exception="java.lang.NullPointerException"         result="error" />         <result name="success">/HelloWorld.jsp</result>         <result name="error">/Error.jsp</result>      </action>   </package></struts>

如上面的例子所示,现在我们已经配置Struts为NullPointerException使用专门的Error.jsp。如果现在重新运行程序,将看到以下输出页面:

Hello World输出

除此之外,Struts2框架还带有一个“logging”拦截器来记录异常。通过启用记录器记录未捕获的异常,我们可以轻松地查看堆栈跟踪记录,并找出哪里出错了。

全局异常映射

我们已经看到了如何处理特定于action的异常。现在,我们可以设置一个全局异常,这将应用于所有的action。例如,为了捕获相同的NullPointerException异常,我们可以在<package...>标签中添加<global-exception-mappings...>标签,并在struts.xml文件的<action...>标签中添加<result...>标签,如下:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts><constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <global-exception-mappings>         <exception-mapping exception="java.lang.NullPointerException"         result="error" />      </global-exception-mappings>      <action name="hello"          class="cn.51coolma.struts2.HelloWorldAction"          method="execute">         <result name="success">/HelloWorld.jsp</result>         <result name="error">/Error.jsp</result>      </action>   </package></struts>


如前章节中所讲到的,Struts提供了两种形式的配置。传统的方式是对所有配置使用struts.xml文件。到目前为止,我们在教程里已经看到了好些这样的例子。配置Struts的另一种方法是使用Java5 的注释功能。使用struts注释,我们可以实现零配置。
要在项目中开始使用注释,请确保WebContent/WEB-INF/lib文件夹中包含以下jar文件:

  • struts2-convention-plugin-x.y.z.jar

  • asm-x.y.jar

  • antlr-x.y.z.jar

  • commons-fileupload-x.y.z.jar

  • commons-io-x.y.z.jar

  • commons-lang-x.y.jar

  • commons-logging-x.y.z.jar

  • commons-logging-api-x.y.jar

  • freemarker-x.y.z.jar

  • javassist-.xy.z.GA

  • ognl-x.y.z.jar

  • struts2-core-x.y.z.jar

  • xwork-core.x.y.z.jar

现在让我们看看如何可以取消struts.xml文件中可用的配置,并将其替换为注释。
为了解释Struts2 中注释的概念,我们必须重新使用在Struts2 验证框架章节中所学习的验证示例。
这里我们将举一个Employee的例子,employee的名字和年龄使用一个简单的页面捕获,我们将进行两次验证,以确保用户始终输入一个名字,并且年龄应在28和65之间。那么,让我们从示例的JSP主页面开始。

创建主页

首先,先开始写用来收集上面提到的Employee相关信息的主页JSP文件index.jsp。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"   pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Employee Form</title></head><body>   <s:form action="empinfo" method="post">      <s:textfield name="name" label="Name" size="20" />      <s:textfield name="age" label="Age" size="20" />      <s:submit name="submit" label="Submit" align="center" />   </s:form></body></html>

index.jsp使用的Struts标签我们还没有涉及到,不过将在标签相关章节中学习它们。现在,假设s:textfield标签印出一个输入字段,并且s:submit印出一个提交按钮。我们为每个标签使用了label属性,即为每个标签创建标记。

创建视图

我们将使用JSP文件的success.jsp,在定义的action返回SUCCESS的情况下调用它。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"	pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Success</title></head><body>   Employee Information is captured successfully.</body></html>

创建Action

Action是使用注释的地方。让我们重新定义具有注释的action类Employee,然后如下所示在Employee.java文件中添加一个名为validate()的方法。需要确保action类扩展了ActionSupport类,否则将不会执行validate方法。

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;import org.apache.struts2.convention.annotation.Action;import org.apache.struts2.convention.annotation.Result;import org.apache.struts2.convention.annotation.Results;import com.opensymphony.xwork2.validator.annotations.*;@Results({   @Result(name="success", location="/success.jsp"),   @Result(name="input", location="/index.jsp")})public class Employee extends ActionSupport{   private String name;   private int age;   @Action(value="/empinfo")   public String execute()    {       return SUCCESS;   }   @RequiredFieldValidator( message = "The name is required" )   public String getName() {       return name;   }   public void setName(String name) {       this.name = name;   }   @IntRangeFieldValidator(message = "Age must be in between 28 and 65",                                      min = "29", max = "65")   public int getAge() {       return age;   }   public void setAge(int age) {       this.age = age;   }}

我们在这个例子中使用了一些注释,让我们逐个了解一下:

  • 首先是例子中包含的Results注释,Results注释是结果的集合。在这个注释集合下,有两个结果注释。它们包含对应于execute方法结果的名称,还包含对应于execute()的返回值所提的视图位置。

  • 下一个注释是Action注释,这可用于装饰execute()方法。Action方法还接收一个值,该值是调用action的URL。

  • 最后,我们使用了两个validation注释。我们已经配置了必填字段验证器上的name字段和整数范围验证器上的age字段,此外还为验证指定了自定义的信息。

配置文件

实际上我们真的不需要struts.xml配置文件,可以删除这个文件,直接来查看web.xml文件的内容:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"   xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"   id="WebApp_ID" version="3.0">   <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>      <init-param>         <param-name>struts.devMode</param-name>         <param-value>true</param-value>      </init-param>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/index.jsp,将显示以下界面:

电子邮件用户输入

先不要输入任何所需的信息,只点击“Submit”按钮。你将看到以下结果:

错误

输入所要求的信息而非错误类的字段,如名称为“text”,年龄为30,然后点击Submit按钮,可以看到以下界面:

成功

Struts2 注释类型

Struts2 应用程序可以使用Java5注释来替代XML和Java属性的配置。你可以查看与不同类别相关的最重要注释的列表:Struts2 注释类型

Struts2 标签有一组标签,可以方便地控制页面执行的流程。以下是主要的Struts2 控制标签:

if和else标签

这些标签执行在每种语言中找到的基本条件流。“If”标签可以单独使用,也可以与“Else If”标签,和单个或是多个“Else”标签一起使用,如下所示:

<s:if test="%{false}">    <div>Will Not Be Executed</div></s:if><s:elseif test="%{true}">    <div>Will Be Executed</div></s:elseif><s:else>    <div>Will Not Be Executed</div></s:else>

查看详细示例

iterator标签

这些iterator将迭代一个值。可迭代值可以是以下任一值:java.util.Collection,java.util.Iterator。在迭代一个iterator时,可以使用Sort标签对结果进行排序,或者使用SubSet标签来获取列表或数组的子集。
以下示例是检索值栈上当前对象的getDays()方法的值,并使用它迭代。<s:property/>标签印出迭代器的当前值。

<s:iterator value="days">  <p>day is: <s:property/></p></s:iterator>

查看详细示例

merge标签

这些merge标签采用两个或多个列表作为参数,并将它们合并在一起,如下所示:

<s:merge var="myMergedIterator">     <s:param value="%{myList1}" />     <s:param value="%{myList2}" />     <s:param value="%{myList3}" /></s:merge><s:iterator value="%{#myMergedIterator}">     <s:property /></s:iterator>

查看详细示例

append标签

这些append标签采用两个或多个列表作为参数,并将它们全部附加在一起,如下所示:

<s:append var="myAppendIterator">     <s:param value="%{myList1}" />     <s:param value="%{myList2}" />     <s:param value="%{myList3}" /></s:append><s:iterator value="%{#myAppendIterator}">     <s:property /></s:iterator>

查看详细示例

generator标签

这些generator标签基于提供的val属性生成迭代器。下面的generator标签生成一个迭代器并使用iterator标签打印出来。

<s:generator val="%{'aaa,bbb,ccc,ddd,eee'}"> <s:iterator>     <s:property /><br/> </s:iterator></s:generator>

查看详细示例


Struts2 的数据标签主要用于操作页面上显示的数据。下面列出了主要的数据标签:

action标签

此标签允许开发人员通过指定action名称和可选的命名空间直接从JSP页面调用action。标签的正文内容用于呈现action的结果。在struts.xml中为此action定义的任何结果处理程序将会被忽略,除非指定executeResult参数。

<div>Tag to execute the action</div><br /><s:action name="actionTagAction" executeResult="true" /><br /><div>To invokes special method  in action class</div><br /><s:action name="actionTagAction!specialMethod" executeResult="true" />

查看详细示例

include标签

这些include标签将用于在另一个JSP页面中包含一个JSP文件。

<-- First Syntax --><s:include value="myJsp.jsp" /><-- Second Syntax --><s:include value="myJsp.jsp">   <s:param name="param1" value="value2" />   <s:param name="param2" value="value2" /></s:include><-- Third Syntax --><s:include value="myJsp.jsp">   <s:param name="param1">value1</s:param>   <s:param name="param2">value2</s:param></s:include>

查看详细示例

bean标签

这些bean标签实例化一个符合JavaBeans规范的类。这个标签有一个主体,可以包含一些Param元素来设置任何mutator方法。如果在BeanTag上设置了var属性,它将把实例化的bean放入值栈的Context中。

<s:bean name="org.apache.struts2.util.Counter" var="counter">   <s:param name="first" value="20"/>   <s:param name="last" value="25" /></s:bean>

查看详细示例

date标签

data标签允许以快速简单的方式格式化日期。用户可以指定自定义日期格式(例如“dd/MM/yyyy hh:mm”),可以生成易读的符号(例如“在2小时14分钟内”),或者可以使用属性文件中的key:“struts.date.format”来回退到预定义的格式。

<s:date name="person.birthday" format="dd/MM/yyyy" /><s:date name="person.birthday" format="%{getText('some.i18n.key')}" /><s:date name="person.birthday" nice="true" /><s:date name="person.birthday" />

查看详细示例

param标签

这些param标签可用于参数化其他标签。此标签具有以下两个参数。

  • name(字符串) - 参数的名称

  • value(对象) - 参数的值

<pre><ui:component> <ui:param name="key"     value="[0]"/> <ui:param name="value"   value="[1]"/> <ui:param name="context" value="[2]"/></ui:component></pre>

查看详细示例

property标签

这些property标签用于获取一个值的属性,如果没有指定,它将默认为在值栈的顶部。

<s:push value="myBean">    <!-- Example 1: -->    <s:property value="myBeanProperty" />    <!-- Example 2: -->TextUtils    <s:property value="myBeanProperty" default="a default value" /></s:push>

查看详细示例

push标签:

这些push标签用于推送堆栈中的值,以简化使用。

<s:push value="user">    <s:propery value="firstName" />    <s:propery value="lastName" /></s:push>

查看详细示例

set标签

这些set标签为指定范围内的变量赋值。当你希望将变量分配给复杂表达式,然后仅仅引用该变量而不是复杂表达式时,它是很有用的。可应用的范围是应用程序,会话,请求,页面和action。

<s:set name="myenv" value="environment.name"/><s:property value="myenv"/>

查看详细示例

text标签

这些text标签用于呈现I18n文本消息。

<!-- First Example --><s:i18n name="struts.action.test.i18n.Shop">    <s:text name="main.title"/></s:i18n><!-- Second Example --><s:text name="main.title" /><!-- Third Examlpe --><s:text name="i18n.label.greetings">   <s:param >Mr Smith</s:param></s:text>

查看详细示例

url标签

这些url标签用于创建URL。

<-- Example 1 --><s:url value="editGadget.action">    <s:param name="id" value="%{selected}" /></s:url><-- Example 2 --><s:url action="editGadget">    <s:param name="id" value="%{selected}" /></s:url><-- Example 3--><s:url includeParams="get">    <s:param name="id" value="%{'22'}" /></s:url>

查看详细示例


表单标签列表是Struts UI标签的子集。这些标签有助于渲染Struts Web应用程序所需的用户界面,主要分为三类,本章将介绍这三种类型的UI标签:

简单UI标签

我们其实已经在前面的示例中使用了这些标签,接下来将在本章中重新回顾一下。以下是一个简单的视图页面email.jsp与几个简单的UI标签:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"	pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><s:head/><title>Hello World</title></head><body>   <s:div>Email Form</s:div>   <s:text name="Please fill in the form below:" />   <s:form action="hello" method="post" enctype="multipart/form-data">   <s:hidden name="secret" value="abracadabra"/>   <s:textfield key="email.from" name="from" />   <s:password key="email.password" name="password" />   <s:textfield key="email.to" name="to" />   <s:textfield key="email.subject" name="subject" />   <s:textarea key="email.body" name="email.body" />   <s:label for="attachment" value="Attachment"/>   <s:file name="attachment" accept="text/html,text/plain" />   <s:token />   <s:submit key="submit" />   </s:form></body></html>

如果你了解HTML,那么就知道所有使用的标签都是非常常见的HTML标签,每个标签带有一个额外的前缀“s:”以及不同的属性。当我们执行上面的程序时,将得出以下用户界面,只要你已经为所有的key设置了正确的映射。

Struts的简单的UI标签

如图所示,s:head生成Struts2 应用程序所需的javascript和stylesheet元素。
接下来,s:div和s:text元素。s:div用于呈现HTML Div元素。这对于不喜欢将HTML和Struts标签混合在一起的人很有用,他们可选择使用s:div来渲染div。
如图所示,s:text用于在屏幕上呈现文本。
接下来是相类似的s:form标签。s:form标签具有确定在何处提交表单的action属性。因为在表单中有一个文件上传元素,我们必须将enctype设置为multipart。否则,就留空。
在表单标签的末尾,有s:submit标签,这用于提交表单。提交表单时,所有表单值都将提交到s:form标签中指定的action。
在s:form标签中,我们有一个称为secret的隐藏属性,这将在HTML中呈现一个隐藏元素。在我们的例子中,“secret”元素的值为“abracadabra”。此元素对最终用户不可见,并用于将状态从一个视图传递到另一个视图。
接下来是s:label,s:textfield,s:password和s:textarea标签。这些分别用于渲染标签,输入字段,密码和文本区域。我们已经在“Struts2 发送电子邮件”章节示例中看到了这些。这里要注意的重要事情是使用“key”属性。“key”属性用于从属性文件中提取这些控件的标签。我们已经在Struts2本地化/国际化(i18n)一章中讨论了这个特性。
然后是s:file标签,它呈现输入文件上传的组件,此组件允许用户上传文件。在这个例子中,我们使用了s:file标签的“accept”参数来指定允许上传哪些文件类型。
最后,s:token标签。token标签生成唯一的token,用于查明表单是否已被两次提交。
呈现表单时,会将一个隐藏变量放置为token(令牌)值。例如令牌是“ABC”,提交此表单时,Struts Fitler将根据存储在会话中的令牌进行检查。如果匹配,则从会话中删除令牌。现在,如果表单意外被重新提交(通过刷新或通过点击浏览器后退按钮),表单将重新提交,用“ABC”作为令牌。在这种情况下,过滤器将对照存储在会话中的令牌再次进行检查。但是因为令牌“ABC”已经从会话中删除,它将不匹配,Struts过滤器将拒绝请求。

群组UI标签

群组UI标签用于创建单选按钮和复选框。让我们看一个简单的带有复选框和单选按钮标签的视图页面HelloWorld.jsp

<%@ page contentType="text/html; charset=UTF-8"%><%@ taglib prefix="s" uri="/struts-tags"%><html><head><title>Hello World</title><s:head /></head><body>   <s:form action="hello.action">   <s:radio label="Gender" name="gender" list="{'male','female'}" />   <s:checkboxlist label="Hobbies" name="hobbies"   list="{'sports','tv','shopping'}" />   </s:form></body></html>

当我们执行上面的程序时,我们的输出将类似于以下内容:

Struts群组UI标签

现在让我们看看这些例子。在第一个例子中,我们创建一个简单的radiobutton,标签为“Gender”。name属性对于radiobutton标签是必需的,那么我们指定一个名为“gender”的name。然后我们提供一个性别列表,该列表用值“male”和“female”填充。因此,在输出中我们得到一个带有两个值的radiobutton。
在第二个例子中,我们创建一个复选框列表。这是为了收集用户的爱好。用户可以有多个爱好,因此我们使用复选框而不是单选按钮。复选框用“sports”,“Tv”和“Shopping”填充列表,将这些爱好作为复选框列表。

选择UI标签

让我们来探讨Struts提供的Select标签的不同变化。让我们看一个简单的带select标签的视图页面HelloWorld.jsp

<%@ page contentType="text/html; charset=UTF-8"%><%@ taglib prefix="s" uri="/struts-tags"%><html><head><title>Hello World</title><s:head /></head><body>   <s:form action="login.action">      <s:select name="username" label="Username"         list="{'Mike','John','Smith'}" />      <s:select label="Company Office" name="mySelection"         value="%{'America'}"         list="%{#{'America':'America'}}">      <s:optgroup label="Asia"          list="%{#{'India':'India','China':'China'}}" />      <s:optgroup label="Europe"         list="%{#{'UK':'UK','Sweden':'Sweden','Italy':'Italy'}}" />      </s:select>      <s:combobox label="My Sign" name="mySign"         list="#{'aries':'aries','capricorn':'capricorn'}"         headerKey="-1"          headerValue="--- Please Select ---" emptyOption="true"         value="capricorn" />      <s:doubleselect label="Occupation" name="occupation"         list="{'Technical','Other'}" doubleName="occupations2"         doubleList="top == 'Technical' ?          {'I.T', 'Hardware'} : {'Accounting', 'H.R'}" />   </s:form></body></html>

当我们执行上面的程序时,输出的结果将类似于以下内容:

Struts的选择UI标签

现在,让我们逐一查看每个案例。
  • 首先,select标签呈现HTML选择框。在第一个例子中,我们创建一个名为“username”和标记“username”的简单选择框。选择框将填充包含姓名Mike,John和Smith的列表。
  • 在第二个例子中,公司在美国设有总部。它还在亚洲和欧洲设有全球办事处。我们想在一个选择框中显示办公点,但要按全球大陆的名称对全球办事处进行分组。这是optgroup的用武之地。我们使用s:optgroup标签创建一个新组,给组一个标记和一个单独的列表。
  • 在第三个示例中,使用组合框。组合框是输入字段和选择框的组合。用户可以从选择框中选择一个值,在这种情况下,输入字段将自动填入用户选择的值。如果用户直接输入值,则将不选择来自选择框的值。
  • 在我们的示例中,我们有组合框列出了星座。选择框只列出四个条目,允许用户输入他的星座,如果它不在列表中。我们还向选择框中添加一个标题条目。headerentry是显示在选择框顶部的。在示例中,我们要显示“Please Select”。如果用户没有选择任何东西,那么我们假设-1作为值。在某些情况下,我们不希望用户选择一个空值。那么,可以将“emptyOption”属性设置为false。最后,在我们的示例中,我们提供“capricorn”作为组合框的默认值。
  • 在第四个例子中,我们有一个双选框。当要显示两个选择框时,使用double select。在第一个选择框中选择的值确定在第二个选择框中显示的值。在示例中,第一个选择框显示“Technical”和“Other”。如果用户选择Technical,我们将在第二个选择框中显示IT和Hardware。否则,将显示Accounting和HR。这可以使用“list”和“doubleList”属性,如示例所示。
在上面的例子中,我们做一个比较,看看顶部的选择框是否等于Techical。如果是,那么我们显示IT和Hardware。我们还需要给顶部框(“name ='Occupations')和底部框(doubleName ='occupations2')命名。

Struts使用DOJO框架来实现AJAX标签。首先,执行示例前,你需要将struts2-dojo-plugin-2.2.3.jar添加到类路径。你可以从struts2 下载的lib文件夹中获取这个文件(C:struts-2.2.3-allstruts-2.2.3libstruts2-dojo-plugin-2.2.3.jar)。

对于这个示例,让我们参照以下内容修改HelloWorld.jsp

<%@ page contentType="text/html; charset=UTF-8"%><%@ taglib prefix="s" uri="/struts-tags"%><%@ taglib prefix="sx" uri="/struts-dojo-tags"%><html><head><title>Hello World</title><s:head /><sx:head /></head><body>   <s:form>      <sx:autocompleter label="Favourite Colour"         list="{'red','green','blue'}" />      <br />      <sx:datetimepicker name="deliverydate" label="Delivery Date"         displayFormat="dd/MM/yyyy" />      <br />      <s:url id="url" value="/hello.action" />      <sx:div href="%{#url}" delay="2000">           Initial Content      </sx:div>      <br/>      <sx:tabbedpanel id="tabContainer">         <sx:div label="Tab 1">Tab 1</sx:div>         <sx:div label="Tab 2">Tab 2</sx:div>      </sx:tabbedpanel>   </s:form></body></html>

当我们运行上面的例子,将得到以下的输出:

Struts的Ajax标签

现在,让我们一步一步地完成这个例子。

首先要注意的是添加一个带有前缀sx的新标签库。这个(struts-dojo-tags)是为ajax集成专门创建的标签库。

然后在HTML头部内,我们称之为sx:head。这将初始化dojo框架,并使其准备好在页面中被所有AJAX调用。这个步骤很重要,如果没有初始化sx:head,你的ajax调用将无法工作。

首先我们有autocompleter标签。autocompleter标签看起来非常像一个选择框。它使用红色,绿色和蓝色值填充。但选择框和autocompleter标签之间的不同是autocompleter标签自动完成。也就是说,如果你开始在gr中输入,它将填充“绿色”。除此之外,这个标签非常类似于我们前面介绍的s:select标签。

接下来,我们有一个日期时间选择器。此标标签创建一个旁边带有按钮的输入字段。当按下按钮时,显示弹出日期时间选择器。当用户选择日期时,日期以在tag属性中指定的格式填充到输入文本中。在我们的示例中,我们指定了dd/MM/yyyy作为日期的格式。

接下来,是我们在之前的示例中为system.action文件创建的一个url标签。它不必是system.action,它可以是之前创建的任何action文件。然后我们有一个div,超链接设置为url,延迟设置为2秒。当你运行时会发生什么,“Initial Content”将显示2秒,然后div的内容将替换为hello.action执行的内容。

最后,我们有一个简单的标签面板,有两个标签。选项卡将其标签标记为Tab1和Tab2。

值得注意的是,Struts中的AJAX标签集成仍然是一项进展,并且此集成的成熟度在每个版本中都在缓慢增长。

Spring是当下流行的Web框架,可提供带有许多常见Web任务的简易的集成。那么问题是,当我们有Struts2时,为什么我们需要Spring?因为Spring不仅仅是一个MVC框架,它提供了许多其他在Struts中不可用的好东西。例如:依赖注入可以对任何框架有用。在本章中,我们将通过一个简单的例子来了解如何将Spring和Struts2集成在一起。
首先,你需要将以下文件添加到Spring的项目的构建路径。你可以从http://www.springsource.org/download下载并安装最新版本的Spring框架。

  • org.springframework.asm-x.y.z.M(a).jar

  • org.springframework.beans-x.y.z.M(a).jar

  • org.springframework.context-x.y.z.M(a).jar

  • org.springframework.core-x.y.z.M(a).jar

  • org.springframework.expression-x.y.z.M(a).jar

  • org.springframework.web-x.y.z.M(a).jar

  • org.springframework.web.servlet-x.y.z.M(a).jar

最后从你的struts lib目录中添加struts2-spring-plugin-x.y.z.jar到你的WEB-INF/lib中。如果你使用Eclipse,那么你可能会遇到一个异常java.lang.ClassNotFoundException:org.springframework.web.context.ContextLoaderListener。要解决这个问题,你应该进到Marker选项卡中右键逐个点击类依赖关系,然后快速修复以发布/导出所有的依赖关系。最后,确保在Marker选项卡下没有可用的依赖冲突。

Struts和Spring集成

现在让我们为Struts-Spring集成设置web.xml,如下所示:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"	xmlns="http://java.sun.com/xml/ns/javaee" 	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 	http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"	id="WebApp_ID" version="3.0">	   <display-name>Struts 2</display-name>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list>   <listener>      <listener-class>         org.springframework.web.context.ContextLoaderListener      </listener-class>   </listener>   <filter>      <filter-name>struts2</filter-name>      <filter-class>         org.apache.struts2.dispatcher.FilterDispatcher      </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping></web-app>

这里需要注意的重点是我们配置的监听器。加载spring上下文文件需要ContextLoaderListener。Spring的配置文件称为applicationContext.xml文件,它必须放置在与web.xml文件相同的级别。
让我们创建一个简单的action类User.java,它有两个属性 - firstName和lastName。

package cn.51coolma.struts2;public class User {   private String firstName;   private String lastName;   public String execute()   {      return "success";   }   public String getFirstName() {      return firstName;   }   public void setFirstName(String firstName) {      this.firstName = firstName;   }   public String getLastName() {      return lastName;   }   public void setLastName(String lastName) {      this.lastName = lastName;   }}

现在,创建spring配置文件applicationContext.xml并实例化User.java类。如前所述,此文件应在WEB-INF文件夹下:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">   <beans>      <bean id="userClass" class="cn.51coolma.struts2.User">      <property name="firstName" value="Michael" />      <property name="lastName" value="Jackson" />   </bean></beans>

如上所示,我们已经配置了用户bean,并且我们已经将值MichaelJackson注入到bean中。我们还给这个bean一个名称“userClass”,以便我们可以在别处重新使用它。接下来,让我们在WebContent文件夹中创建User.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"	pageEncoding="ISO-8859-1"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>Hello World</title></head><body>   <h1>Hello World From Struts2 - Spring integration</h1>   <s:form>      <s:textfield name="firstName" label="First Name"/><br/>      <s:textfield name="lastName" label="Last Name"/><br/>   </s:form>	</body></html>

User.jsp文件很简单。它仅用于一个目的:显示用户对象的firstname和lastname的值。最后,让我们使用struts.xml文件将所有实体放在一起。

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN""http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="helloworld" extends="struts-default">      <action name="user" class="userClass"          method="execute">         <result name="success">/User.jsp</result>      </action>   </package></struts>

重点需要注意的是,我们使用id userClass来引用类,这意味着我们使用spring为User类做依赖注入。

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/User.jsp,将显示以下界面:

Struts和Spring集成

我们现在已经看到如何将两个伟大的框架结合在一起,这就结束了Struts-Spring集成章节。

在本章中,我们会学习到将 Tiles 框架与 Struts2 集成所涉及的步骤。Apache Tiles是一个模板框架,用于简化 Web 应用程序用户界面的开发。
首先,我们需要从 Apache Tiles 网站下载tiles jar文件。你需要将以下 jar 文件添加到项目的类路径。

  • tiles-api-x.y.z.jar

  • tiles-compat-x.y.z.jar

  • tiles-core-x.y.z.jar

  • tiles-jsp-x.y.z.jar

  • tiles-servlet-x.y.z.jar

除了上面的,我们必须从WEB-INF/lib中复制以下jar文件。

  • commons-beanutils-x.y.z.jar

  • commons-digester-x.y.z.jar

  • struts2-tiles-plugin-x.y.z.jar

现在,让我们设置Struts-Tiles集成的 web.xml,如下所示。这里有两个要点要注意。首先,我们需要告诉tile,在哪里可以找到tiles的配置文件tiles.xml。在我们的例子中,它将在/WEB-INF文件夹下。然后,我们需要初始化 Struts2 下载附带的Tiles监听器。

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   id="WebApp_ID" version="2.5">   <display-name>Struts2Example15</display-name>	   <context-param>   <param-name>      org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG   </param-name>   <param-value>      /WEB-INF/tiles.xml   </param-value>   </context-param>   <listener>   <listener-class>      org.apache.struts2.tiles.StrutsTilesListener   </listener-class>   </listener>   <filter>   <filter-name>struts2</filter-name>   <filter-class>   org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter   </filter-class>   </filter>   <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>   </filter-mapping>   <welcome-file-list>      <welcome-file>index.jsp</welcome-file>   </welcome-file-list></web-app>

接下来在 /WEB-INF 文件夹下创建 tiles.xml,内容如下:

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE tiles-definitions PUBLIC   "-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"   "http://tiles.apache.org/dtds/tiles-config_2_0.dtd"><tiles-definitions>   <definition name="baseLayout" template="/baseLayout.jsp">      <put-attribute name="title"  value="Template"/>      <put-attribute name="banner" value="/banner.jsp"/>      <put-attribute name="menu"   value="/menu.jsp"/>      <put-attribute name="body"   value="/body.jsp"/>      <put-attribute name="footer"   value="/footer.jsp"/>   </definition>   <definition name="tiger" extends="baseLayout">      <put-attribute name="title"  value="Tiger"/>      <put-attribute name="body"   value="/tiger.jsp"/>         </definition>   <definition name="lion" extends="baseLayout">      <put-attribute name="title"  value="Lion"/>      <put-attribute name="body"   value="/lion.jsp"/>         </definition>  </tiles-definitions>

接下来,我们在 baseLayout.jsp 中定义一个基本的skeleton布局。它有五个可重用/可覆盖区域。即 titlebannermenubodyfooter。我们提供baseLayout的默认值,然后创建从默认布局扩展的两个自定义。tiger布局类似于基本布局,除了它使用 tiger.jsp 作为其body和文本“Tiger”作为title。类似地,lion布局也类似于基本布局,除了它使用 lion.jsp 作为其 body 和文本“Lion”作为 title。
让我们看看各个jsp文件。以下是 baseLayout.jsp 文件的内容:

<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title><tiles:insertAttribute name="title" ignore="true" /></title></head><body>   <tiles:insertAttribute name="banner" /><br/>   <hr/>   <tiles:insertAttribute name="menu" /><br/>   <hr/>   <tiles:insertAttribute name="body" /><br/>   <hr/>   <tiles:insertAttribute name="footer" /><br/></body></html>

这里我们只是把一个有 tiles 属性的基本的 HTML 页面放在一起。将tile属性插入到需要用到它的地方。接下来,让我们创建具有以下内容的banner.jsp文件:

<img src="//atts.51coolma.cn/attachments/tuploads/struts_2/tp-logo.gif"/>

menu.jsp文件将有以下内容,它们是TigerMenu.action和LionMenu.action的链接。

<%@taglib uri="/struts-tags" prefix="s"%><a href="<s:url action="tigerMenu"/>" Tiger</a><br><a href="<s:url action="lionMenu"/>" Lion</a><br>

lion.jsp 文件将具有以下内容:

<img src="//atts.51coolma.cn/attachments/tuploads/struts_2/Lion.jpg"/>The lion

tiger.jsp 文件将具有以下内容:

<img src="//atts.51coolma.cn/attachments/tuploads/struts_2/tiger.jpg"/>The tiger

接下来,创建一个action类文件 MenuAction.java,它包含以下内容:

package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class MenuAction extends ActionSupport {   public String tiger() { return "tiger"; }   public String lion() { return "lion"; }	}

这是一个非常直接的类。我们声明了两种方法 tiger() 和 lion() ,它们分别返回 tiger 和 lion 作为结果。让我们把它们放在 struts.xml 文件中:

<!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN""http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <package name="default" extends="struts-default">      <result-types>         <result-type name="tiles"          class="org.apache.struts2.views.tiles.TilesResult" />      </result-types>      <action name="*Menu" method="{1}"          class="cn.51coolma.struts2.MenuAction">         <result name="tiger" type="tiles">tiger</result>         <result name="lion" type="tiles">lion</result>      </action>   </package></struts>

让我们回顾一下我们在上面的文件中做的。首先,我们声明了一种称为“tiles”的新结果类型,因为我们现在使用 tile 而不是普通的jsp作为视图技术。Struts2 支持Tiles View结果类型,因此我们创建了结果类型“tiles”作为“org.apache.struts2.view.tiles.TilesResult”类的结果类型。
接下来,我们要说的是,如果请求是 /tigerMenu.action,用户跳到tiger标题页面,如果请求是 /lionMenu.action,用户跳到lion标题页面。
我们使用一些正则表达式来实现这个。在action定义中,我们说任何匹配“*Menu”模式的东西都会被这个action处理。匹配方法将在MenuAction类中调用。也就是说,tigerMenu.action将调用tiger()和lionMenu.action将调用lion()。然后,我们需要将结果映射到适当的标题页面。

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在 Tomcat 的 webapps 目录中部署WAR文件。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/tigerMenu.jsp,将显示以下界面:

Struts和Tiles集成

同样,如果你转到 lionMenu.action 页面,你会看到 lion 页面使用相同的标题布局。

Hibernate是一个高性能的对象/关系留存和查询服务,它是根据开源GNU宽通用公共许可证(LGPL)许可的,可以免费下载。在这一章。 我们将学习如何实现Struts2 与Hibernate的集成。如果你不熟悉Hibernate,可以查看我们的Hibernate教程

数据库设置

对于本教程,我们将使用“struts2_tutorial”MySQL数据库,使用用户名“root”连接到机器上的这个数据库,不设密码。首先,你需要运行以下脚本。此脚本创建一个名为student的新表,并在此表中创建少量记录:

CREATE TABLE IF NOT EXISTS `student` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `first_name` varchar(40) NOT NULL,  `last_name` varchar(40) NOT NULL,  `marks` int(11) NOT NULL,  PRIMARY KEY (`id`));---- Dumping data for table `student`--INSERT INTO `student` (`id`, `first_name`, `last_name`, `marks`)   VALUES(1, 'George', 'Kane', 20);INSERT INTO `student` (`id`, `first_name`, `last_name`, `marks`)   VALUES(2, 'Melissa', 'Michael', 91);INSERT INTO `student` (`id`, `first_name`, `last_name`, `marks`)   VALUES(3, 'Jessica', 'Drake', 21);

Hibernate配置

接下来让我们创建hibernate.cfg.xml,它是hibernate配置文件。

<?xml version='1.0' encoding='utf-8'?><!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD//EN""http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"><hibernate-configuration><session-factory>   <property name="hibernate.connection.driver_class">c      om.mysql.jdbc.Driver   </property>   <property name="hibernate.connection.url">      jdbc:mysql://www.51coolma.cn/struts_tutorial   </property>   <property name="hibernate.connection.username">root</property>   <property name="hibernate.connection.password"></property>   <property name="hibernate.connection.pool_size">10</property>   <property name="show_sql">true</property>   <property name="dialect">      org.hibernate.dialect.MySQLDialect   </property>   <property name="hibernate.hbm2ddl.auto">update</property>   <mapping class="cn.51coolma.hibernate.Student" /></session-factory></hibernate-configuration> 

让我们过一下hibernate配置文件。首先,我们声明使用MySQL驱动程序。然后我们声明了jdbc url用于连接到数据库。接着我们声明连接的用户名,密码和池大小。我们还指出希望通过将“show_sql”打开为true来查看日志文件中的SQL。请通过Hibernate教程了解这些属性的含义。最后,我们将映射类设置为在本章中创建的cn.51coolma.hibernate.Student。

环境搭建

这个项目需要很多jar文件,以下的是所需的JAR文件的完整列表的屏幕截图:

Struts和Hibernate的jar

大多数JAR文件可以作为struts分发的一部分获取。如果你有安装一个应用程序服务器,如glassfish,websphere或jboss,那么你可以从appserver的lib文件夹中获取大多数剩余的jar文件。如果没有,你可以单独下载文件:

其余的文件,你应该能够从struts2 中分配。

Hibernate类

现在让我们为hibernate集成创建所需的java类。按照Student.java的内容:

package cn.51coolma.hibernate;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;import javax.persistence.Table;@Entity@Table(name="student")public class Student {	   @Id   @GeneratedValue   private int id;   @Column(name="last_name")   private String lastName;   @Column(name="first_name")   private String firstName;   private int marks;   public int getId() {    return id;   }   public void setId(int id) {    this.id = id;   }   public String getLastName() {      return lastName;   }   public void setLastName(String lastName) {      this.lastName = lastName;   }   public String getFirstName() {      return firstName;   }   public void setFirstName(String firstName) {      this.firstName = firstName;   }   public int getMarks() {      return marks;   }   public void setMarks(int marks) {      this.marks = marks;   }}

这是一个POJO类,根据Hibernate规范表示的student表。它具有对应于student表列名的属性id,firstName和lastName。接下来让我们创建StudentDAO.java文件,如下所示:

package cn.51coolma.hibernate;import java.util.ArrayList;import java.util.List;import org.hibernate.Session;import org.hibernate.Transaction;import com.googlecode.s2hibernate.struts2.plugin.                     annotations.SessionTarget;import com.googlecode.s2hibernate.struts2.plugin.                     annotations.TransactionTarget;public class StudentDAO {	   @SessionTarget   Session session;   @TransactionTarget   Transaction transaction;   @SuppressWarnings("unchecked")   public List<Student> getStudents()   {      List<Student> students = new ArrayList<Student>();      try      {         students = session.createQuery("from Student").list();      }      catch(Exception e)      {         e.printStackTrace();      }      return students;   }   public void addStudent(Student student)   {      session.save(student);   }}

StudentDAO类是Student类的数据访问层。它有方法来列出所有学生,然后保存一个新的学生记录。

Action类

下面的文件AddStudentAction.java定义了我们的action类。我们在这里有两个action方法:execute()和listStudents()。execute()方法用于添加新的学生记录。我们使用dao的save()方法来实现这一点。另一种listStudents()方法用于列出学生。我们使用dao的列表方法来获取所有学生的列表。

package cn.51coolma.struts2;import java.util.ArrayList;import java.util.List;import com.opensymphony.xwork2.ActionSupport;import com.opensymphony.xwork2.ModelDriven;import cn.51coolma.hibernate.Student;import cn.51coolma.hibernate.StudentDAO;public class AddStudentAction extends ActionSupport             implements ModelDriven<Student>{   Student student  = new Student();   List<Student> students = new ArrayList<Student>();   StudentDAO dao = new StudentDAO();   @Override   public Student getModel() {      return student;   }   public String execute()   {      dao.addStudent(student);      return "success";   }   public String listStudents()   {      students = dao.getStudents();      return "success";   }   public Student getStudent() {      return student;   }   public void setStudent(Student student) {      this.student = student;   }   public List<Student> getStudents() {      return students;   }   public void setStudents(List<Student> students) {      this.students = students;   }	}

你会注意到我们正在实现ModelDriven接口。这是在你的action类处理一个具体的模型类(如Student)而不是个别的属性(如firstName,lastName)时使用。ModelAware接口需要你实现一个方法来返回模型。在我们的例子中,我们返回“student”对象。

创建视图文件

现在创建包含以下内容的student.jsp视图文件:

<%@ page contentType="text/html; charset=UTF-8"%><%@ taglib prefix="s" uri="/struts-tags"%><html><head><title>Hello World</title><s:head /></head><body>   <s:form action="addStudent">   <s:textfield name="firstName" label="First Name"/>   <s:textfield name="lastName" label="Last Name"/>   <s:textfield name="marks" label="Marks"/>   <s:submit/>   <hr/>   <table>      <tr>         <td>First Name</td>         <td>Last Name</td>         <td>Marks</td>      </tr>      <s:iterator value="students">	         <tr>            <td><s:property value="firstName"/></td>            <td><s:property value="lastName"/></td>            <td><s:property value="marks"/></td>           </tr>      </s:iterator>	   </table>   </s:form></body></html>

student.jsp非常简单。在上面部分,我们有一个提交到“addStudent.action”的表单。它接受firstName,lastName和marks。因为addStudent action绑定到ModelAware的“AddSudentAction”,所以将自动创建一个学生bean,其值自动填充为firstName,lastName和marks。
在下面部分,我们浏览学生列表(参见AddStudentAction.java),并在表中显示firstname,lastname和marks的值。

Struts配置

让我们使用struts.xml

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"   "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>   <constant name="struts.devMode" value="true" />   <package name="myhibernate" extends="hibernate-default">      <action name="addStudent" method="execute"         class="cn.51coolma.struts2.AddStudentAction">         <result name="success" type="redirect">               listStudents         </result>      </action>      <action name="listStudents" method="listStudents"         class="cn.51coolma.struts2.AddStudentAction">         <result name="success">/students.jsp</result>      </action></package></struts>

要注意的要点是,我们的包“myhibernate”扩展了名为“hibernate-default”的struts2默认包。然后我们声明两个action:addStudent和listStudents。addStudent调用AddStudentAction类的execute(),然后在成功时调用listStudents方法。listStudent方法调用AddStudentAction类上的listStudents(),并使用student.jsp作为视图。

现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在Tomcat的webapps目录中部署WAR文件。最后,启动Tomcat服务器并尝试访问URL http://localhost:8080/HelloWorldStruts2/student.jsp,将显示以下界面:
Struts和Hibernate的集成

在上面部分,我们得到一个表单,输入新学生记录的值,下面部分列出数据库中的学生。继续添加一个新的学生记录,然后按提交。屏幕将刷新,并在每次单击提交时向你显示更新了的列表。