Struts2简介
Struts2是在WebWork2基础上发展而来的。Struts2和Struts1一样,也都是属于MVC框架。不过有一点大家需要注意的是:虽然Struts2和Struts1在名字上差别不大,但Struts2应用的代码编写风格与Struts1几乎可以说是不一样的。那么既然有了Struts1,为何还要推出Struts2呢?主要是因为Struts2有以下优点:
- 在软件设计上,Struts2没有像Struts1那样跟Servlet API和Struts API有着紧密的耦合,Struts2的应用可以不依赖于Servlet API和Struts API。 Struts2的这种设计属于无侵入式设计,而Struts1却属于侵入式设计。
- Struts2 提供了拦截器,利用拦截器可以进行 AOP 编程,实现如权限拦截等功能。
- Struts2 提供了类型转换器,可以将特殊的请求参数转换成需要的类型。在Struts1中,如果我们要实现同样的功能,就必须向Struts1的底层实现BeanUtil注册类型转换器才行。
- Struts2提供支持多种表现层技术,如:JSP、freeMarker、Velocity等。
- Struts2 的输入验证可以对指定方法进行验证,解决了Struts1长久之痛
- 提供了全局范围、包范围和 Action 范围的国际化资源文件管理实现。
1、搭建Struts2开发环境
搭建Struts2环境时,我们一般需要以下几个步骤:
- 找到开发Struts2应用需要使用到的jar文件
- 编写Struts2的配置文件
- 在web.xml文件中加入Struts2 MVC框架启动配置
1.1、下载Struts2的相关jar包
在开发 Struts2 框架之前先要下载相关的 jar 包,Struts 的官方网站截图如图 3-1 所示: 单击 Download 按钮开始下载,本人所下载的是struts-2.3.24-
all.zip,目前最新版为2.5.14.1。下载的 ZIP 文件内容有Struts2 的示例,源代码及帮助文档。
1.2、Struts2 的 最基本Jar 包
可以从 Struts2 框架解压目录下的 apps 中的 struts2-blank.war中获取。将 struts2-blank.war 扩展名修改为 zip 后,解压。在其 WEB-INF\lib 中所有 Jar 即为 Struts2运行的基本 Jar 包。从使用的两小日志 Jar 包可以看出,Struts2 使用的是 Log4j2 日志技术。
1.3、Struts2 的配置文件
Struts2 的默认配置文件为 struts.xml,该文件需存放在 WEB-INF/classes 下。即,在myEclipse 中应放在 src 目录下。Struts2 配置文件的头部可以从 struts2-core-2.3.24.jar 下的 struts-2.3.dtd 中找到。1.4、配置 Struts2 的启动项
在 Struts2 中,Struts 框架是通过 Filter 启动的。Filter 在 web.xml 中的配置如下:
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
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">
<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>
</web-app>
若忘记了配置细节,可从 struts2-blank.war 解压目录中 WEB-INF 下的 web.xml 中复制。1.5、 搭建成功的测试
将该项目部署到服务器后,启动服务器,在控制台没有报错,则说明 Struts2 应用平台搭建成功。
2、Struts2工作流程
2.1、 开发流程
(1)编写页面
(2)定义 Action 类
(3)注册 Action
(4)编写结果页面
2.2、开发流程分析
从客户端发送请求过来,先经过前端控制器(核心过滤器,StrutsPrepareAndExecuteFilter),过滤器中执行一组拦截器(一组拦截器,就会完成部分功能代码),到底哪些拦截器执行了呢?在Struts2中定义了很多拦截器,在其默认栈中的拦截器会得到执行,这个我们可以通过断点调试的方式测试,拦截器执行完成以后,就会执行目标Action,在Action中返回一个结果视图,根据result的配置进行页面的跳转。用图来表示即为:2.3、Struts2的配置文件的加载顺序
每次从客户端发送请求到服务器都要先经过Struts2的核心过滤器StrutsPrepareAndExecuteFilter,这个过滤器有两个功能:预处理和执行。在预处理中主要就是来加载配置文件的。对应的是过滤器中的init方法,而执行是用来执行一组拦截器完成部分功能的,对应的是过滤器的doFilter方法。所以我们如果要去了解Struts2的配置文件的加载顺序,那么我们需要查询过滤器的init方法。在web.xml配置文件中,按Ctrl+鼠标左键点击StrutsPrepareAndExecuteFilter进入源代码如下:init_DefaultProperties(); // [1]
加载org/apache/struts2/default.properties,该文件配置的是Struts2的所有的常量。
init_TraditionalXmlConfigurations(); // [2]
加载struts-default.xml、struts-plugin.xml、struts.xml。
init_LegacyStrutsProperties(); // [3]
加载用户自定义的struts.properties。
init_CustomConfigurationProviders(); // [5]
加载用户配置的提供对象。
init_FilterInitParameters() ; // [6]
加载web.xml。
init_AliasStandardObjects() ; // [7]
加载标准对象。
根据上面的代码我们可以得出配置文件的加载顺序,如下:
- default.properties
- struts-default.xml
- struts-plugin.xml
- struts.xml,配置Action以及常量。
- struts.properties,配置常量。
- web.xml,配置核心过滤器以及常量。
前三个配置文件我们不用关心,是Struts2内部的配置文件,我们无法修改,能修改的文件就是struts.xml、struts.properties、 web.xml配置文件。这几个配置文件的加载是有一定顺序的。这三个配置文件都可以修改Struts2的常量的值,要记住的是,后加载配置文件中常量的值会将先加载的配置文件中常量的值给覆盖掉。
3、第一个Struts2应用程序
完成功能:
用户登录后在页面显示“Struts2 欢迎你【xxx】,年龄为xx岁!”,将用户名显示出来。
实现步骤:
在搭建好 Struts2 环境后,完成下面步骤:
Step1:新建页面 index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>第一个Struts2应用程序</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/test/login.action" method="post">
用户名:<input type="text" name="name"><br>
年 龄:<input type="text" name="age"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
Step2:创建 Action 类
package com.zenghai.actions;
import com.opensymphony.xwork2.ActionSupport;
public class LoginAction extends ActionSupport {
private static final long serialVersionUID = 1L;
private String name;
private int age;
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;
}
@Override
public String execute() throws Exception {
System.out.println("name = " + name);
System.out.println("age = " + age);
return SUCCESS;
}
}
对于Servlet来说,每次访问Servlet的时候,都会执行Servlet里面的service()方法。而对于Action来说,每次访问Action的时候,默认执行Action里面名称为execute的方法。注意:创建方法的要求是方法不能有参数。
Action类编写好了以后,Struts2框架如何识别它就是一个Action呢?那么我们需要修改struts.xml文件对Action类进行配置。
Step3:修改 struts.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<constant name="struts.devMode" value="true" />
<package name="login" namespace="/test" extends="struts-default">
<action name="login" class="com.zenghai.actions.LoginAction">
<result name="success">/welcome.jsp</result>
</action>
</package>
</struts>
配置代码<constant name="struts.devMode" value="true" />的作用是使 Struts 2 框架运行在开发模式,在此种模式下对异常的报错信息显示的比较完整,便于排错。但在项目部署时要删除。
配置 代 码 <package name="login" namespace="/test" extends="struts-default">的 作 用 是 定 义 一 个package 包。在Struts2框架中使用包来管理Action,包的作用和java中的类包是非常类似的,它主要用于管理一组业务功能相关的Action。在实际应用中,我们应该把一组业务功能相关的Action放在同一个包下。配置包时必须指定name属性,该name属性值可以任意取名,但在整个项目中必须唯一,它不对应java类,如果其他包要继承该包,必须通过该name属性进行引用。
包的namespace属性用于定义该包的命名空间。命名空间作为访问该包下Action的路径的一部分,该属性可以不配置,对本例而言,如果不指定该属性,默认的命名空间为“”(空字符)。命名空间对于Struts2来说有减少重复代码的作用。例如下面的URL
http://localhost:8080/login/one.action
http://localhost:8080/login/two.action
http://localhost:8080/login/three.action
Struts1的配置代码有可能是这样的:
<action path= "/login/one" forward= "one.jsp" >
<action path= "/login/two" forward= "two.jsp" >
<action path= "/login/three" forward= "three.jsp" >
这样就会有很多重复的代码,而是使用Struts2的命名空间属性就可减少重复的代码,Struts2的配置代码:
<package name="login" namespace="/login" extends="struts-default">
<action name="one" class= .... >
<result name="success">one.jsp</result>
</action>
<action name= "two" class= .... >
<result name="success">two.jsp</result>
</action>
<action name="two" class= .... >
<result name="success">three.jsp</result>
</action>
</package>
通常每个包都应该继承struts-default包, struts-default包是由Struts2内置的,它定义了Struts2内部的众多拦截器和Result类型。Struts2很多核心的功能都是通过这些内置的拦截器实现的。如:从请求中把请求参数封装到action、文件上传和数据验证等等都是通过拦截器实现的。当包继承了struts-default包才能使用Struts2提供的这些功能。 struts-default包是在struts2-core-2.x.x.jar文件中的struts-default.xml中定义的。struts-default.xml也是Struts2默认配置文件。 Struts2每次都会自动加载struts-default.xml文件。
action的配置: Action映射是框架中的基本“工作单元”。Action映射就是将一个请求的URL映射到一个Action类中,当一个请求匹配某个Action名称时,框架就使用这个映射来确定如何处理请求。在struts.xml文件中,通过 <action> 元素对请求的Action和Action类进行配置。 <action> 元素中共有4个属性,这4个属性的说明如表所示:
属性 | 说明 |
---|---|
name | 必填属性,标识Action,指定了Action所处理的请求的URL |
class | 可选属性,指定Action对应Action类 |
method | 可选属性,指定请求Action时调用的方法 |
converter | 可选属性,指定类型转换器的类 |
其中name属性和namespace属性共同决定了访问路径,class对应的是Action类的全路径。Method指定了执行Action的那个方法,默认是execute方法。
注意:在一个package标签里面可以写多个action标签,并且action标签的name属性值不能一样。如:
<package name="demo1" extends="struts-default" namespace="/">
<action name= "user" class= "com.zenghai.action.UserAction">
<result name= "ok" >/user.jsp</result>
</action>
<action name="person" class="com.zenghai.action.PersonAction">
<result name="success">/person.jsp</result>
</action>
</package>
result的配置: Action类的方法是有返回值的,配置返回值之后,可跳转到不同的页面中。result标签里面的name属性值即是Action类里面的方法的返回值。如:
<result name="success">/welcome.jsp</result>
返回值为"success"时,跳转到/welcome.jsp页面。在一个action标签里面可写多个result标签,但要注意result标签的name属性值不能相同。
Step4:创建 welcome.jsp 页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>第一个Struts2应用程序</title>
</head>
<body>
Struts2 欢迎你【${name }】,年龄为${age }岁!
</body>
</html>
第一个Struts应用程序完成,启动服务器,访问index.jsp页面,输入信息提交后,显示的页面如下则成功: