一、简介

Apache Struts 2 是一种流行的MVC框架,成功地结合了 WebWork和Struts1.x 两种 web 框架。它的核心功能是使用拦截实现“值栈”的概念,OGNL表达式和Struts2标签来解决应用程序数据,很多注解和约定,使这个框架更加易于使用。


Struts2框架官网下载地址:

https://struts.apache.org/download.cgi#struts25


二、基础jar包

asm-3.3.jar (操作java字节码的类库)

asm-commons-3.3.jar (提供了基于事件的表现形式)

asm-tree-3.3.jar (提供了基于对象的表现形式)

commons-fileupload-1.2.2.jar (Struts文件的上传下载)

commons-io-2.0.1.jar (处理io流的工具)

commons-lang3-3.1.jar (为java.lang包提供扩展)

commons-loggin-1.1.1.jar (Jakarta的通用日志记录包)

freemarker-2.3.19.jar(FreeMarker是一个模板引擎,一个基于模板生成文本输出的通用工具)

javassist-3.11.0.GA.jar (开源Java字节码的类库)

ognl-3.0.5.jar (支持ognl表达式)

strut2-core-2.3.4.jar (struts2的核心包)

xwork-core-2.3.4.jar(xwork核心包)

注:基础jar包可从apps文件夹里的示例项目里找到


三、web.xml

在项目web.xml内的<web-app>标签内添加Struts2过滤器

<filter>
  <filter-name>Struts2Filter</filter-name>
  <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>Struts2Filter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>


四、配置文件struts.xml

<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd" >
<struts>
<!-- bean 标签 用于创建一个JavaBean实例-->

<!-- constant标签 用于Struts2 默认行为标签-->
    <!-- 配置web默认编码集,相当于 HttpServletRequest.setChartacterEncoding用法 -->
    <constant name="struts.i18n.encoding" value="UTF-8"></constant>
    <!-- 默认我们Struts2的请求后缀是.action,也就是说我们不配置该元素,action/do都可以 -->
    <constant name="struts.action.extension" value="action,do"></constant>
    <!-- 设置浏览器是否缓存静态内容,默认值为true,在开发阶段建议关闭,防止修改后测试不到 -->
    <constant name="struts.serve.static.browserCache" value="false"></constant>
    <!-- 当struts 配置文件修改后,系统是否自动重新加载该文件,默认为false -->
    <constant name="struts.configuration.xml.reload" value="true"></constant>
    <!-- 开发模式下使用,这样可以打印出更加详细的错误信息 -->
    <constant name="struts.devMode" value="true"></constant>
    <!-- 默认视图主题 -->
    <constant name="struts.ui.theme" value="simple"></constant>
	
<!-- include标签 用于引入其他的xml配置文件-->
<include file="struts-default.xml"></include>
    
<!-- package标签 包标签,用于区分不同的请求文件的标签,比方说:网站前台请求和网站后台请求
     package的名字必须是唯一的 package可以扩展 当一个package扩展自另一个package时该package会在本身配置的基础上加入扩展的package的配置父package必须在子package前配置
        name:package名称
        extends:继承的父package名称
        abstract:设置package的属性为抽象的 抽象的package不能定义action 值true:false
        namespace:定义package命名空间 该命名空间影响到url的地址,例如此命名空间为/test那么访问是的地址为http://localhost:8080/struts2/test/XX.action
 -->
<package name="com.kay.struts2" extends="struts-default" namespace="/test">
        <interceptors>
            <!-- 定义拦截器 -->
            <interceptor name="拦截器名称" class="拦截器类路径"></interceptor>
            <interceptor name="logger" class="com.kay.logger"></interceptor>
            <!-- 定义拦截器栈 -->
            <interceptor-stack name="mystack">
                <interceptor-ref name="拦截器名称"></interceptor-ref>
                <interceptor-ref name="logger"></interceptor-ref>
            </interceptor-stack>
        </interceptors>
        
        <!-- 定义默认的拦截器 每个Action都会自动引用
         如果Action中引用了其它的拦截器 默认的拦截器将无效 -->
        <default-interceptor-ref name="mystack"></default-interceptor-ref>
        
        
        <!-- 全局results配置 -->
        <global-results>
            <result name="input">/error.jsp</result>
        </global-results>
        
        <!-- Action配置 一个Action可以被多次映射(只要action配置中的name不同)
             name:action名称
             class: 对应的类的路径
             method: 调用Action中的方法名
        -->
        <action name="hello" class="com.kay.struts2.Action.LoginAction">
            <!-- 引用拦截器
                name:拦截器名称或拦截器栈名称
             -->
            <interceptor-ref name="timer"></interceptor-ref>
        
            <!-- 节点配置
                name : result名称 和Action中返回的值相同
                type : result类型 不写则选用superpackage的type struts-default.xml中的默认为dispatcher
             -->
         <result name="success" type="dispatcher">/talk.jsp</result>
         <!-- 参数设置 
             name:对应Action中的get/set方法 
         -->
         <param name="url">http://www.ziry.me</param>
        </action>
        
<!-- 
通配符方式:
Name中第一个*代表CRUD操作的名字,第二个*代表类的名字。所以访问链接地址举例如下:
.../del_User.action将访问到User类的del方法,成功后跳到del_User.jsp页面。补充说明{0}是代表name中所有的*组合。
-->
<action name="*_*" class="me.ziry.{2}Action" method="{1}">
	<result name="success">.../{1}_{2}.jsp</result>
</action>
        
    </package>
</struts>


五、OGNL表达式

  1. #符号:

#符号的三种用法
   1)访问非根对象属性,由于Struts 2中值栈被视为根对象,所以访问其他非根对象时,需要加#前缀。实际上,#相当于ActionContext.getContext();#session.msg表达式相当于ActionContext.getContext().getSession().getAttribute("msg")。
   2)用于过滤和投影(projecting)集合,如示例中的persons.{?#this.age>20}。
   3) 用来构造Map,例如示例中的#{'foo1':'bar1', 'foo2':'bar2'}

2. %符号:

%符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值。
如下面的代码所示:
<h3>构造Map</h3>
<s:set name="foobar" value="#{'foo1':'bar1', 'foo2':'bar2'}" />
<p>The value of key "foo1" is <s:property value="#foobar['foo1']" /></p>
<p>不使用%:<s:url value="#foobar['foo1']" /></p>
<p>使用%:<s:url value="%{#foobar['foo1']}" /></p>
运行界面如下所示。
he value of key "foo1" is bar1
不使用%:#foobar['foo1']
使用%:bar1

3. $符号:

$符号主要有两个方面的用途。
     1) 在国际化资源文件中,引用OGNL表达式,例如国际化资源文件中的代码:reg.agerange=国际化资源信息:年龄必须在${min}同${max}之间。
     2) 在Struts 2框架的配置文件中引用OGNL表达式,例如下面的代码片断所示:
<validators>
    <field name="intb">
      <field-validator type="int">
      <param name="min">10</param>
      <param name="max">100</param>
      <message>BAction-test校验:数字必须为${min}为${max}之间!</message>
      </field-validator>
    </field>
</validators>

3. 其他用法

1.访问值栈中的action的普通属性: 
   username = <s:property value="username"/>
2.访问值栈中对象的普通属性(get set方法):
   <s:property value="user.age"/> | 
   <s:property value="user['age']"/> | 
   <s:property value="user[\"age\"]"/> | 
   wrong: <%--<s:property value="user[age]"/>--%>
3.访问值栈中对象的普通属性(get set方法): 
   <s:property value="cat.friend.name"/>
4.访问值栈中对象的普通方法:
   <s:property value="password.length()"/>
5.访问值栈中对象的普通方法:
   <s:property value="cat.miaomiao()" />
6.访问值栈中action的普通方法:
   <s:property value="m()" />
7.访问静态方法:
   <s:property value="@com.bjsxt.struts2.ognl.S@s()"/>
8.访问静态属性:
   <s:property value="@com.bjsxt.struts2.ognl.S@STR"/>
9.访问Math类的静态方法:
   <s:property value="@@max(2,3)" />
10.访问普通类的构造方法:
   <s:property value="new com.bjsxt.struts2.ognl.User(8)"/>
11.访问List:
   <s:property value="users"/>
12.访问List中某个元素:
   <s:property value="users[1]"/>
13.访问List中元素某个属性的集合:
   <s:property value="users.{age}"/>
14.访问List中元素某个属性的集合中的特定值:
   <s:property value="users.{age}[0]"/> | 
   <s:property value="users[0].age"/>
15.访问Set:
   <s:property value="dogs"/>
16.访问Set中某个元素:
   <s:property value="dogs[1]"/>
17.访问Map:
   <s:property value="dogMap"/>
18.访问Map中某个元素:
   <s:property value="dogMap.dog101"/> | 
   <s:property value="dogMap['dog101']"/> | 
   <s:property value="dogMap[\"dog101\"]"/>
19.访问Map中所有的key:
   <s:property value="dogMap.keys"/>
20.访问Map中所有的value:
   <s:property value="dogMap.values"/>
21.访问容器的大小:
   <s:property value="dogMap.size()"/> | 
   <s:property value="users.size"/> 
22.投影(过滤):
   <s:property value="users.{?#this.age==1}[0]"/>
23.投影:
   <s:property value="users.{^#this.age>1}.{age}"/>
24.投影:
   <s:property value="users.{$#this.age>1}.{age}"/>
25.投影:
   <s:property value="users.{$#this.age>1}.{age} == null"/>
26.[]:
   <s:property value="[0].username"/>


六、struts2标签库

<%@ taglib prefix="s" uri="/struts-tags" %> 
就能使用struts2.0的标签库 

A: 
<s:a href=""></s:a>-----超链接,类似于html里的<a></a> 
<s:action name=""></s:action>-----执行一个view里面的一个action 
<s:actionerror/>-----如果action的errors有值那么显示出来 
<s:actionmessage/>-----如果action的message有值那么显示出来 
<s:append></s:append>-----添加一个值到list,类似于list.add(); 
<s:autocompleter></s:autocompleter>-----自动完成<s:combobox>标签的内容,这个是ajax 

B: 
<s:bean name=""></s:bean>-----类似于struts1.x中的,JavaBean的值 

C: 
<s:checkbox></s:checkbox>-----复选框 
<s:checkboxlist list=""></s:checkboxlist>-----多选框 
<s:combobox list=""></s:combobox>-----下拉框 
<s:component></s:component>-----图像符号 

D: 
<s:date/>-----获取日期格式 
<s:datetimepicker></s:datetimepicker>-----日期输入框 
<s:debug></s:debug>-----显示错误信息 
<s:div></s:div>-----表示一个块,类似于html的<div></div> 
<s:doubleselect list="" doubleName="" doubleList=""></s:doubleselect>-----双下拉框 

E: 
<s:if test=""></s:if> 
<s:elseif test=""></s:elseif> 
<s:else></s:else>-----这3个标签一起使用,表示条件判断 

F: 
<s:fielderror></s:fielderror>-----显示文件错误信息 
<s:file></s:file>-----文件上传 
<s:form action=""></s:form>-----获取相应form的值 

G: 
<s:generator separator="" val=""></s:generator>----和<s:iterator>标签一起使用 

H: 
<s:head/>-----在<head></head>里使用,表示头文件结束 
<s:hidden></s:hidden>-----隐藏值 

I: 
<s:i18n name=""></s:i18n>-----加载资源包到值堆栈 
<s:include value=""></s:include>-----包含一个输出,servlet或jsp页面 
<s:inputtransferselect list=""></s:inputtransferselect>-----获取form的一个输入 
<s:iterator></s:iterator>-----用于遍历集合 

L: 
<s:label></s:label>-----只读的标签 

M: 
<s:merge></s:merge>-----合并遍历集合出来的值 

O: 
<s:optgroup></s:optgroup>-----获取标签组 
<s:optiontransferselect doubleList="" list="" doubleName=""></s:optiontransferselect>-----左右选择框 

P: 
<s:param></s:param>-----为其他标签提供参数 
<s:password></s:password>-----密码输入框 
<s:property/>-----得到'value'的属性 
<s:push value=""></s:push>-----value的值push到栈中,从而使property标签的能够获取value的属性 

R: 

<s:radio list=""></s:radio>-----单选按钮 
<s:reset></s:reset>-----重置按钮 

S: 
<s:select list=""></s:select>-----单选框 
<s:set name=""></s:set>-----赋予变量一个特定范围内的值 
<s:sort comparator=""></s:sort>-----通过属性给list分类 
<s:submit></s:submit>-----提交按钮 
<s:subset></s:subset>-----为遍历集合输出子集 

T: 
<s:tabbedPanel id=""></s:tabbedPanel>-----表格框 
<s:table></s:table>-----表格 
<s:text name=""></s:text>-----I18n文本信息 
<s:textarea></s:textarea>-----文本域输入框 
<s:textfield></s:textfield>-----文本输入框 
<s:token></s:token>-----拦截器 
<s:tree></s:tree>-----树 
<s:treenode label=""></s:treenode>-----树的结构 

U: 
<s:updownselect list=""></s:updownselect>-----多选择框 
<s:url></s:url>-----创建url


七、在Action获取Scope对象

引言:在前面的Action操作中,关键就是Action中的exectue方法,但是此方法并没有request、session、application等对象作为参数,自然就不能利用这些对象来操作。下面我们建立struts2scope项目,并用四种方式来获取这些对象:
方式一、与Servlet解耦合的非IOC方式
获取的scope对象与容器无关,通过ActionContext获取。
LoginAction代码如下:
package com.asm;
public class LoginAction extends ActionSupport {
	private String username;
	ActionContext context;
	Map request;
	Map session;
	Map application;
	public String execute() throws Exception {
		context=ActionContext.getContext();
		request=(Map) context.get("request");
		session=context.getSession();
		application=context.getApplication();
		
		request.put("req", "requst属性");
		session.put("ses", "sesion属性");
		application.put("app", "application属性");
		return SUCCESS;
	}
	...省略username的get/set方法
}
struts.xml配置如下:
<struts>
	<package name="scope" extends="struts-default">
		<action name="login" class="com.asm.LoginAction">
			<result>/loginSuc.jsp</result>
</action>
</package>		
</struts>
login.jsp内容如下:
<form action="<%=request.getContextPath() %>/login.action">
		用户名:<input type="text" name="username"><br>
		<input type="submit" value="login">	
</form>
loginSuc.jsp的主要内容如下:
${requestScope.req}
${sessionScope.ses}
${applicationScope.app}
<h4>以下使用scope.getAttribute的形式来接受</h4>
		request:	<%=request.getAttribute("req") %><br>
		session:	<%=session.getAttribute("ses") %><br>
		application:<%=application.getAttribute("app") %><br>
分析:通过ActionContext的getContext静态方法得到ActionContext对象,然后ActionContext对象调用get方法来获取一个存储在request范围中的对象。我们使用el或通过request.getAttribute这样的方式均可以获取对象值,这说明了这些Map request对象实际是存储在request范围内的对象。
方式二、与Servlet解耦合的IOC方式
我们建立Login2Action,主要代码如下:
package com.asm;
public class Login2Action extends ActionSupport implements RequestAware,SessionAware,ApplicationAware {
	private String username;
	Map request;
	Map session;
	Map application;
	public String execute() throws Exception {
		request.put("req", "requst属性");
		session.put("ses", "sesion属性");
		application.put("app", "application属性");
		return SUCCESS;
	}
	public void setRequest(Map<String, Object> request) {
		this.request=request;
	}
	public void setSession(Map<String, Object> session) {
		this.session=session;
	}
	public void setApplication(Map<String, Object> application) {
		this.application=application;
	}
	...省略username的get/set方法	
}
注册此Action的name为login2,随后修改登录提交为.../login2.action。便可以发布测试。说明:此方法其实和方式一很相似,只是在方式一中我们需要手动的为Map request赋值,但是在方式二中它是通过实现接口,在重写接口中的方法中完成对Map requset的赋值,所以称之IOC方式。借助此例,略谈下依赖注入与控制反转:所谓依赖注入就是一个对象自己本身的初始化是依赖其它对象。比如这里Map request这些对象会依赖struts2来给其初始化,称为依赖注入,而依赖注入的就表示,这些对象的控制权不再由此类本身掌握,而是交给了别的对象,即是控制权反转了。 强调:方式二是开发中主要用的方式,应重点掌握
方式三、与Servlet耦合的非IOC方式
建立Login3Action,代码如下:
package com.asm;
public class Login3Action extends ActionSupport {
	private String username;
	HttpServletRequest request;
	HttpSession session;
	ServletContext application;
	public String execute() throws Exception {
		request = ServletActionContext.getRequest();
		session = request.getSession();
		application = ServletActionContext.getServletContext();

		request.setAttribute("req", "requst属性");
		session.setAttribute("ses", "sesion属性");
		application.setAttribute("app", "application属性");
		return SUCCESS;
	}
	...省略username的get/set方法。
}
此方法获取的纯粹的Scope对象,它与容器相关,这些Scope对象操作更强。同样只需要注册此Action并修改登录页面便可进行测试。
方式四、与Servlet耦合的IOC方式
建立Login4Action,代码如下:
package com.asm;
public class Login4Action extends ActionSupport implements ServletRequestAware,ServletContextAware{
	private String username;
	ActionContext context;
	HttpServletRequest request;
	HttpSession session;
	ServletContext application;
	public String execute() throws Exception {
		context=ActionContext.getContext();
		session=request.getSession();	
		request.setAttribute("req", "requst属性");
		session.setAttribute("ses", "sesion属性");
		application.setAttribute("app", "application属性");
		return SUCCESS;
	}
	
	public void setServletRequest(HttpServletRequest request) {
		System.out.println("测试:"+request);
		this.request=request;
	}
	public void setServletContext(ServletContext application) {
		System.out.println("测试:"+application);
		this.application=application;
	}
	...省略username的get/set方法
}
同样只需要注册此Action并修改登录页面便可发布测试


八、struts2注解

1) @ParentPackage 指定父包
2) @Namespace 指定命名空间
3) @Results 一组结果的数组
4) @Result(name="success",location="/msg.jsp") 一个结果的映射
5) @Action(value="login") 指定某个请求处理方法的请求URL。注意,它不能添加在Action类上,要添加到方法上。
6) @ExceptionMappings 一级声明异常的数组
7) @ExceptionMapping 映射一个声明异常


以上只是简略总结,详细学习可参考:

http://wenku.baidu.com/view/8b29fa125f0e7cd184253638



注意:本文归作者所有,未经作者允许,不得转载