深入Struts2配置元素

本章重点描述了一下struts拦截器的使用,文章的前面顺带介绍了一下struts的Bean配置、常量配置和包配置

1、Bean配置

Struts2是一个高度可拓展的框架,框架大部分核心组件都是以配置的方式写在配置文件中的,当开发者需要替换其核心组件的时候,只需要写好自己的实现类,

然后配置到配置文件中。我们打开struts2-core-2.x.x.jar文件,打开里面的struts-default.xml文件,看到该文件配置了大量的Bean定义,该配置文件部分

代码如下所示:

	
    
    
    
	
	
上面配置文件中配置了Struts2的核心的Bean。在struts.xml文件中Bean通常有两个作用:

(1)创建该实例Bean,作为struts2的核心Bean。

(2)Bean包含的一些静态方法需要值传入。

注意,对绝大多数Struts2的应用而言,无需重新定义Struts2内的核心组件,也无需在struts.xml中配置Bean标签。

2、常量配置

前面说了,这块可以在struts.xml中配置,也可以在struts.properties中配置,其实还可以在web.xml加载FilterDispatcher的时候加载常量参数。

在struts.xml中配置的方式:

3、包配置

Struts2的核心就是Action、拦截器,Struts2使用包来管理Action和拦截器。每个包下就是多个Action、多个拦截器、多个拦截器的引用的集合。

配置包时必须指定name属性,除此之外还可以指定一个可选属性extends,extends属性值必须是另一个包的name属性的值,使用exdends属性的目的是继承

其他包,继承父包中的Action、拦截器等配置。

除此之外,Struts2还提供了一种抽象包,抽象包的含义是该包不能有Action的定义。为了显示指定一个抽象包,必须将package元素的abstract属性设置成

true。

namespase用来指定命名空间是一个可选属性。

考虑到同一个应用可能会用到同名的Action,Struts2以命名空间的方式来管理它们,同一个命名空间下不能有相同的Action,不同的命名空间下可以有相同的

Action。

Struts2不支持为单独的Action设置命名空间,而是通过为package指定namespase属性来为该包下的所有Action统一指定命名空间。

 

	
		
		
			/error.jsp
			/welcome.jsp
		
	
	
		
			/login.jsp
		
		
对于上面的这个配置文件,配置了两个包,一个是org一个是get,其中get包设置了namespase属性/apple,对于org包而言,没有设置namespase属性。

对于没有配置namespase属性的包,其为默认包,默认的namespase=" "

当为某个包配置了namespase属性的时候,那么访问的时候就需要是namespase的值加上Action的值。访问路径:

/**
其中strutsDemo是项目名称,apple是命名空间,login是Action的name
*/
http://localhost:8080/strutsDemo/apple/login

除此之外,struts还可以通过namespase="/"来指定根命名空间。

如果Url为/apple/login 那么系统首先会在命名空间为apple的包下寻找name值为login的Action,如果该包下找到了那么就处理请求,如果没有找到,继续在

默认命名空间中寻找,如果找到则处理请求,如果还没找到,那么抛出异常。

如果Url为/login,则首先会在根命名空间中寻找,其次去默认命名空间中寻找,如果两者都没有找到,抛出异常。

4、拦截器的配置

这部分很重要!!!

(1)理解拦截器

struts2拦截器是在访问某个action或者某个action方法的,访问之前或者之后实施拦截,并且Struts2拦截器是可拔插的,拦截器是AOP的一种实现。

拦截器栈(Interceptor Stack)。Struts2拦截器栈就是将拦截器按一定的顺序连结成一条链。在访问被拦截的方法或者字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用。

(2)实现Struts2拦截器原理

Struts2拦截器的实现原理相对简单,当请求struts2的action时,struts2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串联成一个列表,最后一个一个的调用列表中的拦截器。

深入Struts2配置元素_第1张图片

图中我们可以发现,Struts2的Interceptor一层一层的把action包裹在最里面,这样的结构,大概有以下一些特点:
1)、整个结构就如同一个堆栈,除了Action以外,堆栈中的其他元素是Interceptor
2)、Action位于堆栈的底部。由于堆栈“先进后出”的特性,如果我们试图把Action拿出来执行,我们必须首先把位于Action上端的所有Interceptor拿出来执
行。这样,整个执行就形成了一个递归调用。
3)、每个位于堆栈中的Interceptor,除了需要完成自身的逻辑外,还需要完成一个特殊的职责。这个执行职责有三种选择:
中止整个执行,直接返回一个字符串作为relultCode
通过递归调用负责调用堆栈中下一个Interceptor的执行
如果在堆栈内已经不存在任何的Interceptor,那么调用Action
(3)部署拦截器
为了能够正常使用拦截器,首先我们必须在struts.xml中正确部署拦截器。具体的做法为在标签对内使用标签
引入具体拦截器,需要指定拦截器的名称和类:



    
        
            
            
            ………………………………………………………………………………………………………………………………………………
            
        
        
    
 
部署好拦截器之后,我们就可以利用拦截器为指定的Action应用添加功能了。具体的做法是在标签对内使用标签引入所
需的拦截器:



    
        
         
        
            
            
            
            
            ……………………………………………………………………………………………………
            
        
    
还可以为拦截器设置参数:



    
        
            
                参数值
            
        
        
            
            
                参数值
            
             
    
 

(4)如何使用拦截器栈

一个拦截器栈可以包括一个或者多个拦截器,也可以包括其他拦截器栈。





    
        
            
            
            ………………………………………………………………………………………………………………………………………………
            
             
            
                
                
                
            
             
            
                
                
            
           
    

为Action应用拦截器栈的方式和应用拦截器一样。

(5)自定义拦截器

自定义拦截器有2种实现方式,一种是实现Interceptor接口,另一种是继承AbstractInterceptor类。

看下实现Inteceptor接口的示例:

package wwfy.interceptor;

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

@SuppressWarnings("serial")
public class CustomInterceptor1 implements Interceptor {
    public void destroy() {
        // TODO Auto-generated method stub
    }
    public void init() {
        // TODO Auto-generated method stub
    }

    public String intercept(ActionInvocation invocation) throws Exception {
        System.out.println("--------拦截器开始----------");
        String result = invocation.invoke();
        System.out.println("--------拦截器结束----------");
        return result;
    }

}
看下继承AbstractInterceptor类的实例:

package wwfy.interceptor;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
@SuppressWarnings("serial")
public class CustomInterceptor2 extends AbstractInterceptor {

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        System.out.println("--------拦截器开始----------");
        String result = invocation.invoke();
        System.out.println("--------拦截器结束----------");
        return result;
    }

}

invocation.invoke()的作用:

在这个实现类中,实际上已经实现了最简单的拦截器的雏形。或许大家对这样的代码还比较陌生,这没有关系。我在这里需要指出的是一个很重要的方法

invocation.invoke()。

这是ActionInvocation中的方法,而ActionInvocation是Action调度者,所以这个方法具备以下2层含义:

如果拦截器堆栈中还有其他的Interceptor,那么invocation.invoke()将调用堆栈中下一个Interceptor的执行。

如果拦截器堆栈中只有Action了,那么invocation.invoke()将调用Action执行。

所以,我们可以发现,invocation.invoke()这个方法其实是整个拦截器框架的实现核心。基于这样的实现机制,我们还可以得到下面2个非常重要的推论:

如果在拦截器中,我们不使用invocation.invoke()来完成堆栈中下一个元素的调用,而是直接返回一个字符串作为执行结果,那么整个执行将被中止。

我们可以以invocation.invoke()为界,将拦截器中的代码分成2个部分,在invocation.invoke()之前的代码,将会在Action之前被依次执行,而在

invocation.invoke()之后的代码,将会在Action之后被逆序执行。

由此,我们就可以通过invocation.invoke()作为Action代码真正的拦截点,从而实现AOP。 

你可能感兴趣的:(J2EE,面试秘籍)