拦截器原理

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

2、intercept方法所依赖的参数ActionInvocation则是Action调度者。ActionInvocation中的invoke()方法具备以下2层含义(详细看DefaultActionInvocation源代码):

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

拦截器和过滤器的比较

1、拦截器和过滤器的概念非常类似,拦截器中的intercept()和过滤器中的doFilter()方法。

2、拦截器是基于动态代理来实现,而过滤器是基于函数回调。

3、过滤器隶属于web容器,可以过滤一切请求(包括action、servlet、jsp、html等等)。

4、而拦截器隶属于struts2框架,只能拦截action(无法拦截对jsp的请求)。

5、在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次

6、执行顺序 :过滤前 - 拦截前 - Action处理 - 拦截后 - 过滤后。

 实现拦截器类

1、实现com.opensymphony.xwork2.interceptor.Interceptor 接口

  • 实现其中的destroy() 、init() 、intercept() 方法

    package ecut.interceptors.interceptor;
    
    import java.util.Map;
    
    import com.opensymphony.xwork2.ActionContext;
    import com.opensymphony.xwork2.ActionInvocation;
    import com.opensymphony.xwork2.interceptor.Interceptor; /**
    * 1、通过实现 com.opensymphony.xwork2.interceptor.Interceptor 接口 来实现自定义的拦截器类
    */
    public class CheckLoginInterceptor implements Interceptor { private static final long serialVersionUID = -3115350062208083018L; public CheckLoginInterceptor() {
    System.out.println( "创建 CheckLoginInterceptor 的实例" );
    } @Override
    public void init() {
    System.out.println( "对 CheckLoginInterceptor 的实例进行初始化" );
    } @Override
    public String intercept( ActionInvocation invocation ) throws Exception {
    System.out.println( this);
    // 获得 Action 的上下文对象
    ActionContext context = invocation.getInvocationContext();
    // 获得正在被访问的 <action> 的名称
    String name = context.getName() ;
    System.out.println( "action name : " + name +"准备执行");
    String resultName = "input" ;
    // 如果被访问的 <action> 的名称是 main
    if( "main".equals( name ) ) {
    Map<String,Object> sessionMap = context.getSession();
    if( sessionMap.containsKey( "username" ) ) {
    System.out.println( "即将执行: " + name );
    resultName = invocation.invoke();
    System.out.println( name + "执行结束并返回: " + resultName );
    }
    } if( "logout".equals( name ) ){
    resultName = invocation.invoke();
    System.out.println( name + "执行结束并返回: " + resultName );
    } return resultName ;
    } @Override
    public void destroy() {
    } }
    package ecut.interceptors.interceptor;
    
    import com.opensymphony.xwork2.ActionContext;
    import com.opensymphony.xwork2.ActionInvocation;
    import com.opensymphony.xwork2.interceptor.Interceptor; public class ParamInterceptor implements Interceptor { private static final long serialVersionUID = 6273500806976834662L; private String interceptorParam ; public ParamInterceptor () {
    System.out.println( "创建实例ParamInterceptor" );
    System.out.println( "实例化 ParamInterceptor ,interceptorParam : " + interceptorParam );
    } @Override
    public void init() {
    System.out.println( "初始化 ParamInterceptor 实例 , interceptorParam : " + interceptorParam );
    } @Override
    public String intercept( ActionInvocation invocation ) throws Exception {
    System.out.println( this + " ," + interceptorParam );
    ActionContext context = invocation.getInvocationContext();
    System.out.println( "准备执行: " + context.getName() );
    String resultName = invocation.invoke();
    System.out.println( "执行结束: " + context.getName() + " , 返回的 Result 名称是 : " + resultName );
    return resultName ;
    } @Override
    public void destroy() {
    } public String getInterceptorParam() {
    return interceptorParam;
    } public void setInterceptorParam(String interceptorParam) {
    this.interceptorParam = interceptorParam;
    } }

    在拦截器中写一个无参构造,可以在日志中看出,配置文件每引用一次拦截器,就会执行一次实例化操作和初始化操作。

2、继承com.opensymphony.xwork2.interceptor.AbstractInterceptor 类

  • 实现其中的intercept() 方法

定义拦截器(声明)

1、定义拦截器

  • 定义不带参数的拦截器

    <?xml version="1.0" encoding="UTF-8"?>
    
    <!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
    "http://struts.apache.org/dtds/struts-2.5.dtd"> <struts> <!-- 允许在 action 的 名称 中使用 / 字符 <constant name="struts.enable.SlashesInActionNames" value="true" /> -->
    <!-- 启用动态方法调用 <constant name="struts.enable.DynamicMethodInvocation" value="true" /> --> <!-- 修改 action 请求路径的后缀 value="do,,action既可以是action后缀也可以是do后缀也可以啥都不写"-->
    <constant name="struts.action.extension" value="do,," /> <package name="interceptor" namespace="/interceptor" extends="struts-default" > <!-- 在 package 内部 使用 interceptors 可以定义 拦截器 和 拦截器栈 -->
    <interceptors> <!-- 使用 interceptor 声明拦截器(定义),引用一个拦截器,就创建了一个指定类型的对象 -->
    <interceptor name="checkLogin" class="ecut.interceptors.interceptor.CheckLoginInterceptor" />
           </interceptors>
    
    </struts>
  • 定义带参数的拦截器
    <?xml version="1.0" encoding="UTF-8"?>
    
    <!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
    "http://struts.apache.org/dtds/struts-2.5.dtd"> <struts> <!-- 允许在 action 的 名称 中使用 / 字符 <constant name="struts.enable.SlashesInActionNames" value="true" /> -->
    <!-- 启用动态方法调用 <constant name="struts.enable.DynamicMethodInvocation" value="true" /> --> <!-- 修改 action 请求路径的后缀 value="do,,action既可以是action后缀也可以是do后缀也可以啥都不写"-->
    <constant name="struts.action.extension" value="do,," /> <package name="interceptor" namespace="/interceptor" extends="struts-default" > <!-- 在 package 内部 使用 interceptors 可以定义 拦截器 和 拦截器栈 -->
    <interceptors> <!-- 在声明拦截器时指定拦截器的参数值 -->
    <interceptor name="param" class="ecut.interceptors.interceptor.ParamInterceptor" >
    <param name="interceptorParam">声明时所指定的拦截器参数的值就是参数的默认值</param>
    </interceptor>
    </interceptors>
    </struts>

    可以通过param指定拦截器中interceptorParam的默认值,对应的拦截器类中定义跟参数名相同的属性,并提供getter 和setter 。Struts 2 框架会自动把参数的值设置到相应的属性中去。

2、定义拦截器栈

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd"> <struts> <!-- 允许在 action 的 名称 中使用 / 字符 <constant name="struts.enable.SlashesInActionNames" value="true" /> -->
<!-- 启用动态方法调用 <constant name="struts.enable.DynamicMethodInvocation" value="true" /> --> <!-- 修改 action 请求路径的后缀 value="do,,action既可以是action后缀也可以是do后缀也可以啥都不写"-->
<constant name="struts.action.extension" value="do,," /> <package name="interceptor" namespace="/interceptor" extends="struts-default" > <!-- 在 package 内部 使用 interceptors 可以定义 拦截器 和 拦截器栈 -->
<interceptors> <!-- 声明拦截器栈 -->
<interceptor-stack name="myStack">
<!-- 引用已声明的拦截器栈 -->
<interceptor-ref name="defaultStack" />
<!-- 引用已声明的拦截器,引用一次就创建一个该拦截器的实例,并初始化-->
<interceptor-ref name="checkLogin" />
<interceptor-ref name="param" >
<param name="interceptorParam">拦截器栈</param>
</interceptor-ref>
</interceptor-stack> </interceptors>
</struts>

拦截器的执行顺序按照引用顺序依次执行,拦截器栈中拦截器,按照拦截器栈的顺序去依次执行

使用拦截器(引用)

1、可以在拦截器栈中引用拦截器或拦截器栈

<!-- 声明拦截器栈 -->
<interceptor-stack name="myStack">
  <!-- 引用已声明的拦截器栈 -->
  <interceptor-ref name="defaultStack" />
  <!-- 引用已声明的拦截器,引用一次就创建一个该拦截器的实例,并初始化-->
  <interceptor-ref name="checkLogin" />
  <interceptor-ref name="param" >
    <param name="interceptorParam">拦截器栈</param>
  </interceptor-ref>
</interceptor-stack>

2、也可以在<action> 中引用拦截器

Action类

package ecut.interceptors.action;

import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext; public class LoginAction implements Action { private static Logger logger = LogManager.getLogger(); private String username;
private String password; @Override
public String execute() throws Exception {
logger.info( "username : " + username );
logger.info( "password : " + password ); ActionContext context = ActionContext.getContext(); Map<String,Object> sessionMap = context.getSession(); sessionMap.put( "username" , username ); return SUCCESS ;
} public String logout() throws Exception { System.out.println("logout");
ActionContext context = ActionContext.getContext(); Map<String,Object> sessionMap = context.getSession(); sessionMap.remove( "username"); return SUCCESS ;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} }

struts.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd"> <struts>
    <!-- 全局的result需要在拦截器之后 -->
<global-results>
<result name="input" type="redirect">
<param name="location">/interceptor/index.jsp</param>
</result>
</global-results> <action name="login" class="ecut.interceptors.action.LoginAction" method="execute">
<result name="success" type="redirectAction">
<param name="actionName">main</param>
</result>
</action> <action name="main" >
<result>/WEB-INF/pages/interceptor/main.jsp</result>
<!--如果引用了自己的拦截器则默认拦截器就不起作用了,默认拦截器在struts-default.xml使用 default-interceptor-ref指定(defaultStack),
defaultStack中引用了modelDriven拦截器,因此参数都为null,需要在自己的拦截器前面引用默认的拦截器
-->
<!-- <interceptor-ref name="defaultStack" />
<interceptor-ref name="checkLogin" />
<interceptor-ref name="param" >
<param name="interceptorParam">张三丰</param>
</interceptor-ref>
<interceptor-ref name="param" >
<param name="interceptorParam">张翠山</param>
</interceptor-ref> --> <!-- 引用拦截器栈,以便于对当前的action进行拦截 -->
<interceptor-ref name="myStack">
<!-- 形式上 是在 覆盖 param 的 interceptorParam 参数的值 -->
<param name="param.interceptorParam">Action</param>
<!-- 实际上 是将本次引用中的 param 对应的对象 替换成一个新的对象 -->
</interceptor-ref>
</action> <action name="logout" class="ecut.interceptors.action.LoginAction" method="logout">
<result name="success" type="redirectAction">
<param name="actionName">main</param>
</result>
<!-- 引用之前已经声明好的拦截器,没有明确指定param拦截器里interceptorParam属性值就使用默认的属性值 -->
<interceptor-ref name="myStack" />
</action>
</struts>

在默认包struts-default 中定义了一系列拦截器和拦截器栈,同时使用default-interceptor-ref 定义了一个默认拦截器defaultStack 。因为继承了struts-default 包,同时也就继承了defaultStack ,所以只要没有显式指定拦截器,都会使用默认的拦截器。如果引用了自己的拦截器则默认拦截器就不起作用了,默认拦截器在struts-default.xml使用 default-interceptor-ref指定(defaultStack), defaultStack中引用了modelDriven拦截器,因此参数都为null,需要在自己的拦截器前面引用默认的拦截器。在引用拦截器时可以指定拦截器中的参数值。每引用一次拦截器,就会执行一次实例化操作和初始化操作。

index.jsp

<%@ page language = "java" pageEncoding = "UTF-8" %>
<%@ page contentType = "text/html; charset= UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Interceptor</title>
</head>
<body> <h1>Interceptor</h1> <form action="${ pageContext.request.contextPath }/interceptor/login" method="post" >
<input type="text" name="username" >
<input type="password" name="password" >
<input type="submit" value="登录">
</form>
<a href="${ pageContext.request.contextPath }/interceptor/main">查看主页面</a>
</body>
</html>

main.jsp

<%@ page language = "java" pageEncoding = "UTF-8" %>
<%@ page contentType = "text/html; charset= UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>主页</title>
</head>
<body> <h1>Hello , ${ username }</h1>
<a href="${ pageContext.request.contextPath }/interceptor/logout">退出登录</a>
</body>
</html>

转载请于明显处标明出处

https://www.cnblogs.com/AmyZheng/p/9224129.html

Struts2学习(六)的更多相关文章

  1. Struts2学习六----------默认Action

    © 版权声明:本文为博主原创文章,转载请注明出处 默认Action - 当访问action不存在时,可通过指定默认action的方式避免出现错误代码页面 - 使用default-action-ref指 ...

  2. Java后台处理框架之struts2学习总结

    Java后台处理框架之struts2学习总结 最近我在网上了解到,在实际的开发项目中struts2的使用率在不断降低,取而代之的是springMVC.可能有很多的朋友看到这里就会说,那还不如不学str ...

  3. [原创]java WEB学习笔记75:Struts2 学习之路-- 总结 和 目录

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  4. [原创]java WEB学习笔记66:Struts2 学习之路--Struts的CRUD操作( 查看 / 删除/ 添加) 使用 paramsPrepareParamsStack 重构代码 ,PrepareInterceptor拦截器,paramsPrepareParamsStack 拦截器栈

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  5. Hbase深入学习(六) Java操作HBase

    Hbase深入学习(六) ―― Java操作HBase 本文讲述如何用hbase shell命令和hbase java api对hbase服务器进行操作. 先看以下读取一行记录hbase是如何进行工作 ...

  6. TweenMax动画库学习(六)

    目录            TweenMax动画库学习(一)            TweenMax动画库学习(二)            TweenMax动画库学习(三)            Tw ...

  7. Struts2学习笔记⑧

    今天是Struts2学习笔记的最后一篇文章了.用什么做结尾呢,这两天其实还学了很多东西,没有记录下,今天就查漏补缺一下. 文件上传与下载.FreeMarker以及昨天没做完的例子 文件上传与下载 文件 ...

  8. Struts2学习笔记①

    Struts2 学习笔记① 所有的程序学习都从Hello World开始,今天先跟着书做一个HW的示例. Struts2是一套MVC框架,使用起来非常方便,接触到现在觉得最麻烦的地方是配置文件.我的一 ...

  9. Struts2学习笔记NO.1------结合Hibernate完成查询商品类别简单案例(工具IDEA)

    Struts2学习笔记一结合Hibernate完成查询商品类别简单案例(工具IDEA) 1.jar包准备 Hibernate+Struts2 jar包 struts的jar比较多,可以从Struts官 ...

  10. Struts2学习:interceptor(拦截器)的使用

    对于需要登陆验证.权限验证等功能的网站,每一次请求,每一个action都写一段验证的代码,未免显得冗余且不易维护.struts2提供了拦截器interceptor,为这些页面提供一个切面,或者说公共组 ...

随机推荐

  1. python之 '随机'

    Q:想生成随机数,用哪个库? import random Q:想生成一个随机整数,范围在[0, 100]之内,怎么弄? >>> random.randint(0, 100) 7 Q: ...

  2. 【C语言】用指针描述数组,实现冒泡法排序

    #include <stdio.h> int main() { ], t; int i, j;printf("请输入10个数:\n"); ; i < ; i++) ...

  3. js 页面滚动到指定位置

    当页面的长度比较长时,如果进行刷新页面,我们希望能够在刷新完成页面之后,能够停留在当前位置,而不是从头再手动滚动到当前位置. 那么这样的效果如何实现呢?下面开始简单描写(由于博客园不支持效果展示,所以 ...

  4. Spring IoC 源码分析 (基于注解) 之 包扫描

    在上篇文章Spring IoC 源码分析 (基于注解) 一我们分析到,我们通过AnnotationConfigApplicationContext类传入一个包路径启动Spring之后,会首先初始化包扫 ...

  5. python文件打开模式&time&python第三方库

    r:以只读方式打开文件.文件的指针将会放在文件的开头.这是默认模式. w:打开一个文件只用于写入.如果该文件已存在则将其覆盖.如果该文件不存在,创建新文件. a:打开一个文件用于追加.如果该文件已存在 ...

  6. TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q

    TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q 一.TCP协议下的服务端并发 ''' 将不同的功能尽量拆分成不同的函数,拆分出来的功能可以被多个地方使用 TCP服务 ...

  7. 吴裕雄 python 机器学习——数据预处理流水线Pipeline模型

    from sklearn.svm import LinearSVC from sklearn.pipeline import Pipeline from sklearn import neighbor ...

  8. Jenkins+Maven+Github+Springboot实现可持续自动部署(非常详细)

    目前公司开发的项目已经部署到服务器上,部署项目的测试环境和生产环境,加上每个项目n个服务,于是我就 , 骚就是骚,但是就是太累了,于是花点时间研究了一下Jenkins. Jenkins的作用和它的lo ...

  9. Linux修改本机/etc/hosts的hostName后经常不生效

    1.Linux修改本机别名/etc/hosts的hostName后经常不生效解决 Linux修改本机别名/etc/hosts的hostName后经常不生效, 比如我们/etc/hosts的内容如下: ...

  10. SQL 层级数据查询出树形状态

    WITH TEST AS (SELECT  DEPTID,PARENTDEPT,SORTORDER,1 SPAC,CONVERT(CHAR(200),RTRIM(DEPTID)+CONVERT(CHA ...