1.struts1的action是单例模式且必须是线程安全的,action的一个实例处理所有请求. struts2的action对象为每个请求产生一个实例,没有线程安全问题. struts1的action依赖于servlet api,struts2的action不依赖与容器,允许脱离容器单独测试. 2.struts1的execute方法依赖于servlet api,使得测试要依赖于容器.struts2的action可以通过初始化,设置属性,调用方法来测试,依赖注入支持是测试更容易. struts1试用ActionForm对象捕获输入,普通JavaBean不能捕获输入.动态bean可以作为ActionForm的选择,但是是在重复描述已经存在的Javabean. struts2直接试用action属性作为输入属性,消除了对第二个输入对象的需求.也支持ActionForm模式,这种ModelDriven特性简化了tiglib对POJO对象的应用. 3.struts1整合的JSTL,试用JSTL EL,EL有基本对象图遍历功能,但是对集合和索引属性的支持很弱 struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言-- Object Graph Notation Language(OGNL) 4.struts1试用标准jsp机制把对象绑定到页面中来访问 struts2试用ValueStack技术,允许试用一系列名称相同但类型不同的属性重用页面 5.struts1的ActionForm通常都是String类型,试用BeanUtils进行类型转换 struts2使用OGNL进行类型转换,提供基本和常用对象的转化器. 6.struts1支持在ActionForm的validate方法中手动效验,或者通过validator扩展效验 struts2支持通过validate方法和XWork效验框架来进行效验 7.struts1支持每个模块有单独的request生命周期,但是模块中的所有action必须共享相同的生命周期 struts2支持通过拦截器interceptor stacks为每个action创建不同的生命周期
在本系列教程中我们将学习到 Struts2 的各种技术。在本教程中使用的工具和程序库的版本如下:
开发工具: MyEclipse6
Web 服务器: Tomcat6
Struts 版本: Struts2.0.11.1
JDK 版本: JDK1.5.0_12
J2EE 版本: Java EE5.0
在本系列教程中 Web 工程的上下文路径都是 struts2 ,如果在 Web 根目录有一个 index.jsp 文件,则访问路径如下:
http://localhost:8080/struts2/index.jsp
由于 MyEclipse6 目前并不支持 Struts2 ,所以我们需要到 struts.apache.org 去下载 Struts2 安装包。要想正常使用 Struts2 ,至少需要如下五个包(可能会因为 Struts2 的版本不同,包名略有差异,但包名的前半部是一样的)。
struts2-core-2.0.11.1.jar
xwork-2.0.4.jar
commons-logging-1.0.4.jar
freemarker-2.3.8.jar
ognl-2.6.11.jar
Struts2 虽然在大版本号上是第二个版本,但基本上在配置和使用上已经完全颠覆了 Struts1.x 的方式(当然, Struts2 仍然是基于 MVC 模式的,也是动作驱动的,可能这是唯一没变的东西)。 Struts2 实际上是在 Webwork 基础上构建起来的 MVC 框架。我们从 Struts2 的源代码中可以看到,有很多都是直接使用的 xwork(Webwork 的核心技术 ) 的包。既然从技术上来说 Struts2 是全新的框架,那么就让我们来学习一下这个新的框架的使用方法。
如果大家使用过 Struts1.x ,应该对建立基于 Struts1.x 的 Web 程序的基本步骤非常清楚。让我们先来回顾一下建立基于 Struts1.x 的 Web 程序的基本步骤。
1. 安装 Struts 。由于 Struts 的入口点是 ActionServlet ,所以得在 web.xml 中配置一下这个 Servlet 。
2. 编写 Action 类(一般从 org.apache.struts.action.Action 类继承)。
3. 编写 ActionForm 类(一般从 org.apache.struts.action.ActionForm 类继承),这一步不是必须的,如果要接收客户端提交的数据,需要执行这一步。
4. 在 struts-config.xml 文件中配置 Action 和 ActionForm 。
5. 如果要采集用户录入的数据,一般需要编写若干 JSP 页面,并通过这些 JSP 页面中的 form 将数据提交给 Action 。
下面我们就按着编写 struts1.x 程序的这五步和 struts2.x 程序的编写过程一一对应,看看它们谁更 “ 酷 ” 。下面我们来编写一个基于 Struts2 的 Web 程序。这个程序的功能是让用户录入两个整数,并提交给一个 Struts Action ,并计算这两个数的代数和,如果代码和为非负数,则跳转到 positive.jsp 页面,否则跳转到 negative.jsp 页面。
【第 1 步】 安装 Struts2
这一步对于 Struts1.x 和 Struts2 都是必须的,只是安装的方法不同。 Struts1 的入口点是一个 Servlet ,而 Struts2 的入口点是一个过滤器 (Filter) 。因此, Struts2 要按过滤器的方式配置。下面是在 web.xml 中配置 Struts2 的代码:
<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>
【第 2 步】 编写 Action 类
这一步和 Struts1.x 也必须进行。只是 Struts1.x 中的动作类必须从 Action 类中继承,而 Struts2.x 的动作类需要从 com.opensymphony.xwork2.ActionSupport 类继承。下面是计算两个整数代码和的 Action 类,代码如下:
package action;
import com.opensymphony.xwork2.ActionSupport;
public class FirstAction extends ActionSupport
{
private int operand1;
private int operand2;
public String execute() throws Exception
{
if (getSum() >= 0) // 如果代码数和是非负整数,跳到 positive.jsp 页面
{
return "positive";
}
else // 如果代码数和是负整数,跳到 negative.jsp 页面
{
return "negative";
}
}
public int getOperand1()
{
return operand1;
}
public void setOperand1(int operand1)
{
System.out.println(operand1);
this.operand1 = operand1;
}
public int getOperand2()
{
return operand2;
}
public void setOperand2(int operand2)
{
System.out.println(operand2);
this.operand2 = operand2;
}
public int getSum()
{
return operand1 + operand2; // 计算两个整数的代码数和
}
}
从上面的代码可以看出,动作类的一个特征就是要覆盖 execute 方法,只是 Struts2 的 execute 方法没有参数了,而 Struts1.x 的 execute 方法有四个参数。而且 execute 方法的返回值也不同的。 Struts2 只返回一个 String ,用于表述执行结果(就是一个标志)。上面代码的其他部分将在下面讲解。
【第 3 步】 编写 ActionForm 类
在本例中当然需要使用 ActionForm 了。在 Struts1.x 中,必须要单独建立一个 ActionForm 类(或是定义一个动作 Form ),而在 Struts2 中 ActionForm 和 Action 已经二合一了。从第二步的代码可以看出,后面的部分就是应该写在 ActionForm 类中的内容。所以在第 2 步,本例的 ActionForm 类已经编写完成(就是 Action 类的后半部分)。
【第 4 步】 配置 Action 类
这一步 struts1.x 和 struts2.x 都是必须的,只是在 struts1.x 中的配置文件一般叫 struts-config.xml (当然也可以是其他的文件名),而且一般放到 WEB-INF 目录中。而在 struts2.x 中的配置文件一般为 struts.xml ,放到 WEB-INF"classes 目录中。下面是在 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>
<package name="struts2" namespace="/mystruts"
extends="struts-default">
<action name="sum" class="action.FirstAction">
<result name="positive">/positive.jsp</result>
<result name="negative">/negative.jsp</result>
</action>
</package>
</struts>
在 <struts> 标签中可以有多个 <package> ,第一个 <package> 可以指定一个 Servlet 访问路径(不包括动作名),如 “/mystruts” 。 extends 属性继承一个默认的配置文件 “struts-default” ,一般都继承于它,大家可以先不去管它。 <action> 标签中的 name 属性表示动作名, class 表示动作类名。
<result> 标签的 name 实际上就是 execute 方法返回的字符串,如果返回的是 “positive” ,就跳转到 positive.jsp 页面,如果是 “negative” ,就跳转到 negative.jsp 页面。在 <struts> 中可以有多个 <package> ,在 <package> 中可以有多个 <action> 。我们可以用如下的 URL 来访问这个动作:
http://localhost:8080/struts2/mystruts/sum.action
注: Struts1.x 的动作一般都以 .do 结尾,而 Struts2 是以 .action 结尾。
【第 5 步】 编写用户录入接口( JSP 页面)
1. 主界面( sum.jsp )
在 Web 根目录建立一个 sum.jsp ,代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="GBK" %>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title> 输入操作数 </title>
</head>
<body>
求代数和
<br/>
<s:form action="mystruts/sum.action" >
<s:textfield name="operand1" label=" 操作数 1"/>
<s:textfield name="operand2" label=" 操作数 2" />
<s:submit value=" 代数和 " />
</s:form>
</body>
</html>
在 sum.jsp 中使用了 Struts2 带的 tag 。在 Struts2 中已经将 Struts1.x 的好几个标签库都统一了,在 Struts2 中只有一个标签库 /struts-tags 。这里面包含了所有的 Struts2 标签。但使用 Struts2 的标签大家要注意一下。在 <s:form> 中最好都使用 Struts2 标签,尽量不要用 HTML 或普通文本,大家可以将 sum.jsp 的代码改为如下的形式,看看会出现什么效果:
... ...
求代数和
<br/>
<s:form action="mystruts/sum.action" >
操作数 1 : <s:textfield name="operand1" /><br/>
操作数 2 : <s:textfield name="operand1" /><br/>
<s:submit value=" 代数和 " />
</s:form>
... ...
提示一下,在 <s:form> 中 Struts2 使用 <table> 定位。
2. positive.jsp
<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title> 显示代数和 </title>
</head>
<body>
代数和为非负整数 <h1><s:property value="sum" /></h1>
</body>
</html>
3. negative.jsp
<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title> 显示代数和 </title>
</head>
<body>
代数和为负整数 <h1><s:property value="sum" /></h1>
</body>
</html>
这两个 jsp 页面的实现代码基本一样,只使用了一个 <s:property> 标签来显示 Action 类中的 sum 属性值。 <s:property> 标签是从 request 对象中获得了一个对象中得到的 sum 属性,如我们可以使用如下的代码来代替 <s:property value=”sum”/> :
<%
com.opensymphony.xwork2.util.OgnlValueStack ovs =
(com.opensymphony.xwork2.util.OgnlValueStack)request.getAttribute("struts.valueStack");
out.println(ovs.findString("sum"));
%>
启动 Tomcat 后,在 IE 中输入如下的 URL 来测试这个例子:
http://localhost:8080/struts2/sum.jsp
1.<Data-sources> :用来配置数据源,连接数据库。
<data-source> : 具体是数据库连接。
Type : type="org.apache.dbcp.BasicDataSource" Struts 中连接数据库的类。
< set-property> :此标签中配置具体的链接内容。如:
<set-property property="driverClassName" value="com.mysql.jdbc.Driver" />
数据库驱动
<set-property property="url" value="jdbc:mysql://localhost:3306/exam" />
数据库地址。
<set-property property="username" value="root" />
数据库登录名。
<set-property property="password" value="root" />
数据库密码。
<set-property property="autoCommit" value="true" />
自动提交。
<set-property property="maxActive" value="10" />
最大连接数。
<set-property property="maxWait" value="5000" />
最大等待数。
<set-property property="defaultAutoCommit" value="false" />
默认自动提交。
<set-property property="defaultReadOnly" value="false" />
默认为只读。
<set-property property="validationQuery"
value="SELECT COUNT(*) FROM users" />
这里可以不加,不过加了就保证能至少能够返回一条记录。
2.< form-beans> :用来配置多个 ActionForm, 包含一个或者多个 <form-bean> 子元素。每个 <form-bean> 子元素里都有很多属性。
Classname :制定 <form-bean> 配置的类。
Name : 制定该 ActionForm 的唯一标识。
Type : 制定该 ActionForm 的路径,带包名。
<form-property> :指定动态的 Form 的元。
3. <global-exceptions> : 用于配置异常处理 , 元素可以包含一个或者多个 <exception> 元素 , 用来设置 JAVA 异常和异常处理类 ExceptionHandler 之间的映射。
className :指定和元素对应的配置类 , 默认的不用动 .
Handler :指定异常处理类,默认是 ExceptionHandler.key 指定在本地资源文件中异常的消息。
Key,path :指定当前异常发生的时候转发的路径。
Scope :指定 ActionMessages 实例存放的范围。
Type :指定需要处理异常类的名字,必须的。
Bundle :指定 Resource Bundle 。
4. < global-forwards> :用来声明全局转发,元素可以有一个或者多个 <forward> 元素组成,用于把一个逻辑名映射到特定的 URL ,通过这种方法 Action 类或者 JSP 页面无需指定 URL ,只要指定逻辑名称就可以实现请求转发或者重定向。这样可以减少控制组件和视图的聚合。易于维护。
className :对应的配置类。
contextRelative :如果为 true 表示当 path 属性以 / 开头的时候,给出的是对应的上下文 URL 默认是 false.name 转发路径的逻辑名,必须写 .
Path :转发或者重定向的 URL ,必须写,必须是以 / 开头。
Redirect :设置为 true 的时候表示执行重定向操作,此项为 false 的时候,表示执行请求转发操作。重定向与请求转发的区别以后就是重定向是把请求生成应答给客户端然后,再重新发送给定向的 URL ,浏览器地址栏会有显示。而转发就是直接把请求转发给本应用的另一个文件,不生成应答所以客户端 IE 没显示。
5. < action-mapping> :包含一个或者多个 <action> 元素,描述了从特定的请求路径到响应的 Action 的映射。在 <action> 元素中可以包含多个 <exception> 和 <forward> 子元素,他们分别配置局部异常处理和局部转发。
Attribute : 设置 Action 关联的 ActionForm 在 request 或者 session 范围内的 key 。就是在 request 或 者 session 共享内的名称。
className :对应配置元素的类 . 默认的是 ActionMapping 。
Forward :指定转发 URL 路径。
Include :指定包含 URL 路径。
Input :指定包含表单的 URL ,当表单验证失败的时候发送的 URL.
Name :指定和该 Action 关联的 Form 名字。该名字必须是在 form-bean 中定义过的,可写可不写。
Path :必须 / 开头的方位 Action 的路径。
Parameter :指定 Action 配置 参数。在 Action 的 execute() 方法中可以调用 ActionMapping 的 getParameter() 方法来读取匹配的参数。
Roles :指定允许调用该 Action 的安全角色,多个角色之间逗号格开。
Scope :指定 Form 的存在范围 . 默认是 session.tyep 指定 Action 的完整类名。
Unknown :如果是 true 表示可以处理用户发出的所有的无效的 ActionURL 默认是 false 。
Validate :指定是否调用 ActionForm 的 validate 方法。
6 . <controller> :用于配置 ActionServlet.
buffreSize 指定上载文件的输入缓冲大小。该属性为可选默认 4096 。
className :指定元素对应的配置类, ControllerConfig 。然后是 contentType 指定响应结果内容类型和字符编码,该属性为可选 , 默认是 text/html 如果在 Action 或者 JSP 网页也设置了类型内容,会覆盖这个。
Locale :指定是否把 Locale 对象保存到当前用户的 session 中默认 false 。
tempDir :指定处理文件上载的临时工作目录。
Nochache :如果是 true 在响应结果中加入特定的头参数。
7 . <message-resources> :用来配置 Resource Bundle 。用于存放本地文本消息文件。
className :元素对应的配置类。
MessageResourcesConfig.factory :指定消息的工厂类。
Key :指定文件存放的 Servlet 对象中采用的属性。
Key.null :指定如何处理未知消息。
Parameter :指定消息的文件名。
8 . <plug-in> :用于配置 Struts 插件。
PS:
配置多应用模块: 所有的子应用都可以共享同一个 ActionServlet 实例,但是每个子应用都有单独的配置文件。把应用划分为多个子应用模块。首先为每个应用创建单独的 Struts 配置文件,在 web.xml 的 ActionServlet 配置代码中添加几个子应用信息。采用 <forward> 元素来实现应用之间的切换。