struts2总结(四)

struts2中的拦截器

 

拦截器概述

在Webwork的中文文档的解释为——拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者在定义的action执行的前后加入执行的代码,也可以在一个action执行前阻止其执行。也就是说它提供了一种可以提取action中可重用代码,统一管理和执行的方式。

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

说到这里,可能大家脑海中有了一个疑问,这不是我们之前学的过滤器吗?是的它和过滤器是有几分相似,但是也有区别,接下来我们就来说说他们的区别:

过滤器是servlet规范中的一部分,任何java web工程都可以使用。

拦截器是struts2框架自己的,只有使用了struts2框架的工程才能用。

过滤器在url-pattern中配置了/*之后,可以对所有要访问的资源拦截。

拦截器它是只有进入struts2核心内部之后,才会起作用,如果访问的是jsp,html,css,image或者js是不会进行拦截的。

同时,拦截器还是AOP编程思想的具体体现形式。AOP(Aspect-Oriented Programming)简单的说就是:

在不修改源码的基础上,已有的方法进行动态增强。

在struts2中,拦截器它就是对我们的动作方法进行增强。(其实就是把重复性的代码提取出来,然后放到拦截器中,统一管理,统一调用)

 

 

拦截器的作用

Struts2中的很多功能都是由拦截器完成的。我们在介绍struts2配置文件时,介绍了名称为struts-default.xml的配置文件,该配置文件中有struts2框架给我们提供的很多拦截器。比如:servletConfig,staticParam,params,modelDriven等等。我们通过实现接口方式获取ServletAPI以及模型驱动封装请求参数,都是拦截器在帮我们做。

 

拦截器的执行时机

在访问struts2核心内部时,在动作方法执行之前先正序执行,然后执行动作方法,执行完动作方法和结果视图之后,再倒序执行。所以它是先进后出,是个栈的结构。具体可参考下图:

 

 

自定义拦截器

在程序开发过程中,如果需要开发自己的拦截器类,就需要直接或间接的实现com.opensymphony.xwork2.interceptor.Interceptor接口。其接口的代码如下:

public interface Interceptor extends Serializable {

void init();

void destroy();

    String intercept(ActionInvocation invocation) throws Exception;

}

该接口提供了三个方法,其具体介绍如下。

  1. void init():该方法在拦截器被创建后会立即被调用, 它在拦截器的生命周期内只被调用一次. 可以在该方法中对相关资源进行必要的初始化。
  2. void destroy():该方法与init方法相对应,在拦截器实例被销毁之前,将调用该方法来释放和拦截器相关的资源。它在拦截器的生命周期内,也只被调用一次。
  3. String intercept(ActionInvocation invocation) throws Exception:该方法是拦截器的核心方法,用来添加真正执行拦截工作的代码,实现具体的拦截操作。它返回一个字符串作为逻辑视图,系统根据返回的字符串跳转到对应的视图资源。每拦截一个动作请求, 该方法就会被调用一次。该方法的ActionInvocation参数包含了被拦截的Action的引用,可以通过该参数的invoke()方法,将控制权转给下一个拦截器或者转给Action的execute()方法。

如果需要自定义拦截器,只需要实现Interceptor接口的三个方法即可。然而在实际开发过程中,除了实现Interceptor接口可以自定义拦截器外,更常用的一种方式是继承抽象拦截器类AbstractIntercepter。该类实现了Interceptor接口,并且提供了init()方法和destroy()方法的空实现。使用时,可以直接继承该抽象类,而不用实现那些不必要的方法。拦截器类AbstractInterceptor中定义的方法如下所示:

public abstract class AbstractInterceptor implements Interceptor {

    public void init() {}

    public void destroy() {}

    public abstract String intercept(ActionInvocation invocation)

throws Exception;

}

从上述代码中可以看出,AbstractInterceptor类已经实现了Interceptor接口的所有方法,一般情况下,只需继承AbstractInterceptor类,实现interceptor()方法就可以创建自定义拦截器。

只有当自定义的拦截器需要打开系统资源时,才需要覆盖AbstractInterceptor类的init()方法和destroy()方法。与实现Interceptor接口相比,继承AbstractInterceptor类的方法更为简单。

当然还有更简单的,AbstractInterceptor还有一个子类,MethodFilterInterceptor,该类中提供了两个属性,可以告知拦截器对哪些方法进行拦截或者对哪些方法排除。

下图展示的就是拦截器的类结构视图:

 

 

 

 

自定义步骤

通过在拦截器类视图上我们可以得知,我们定义拦截器可以有三种办法:

第一种:定义一个类,实现Interceptor接口

第二种:定义一个类,继承AbstractInterceptor

第三种:定义一个类,继承MethodFilterInterceptor

在这三种方式中,我们选择第二种和第三种都可以。那么后两种有什么区别呢?

我们来看看AbstractorInteractor类中的代码:

我们再来看看MethodFilterInterceptor中的代码:

 

看完两个类之后,我们有了结论。即:选择第三种方式,比第二种多了一个功能,就是告知拦截器哪些方法我们需要拦截,哪些方法我们不需要拦截。

根据以上的内容,我们开始编写我们自己的拦截器。

第一步:编写一个普通java类,继承MethodFilterInterceptor

 


/**
 * 自定义拦截器
*/
public class MyInterceptor extends AbstractInterceptor {

	@Override
	public String intercept(ActionInvocation invocation) throws Exception {
		System.out.println("MyInterceptor拦截了。。。。");
	}
}

第二步:在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"></constant>
	
	<package name="p1" extends="struts-default">
		<!-- 声明拦截器 -->
		<interceptors>
			<interceptor name="myInterceptor" 
			class="com.itheima.web.interceptors.MyInterceptor"></interceptor>
		</interceptors>
	
		<action name="demo1" 
			class="com.itheima.web.action.Demo1Action" method="demo1">
			<!-- 引用拦截器 -->
			<interceptor-ref name="myInterceptor"></interceptor-ref>
			<result name="error">/success.jsp</result>
		</action>
	</package>
</struts>

注意,此时我们创建动作类,配置动作类和编写访问动作了的jsp全都省略了。
代码如下:


/**
 * 一个动作类
 */
public class Demo1Action extends ActionSupport {
	public String demo1(){
		System.out.println("Demo1Action的demo1方法执行了");
		return ERROR;
	}
}

<%@ 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>
<a href="${pageContext.request.contextPath}/demo1.action">demo1</a>
</body>
</html>

<%@ 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>success.jsp</title>
</head>
<body>
<%System.out.println("success.jsp执行了"); %>
执行成功!
</body>
</html>

这时候我们执行代码,发现控制的输出的只有【MyInterceptor拦截了。。。。】,如下图

拦截器的放行


在拦截器中如何放行呢?我们之前已经介绍过几个拦截器了,例如ServletConfigInterceptor拦截器,可以看看它是怎么放行的。拦截器的方式:
invocation.invoke()方法。请看下面的代码: 


/**
 * 自定义拦截器
*/
public class MyInterceptor extends AbstractInterceptor {

	@Override
	public String intercept(ActionInvocation invocation) throws Exception {
		System.out.println("执行动作方法之前:MyInterceptor拦截了。。。。");
		String rtValue = invocation.invoke();//放行			
		System.out.println("执行动作方法之后:MyInterceptor拦截了。。。。");
		System.out.println(rtValue);
		return rtValue;
	}

}

当上面的代码执行完,发现action和jsp都执行了。那么这个rtValue值是什么呢?


拦截器的返回值

其实拦截器的返回值,就是我们Action中,执行的动作方法返回值。

多个拦截器的执行顺序

我们也可以自定义多个拦截器,那么多个拦截器之间执行顺序是靠引用拦截器时配置的顺序来决定的。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值