`
在水伊方
  • 浏览: 106931 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

Struts2--自定义拦截器

 
阅读更多

为什么会有拦截器:

许多Action都需要做一些相同的事情,比如说登录验证,表单输入验证,上传文件时的初始化操作,而有些Action则需要在页面显示前做一些预先填充数据的准备,这些需求在项目中都是很常见的,设想一下,如果在每个action都做一些重复性的功能逻辑,这样实现即繁琐,又违背了软件复用的思想,所以为了解决这个问题,Struts2的设计者们把这些共有的逻辑独立出来,实现成一个个的拦截器,拦截器由此而诞生。

 

什么是拦截器:

拦截器,在AOPAspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作,拦截是AOP的一种实现策略。

谈到拦截器,还有一个词需要提一下——拦截器链(Interceptor Chain,在Struts 2中称为拦截器栈Interceptor Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用,访问完之后,拦截器链中的拦截器就会按其之前定义的顺序被逆序调用。

 

理解拦截器:

拦截器是在某个Action被调用之前与之后执行的,许多框架的核心功能都实现为拦截器,如重复提交,类型转换,校验,文件上传等等,这些实现多亏了拦截器才得以简单实现,每个拦截器都是可插拔的,所以你可以精确为某个需要某种功能的Action配置相应的拦截器。

可以为每个Action配置拦截器,用户自定义的拦截器可以与框架附带的拦截器混合搭配使用,拦截器会在Action执行前做很多繁琐的事情,这样就避免了在每个Action中出现重复代码。

 

    下面是Action的生命周期图:

 

 

从图中可以看出Struts2Interceptor一层一层把Action包裹在最里面,所有的用户请求都会被拦截器所拦截,然后交给Action处理,处理结果以逻辑视图方式返回给用户。而这个调用执行流程,是由Struts 2的配置文件来实现的。可以定义一个拦截器栈为多个拦截器指定执行顺序,在某些时候,拦截器栈中的拦截器的执行顺序是非常重要的。 

       

每个位于堆栈中的Interceptor,除了需要完成它自身的逻辑,还需要完成一个特殊的执行职责。这个执行职责有3种选择:

1) 中止整个执行,直接返回一个字符串作为resultCode

2) 通过递归调用负责调用堆栈中下一个Interceptor的执行

3) 如果在堆栈内已经不存在任何的Interceptor,调用Action 

      

Struts2的拦截器结构的设计,实际上是一个典型的责任链模式的应用。首先将整个执行划分成若干相同类型的元素,每个元素具备不同的逻辑责任,并将他们纳入到一个链式的数据结构中(我们可以把堆栈结构也看作是一个递归的链式结构),而每个元素又有责任负责链式结构中下一个元素的执行调用。

 

 

拦截器都是通过代理的方式调用的,当用户请求到达Struts 2ServletDispatcher时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表(List),然后逐个地调用列表中的拦截器,拦截器时序图如下图所示。 

 

从上图中可以看出,拦截器的执行顺序是:

Action之前,拦截器的执行顺序与堆栈中定义的一致;而在ActionResult之后,拦截器的执行顺序与堆栈中定义的顺序相反。这就好比我们穿衣服一样,早上起床一件一件的套在身上,晚上睡觉前,再一件一件的脱下来。 

 

配置拦截器:      

<interceptors>
	<interceptor name="拦截器名" class="拦截器对应的类" />
	<interceptor-stack name="拦截器栈名">
		<interceptor-ref name="拦截器名或拦截器栈名1" />
		<interceptor-ref name="拦截器名或拦截器栈名2" />
	</interceptor-stack>
</interceptors>

   引用拦截器:  

<action name="Action的名称" class="Action对应的类">
	<result name="success">视图资源</result>
	<!-- 使用拦截器,一般配置在result之后, -->
	<interceptor-ref name="拦截器名或拦截器栈名" />
</action>

   此处需要注意的是,如果为Action指定了一个拦截器,则系统默认的拦截器栈将会失去作用。为了继续使用默认拦截器,我们可以在配置文件中手动引入默认拦截器。

 

<action name="Action的名称" class="Action对应的类">
	<result name="success">视图资源</result>
	<!-- 使用拦截器,一般配置在result之后, -->
	<interceptor-ref name="defaultStack"/>
	<interceptor-ref name="拦截器名或拦截器栈名" />
</action>

       需要把默认的拦截器放在自定义的拦截器前面,否则会出错。 

如果不想为每个Action都配置相同的拦截器或拦截器栈,则可以在配置文件中定义一个默认的拦截器或拦截器栈

<!-- 这句是设置所有Action自动调用的拦截器堆栈 --> 
<default-interceptor-ref name="拦截器名或拦截器栈名" />
<action name="Action的名称1" class="Action对应的类1" />
<action name="Action的名称2" class="Action对应的类2" />

 注意:每个包只能指定一个默认拦截器。另外,一旦我们为该包中的某个action显式指定了某个拦截器,则默认拦截器不会起作用。

 

自定义拦截器:      

自定义一个拦截器需要三步:

1 、自定义一个实现Interceptor接口(或者继承自AbstractInterceptor)的类。

2strutx.xml中注册上一步中定义的拦截器。

3 、在需要使用的Action中引用上述定义的拦截器,为了方便也可将拦截器定义为默认的拦截器,这样在不加特殊声明的情况下所有的Action都被这个拦截器拦截。 

 

    所有的Struts 2的拦截器都直接或间接实现接口com.opensymphony.xwork2.interceptor.Interceptor该接口提供了三个方法:

1)      void init(); 在该拦截器被初始化之后,在该拦截器执行拦截之前,系统回调该方法。对于每个拦截器而言,此方法只执行一次。

2)      void destroy();该方法跟init()方法对应。在拦截器实例被销毁之前,系统将回调该方法。

3)    String intercept(ActionInvocation invocation) throws Exception; 该方法是用户需要实现的拦截动作。该方法会返回一个字符串作为逻辑视图。

除此之外,继承类com.opensymphony.xwork2.interceptor.AbstractInterceptor是更简单的一种实现拦截器类的方式,因为此类提供了init()destroy()方法的空实现,这样我们只需要实现intercept方法。

 

下面是一个用于验证是否登录的拦截器:

package com.struts.interceptor;

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

public class PermissionInterceptor implements Interceptor {

	private static final long serialVersionUID = -1615930166094288049L;

	public void destroy() {
	}

	public void init() {
	}

	public String intercept(ActionInvocation invocation) throws Exception {
		ActionContext ac = ActionContext.getContext();

		Object name = ac.getSession().get("user");

		if (name != null) {
			return invocation.invoke(); // 返回代表视图的字符串,如果还有拦截器则继续执行
		} else {
			return "error";
		}
	}
}

 

简陋的不能在简陋的登陆页面login.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登录页面</title>
</head>
<body>
	<% request.getSession().setAttribute("user", "jetty"); %>
	用户登录
</body>
</html>

 

 如果用户访问过该页面,则在session域中存放键为user,值为jetty的键值对。

 

 下面是配置文件:

<?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="struts" namespace="/test" extends="struts-default">
		<interceptors>
			<!-- 自定义拦截器  -->
			<interceptor name="permissionInterceptor" class="com.struts.interceptor.PermissionInterceptor" />
			
			<interceptor-stack name="permissionStack">
				<!-- 默认的拦截器栈,定义在struts2-core-2.3.8.jar的struts-default.xml中,
				             因为struts2中如文件上传,数据验证,封装请求参数到action等功能都是由系统默认的defaultStack中的拦截器实现的,
				             所以我们定义的拦截器需要引用系统默认的defaultStack,这样应用才可以使用struts2框架提供的众多功能。-->
				<interceptor-ref name="defaultStack" />
				<interceptor-ref name="permissionInterceptor" />
			</interceptor-stack>
		</interceptors>
	
		<global-results>
			<result name="error">/WEB-INF/pages/error.jsp</result>
		</global-results>
		
		<action name="view" class="com.struts.action.ViewInfoAction" method="execute">
			<!-- 引用拦截器   -->
			<interceptor-ref name="permissionStack" />
			<result name="success">/WEB-INF/pages/viewinfo.jsp</result>
		</action>
	</package>
</struts>

 

简单的Action:

package com.struts.action;

public class ViewInfoAction {
	private String message;

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}
	
	public String execute() {
		this.message = "Hello, my name is Jetty";
		return "success";
	}

}

 

 如果用户没有访问过login.jsp,而直接访问名称为view的action,则会跳转到error.jsp

简单的error.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>提示信息页面</title>
</head>
<body>
	您没有权限查看该页面,请登录后查看!
</body>
</html>

 如果用户访问过login.jsp,则用户访问名称为view的action时,会跳转到viewinfo.jsp

简单的viewinfo.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>信息</title>
</head>
<body>
	${message }
</body>
</html>

 即可以在浏览器中看到Hello, my name is Jetty信息。 

 

注:Struts2默认的拦截器栈,定义在struts2-core-2.x.x.jar的struts-default.xml中

  • 大小: 17.1 KB
  • 大小: 17.5 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics