Struts2学习总结

Posted TOMSCUT

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Struts2学习总结相关的知识,希望对你有一定的参考价值。

本文包括以下五个部分:

  1. 值栈。
  2. Ognl表达式。
  3. struts2标签库。
  4. 国际化。
  5. 表单数据校验
  6. 拦截器。
  7. struts2的执行过程。

一、值栈

采用servlet和JSP开发时,servlet通过域对象保存数据,在JSP页面通过jstl标签+el表达式获取数据。

采用struts2和JSP框架进行开发时,Action通过值栈对象保存数据,在JSP页面通过struts标签+ognl表达式获取数据。

1.1 值栈(ValueStack)的概念

        值栈就是存放action的堆栈,用来存储请求响应数据,是Struts2存取数据的核心。值栈将数据统一管理起来,方便Action、Result、Interceptor的使用。值栈有一个标准接口ValueStack,而在实际的项目开发中,是通过一个实现类OgnlValueStack来存储数据的。

1.2 值栈的结构

        值栈分为值栈分为两个逻辑结构(数据结构):

  • Object Stack(对象栈):ArrayList (CompoundRoot),底层数据结构为ArrayList集合+栈的结构(先进后出)。

                        对象栈主要存储Action对象和Provider代理对象。

  • Context Map(映射栈): HashMap (OgnlContext),底层的数据结构为Map集合的结构。               

                        a. 映射栈主要存放各个域存放的数据和用户的参数信息。

                        b. 对象栈主要有五个对象:

                          

Key Value
request RequestMap
session SessionMap
application ApplicationMap
parameters ParaemterMap
attr AttributeMap (封装了三个Map(request,session,application))
                     

1.3 操作值栈对象

                    1.3.1 操作Object Stack    

                //得到ActionContext对象
		ActionContext ac = ActionContext.getContext();
		//得到值栈对象
		ValueStack vs = ac.getValueStack();

                                      push(Object o):压入栈顶

                                      Object pop():推出栈顶元素

                    1.3.2 操作Context Map

                                      Map<String,Object> getContext(): 得到Context Map对象

                                     ActionContxt.get("request").put("name",Object): 操作Context Map中的reqest元素
                                     ActionContxt.getSession().put("name",Object): 操作Context Map中的session元素
                                     ActionContxt.getApplication().put("name",Object): 操作Context Map中的application元素

package edu.scut.d_valuestack;

import java.util.Date;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;
//演示值栈
public class BookAction extends ActionSupport {
	public String list(){
		//值栈是由struts2框架在每次访问Action的方法时创建的,然后将其存入ActionContext
		
		//1 得到ActionContext对象
		ActionContext ac = ActionContext.getContext();
		//2 得到值栈对象
		ValueStack vs = ac.getValueStack();
		System.out.println(vs);
		
		//3 操作值栈
		//Object Stack(对象栈)
		Book book = new Book();
		book.setName("java编程思想");
		book.setPrice(58);
		book.setPublishtime(new Date());
		
		//3.1 压入元素(栈定)
		vs.push(book);
		System.out.println(vs);
		
		//3.2 推出元素
		vs.pop();
		System.out.println(vs);
		
		//4 映射栈(Context Map)
		//4.1 操作request属性
		Map requestMap = (Map) ac.get("request");
		requestMap.put("r_book", book);
		
		//4.2 操作session属性
		ac.getSession().put("s_book", book);
		
		//4.3 操作application属性
		ac.getApplication().put("c_book", book);		
		
		System.out.println(vs);
		return SUCCESS;
	}
}

二、Ognl表达式

2.1 Ognl表达式简介

        OGNL是Object GraphicNavigation Language(对象图导航语言)的缩写,它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。在struts2项目中导入ognl.jar  包来实现支持ognl表达式。

2.2 Ognl表达式和EL表达式的比较

Ognl表达式 EL表达式

获取域对象的数据。可以存放数据,可以调用方法。

获取域对象的数据。不能存放数据,不能调用方法

2.3 Ognl表达式的优势

  • 支持对象方法调用,如xxx.doSomeSpecial();
  • 支持类静态的方法调用和值访问,表达式的格式:

    @[类全名(包括包路径)]@[方法名 |  值名],例如:

           @[email protected](‘foo %s‘, ‘bar‘)或者

           @[email protected]_NAME。

  • 支持赋值操作和表达式串联,如(price=10,discount=0.6,calculatePrice()),这个表达式会返回6.0;

  • 可以访问OGNL上下文(OGNL context)和ActionContext;
  • 可以操作集合对象。

2.4 Ognl表达式的核心对象(OgnlContext)

2.4.1 Ognl表达式的核心对象OgnlContext对象的使用

package edu.scut.a_ognl;

import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
import org.junit.Test;

//演示Ognl
public class OgnlDemo {
	//1 学习了解Ognl表达式的核心对象OgnlContext对象的使用
	@Test
	public void test1(){
		User user = new User();
		user.setId(1);
		user.setUserName("乔峰");
		user.setUserPsw("666666");
		
		//1 创建一个OgnlContext对象
		OgnlContext context = new OgnlContext();
		
		//2 把user对象存入OgnlContext对象
		context.put("user", user);
		//3 从OgnlContext对象取出数据
		User user2 = (User) context.get("user");
		System.out.println(user2.getId()+"\t"+user2.getUserName()+"\t"+user2.getUserPsw());
	}
}

2.4.2 使用Ognl表达式取出OgnlContext的数据,根对象不需要有key,取值不需要#

package edu.scut.a_ognl;

import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
import org.junit.Test;

//演示Ognl
public class OgnlDemo {
	
	//2 使用Ognl表达式取出OgnlContext的数据,根对象不需要有key,取值不需要#
	@Test
	public void test2() throws Exception{
		User user = new User();
		user.setId(3);
		user.setUserName("段誉");
		user.setUserPsw("88888888");
		
		//1 创建一个OgnlContext对象
		OgnlContext context = new OgnlContext();
		
		//2 把user对象存入OgnlContext对象
		//根对象要存储数据需要key
		context.setRoot(user);
		//3 从OgnlContext对象取出数据,使用Ognl表达式取数据
		Object ognlObj = Ognl.parseExpression("userName");
		Object result = Ognl.getValue(ognlObj, context, context.getRoot());
		
		System.out.println(result);
	}

}

2.4.3 使用Ognl表达式取出OgnlContext的数据,非根对象需要有key,取值需要#

package edu.scut.a_ognl;

import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
import org.junit.Test;

//演示Ognl
public class OgnlDemo {
	
<pre name="code" class="java">        //3 使用Ognl表达式取出OgnlContext的数据,非根对象需要有key,取值需要#
	@Test
	public void test3() throws Exception{
		User user = new User();
		user.setId(2);
		user.setUserName("虚竹");
		user.setUserPsw("7777777");
		
		//1 创建一个OgnlContext对象
		OgnlContext context = new OgnlContext();
		
		//2 把user对象存入OgnlContext对象
		//非根对象要存储数据需要key
		context.put("user", user);
		//3 从OgnlContext对象取出数据,使用Ognl表达式取数据
		Object ognlObj = Ognl.parseExpression("#user.userName");
		Object result = Ognl.getValue(ognlObj, context, context.getRoot());
		
		System.out.println(result);
	}
}



2.4.4 Ognl表达式调用静态方法

package edu.scut.a_ognl;

import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
import org.junit.Test;

//演示Ognl
public class OgnlDemo {
	
	//4 Ognl表达式调用静态方法
	@Test
	public void test4() throws Exception{
		System.out.println(Math.round(12.55));
		//1 创建一个OgnlContext对象
		OgnlContext context = new OgnlContext();
		//使用Ognl表达式取数据
		Object ognlObject = Ognl.parseExpression("@[email protected](10.5)");
		Object result = Ognl.getValue(ognlObject, context, context.getRoot());
		System.out.println(result);
	}
}

结论:

            a. 从OgnlContext对象的根对象取出数据,不需要#号。

            b. 从OgnlContext对象的非根对象取出数据,需要#号。

2.5 值栈如何共享和获取数据

2.5.1 值栈如何传递到jsp页面

struts2框架在Action中最后把值栈对象传递到jsp页面,是通过request域对象的struts.valueStack名称的属性传递到jsp页面的。

 class Action{
		1.创建OgnlValueStack对象			

	public String list(){
		2.得到OgnlValueStack对象,然后操作OgnlValueStack对象		
	}

        3.把OgnlValueStack对象放入request域对象
                request.setAttribute("struts.valueStack",OgnlValueStack对象);
}

2.5.2 查看值栈对象所有内容

<s:debug/>

2.5.3 获取值栈数据

2.5.3.1 获取值栈数据的条件

a. 必须使用ognl表达式获取,需要学习ognl表达式语法。

b. ognl表达式必须依赖struts2的标签。

struts2获取数据的标签:
            <s:property value="ognl表达式"/> 

2.5.3.1 获取值栈数据的规则

a. 获取Object Stack: 不带#号直接获取       

              (a)  获取对象(对象栈):  [下标]    下标从0开始 。

                   规则:从对象栈的指定下标的元素开始查找,直到最后一个元素为止!
                       [0]  从第一个元素开始查找
                       [1]  从第二个元素开始查找

 <s:property value="[1]"/>

             (b)  获取对象属性: [下标].属性    注意:下标可以不写,默认从第一个元素开始查找。
                   规则:从对象栈的指定下标的元素开始查找指定的属性,如果找到了就直接返回了,如果没有继续查找,直到最后一个元素为止!

 <s:property value="[1].name"/>

b. 获取Context Map(映射栈):带#号获取      

<s:property value="#name"/>
<s:property value="#request.r_book.price"/><br/>
<s:property value='#session.s_book.price'/>	
<s:property value='#application.c_book.price'/>
<s:property value="#parameters.email"/>
<s:property value="#attr.request.r_book.price"/>

三、struts2标签库

3.1 逻辑类标签: 类似于jstl里面的的条件判断,循环等,用于处理jsp页面的逻辑

<s:set/>  保存数据

<s:property/> 获取数据

<s:if/>+<s:elseif/>+<s:else>  条件判断

<s:iterator/>  循环

 <body>
   <%-- <s:set> 设置数据, <s:property> 获取数据--%>
    <s:set var="message" value="'itcast'" scope="request"/>
    <s:set var="message" value="'itcast'" scope="session"/>
    <s:set var="message" value="'itcast'" scope="application"/>
    <s:property value="#request.message"/>
    <hr>
   
   <%--条件判断 <s:if>  <s:elseif>  <s:else> --%>
   <%--默认登录数据放在ContextMapd的session中 --%>
   	<s:set var="loginInfo" value="'rose'" scope="session" ></s:set> 
   	<s:if test="#session.loginInfo==null">
   		请先登录
   	</s:if>
   	<s:else>
              欢迎你,用户名:<s:property value="#session.loginInfo"/>
   	</s:else>
   	<hr>
   
   <%--<S:iterator>循环迭代  --%>
   <s:iterator value="#request.books" status="vs" id="book">
   		序号:<s:property value="#vs.count"/>
   		书名:<s:property value="#book.name"/>
   		价格:<s:property value="#book.price"/><br>
   </s:iterator>
</body>

3.2 UI标签:用于简化html标签(表单)使用

<s:form>

<s:textfield>    

<s:password>    

<s:submit>

<s:reset>      

<s:checkbox>     

*<s:checkboxlist>      

*<s:radio>     

*<s:select>

<body>
   	<s:form action="book_list" namespace="/ognl">
   	<%--Struts2的UI部分不是代表ognl表达式,如果要让他们成为OGNL表达式,要加上%{}
   		%{ognl表达式}
   	 --%>
   		<s:textfield label="用户名" name="curUser.userName" cssClass="style2"></s:textfield>
   		<s:password label="密码" name="curUser.userPsw" ></s:password>
   		<s:textarea label="简介" name="info"></s:textarea>
   		<s:submit value="注册" align="left"></s:submit>
   		<s:checkbox name="hobby" label="篮球" value="打篮球"></s:checkbox>
   		<s:checkbox name="hobby" label="足球" value="足球"></s:checkbox>
   		<s:checkbox name="hobby" label="网球" value="网球"></s:checkbox>
   		
   	<%-- 可以用ognllist进行数据的展示
   		ognl表达式创建List集合
   		ognl表达式创建Map集合
   	 --%>
   	<%--label和value一致的情况 --%>
   		<s:checkboxlist name="hobby" list="{'篮球','足球','网球'}"></s:checkboxlist>
   		<s:checkboxlist name="types" list="#request.types"></s:checkboxlist>
   	
   	<%--lable和value不一致的情况 --%>
		<s:checkboxlist name="hobby" list="#{'eat':'吃','drink':'喝','play':'玩'}"></s:checkboxlist>
	
	<%--list:所以checkbox的值
	    value:默认选中的checkbox的值 --%>
   	<s:checkboxlist name="types" list="#request.typesMap" value="curTypes" ></s:checkboxlist>
   	<s:select name="types" list="#request.typesMap" value="curTypes"></s:select>
   	<s:radio list="#request.typesMap" value="%{curTypes}"></s:radio>
 	<s:reset value="重置" align="left" theme="simple"></s:reset>
   	</s:form>
</body>

四、国际化

国际化步骤:

1. 在src目录下创建resource包,在resource包下创建国际化的properties文件:

message_en_US.properties:

user=USERNAME
password=PASSWORD
login=LOGIN

message_zh_CN.properties:

user=\u7528\u6237\u540D
password=\u5BC6\u7801
login=\u767B\u5F55

2. 统一绑定资源包。

在struts.xml配置文件中添加国际化的常量配置。

<!-- 修改国际化资源包的路径 -->
<constant name="struts.custom.i18n.resources" value="resource.message"></constant>

3. 使用国际化

a. Action:注意action类要继承ActionSupport类,用getText()方法获取需要国际化的属性。

package edu.scut.a_ognl;

import com.opensymphony.xwork2.ActionSupport;

public class BookAction extends ActionSupport{
	public String i18n(){
		//获取国际化内容
		String user = getText("user");
		String password = getText("password");
		String login = getText("login");
		System.out.println(user);
		System.out.println(password);
		System.out.println(login);
		
		return "i18n";
	}
}
b. JSP页面:注意用key接收需要国际化的属性。

<body>
  <%--在标签中使用国际化内容 --%>
  <s:form>
   	<s:textfield key="user"/>
   	<s:password key="password"/>
   	<s:submit key="login"/>
  </s:form>
</body>

五、表单数据校验

         采用javascript页面前端进行验证安全性不够,容易被绕过去,为了提高安全性,一般要进行后台验证。

5.1 使用代码验证

使用代码进行验证的方式灵活太差,一般比较少用。

5.1.1 全局验证(所有的方法都验证)

a. 编写一个Action类,继承ActionSupport(为了实现Valiateable接口)。b. 覆盖validate()方法。

b. 覆盖validate()方法。

下面的代码中对reg()和list()两个方均进行了验证。

package edu.scut.b_validate;

import org.hibernate.validator.constraints.Email;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
//采用方式进行验证,必须继承actionSupport
public class UserAction extends ActionSupport implements ModelDriven<User> {
	//接受页面数据
	private User user = new User();
	@Override
	public User getModel() {
		// TODO Auto-generated method stub
		return user;
	}
	
	/**
	 * 1)用户名不能为空,必须为数字或字母,长度4-16位
	 * 2)密码不能为空,必须为数字,长度为6-16位						
	 */	
 	@Override
	public void validate() {
  		System.out.println("执行数据校验!");
 		System.out.println(user);
 		if(user!=null){
			//进行数据校验
 			 //用户名
			if(user.getName()==null || user.getName().equals("")){
 				//用户名不能为空
  				//将错误信息带入注册页面
				addFieldError("username", "用户名不能为空!");
  			}else{
 				//必须是字母或者数字。并且长度为4-16位
 				if(!user.getName().matches("[0-9a-zA-Z]{4,16}")){
  					addFieldError("username", "用户名格式错误!");
 				};
  			}
			
			 //密码
 			if(user.getPassword()==null || user.getPassword().equals("")){
 				//密码不能为空
 				addFieldError("password", "密码不能为空!");
 	 		 }else{
 				//必须为数字,4-16位
 				if(!user.getPassword().matches("[0-9]{6,16}")){
 					addFieldError("password", "密码格式有误!");
				}
  			}
 	}
 	
	 public String reg(){
  		System.out.println(user);
 		return SUCCESS;
  	}
<span style="color:#FF0000;"><span style="color:#000000;"></span></span><pre name="code" class="java">        public String list(){
		System.out.println(user);
		return "list";
	}
}


c. 在struts.xml文件中对应的action配置加上input视图,然后struts2就会自动把错误信息转发到input视图的页面上去。

<result name="input">/reg.jsp</result>
d. 在input视图页面上,打印出错误信息

<s:fielderror></s:fielderror>

5.1.2 局部验证(对一个方法验证)

局部校验时,只需要把需要验证的方法名改成固定格式(validate+需要验证的方法名称)即可。

例如,要对只对reg()方法验证,而不对其他方法验证,只需将reg()方法名称改成validateReg()即可。

        //代码方式局部验证,编写validate+需要验证的方法名称!!!
	public void validateReg(){
		//有错误信息,struts2会自动跳转到input页面
		if(user!=null){
			//用户名验证
			if(user.getName()==null || user.getName().equals("")){
				addFieldError("name", "用户名不能为空!");
			}else{
				if(!user.getName().matches("[0-9a-zA-Z]{4,16}")){
					addFieldError("name", "用户名格式错误!");
				}
			}
			
		}
	}

5.2 使用配置文件验证

为了提高数据校验的灵活性,可以使用配置文件的方式完成校验。

5.2.1 全局验证(所有的方法都验证)

这种配置方式对action的所有方法都生效。

a. 编写一个xml文件,名称:  Action文件名-validation.xml。

b. 该xml文件必须放在Action文件的同一目录。

例如:UserAction-validation.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator 1.0.2//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
<validators>
	<!-- 验证一个属性 name是属性名 -->
	<field name="name">
		<!-- 属性验证器 -->
		<field-validator type="requiredstring">
			<!-- 错误信息 -->
			<message key="name.requried"></message>
		</field-validator>
		<field-validator type="regex">
			<!-- 给验证器注入一个参数 -->
			<param name="expression">[0-9a-zA-Z]{4,16}</param>
			<!-- 错误信息 -->
			<message key="name.formaterror"></message>
		</field-validator>
	</field>
	
	<field name="email">
		<field-validator type="requiredstring">
			<message key="email.requried"></message>
		</field-validator>
		<field-validator type="email">
			<message key="email.formaterror"></message>
		</field-validator>
	</field>
</validators>

5.2.2 局部验证(对一个方法验证)

这种配置方式对action的指定方法都生效。

a. 编写一个xml文件,名称: Action文件名-访问方法路径-validation.xml。

b. 该xml文件必须放在Action文件的同一目录。

例如:UserAction-user_reg-validation.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator 1.0.2//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
<validators>
	<!-- 验证一个属性 name是属性名 -->
	<field name="name">
		<!-- 属性验证器 -->
		<field-validator type="requiredstring">
			<!-- 错误信息 -->
			<message key="name.requried"></message>
		</field-validator>
		<field-validator type="regex">
			<!-- 给验证器注入一个参数 -->
			<param name="expression">[0-9a-zA-Z]{4,16}</param>
			<!-- 错误信息 -->
			<message key="name.formaterror"></message>
		</field-validator>
	</field>
	
	<field name="email">
		<field-validator type="requiredstring">
			<message key="email.requried"></message>
		</field-validator>
		<field-validator type="email">
			<message key="email.formaterror"></message>
		</field-validator>
	</field>
</validators>

六、拦截器

6.1 拦截器简介

         拦截器的功能类似于过滤器,但是过滤器可以过滤项目的任何请求(servlet/jsp/html/img),拦截器只能拦截Action资源。拦截器是struts2框架的核心,因为struts2的核心功能都是通过拦截器来实现的。

例如:

          参数的接收拦截器:com.opensymphony.xwork2.interceptor.ParametersInterceptor

          文件上传拦截器:org.apache.struts2.interceptor.FileUploadInterceptor

          国际化拦截器:com.opensymphony.xwork2.interceptor.I18nInterceptor

6.2 拦截器和过滤器的比较

拦截器 过滤器
可以拦截代码 可以拦截代码
struts2的组件之一,主要是拦截的action(方法) servlet的三大组件之一,主要是拦截请求(静态内容和动态内容)和响应

6.3 自定义拦截器的开发步骤

               struts2框架有很多拦截器,来支持其核心功能。但是,有时候不能满足实际开发的需求,用户需要自定义具有特殊功能的拦截器。struts2支持自定义拦截器。 自定义拦 截器的开发步骤如下:

             a. 编写java类,实现Intercepor接口。

Example

编写两个拦截器:

MyInterceptor1

package edu.scut.d_Interceptor;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

public class MyInterceptor1 implements Interceptor {

	@Override
	public void destroy() {
	}

	@Override
	public void init() {
	}

 	@Override
	public String intercept(ActionInvocation invocation) throws Exception {
 		System.out.println("1 执行interceptor1的action前面的代码!");
		String result = invocation.invoke();
 		System.out.println("5 执行interceptor1的action后面的代码!");
		return result;
 	}
}

MyInterceptor2

package edu.scut.d_Interceptor;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

public class MyInterceptor2 implements Interceptor {

	@Override
	public void destroy() {
	}

	@Override
	public void init() {
	}

	@Override
 	public String intercept(ActionInvocation invocation) throws Exception {
		System.out.println("2 执行interceptor2的action前面的代码!");
 		String result = invocation.invoke();
		System.out.println("4 执行interceptor2的action后面的代码!");
 		return result;
 	}
}

action类

package edu.scut.d_Interceptor;

import com.opensymphony.xwork2.ActionSupport;
//图书操作类
public class BookAction extends ActionSupport {
	//接收页面参数
	private String name;
	public void setName(String name) {
		this.name = name;
	}
	
	private String password;
	public void setPassword(String password) {
		this.password = password;
	}

       public String list(){
		System.out.println("3 执行了图书的list方法!");
		System.out.println(name);
 		System.out.println(password);
		return SUCCESS;
 	}
}

b. 在struts.xml文件中配置拦截器,并定义拦截器栈。。

注意:在配置action时,引用了自定义的拦截器栈后,默认的拦截器栈(defaultStack)也要引用,并且放在配置的第一位置。否则,struts2的很多核心功能将实效。例如不能接收页面传过来的参数。

<?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>
	<package name="interceptor" extends="struts-default" namespace="/interceptor">
		<!-- 配置自定义拦截器 -->
		<interceptors>
			<!-- 定义拦截器 -->
			<interceptor name="interceptor1" class="edu.scut.d_Interceptor.MyInterceptor1"/>
			<interceptor name="interceptor2" class="edu.scut.d_Interceptor.MyInterceptor2"/>
			<!-- 定义拦截器栈 -->
			<interceptor-stack name="myStack">
				<!-- 一个拦截器栈包含多个拦截器 -->
				<!-- 注意:struts2的默认拦截器一定要配置在第一位!否则会被覆盖! -->
				<interceptor-ref name="defaultStack"></interceptor-ref>
				<interceptor-ref name="interceptor1"></interceptor-ref>
				<interceptor-ref name="interceptor2"></interceptor-ref>
			</interceptor-stack>
		</interceptors>
	
		<action name="book_*" class="edu.scut.d_Interceptor.BookAction" method="{1}" >
			<!-- 引入拦截器 -->
			<interceptor-ref name="myStack"></interceptor-ref>
			<result >/succ.jsp</result>
		</action>
	</package>
</struts>

以上Example的运行结果:

1 执行interceptor1的action前面的代码!
2 执行interceptor2的action前面的代码!
3 执行了图书的list方法!
4 执行interceptor2的action后面的代码!
5 执行interceptor1的action后面的代码!

可以看出,页面发送的请求,必须经过拦截器才能访问action类,而且通过拦截器的顺序是根据struts2里面的配置顺序进行的。执行了第一个拦截器的(String result = invocation.invoke();)才能放行,依次执行后面的拦截器或者方法。

七、struts2的执行过程

下面这个图不是我自己画的,但是为了说明问题,我引用一下。跟着步骤仔细看一遍,会加深理解。

技术分享



























































以上是关于Struts2学习总结的主要内容,如果未能解决你的问题,请参考以下文章

springMVC学习总结路径映射和请求方法限定

Struts2 引入

Struts2_Action学习总结

SpringMVC与Struts2区别与比较总结

Struts2学习

Struts2学习---namespace,file模块包含,默认action