Struts2 是目前较为普及和成熟的基于MVC设计模式的web应用程序框架,它不仅仅是Struts1 的升级版本,更是一个全新的Struts架构。最初,是以WebWork框架和Struts框架为基础,通过提供增强和改进的Struts框架,进而实现简化web技术人员开发工作的目标。不久之后,Webwork框架和Struts社区联合创造了现在流行的Struts2框架。
模型(Model)-视图(View)-控制器(Controller),通常简称MVC,是一种开发web应用程序的软件设计模式。该软件设计模式由以下三部分组成:
我们的第一个任务是运行一个最小的Struts2 应用程序。本章将指导你如何搭建Struts2 开发环境进行工作。我们假设你的电脑已经安装了JDK(5+)、Tomcat以及Eclipse,如果你没有安装这些组件那就按照下面列出快捷方式安装:
你可以在甲骨文网站的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给出的文档做正确的设置。
%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/ 进行访问了。如果一切正常,那么会显示以下结果:
%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
%C:eclipseeclipse.exe在Unix(或Solaris、Linux等)环境下,可以通过执行以下指令启动Eclipse:
$/usr/local/eclipse/eclipse启动成功后,如果一切正常,那么会显示以下结果:
从一个高水平角度看,Struts2 是一个MVC拉动的(或MVC2)框架,Struts2 的模型-视图-控制器模式是通过以下五个核心部分进行实现的:
通过学习Struts2 框架可以了解到,当你在Struts2 的web应用程序里点击一个超链接或提交一个HTML表单时,会由控制器收集输入并发送一个叫Actions的Java类。Action被执行后,Result会选择一个资源给予响应。这个资源通常是一个JSP,也可以是一个PDF文件,一个Excel表格,或者是一个Java小程序窗口。
假设你已经建好了你的开发环境,那么现在让我们继续构建第一个Struts2 项目:Hello World 。这个项目的目标是构建一个收集用户名并在用户名后跟随显示“Hello World”的web应用程序。我们需要为每个Struts2 项目构建以下四个组件:
序号 | 名称及描述 |
1 | Action(操作) |
创建一个动作类,包含完整的业务逻辑并控制用户、模型以及视图间的交互。 | |
2 | Interceptors(拦截器) |
这是控制器的一部分,可依据需求创建拦截器,或使用现有的拦截器。 | |
3 | View(视图) |
创建一个JSP与用户进行交互,获取输入并呈现最终信息。 | |
4 | Configuration Files(配置文件) |
创建配置文件来连接动作、视图以及控制器,这些文件分别是struts.xml、web.xml以及struts.properties。 |
我们如果打算使用Eclipse IDE,那么所有必需的组件都要在动态Web项目(Dynamic Web Project)下创建。因此我们就先从创建动态Web项目开始。
按照下图选择所有默认选项,最后检查 Generate Web.xml deployment descriptor 选项。这个将在Eclipse为你创建一个动态web项目。现在点击“Windows”>“Show”>“View”>“Project Explorer”,你就可以看到你的项目窗口,如下图:
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; }}
<%@ 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>
<%@ 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>
<?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>
<?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-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>
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 ,将会呈现如下图所示的结果:
输入一个“Struts2”值并提交页面,你可以看到以下页面
注意,你可以在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.xml、struts.xml、struts-config.xml以及struts.properties。
实际上,你可以继续依赖于使用web.xml和struts.xml配置文件,并且你已经在前面的章节中了解到,我们的示例是使用这两个文件运作的,不过为了让你了解更多,我们还是再来说明一下其他的文件。
正如前面所讨论的,这个文件为每个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代替。
<?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不能被最终用户使用。 |
namespace | Actions的唯一命名空间 |
<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配置文件是Web Client中View和Model组件之间的链接,但在你99.99%的项目里你不必使用这些设置。 struts-config.xml配置文件包含以下主要元素:
序号 | 拦截器和说明 |
---|---|
1 | struts-config 这是配置文件的根节点。 |
2 | form-beans 这是你将ActionForm子类映射到name的位置,你可以在struts-config.xml文件的其余部分,甚至在JSP页面上,将这个name用作ActionForm的别名。 |
3 | global forwards 此部分将你在webapp上的页面映射到name,你可以使用这个name来引用实际页面。这避免了对你网页上的URL进行硬编码。 |
4 | action-mappings 这是你声明表单处理程序的地方,也被称为操作映射(action mappings)。 |
5 | controller 这部分是配置Struts的内部,在实际情况中很少使用。 |
6 | plug-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配置文件中包含的所有属性也可以在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默认忽略。
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”之外的任何词,你会看到如下页面:
你会需要频繁定义多个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个拦截器。
Struts 2框架提供了一个良好的开箱即用的拦截器列表,这些拦截器预先配置好并可以使用。 下面列出了几个重要的拦截器:
序号 | 拦截器和说明 |
---|---|
1 | alias 允许参数在请求之间使用不同的别名。 |
2 | checkbox 通过为未检查的复选框添加参数值false,以辅助管理复选框。 |
3 | conversionError 将字符串转换为参数类型的错误信息放置到action的错误字段中。 |
4 | createSession 自动创建HTTP会话(如果尚不存在)。 |
5 | debugging 为开发人员提供一些不同的调试屏幕。 |
6 | execAndWait 当action在后台执行时,将用户发送到中间的等待页面。 |
7 | exception 映射从action到结果抛出的异常,允许通过重定向自动处理异常。 |
8 | fileUpload 便于文件上传。 |
9 | i18n 在用户会话期间跟踪选定的区域。 |
10 | logger 通过输出正在执行的action的名称提供简单的日志记录。 |
11 | params 设置action上的请求参数。 |
12 | prepare 这通常用于执行预处理工作,例如设置数据库连接。 |
13 | profile 允许记录action的简单分析信息。 |
14 | scope 在会话或应用程序范围内存储和检索action的状态。 |
15 | ServletConfig 提供可访问各种基于servlet信息的action。 |
16 | timer 以action执行时间的形式提供简单的分析信息。 |
17 | token 检查action的有效性,以防止重复提交表单。 |
18 | validation 提供action的验证支持。 |
你可以阅读Struts 2文档,了解上述拦截器的完整信息。接下来我们会告诉你如何在Struts应用程序中使用拦截器。
<?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()方法。
我们接下来在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()调用执行,所以你可以根据你的需求做一些预处理和一些后处理。
我们在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。将显示如下图片:
现在,在给的定文本框中输入任意单词,然后单击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 name="hello" class="com.tutorialspoint.struts2.MyAction"> <interceptor-ref name="basicStack"/> <result>view.jsp</result></action
上述的“basicStack”注册将完整注册hello action的所使用的六个拦截器。要注意的是,拦截器按照它们被配置的顺序执行。例如,在上面的例子中,exception将首先执行,第二个将是servlet-config等。
dispatcher结果类型是默认的类型,如果未指定其他结果类型,则使用此类型。它用于转发到服务器上的servlet,JSP,HTML等页面。它使用RequestDispatcher.forward()方法。
<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是一个流行的模板引擎,使用预定义的模板生成输出。让我们创建一个包含以下内容的名为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结果类型调用标准的response.sendRedirect()方法,使得浏览器向给定的位置创建一个新请求。
<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示例,以便更详细地了解。
序号 | 对象和说明 |
---|---|
1 | Temporary对象 实际中存在各种在页面执行期间创建的temporary对象。例如,JSP标签循环集合的当前迭代值。 |
2 | Model对象 如果在struts应用程序中使用Model对象,则当前Model对象放在值堆栈上的action之前。 |
3 | Action对象 这是指正在执行的当前action对象。 |
4 | 命名对象 这些对象包括#application,#session,#request,#attr和#parameters以及所引用的相应的servlet作用域。 |
值栈可以通过为JSP,Velocity或Freemarker提供的标签进行访问。我们将在单独的章节中学习到用于获取和设置struts2 值栈的各种标签。你可以在action中获取值栈对象,如下所示:
ActionContext.getContext().getValueStack()
一旦你有一个值栈对象,你可以使用以下方法来操纵该对象:
序号 | 值栈方法和说明 |
---|---|
1 | Object findValue(String expr) 通过在默认搜索顺序中对值栈评估所给定的表达式来查找值。 |
2 | CompoundRoot getRoot() 获取将对象推入值栈的CompoundRoot。 |
3 | Object peek() 获取值栈顶部的对象而不改变值栈。 |
4 | Object pop() 获取值栈顶部的对象,并将其从值栈中删除。 |
5 | void push(Object o) 将对象放在值栈的顶部。 |
6 | void set(String key,Object o) 使用给定的key在值栈上设置一个对象,使其可通过findValue(key,...)检索。 |
7 | void setDefaultType(Class defaultType) 设置在获取值时要转换的默认类型。 |
8 | void setValue(String expr,Object value) 尝试使用由默认搜索顺序给定的表达式在值栈的bean上设置属性。 |
9 | int size() 获取值栈中的对象数。 |
OGNL(Object-Graph Navigation Language,对象图导航语言)是一种强大的表达式语言,用于引用和操作值栈上的数据,还可用于数据传输和类型转换。
应用程序 - 应用程序作用域变量
会话 - 会话作用域变量
根/值栈 - 所有的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表达式很智能地将“红色”,“黄色”,“绿色”解释为颜色,并基于此构建了列表。
让我们参考下面用于访问值栈的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的值。
创建视图时需要浏览和上传选定的文件。因此,让我们先使用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配置。
<%@ 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>
接下来,让我们创建一个名为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 配置属性:
序号 | 属性和说明 |
---|---|
1 | struts.multipart.maxSize 可接受的上传文件的最大值(以字节为单位),默认值为250M。 |
2 | struts.multipart.parser 用于上传多部分表单的库,默认为jakarta。 |
3 | struts.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拦截器有两个参数:maximumSize和allowedTypes。 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和说明 |
---|---|
1 | struts.messages.error.uploading 无法上传文件时发生的常规错误。 |
2 | struts.messages.error.file.too.large 当上传的文件过大(由maximumSize指定)时发生。 |
3 | struts.messages.error.content.type.not.allowed 当上传的文件与指定的预期内容类型不匹配时发生。 |
你可以在WebContent/WEB-INF/classes/messages.properties资源文件中覆盖这些消息文本。
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类具有与数据库表中的列对应的属性。我们有user,password和name作为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,将显示以下界面:
输入错误的用户名和密码,你看到以下页面:
现在输入scott作为用户名,navy作为密码,可以应该看到以下页面:
本章内容将教你如何使用Struts2 应用程序发送电子邮件。学习前,你需要从JavaMail API 1.4.4下载并安装mail.jar,并将mail.jar文件放在WEB-INFlib文件夹中,然后继续按照以下标准步骤创建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按钮。如果一切正常,那么你可以看到以下页面:
我们接下来编写用于收集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类: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按钮,可以看到以下界面:
addFieldError("name","The name is required");
要处理input的返回值,我们需要将以下结果添加到struts.xml中的action节点。
<result name="input">/index.jsp</result>
<!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验证器”的详细信息。
UI标签
信息和错误。
Action类。
Struts2使用资源束为Web应用程序的用户提供多种语言和区域的设置选项。你不必担心需要用不同的语言编写页面,你需要做的只是为每种你想要的语言创建一个资源束。资源束将包含用户语言中的标题,消息和其他文本,是包含应用程序默认语言的一对key/value的文件。
bundlename_language_country.properties这里的bundlename可以是ActionClass,Interface,SuperClass,Model,Package,Global资源属性。下一部分language_country表示国家区域设置,例如西班牙语(西班牙)区域设置由es_ES表示,英语(美国)区域设置由en_US表示等。这里先跳过可选国家的部分。
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的目的是不同的:
package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class Locale extends ActionSupport{ public String execute() { return SUCCESS; }}
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.name = Nameglobal.age = Ageglobal.submit = Submitglobal.heading = Select Localeglobal.success = Successfully authenticated
global.name = Nom d'utilisateur global.age = l'âgeglobal.submit = Soumettre desglobal.heading = Sé lectionnez Localglobal.success = Authentifi é avec succès
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按钮,当在西班牙语环境时,会显示以下界面:
恭喜,你现在有了多语言的网页,可以在尝试在全球推送你的网站。
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.jsp和SystemDetails.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.ftl和s: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.templateSuffix和struts.ui.templateDir在struts.properties中设置配置。
<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为不同的异常显示不同的错误页面。
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。将显示如下页面:
输入值“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。如果现在重新运行程序,将看到以下输出页面:
除此之外,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>
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
首先,先开始写用来收集上面提到的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类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 应用程序可以使用Java5注释来替代XML和Java属性的配置。你可以查看与不同类别相关的最重要注释的列表:Struts2 注释类型。
Struts2 标签有一组标签,可以方便地控制页面执行的流程。以下是主要的Struts2 控制标签:
这些标签执行在每种语言中找到的基本条件流。“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>
<s:iterator value="days"> <p>day is: <s:property/></p></s:iterator>
这些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标签采用两个或多个列表作为参数,并将它们全部附加在一起,如下所示:
<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标签基于提供的val属性生成迭代器。下面的generator标签生成一个迭代器并使用iterator标签打印出来。
<s:generator val="%{'aaa,bbb,ccc,ddd,eee'}"> <s:iterator> <s:property /><br/> </s:iterator></s:generator>
Struts2 的数据标签主要用于操作页面上显示的数据。下面列出了主要的数据标签:
此标签允许开发人员通过指定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标签将用于在另一个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标签实例化一个符合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>
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标签可用于参数化其他标签。此标签具有以下两个参数。
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标签用于获取一个值的属性,如果没有指定,它将默认为在值栈的顶部。
<s:push value="myBean"> <!-- Example 1: --> <s:property value="myBeanProperty" /> <!-- Example 2: -->TextUtils <s:property value="myBeanProperty" default="a default value" /></s:push>
这些push标签用于推送堆栈中的值,以简化使用。
<s:push value="user"> <s:propery value="firstName" /> <s:propery value="lastName" /></s:push>
这些set标签为指定范围内的变量赋值。当你希望将变量分配给复杂表达式,然后仅仅引用该变量而不是复杂表达式时,它是很有用的。可应用的范围是应用程序,会话,请求,页面和action。
<s:set name="myenv" value="environment.name"/><s:property value="myenv"/>
这些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。
<-- 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标签:
我们其实已经在前面的示例中使用了这些标签,接下来将在本章中重新回顾一下。以下是一个简单的视图页面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设置了正确的映射。
群组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提供的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使用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>
当我们运行上面的例子,将得到以下的输出:
现在,让我们一步一步地完成这个例子。
首先要注意的是添加一个带有前缀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集成在一起。
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集成设置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文件相同的级别。
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,并且我们已经将值Michael和Jackson注入到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集成章节。
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布局。它有五个可重用/可覆盖区域。即 title,banner,menu,body和footer。我们提供baseLayout的默认值,然后创建从默认布局扩展的两个自定义。tiger布局类似于基本布局,除了它使用 tiger.jsp 作为其body和文本“Tiger”作为title。类似地,lion布局也类似于基本布局,除了它使用 lion.jsp 作为其 body 和文本“Lion”作为 title。
<%@ 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”类的结果类型。
现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在 Tomcat 的 webapps 目录中部署WAR文件。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/tigerMenu.jsp,将显示以下界面:
同样,如果你转到 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.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文件的完整列表的屏幕截图:
大多数JAR文件可以作为struts分发的一部分获取。如果你有安装一个应用程序服务器,如glassfish,websphere或jboss,那么你可以从appserver的lib文件夹中获取大多数剩余的jar文件。如果没有,你可以单独下载文件:
Hibernate的jar文件- Hibernate.org
Struts的Hibernate插件- Struts hibernate plugin
JTA文件- JTA file
Dom4j文件- Dom4j
SLF4J文件- SLF4J
log4j文件- log4j
其余的文件,你应该能够从struts2 中分配。
现在让我们为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类的数据访问层。它有方法来列出所有学生,然后保存一个新的学生记录。
下面的文件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。
让我们使用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,将显示以下界面:
在上面部分,我们得到一个表单,输入新学生记录的值,下面部分列出数据库中的学生。继续添加一个新的学生记录,然后按提交。屏幕将刷新,并在每次单击提交时向你显示更新了的列表。
Struts2 是目前较为普及和成熟的基于MVC设计模式的web应用程序框架,它不仅仅是Struts1 的升级版本,更是一个全新的Struts架构。最初,是以WebWork框架和Struts框架为基础,通过提供增强和改进的Struts框架,进而实现简化web技术人员开发工作的目标。不久之后,Webwork框架和Struts社区联合创造了现在流行的Struts2框架。
模型(Model)-视图(View)-控制器(Controller),通常简称MVC,是一种开发web应用程序的软件设计模式。该软件设计模式由以下三部分组成:
我们的第一个任务是运行一个最小的Struts2 应用程序。本章将指导你如何搭建Struts2 开发环境进行工作。我们假设你的电脑已经安装了JDK(5+)、Tomcat以及Eclipse,如果你没有安装这些组件那就按照下面列出快捷方式安装:
你可以在甲骨文网站的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给出的文档做正确的设置。
%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/ 进行访问了。如果一切正常,那么会显示以下结果:
%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
%C:eclipseeclipse.exe在Unix(或Solaris、Linux等)环境下,可以通过执行以下指令启动Eclipse:
$/usr/local/eclipse/eclipse启动成功后,如果一切正常,那么会显示以下结果:
从一个高水平角度看,Struts2 是一个MVC拉动的(或MVC2)框架,Struts2 的模型-视图-控制器模式是通过以下五个核心部分进行实现的:
通过学习Struts2 框架可以了解到,当你在Struts2 的web应用程序里点击一个超链接或提交一个HTML表单时,会由控制器收集输入并发送一个叫Actions的Java类。Action被执行后,Result会选择一个资源给予响应。这个资源通常是一个JSP,也可以是一个PDF文件,一个Excel表格,或者是一个Java小程序窗口。
假设你已经建好了你的开发环境,那么现在让我们继续构建第一个Struts2 项目:Hello World 。这个项目的目标是构建一个收集用户名并在用户名后跟随显示“Hello World”的web应用程序。我们需要为每个Struts2 项目构建以下四个组件:
序号 | 名称及描述 |
1 | Action(操作) |
创建一个动作类,包含完整的业务逻辑并控制用户、模型以及视图间的交互。 | |
2 | Interceptors(拦截器) |
这是控制器的一部分,可依据需求创建拦截器,或使用现有的拦截器。 | |
3 | View(视图) |
创建一个JSP与用户进行交互,获取输入并呈现最终信息。 | |
4 | Configuration Files(配置文件) |
创建配置文件来连接动作、视图以及控制器,这些文件分别是struts.xml、web.xml以及struts.properties。 |
我们如果打算使用Eclipse IDE,那么所有必需的组件都要在动态Web项目(Dynamic Web Project)下创建。因此我们就先从创建动态Web项目开始。
按照下图选择所有默认选项,最后检查 Generate Web.xml deployment descriptor 选项。这个将在Eclipse为你创建一个动态web项目。现在点击“Windows”>“Show”>“View”>“Project Explorer”,你就可以看到你的项目窗口,如下图:
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; }}
<%@ 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>
<%@ 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>
<?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>
<?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-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>
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 ,将会呈现如下图所示的结果:
输入一个“Struts2”值并提交页面,你可以看到以下页面
注意,你可以在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.xml、struts.xml、struts-config.xml以及struts.properties。
实际上,你可以继续依赖于使用web.xml和struts.xml配置文件,并且你已经在前面的章节中了解到,我们的示例是使用这两个文件运作的,不过为了让你了解更多,我们还是再来说明一下其他的文件。
正如前面所讨论的,这个文件为每个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代替。
<?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不能被最终用户使用。 |
namespace | Actions的唯一命名空间 |
<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配置文件是Web Client中View和Model组件之间的链接,但在你99.99%的项目里你不必使用这些设置。 struts-config.xml配置文件包含以下主要元素:
序号 | 拦截器和说明 |
---|---|
1 | struts-config 这是配置文件的根节点。 |
2 | form-beans 这是你将ActionForm子类映射到name的位置,你可以在struts-config.xml文件的其余部分,甚至在JSP页面上,将这个name用作ActionForm的别名。 |
3 | global forwards 此部分将你在webapp上的页面映射到name,你可以使用这个name来引用实际页面。这避免了对你网页上的URL进行硬编码。 |
4 | action-mappings 这是你声明表单处理程序的地方,也被称为操作映射(action mappings)。 |
5 | controller 这部分是配置Struts的内部,在实际情况中很少使用。 |
6 | plug-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配置文件中包含的所有属性也可以在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默认忽略。
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”之外的任何词,你会看到如下页面:
你会需要频繁定义多个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个拦截器。
Struts 2框架提供了一个良好的开箱即用的拦截器列表,这些拦截器预先配置好并可以使用。 下面列出了几个重要的拦截器:
序号 | 拦截器和说明 |
---|---|
1 | alias 允许参数在请求之间使用不同的别名。 |
2 | checkbox 通过为未检查的复选框添加参数值false,以辅助管理复选框。 |
3 | conversionError 将字符串转换为参数类型的错误信息放置到action的错误字段中。 |
4 | createSession 自动创建HTTP会话(如果尚不存在)。 |
5 | debugging 为开发人员提供一些不同的调试屏幕。 |
6 | execAndWait 当action在后台执行时,将用户发送到中间的等待页面。 |
7 | exception 映射从action到结果抛出的异常,允许通过重定向自动处理异常。 |
8 | fileUpload 便于文件上传。 |
9 | i18n 在用户会话期间跟踪选定的区域。 |
10 | logger 通过输出正在执行的action的名称提供简单的日志记录。 |
11 | params 设置action上的请求参数。 |
12 | prepare 这通常用于执行预处理工作,例如设置数据库连接。 |
13 | profile 允许记录action的简单分析信息。 |
14 | scope 在会话或应用程序范围内存储和检索action的状态。 |
15 | ServletConfig 提供可访问各种基于servlet信息的action。 |
16 | timer 以action执行时间的形式提供简单的分析信息。 |
17 | token 检查action的有效性,以防止重复提交表单。 |
18 | validation 提供action的验证支持。 |
你可以阅读Struts 2文档,了解上述拦截器的完整信息。接下来我们会告诉你如何在Struts应用程序中使用拦截器。
<?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()方法。
我们接下来在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()调用执行,所以你可以根据你的需求做一些预处理和一些后处理。
我们在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。将显示如下图片:
现在,在给的定文本框中输入任意单词,然后单击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 name="hello" class="com.tutorialspoint.struts2.MyAction"> <interceptor-ref name="basicStack"/> <result>view.jsp</result></action
上述的“basicStack”注册将完整注册hello action的所使用的六个拦截器。要注意的是,拦截器按照它们被配置的顺序执行。例如,在上面的例子中,exception将首先执行,第二个将是servlet-config等。
dispatcher结果类型是默认的类型,如果未指定其他结果类型,则使用此类型。它用于转发到服务器上的servlet,JSP,HTML等页面。它使用RequestDispatcher.forward()方法。
<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是一个流行的模板引擎,使用预定义的模板生成输出。让我们创建一个包含以下内容的名为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结果类型调用标准的response.sendRedirect()方法,使得浏览器向给定的位置创建一个新请求。
<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示例,以便更详细地了解。
序号 | 对象和说明 |
---|---|
1 | Temporary对象 实际中存在各种在页面执行期间创建的temporary对象。例如,JSP标签循环集合的当前迭代值。 |
2 | Model对象 如果在struts应用程序中使用Model对象,则当前Model对象放在值堆栈上的action之前。 |
3 | Action对象 这是指正在执行的当前action对象。 |
4 | 命名对象 这些对象包括#application,#session,#request,#attr和#parameters以及所引用的相应的servlet作用域。 |
值栈可以通过为JSP,Velocity或Freemarker提供的标签进行访问。我们将在单独的章节中学习到用于获取和设置struts2 值栈的各种标签。你可以在action中获取值栈对象,如下所示:
ActionContext.getContext().getValueStack()
一旦你有一个值栈对象,你可以使用以下方法来操纵该对象:
序号 | 值栈方法和说明 |
---|---|
1 | Object findValue(String expr) 通过在默认搜索顺序中对值栈评估所给定的表达式来查找值。 |
2 | CompoundRoot getRoot() 获取将对象推入值栈的CompoundRoot。 |
3 | Object peek() 获取值栈顶部的对象而不改变值栈。 |
4 | Object pop() 获取值栈顶部的对象,并将其从值栈中删除。 |
5 | void push(Object o) 将对象放在值栈的顶部。 |
6 | void set(String key,Object o) 使用给定的key在值栈上设置一个对象,使其可通过findValue(key,...)检索。 |
7 | void setDefaultType(Class defaultType) 设置在获取值时要转换的默认类型。 |
8 | void setValue(String expr,Object value) 尝试使用由默认搜索顺序给定的表达式在值栈的bean上设置属性。 |
9 | int size() 获取值栈中的对象数。 |
OGNL(Object-Graph Navigation Language,对象图导航语言)是一种强大的表达式语言,用于引用和操作值栈上的数据,还可用于数据传输和类型转换。
应用程序 - 应用程序作用域变量
会话 - 会话作用域变量
根/值栈 - 所有的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表达式很智能地将“红色”,“黄色”,“绿色”解释为颜色,并基于此构建了列表。
让我们参考下面用于访问值栈的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的值。
创建视图时需要浏览和上传选定的文件。因此,让我们先使用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配置。
<%@ 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>
接下来,让我们创建一个名为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 配置属性:
序号 | 属性和说明 |
---|---|
1 | struts.multipart.maxSize 可接受的上传文件的最大值(以字节为单位),默认值为250M。 |
2 | struts.multipart.parser 用于上传多部分表单的库,默认为jakarta。 |
3 | struts.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拦截器有两个参数:maximumSize和allowedTypes。 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和说明 |
---|---|
1 | struts.messages.error.uploading 无法上传文件时发生的常规错误。 |
2 | struts.messages.error.file.too.large 当上传的文件过大(由maximumSize指定)时发生。 |
3 | struts.messages.error.content.type.not.allowed 当上传的文件与指定的预期内容类型不匹配时发生。 |
你可以在WebContent/WEB-INF/classes/messages.properties资源文件中覆盖这些消息文本。
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类具有与数据库表中的列对应的属性。我们有user,password和name作为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,将显示以下界面:
输入错误的用户名和密码,你看到以下页面:
现在输入scott作为用户名,navy作为密码,可以应该看到以下页面:
本章内容将教你如何使用Struts2 应用程序发送电子邮件。学习前,你需要从JavaMail API 1.4.4下载并安装mail.jar,并将mail.jar文件放在WEB-INFlib文件夹中,然后继续按照以下标准步骤创建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按钮。如果一切正常,那么你可以看到以下页面:
我们接下来编写用于收集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类: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按钮,可以看到以下界面:
addFieldError("name","The name is required");
要处理input的返回值,我们需要将以下结果添加到struts.xml中的action节点。
<result name="input">/index.jsp</result>
<!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验证器”的详细信息。
UI标签
信息和错误。
Action类。
Struts2使用资源束为Web应用程序的用户提供多种语言和区域的设置选项。你不必担心需要用不同的语言编写页面,你需要做的只是为每种你想要的语言创建一个资源束。资源束将包含用户语言中的标题,消息和其他文本,是包含应用程序默认语言的一对key/value的文件。
bundlename_language_country.properties这里的bundlename可以是ActionClass,Interface,SuperClass,Model,Package,Global资源属性。下一部分language_country表示国家区域设置,例如西班牙语(西班牙)区域设置由es_ES表示,英语(美国)区域设置由en_US表示等。这里先跳过可选国家的部分。
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的目的是不同的:
package cn.51coolma.struts2;import com.opensymphony.xwork2.ActionSupport;public class Locale extends ActionSupport{ public String execute() { return SUCCESS; }}
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.name = Nameglobal.age = Ageglobal.submit = Submitglobal.heading = Select Localeglobal.success = Successfully authenticated
global.name = Nom d'utilisateur global.age = l'âgeglobal.submit = Soumettre desglobal.heading = Sé lectionnez Localglobal.success = Authentifi é avec succès
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按钮,当在西班牙语环境时,会显示以下界面:
恭喜,你现在有了多语言的网页,可以在尝试在全球推送你的网站。
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.jsp和SystemDetails.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.ftl和s: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.templateSuffix和struts.ui.templateDir在struts.properties中设置配置。
<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为不同的异常显示不同的错误页面。
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。将显示如下页面:
输入值“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。如果现在重新运行程序,将看到以下输出页面:
除此之外,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>
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
首先,先开始写用来收集上面提到的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类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 应用程序可以使用Java5注释来替代XML和Java属性的配置。你可以查看与不同类别相关的最重要注释的列表:Struts2 注释类型。
Struts2 标签有一组标签,可以方便地控制页面执行的流程。以下是主要的Struts2 控制标签:
这些标签执行在每种语言中找到的基本条件流。“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>
<s:iterator value="days"> <p>day is: <s:property/></p></s:iterator>
这些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标签采用两个或多个列表作为参数,并将它们全部附加在一起,如下所示:
<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标签基于提供的val属性生成迭代器。下面的generator标签生成一个迭代器并使用iterator标签打印出来。
<s:generator val="%{'aaa,bbb,ccc,ddd,eee'}"> <s:iterator> <s:property /><br/> </s:iterator></s:generator>
Struts2 的数据标签主要用于操作页面上显示的数据。下面列出了主要的数据标签:
此标签允许开发人员通过指定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标签将用于在另一个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标签实例化一个符合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>
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标签可用于参数化其他标签。此标签具有以下两个参数。
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标签用于获取一个值的属性,如果没有指定,它将默认为在值栈的顶部。
<s:push value="myBean"> <!-- Example 1: --> <s:property value="myBeanProperty" /> <!-- Example 2: -->TextUtils <s:property value="myBeanProperty" default="a default value" /></s:push>
这些push标签用于推送堆栈中的值,以简化使用。
<s:push value="user"> <s:propery value="firstName" /> <s:propery value="lastName" /></s:push>
这些set标签为指定范围内的变量赋值。当你希望将变量分配给复杂表达式,然后仅仅引用该变量而不是复杂表达式时,它是很有用的。可应用的范围是应用程序,会话,请求,页面和action。
<s:set name="myenv" value="environment.name"/><s:property value="myenv"/>
这些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。
<-- 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标签:
我们其实已经在前面的示例中使用了这些标签,接下来将在本章中重新回顾一下。以下是一个简单的视图页面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设置了正确的映射。
群组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提供的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使用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>
当我们运行上面的例子,将得到以下的输出:
现在,让我们一步一步地完成这个例子。
首先要注意的是添加一个带有前缀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集成在一起。
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集成设置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文件相同的级别。
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,并且我们已经将值Michael和Jackson注入到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集成章节。
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布局。它有五个可重用/可覆盖区域。即 title,banner,menu,body和footer。我们提供baseLayout的默认值,然后创建从默认布局扩展的两个自定义。tiger布局类似于基本布局,除了它使用 tiger.jsp 作为其body和文本“Tiger”作为title。类似地,lion布局也类似于基本布局,除了它使用 lion.jsp 作为其 body 和文本“Lion”作为 title。
<%@ 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”类的结果类型。
现在,右键单击项目名称,然后单击“Export”> “WAR File”以创建WAR文件。然后在 Tomcat 的 webapps 目录中部署WAR文件。最后,启动 Tomcat 服务器并尝试访问 URL http://localhost:8080/HelloWorldStruts2/tigerMenu.jsp,将显示以下界面:
同样,如果你转到 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.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文件的完整列表的屏幕截图:
大多数JAR文件可以作为struts分发的一部分获取。如果你有安装一个应用程序服务器,如glassfish,websphere或jboss,那么你可以从appserver的lib文件夹中获取大多数剩余的jar文件。如果没有,你可以单独下载文件:
Hibernate的jar文件- Hibernate.org
Struts的Hibernate插件- Struts hibernate plugin
JTA文件- JTA file
Dom4j文件- Dom4j
SLF4J文件- SLF4J
log4j文件- log4j
其余的文件,你应该能够从struts2 中分配。
现在让我们为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类的数据访问层。它有方法来列出所有学生,然后保存一个新的学生记录。
下面的文件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。
让我们使用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,将显示以下界面:
在上面部分,我们得到一个表单,输入新学生记录的值,下面部分列出数据库中的学生。继续添加一个新的学生记录,然后按提交。屏幕将刷新,并在每次单击提交时向你显示更新了的列表。