从头开始 Struts 2 入门
[序]
本文采用 Maven2 工具进行 Struts2 的开发管理。用户只需安装JDK 5 (或6),和 Maven2 工具即可,不需安装 Struts2 以及 Tomcat 等。唯一的要求是能够连接互联网。
[下载和安装 JDK] (略)
[下载和安装 Maven2 ]
到 http://maven.apache.org/download.html 下载 Maven 2.2.1
(比如说) 解压缩到C 盘,c:apache-maven-2.2.1-binapache-maven-2.2.1
[编写环境变量脚本]
- 在 c:apache-maven-2.2.1-binapache-maven-2.2.1 下新建文件 setEnv.bat (也可以放在任何别的地方,只要你用着方便就行。),内容如下:
set M2_HOME=c:apache-maven-2.2.1-binapache-maven-2.2.1
set JAVA_HOME="C:Program FilesJavajdk1.6.0_18"
set M2=%M2_HOME%bin
set path=%path%;"%JAVA_HONE%/bin";%M2%
(注:以上环境变量也可以通过 Windows 系统的环境变量管理工具直接配置到系统中,如果这样,下面的运行脚本就可以省略了。)
[运行并验证 Maven ]
打开 CMD 窗口,运行
C:> c:apache-maven-2.2.1-binapache-maven-2.2.1setEnv.bat
C:> mvn --version
屏幕显示:
Apache Maven 2.2.1 (r801777; 2009-08-07 03:16:01+0800)
Java version: 1.6.0_18
Java home: C:Program FilesJavajdk1.6.0_18jre
Default locale: zh_CN, platform encoding: GBK
OS name: "windows xp" version: "5.1" arch: "x86" Family:
"windows"
即表示 Maven 安装成功!
[配置代理]
如果用户采用的是代理服务器连接互联网,则需要为 Maven 设置代理,
<settings>
<proxies>
<proxy>
<active>true</active>
<protocol>http</protocol>
<host>proxy.somewhere.com</host>
<port>8080</port>
<username>proxyuser</username>
<password>somepassword</password>
<nonProxyHosts>www.google.com|*.somewhere.com</nonProxyHosts>
</proxy>
</proxies>
</settings>
至此,开发环境安装和配置完毕!
(注:Maven 可以进行多种Java应用类型的开发管理,它的安装包并不包含需要开发的各种应用的类库,相反,它把所有的开发库放在服务器端。因此,当你需要开发特定类型应用时,需要从服务器上下载类库,因此,需要你的开发环境实时连接到网络。)
[第一个 Struts2 应用]
Maven 能够为 Struts2 快速生成应用和开发框架。为了方便,我们假设在 C: 盘新建了 MyProjects 目录。然后在 CMD 中,
C:> cd C:MyProjects
C:MyProjects> c:apache-maven-2.2.1-binapache-maven-2.2.1setEnv.bat
C:MyProjects> mvn --version
以上用于验证环境是否好用。如果没问题,则运行下面命令来创建一个 Struts2 的开发和应用框架。
C:MyProjects> mvn archetype:generate
-DgroupId=com.mycompany.app
-DartifactId=mystruts
-DarchetypeGroupId=org.apache.struts
-DarchetypeArtifactId=struts2-archetype-starter
(注:以上命令是让 Maven 在当前目录下创建一个名字为 mystruts 的类型为 struts2-archetype-starter, 即一个简单的 Struts2 的应用, mystruts 是你起的名字,struts2-archetype-starter 是 Maven 支持的开发 struts2 的类型名字(想知道 Maven 共支持哪些类型? 只需运行 mvn archetype:generate 即可。)。所有的源程序包括库文件和配置文件都在 src 目录下)
编译、部署和运行这个项目,只需一个命令即可。
C:MyProjects cd mystruts
C:MyProjectsmystruts> mvn jetty:run
(注:jetty 是个 mvn 插件,是个 Web 服务器。这也是我们不需要 Tomcat 的原因。)
(注:mvn 的生命周期管理是把应用的生命期定义为顺序的多个阶段,当你执行某个阶段时,它会把这个阶段以前的所有阶段都执行,因此,运行run,它会把编译、打包等一并运行。) 所有的目标文件都在 target 目录下。
运行完 mvn jetty:run 在DOS 窗口显示 Started Jetty Server 之后,意味着应用已经编译、打包、部署完毕了,下面就可以用浏览器访问了。
http://localhost:8080/mystruts/
如果你不想用 jetty,而是其他的 web 服务器,如 tomcat 来使用你开发的应用。则你要做的就是把应用编译、打包,运行
C:MyProjectsmystruts> mvn package
即可生成标准的 Web 应用包: C:MyProjectsmystrutstargetmystruts.war。这个包含有你开发的应用程序和它依赖的所有类库,你不需在 Tomcat 上做任何额外的配置。
无论用 jetty 还是 tomcat, 我们发现这是个有点复杂的应用。下面我们通过这个例子,一点一点的学习 Struts2 的基本概念。
C:MyProjectsmystrutspom.xml 文件,是 Maven 用于开发的项目管理配置文件(与Struts 无关),从这个配置文件中,我们可以看出应用依赖的所有外部的东西和他们的版本。例如:struts2-archetype-starter 这个类型的应用使用 struts2 2.0.11.2, Servlet 2.4, JSP 2.0 等。这个
(注意:这些依赖的类库首先是从 Maven 服务器端下载到你的本地库中,它缺省的位置在 C:Documents and SettingsAdministrator.m2repository)。
在 C:MyProjectsmystrutssrcmainwebappWEB-INFweb.xml 中,可以看到如下配置,
<!-- Welcome file lists -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
因此,当我们访问 http://localhost:8080/mystruts/ 时,web 服务器根据上面的配置,在 web 应用的根目录 C:MyProjectsmystrutssrcmainwebapp 下找到了index.jsp。因此,实际服务器调用的是
http://localhost:8080/mystruts/index.jsp
打开 index.jsp ,我们看到它只有一句话
<% response.sendRedirect("index.action"); %>
这是标准的 JSP Java 代码元素的代码段(scriplets) 语句(关于JSP,参照本站其他文章)。它调用了内置的响应对象的重定向的方法,即把响应重定向到index.action, 相当于
http://localhost:8080/mystruts/index.action
我们看到了以 action 为类型的URL,web 服务器会根据 web.xml 中 struts filter
的配置,用 action 过滤器来处理这类URL。这是 Struts 框架定义的内容:Struts (web) 应用都必须在 web.xml 中配置它的filter,主要有:
<filter>
<filter-name>action2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
并把它配置成适用于所有请求类型:
<filter-mapping>
<filter-name>action2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
这些过滤器会从URL中读出请求的 action 名字,本例中是 “index”, 然后根据 C:MyProjectsmystrutssrcmainresourcesstruts.xml 中的配置去寻找实际的 Action,和与之对应的jsp
<action name="index"
class="com.mycompany.app.IndexAction">
<result>/jsp/index.jsp</result>
</action>
Struts 采用 MVC 的架构模式,上面提到的 filter 相当于 control,action 则是 module,用于业务逻辑,而<result>中的JSP则是 View。在配置时,我们只需配置 action 和与之对应的 JSP results。
http://localhost:8080/mystruts/index.action 这个请求,在服务器端,经过 struts 过滤器的处理,通过struts.xml 的配置,终于找到了com.mycompany.app.IndexAction,并调用它的 execute 方法。
IndexAction 的 execute 非常简单,只是把本身的时间属性更新了一下。
public String execute() throws Exception
{
now = new Date(System.currentTimeMillis());
return SUCCESS;
}
我们注意到,IndexAction 有一个重要的方法:
public Date getDateNow() { return now; }
这个方法不简单,IndexAction 是一个Java 组件 (即Java bean ),now 是他的属性,但 now这个名字是内部名字,如果让外部可以访问这个属性,就要通过 getter 方法, getDataNow,相当于告诉外部的对象,我的属性叫“dateNow”。
这个 action 做完后,struts 马上调用 inex.jsp 去现实结果。
在 index.jsp 中,有下面这个语句:
<s:textfield label="What is the date?" name="dateNow" />
前面我们提到,IndexAction 与 index.jsp 被配置成对应的 Model - View 的关系,因此 view index.jsp 对 IndexAction 具有访问权,"dataNow" 就是IndexAction 的属性 dataNow 的值 (通过getDateNow) 方法。
第一个例子完成了。通过这个例子,我们可以看到,Struts 框架为我们隐藏了一些细节。我们需要做得事情很简单:定义Action,配置与之对应的JSP view, 并在 JSP view 中使用 action 属性。
用一句话总结就是: URL 客户端请求 -> Struts filter -> Action -> JSP -> 客户端
多简单啊!
继续:
在 index.jsp 中定义了
<s:form action="helloWorld">
<s:textfield
label="What is your name?" name="name" />
<s:textfield
label="What is the date?" name="dateNow" />
<s:submit
/>
</s:form>
我们看到这里的Action是一个 id: "helloWorld", 而不是具体的Action类,这是什么意思呢? 原来,在 C:MyProjectsmystrutssrcmainresourceapplicationContext.xml 文件中,
<?xml version="1.0"
encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC
"-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- Example of SAF2 action
instantiated by Spring -->
<bean id="helloWorldAction"
class="com.mycompany.app.HelloWorldAction" singleton="false"
/>
</beans>
helloWorldAction 已经被定义成一个Java bean。原来,Struts2 采用了 Spring 框架中的 bean 管理机制用于创建 Action Bean 。如果一个Action 定义成 bean, 则 bean 工厂负责它们的创建,而且,如果该bean 定义成 singleton,则该实例只创建一次。
dateNow 和 name 都是在 helloWorldAction 这个 bean 的属性。当点击 submit 时,系统会调用 HelloWorld Action 里的 setName 和 setDateNow 方法。也就是自动的把。也就是说,请求对象 request 的参数会自动的赋值到相应的Action 中,而且,针对数据类型不一致的情况,我们还可以做转换。
执行完它的 execute 方法 (其实什么都没做)后,根据 strut.xml 中的配置,返回 HelloWorld.jsp 给浏览器,它又取出 HelloWorld Acion 的属性值,并显示出来。
好了,说到这,应该算是基本入门了。需要注意几点:
Struts 框架是完全基于 Servlet 和 JSP 技术的 MVC 框架实现。
JavaBean (就是普通的Java 类加两点限制:无参数的构造方法和属性的setter,getter 方法)实现业务逻辑(数据访问等),JSP 用于显示 (就是标准的 HTML 格式嵌入和读取 action (Java bean)属性值的语句。
深入学习 struts 并想精通,你最好精通 Java 语言及开发,Servlet 和 JSP 规范,Java Bean 规范,设计模式, XML 语言等。
会使用英文是学习好 Open source 技术的另一个必须的工具。
下面再深入探讨这个例子。
[再说 Struts 配置]
filter 是在 web.xml 中配置的,而 Struts.properties 用于配置Struts 框架。一般来说,你可以不管这个文件,除非你想要一个特别的开发环境,(例如,debugging 的需要)。
struts.properties 里的属性可以在 web.xml 通过 <init-param> 配置,也可以在 struts.xml 里通过“静态”标签配置。Struts.properties 属性可以在 http://struts.apache.org/2.x/docs/strutsproperties.html 查询。缺省的struts.properties 在 struts2.jar 中,如果你定义了自己的 struts.properties, 则他会覆盖 struts2.jar 中的值。见下面开发模式的例子。
struts.xml 是配置 Action 和 View 的主要场所。现在,可以完全不用Struts.xml,annotations,“web.xml" 开始参数,和 URL 映射 schemes 都可以替代它。而全局结果,异常处理,和定制的interceptor stack 还需要它。
[开发模式]
举个例子,struts.propertieds 里有一个属性,控制是否是开发模式。这个值缺省的是false。
struts.devMode = false
我们可以直接在struts.properties 里改这个设置,也可以在struts.xml 中 “覆盖”它:
<struts>
<constant name="struts.devMode"
value="true" />
...
</struts>
注意: 它一定是 <struts> 元素的直接子元素。也可以在 web.xml 中覆盖它:
...
<filter>
<filter-name>struts</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>
...
[Action 实例的创建]
Action 的实例是什么时候创建的? 我们编写它们的构造方法,并在其中打印相关信息:
HelloWorldAction.java
...
public
HelloWorldAction()
{
MyLog.log("HelloWorldAction()");
}
...
IndexAction.java
...
public
IndexAction()
{
MyLog.log("IndexAction()");
}
...
MyLog 是我编写的小函数,用于打印线程信息和log 信息:
package com.mycompany.app;
public class MyLog
{
public static void log(String s)
{
String s1 =
Thread.currentThread().toString();
System.out.println("[" + s1 +
"]" + " || " + s);
}
}
然后,运行 mvn jetty:run 重新编译、打包、部署应用和重新启动jetty。从窗口中我们可以看到这个两个Action是在何时创建的。
===========================以下内容尚未整理=============================
InfoQ 出版了一本免费的介绍 struts 的书,http://www.infoq.com/minibooks/starting-struts2 下面就总结一下其中的主要学习点。
介绍: Java web 开发可以追溯到 Servlet 技术出现的 1997 年, 之后 Java Web 技术发展迅速,Struts 的出现和发展是其中最具有创新和广泛使用的技术之一。
Struts 最初的作者是 Craig McClanahan, 2001 年, Struts 1.0 正式发布。那时,“.com 泡沫”正风起云涌,Struts 的出现成了 Web 开发最及时的工具。
Struts 2 是下一代的 Struts 技术,但它并不是 Struts 1.0 的简单升级和延续。它结合了 WebWork 框架,提供了一个全新的应用开发技术。
WebWork 基于 XWork,后者提供了一般的命令架构,提供Action、validation、interceptors,以及内部依赖注射机制,它与运行环境完全无关。
Struts2 在简单性方面做了改进,如,
- 减少 XML 配置,采用“聪明”的缺省配置,
- 使用 annotation,并提供配置惯例。
- 现在的 Action 是 POJOs,增加了可测试性,降低了对框架的依赖。
- HTML Form 属性数据与 Action 属性之间,提供了类型转换机制。
- 通过 interceptor 的使用,增加请求对象的处理前和处理后的功能,更加模块化。
- 插件功能使框架的使用更加灵活。
- 结果显示,不仅局限于JSP,Velocity,Freemarker templates
- 采用 Spring 框架的依赖注射
现在有超过40个 web 框架技术!Struts2 的特点有哪些:
- 基于Action的框架
- 成熟
- 支持 Annotation 和 XML 配置两种技术
- 基于 POJO 的 Action, 更利于测试
- 集成了 Spring,SiteMesh, 和 Tiles
- 集成了 OGNL 表达式语言
- 基于主题的标签库和 Ajax 标签
- 支持多种视图:JSP, Freemarker, Velocity, XSLT
- 扩展或者改变框架的插件
使用的 Java Web 技术:
- Servlet
- JSP
- 基于 Action 的框架
- 基于 组件的 框架
- Ajax
核心组件:
从本质上说,Struts2 是个“拉”结构的 MVC 框架,共有5个组件
- 模型:actions,
- 控制:filter 以及 interceptors,
- 与其他组件集成:value stack/OGNL,
- 视图:result types, result views
struts.xml 的根元素必须是 <struts>,<include file="..." /> 可以包含其他文件,且必须在<structs> 的下面。除了显示的包含文件之外,有两个缺省的必须包含的文件: "struts-default.xml" 和 "struts-plugin.xml"。这些配置也可以在 struts.properties 中设置。
当 Action 根据情况返回不同结果,例如:
class MyAction {
public void String execute() throws Exception
{
if(
myLogicWorked() ) {
return "success";
} else
{
return "error";
}
}
}
<action name="my"
class="com.fdar.infoq.MyAction" >
<result>view.jsp</result>
<result
name="error">error.jsp</result>
</action>
调用 Action 时的参数传递,例如:
调用“/home.action?framework=struts&version=2” 时, 该Action 的实现应该有一个 setFramework 和 setVersion 方法。这样,这些请求对象的参数值就直接赋给了Action (Javabean)。
struts 做了类型转换工作,同时也提供一个简化的访问方式。 如, person.address.home.postcode=2 相当于 getPerson().getAddress().getHome().setPostcode(2)。
依赖注射
Action 是业务业务逻辑实现组件,需要调用其他的业务逻辑组件完成功能,struts2 使用 setter 方式的依赖注射,实现了控制翻转:即不是Action依赖于更具体的业务逻辑,而是倒过来。
Struts2 中使用的依赖注射是以插件的形式使用的Spring 框架中的依赖注射。
另一个选择是 Plexus。
WebWork 有他自己的(接口方式的)依赖注射框架,从2.2 开始,这个功能被 Spring 取代。对于那些没有被Spring 管理的对象,如 HttpServletRequest, 采用的是setter方式和接口方式结合的依赖注射。
interceptors
类似于filter,配置给每个 Action。
value stack/OGNL
Value stack 是一组java 对象栈,OGNL 是访问这些栈的语言。栈对象包括:
- 临时对象
- Model 对象, 在actions前面
- Action 对象
- 命名对象:#application, #session, #request, #attr, #parameters