Struts2 * Interceptor的原理与配置实例详解
作者:kingmax54212008 发布时间:2022-06-23 17:34:45
一、Struts2 * 原理:
Struts2 * 的实现原理相对简单,当请求struts2的action时,Struts 2会查找配置文件,并根据其配置实例化相对的 * 对象,然后串成一个列表,最后一个一个地调用列表中的 * 。
比如:应用要求用户登陆,且必须为指定用户名才可以查看系统中某个视图资源;否则,系统直接转入登陆页面。对于上面的需求,可以在每个Action的执行实际处理逻辑之前,先执行权限检查逻辑,但这种做法不利于代码复用。因为大部分Action里的权限检查代码都大同小异,故将这些权限检查的逻辑放在 * 中进行将会更加优雅。
PS:
1. Struts2 * 是在访问某个Action或Action的某个方法,字段之前或之后实施拦截,并且Struts2 * 是可插拔的, * 是AOP的一种实现.
2. * 栈(Interceptor Stack)。Struts2 * 栈就是将 * 按一定的顺序联结成一条链。在访问被拦截的方法或字段时,Struts2 * 链中的 * 就会按其之前定义的顺序被调用。
二、Struts2 * 接口实现:
Struts2规定用户自定义 * 必须实现com.opensymphony.xwork2.interceptor.Interceptor
接口。该接口声明了3个方法,其中,init和destroy方法会在程序开始和结束时各执行一遍,不管使用了该 * 与否,只要在struts.xml中声明了该Struts2 * 就会被执行。intercept方法就是拦截的主体了,每次 * 生效时都会执行其中的逻辑。
void init();
void destroy();
String intercept(ActionInvocation invocation) throws Exception;
1:所有 * 都使用接口Interceptor ,Action去实现这个接口;
Init()
方法:在服务器起动的时候加载一次,并且只加载一次;Destroy()
方法:当 * 销毁时执行的方法;Interceptor()
方法:其中里边有一个参数invocation;
public String intercept(ActionInvocation invocation) throws xception {
System.out.println("interceptor!!");
String result=invocation.invoke();
return result;
}
其中intercept方法是 * 的核心方法,所有安装的 * 都会调用之个方法。在Struts2中已经在struts-default.xml中预定义了一些自带的 * ,如timer、params等。如果在<package>标签中继承struts-default,则当前package就会自动拥有struts-default.xml中的所有配置。
Invocation.invoke()
是如果只有一个 * 执行完这个方法后,会返回给视图,如果有多个 * ,它顺序的执行完所有的 * ,才返回给视图,也就是调用后面的action继续执行。
二、Struts2 * 详细配置:
默认 * 是在不设置任何 * 的时候,给予默认设置的,当只要设置任何一个 * 就会覆盖掉默认 * , 故此,我们需要手动设置
一旦实现了检查 * ,就可以在所有需要实现权限控制的Action中复用上面的 * 。
为了使用该 * ,首先在struts.xml文件中定义 * ,定义 * 的配置片段如下:
<!-- 用户 * 定义在该元素下 -->
<interceptors>
<!-- 定义了一个名为authority的 * -->
<interceptor name="authority" class="lee.AuthorityInterceptor"/>
</interceptors>
定义了该 * 之后,可以在Action中应用该 * ,应用该 * 的配置片段如下:
<!-- 定义一个名为viewBook的Action,其实现类为ActionSupport -->
<action name="viewBook">
<!-- 返回success视图名时,转入/WEB-INF/jsp/viewBook.jsp页面 -->
<result>/WEB-INF/jsp/viewBook.jsp</result>
<!-- * 一般配置在result元素之后! -->
<interceptor-ref name="defaultStack"/>
<!-- 应用自定义 * -->
<interceptor-ref name="authority"/>
</action>
上面名为viewBook的Action,没有指定class属性,默认使用ActionSupport类,配置该Action时,只是指定了一个Result,指定返回success字符串时,系统将转入/WEBINF/jsp/viewBook.jsp页面。但并为未配置login视图对应的JSP页面。
考虑到这个 * 的重复使用,可能在多个Action都需要跳转到login逻辑试图,故将login Result定义成一个全局Result。
下面是配置login Result的配置片段:
<!-- 定义全局Result -->
<global-results>
<!-- 当返回login视图名时,转入/login.jsp页面 -->
<result name="login">/login.jsp</result>
</global-results>
经过上面的配置,如果浏览者在浏览器中直接发送viewBook请求,将会转入如图所示的页面。
这种通过 * 进行权限控制的方式,显然具有更好的代码复用。
如果为了简化struts.xml文件的配置,避免在每个Action中重复配置该 * ,可以将该 * 配置成一个默认 * 栈(这个默认 * 栈应该包括default-stack * 栈和权限检查 * )。
定义自己的默认 * 栈的配置片段如下:
<interceptors>
<!-- 定义权限检查 * -->
<interceptor name="authority" class="lee.AuthorityInterceptor"/>
<!-- 定义一个包含权限检查的 * 栈 -->
<interceptor-stack name="mydefault">
<!-- 定义 * 栈包含default-stack * 栈 -->
<interceptor-ref name="default-stack"/>
<!-- 定义 * 栈包含authority * -->
<interceptor-ref name=" authority"/>
</interceptor- stack >
</interceptors>
一旦定义了上面的mydefault * 栈,这个 * 栈包含了权限检查 * 和系统默认的 * 栈。如果将这个 * 栈定义成默认 * ,则可以避免在每个Action需要重复定义权限检查 * 。
下面是定义默认 * 的配置片段:
<default-interceptor-ref name="mydefault"/>
一旦在某个包下定义了上面的默认 * 栈,在该包下的所有Action都会自动增加权限检查功能。对于那些不需要使用权限控制的Action,将它们定义在另外的包中——这个包中依然使用系统原来的默认 * 栈,将不会有权限控制功能。
PS: * , * 栈和默认的 * 之间的关系
1: * 和 * 栈是一个级别的,也就是说一个 * 栈中包括许多 * , 一个 * 栈中还可以包括许多 * 栈,配置如下方式:
<interceptors>
<!-- 先定义 * -->
<interceptor name="myInterceptor" class="com.struts2.interceptor.MyInterceptor">
<!-- 指定系统初始化给 * 的参数 -->
<param name="hello">张--</param>
</interceptor>
<!-- 加到自己设置的 * 栈里边去 -->
<interceptor-stack name="myStack">
<interceptor-ref name="myInterceptor">
</interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
* 的使用:
1.先定义;
2.在引用使用;
<interceptor name="myInterceptor" class="com.struts2.interceptor.MyInterceptor">
<interceptor-ref name="myInterceptor">
</interceptor-ref>
2:struts2中有一个系统默认的 * 栈是 defaultStack,如果你手动引用自己的 * ,系统默认的 * 栈将不起作用;这样必需手动引入系统的 * 栈
<interceptor-ref name="defaultStack">
</interceptor-ref>
如果想改变系统默认的 * 栈,可以这样配置:
<default-interceptor-ref name="myStack">
</default-interceptor-ref>
其中myStack是自己定义的 * 栈名字;
如果 * 栈中有多个 * ,在执行action之前的顺序跟配置 * 的顺序一致,而在action之后执行的顺序是相反的;
PS:最后还附加一点过滤器的东西
过滤器,是在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的 action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者 struts的action前统一设置字符集,或者去除掉一些非法字符
* ,是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如 * 就是 * 的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。
* 与过滤器的区别 :
1、 * 是基于java的反射机制的,而过滤器是基于函数回调。
2、 * 不依赖与servlet容器,过滤器依赖与servlet容器。
3、 * 只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
4、 * 可以访问action上下文、值栈里的对象,而过滤器不能访问。
5、在action的生命周期中, * 可以多次被调用,而过滤器只能在容器初始化时被调用一次
6、执行顺序 :过滤前 - 拦截前 - Action处理 - 拦截后 - 过滤后。
过滤是一个横向的过程,首先把客户端提交的内容进行过滤(例如未登录用户不能访问内部页面的处理);过滤通过后, * 将检查用户提交数据的验证,做一些前期的数据处理,接着把处理后的数据发给对应的Action;Action处理完成返回后, * 还可以做其他过程(还没想到要做啥),再向上返回到过滤器的后续操作。
一个Filter 可负责拦截多个请求或响应:一个请求或响应也可被多个请求拦截。
创建一个Filter 只需两个步骤:
(1)创建Filter 处理类:
(2)在web.xml 文件中配置Filter 。
创建Filter 必须实现javax.servlet.Filter
接口,在该接口中定义了三个方法。
• void init(FilterConfig config)
: 用于完成Filter 的初始化。
• void destroy()
: 用于Filter 销毁前,完成某些资源的回收。
• void doFilter(ServletRequest request, ServletResponse response,FilterChain chain)
: 实现过滤功能,该方法就是对每个请求及响应增加的额外处理。
过滤器Filter也具有生命周期:init()->doFilter()->destroy(),由部署文件中的filter元素驱动。在servlet2.4中,过滤器同样可以用于请求分派器,但须在web.xml中声明,<dispatcher>INCLUDE或FORWARD或REQUEST或ERROR</dispatcher>该元素位于filter-mapping中。
实例教程
下面写一个自定义 * 的例子,判断用户是否登录,就是检查当前用户的session中的user属性是否为空,如果为空,就跳到登录页面,否则,继续执行.
1.编写 * ,在interceptor包下常见一个java类,名为LoginInterceptor,继承AbstractInterceptor:
public class LoginInterceptor extends AbstractInterceptor{
@Override
public String intercept(ActionInvocation invocation) throws Exception {
//得到拦截到的action的名称,看是否是login,当是login的时候,不用进行下面的检测了,直接执行下一个 *
String actionName=invocation.getProxy().getActionName();
if("login".equals(actionName)){
return invocation.invoke();
}
//如果不是login.则判断是否已登录,及检测session中key为user的值是否存在,如果不存在,跳回到登录页面
String user=(String)invocation.getInvocationContext().getSession().get("user");
if(user==null){
System.out.println("未登录");
return "login";
}
//进行到这里.说明用户已登录,则跳转到下一个 *
return invocation.invoke();
}
}
2,在struts.xml中配置interceptor,主要特别注意的是,当使用了自定义的 * 后,默认 * 将不起作用,默认 * 实在struts-default.xml中配置的,当引用了自定义 * ,又想使用struts2提供的默认 * 功能,需要手动配置:这里我将默认 * 和我写的进行登录权限验证的 * ,写到一个 * 栈里,然后调用这个默认 * 栈:
<package name="default" namespace="/" extends="struts-default">
<interceptors>
<!-- 配置自定义的 * -->
<interceptor name="checkLogin" class="com.wang.interceptor.LoginInterceptor"/>
<!--配置一个 * 栈,里面包含自己定义的 * 和defaultStack默认 * -->
<interceptor-stack name="myStack">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="checkLogin"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!--引用默认的 * (栈)-->
<default-interceptor-ref name="myStack"></default-interceptor-ref>
<!--配置一个全局结果集-->
<global-results>
<result name="login">/login.jsp</result>
</global-results>
<action name="login" class="com.wang.action.LoginAction" >
<result>/succ.jsp</result>
<result name="error">/login.jsp</result>
</action>
</package>
这里我使用了默认 * 标签,即相当于在每个action标签下,使用了 <interceptor-ref name="myStack"></interceptor-ref>.jsp页面和LoginAction类这里就省略了.
再来介绍一下方法 * ,方法 * 比action * 控制的更加精细,大体实现方式和action * 相同,不同的是它继承的是MethodFilterInterceptor类,重写的是doInterceptor()
方法,在struts.xml的配置上也有些不同,大体是这样:
<interceptor-ref name="methodInterceptor">
<!--配置被拦截的方法-->
<param name="includeMethods">methodA,methodsB</param>
<!--配置不被拦截的方法-->
<param name="excludeMethods">methodsC,methodsD</param>
</interceptor-ref>
来源:http://blog.csdn.net/kingmax54212008/article/details/51777851


猜你喜欢
- 本文实例为大家分享了Android Studio实现简单计算器功能的具体代码,供大家参考,具体内容如下程序步骤:(1)在布局文件定义一些计算
- 写下来自己以后看:先是item的布局文件:里边放了一个图片和一个文本框<?xml version="1.0" en
- Java List 用法实例详解Java中可变数组的原理就是不断的创建新的数组,将原数组加到新的数组中,下文对Java List用法做了详解
- 前言我身边有一部分开发的小伙伴,存在着这样一种习惯。某一天,突然看到某一款 App 上有个很漂亮的自定义控件(动画)效果,就会绞尽脑子想办法
- 前言经过前面《Unity3D入门教程》系列讲解,再加上我们自己的探索,相信大家已经掌握了Unity3D的相关知识和基本方法。本文将使用前面学
- 如何建立哈夫曼树的,网上搜索一堆,这里就不写了,直接给代码。1.哈夫曼树结点类:HuffmanNode.h#ifndef HuffmanNo
- 这是一个演示如何使用java执行定时任务的实例,本实例开始运行后不会自动结束,请在运行本实例后手动结束程序。package com.hong
- 一、前言随着 JDK 1.8 Streams API 的发布,使得 HashMap 拥有了更多的遍历的方式,但应该选择那种遍历方式?反而成了
- 1.实现方式说明本文在---- 手写redis @ Cacheable注解支持过期时间设置 的基础之上进行扩展。1.1问题说明
- Select Count(*)的返回值类型<select id="queryAlarmStatisticalAnalysis
- 下面本文将针对以上几点问题进行描述讨论,我们就以“中文”两个字为例来说明,查找相关资料可知“中文”的GB2312编码是“d6d0 cec4”
- Spring Bean的生命周期?首先说一下Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy;Sp
- 一、申请你的AppIDhttp://open.weixin.qq.com/ 友情提示:推荐使用eclipse打包软件最后一步的M
- 本文主要讨论C#开发使用百度语音合成API在线将文本内容合成语音,保存为 MP3 文件,本文最后会提供本安全源代码以及运行软件包,
- 对于之前最火的无外乎集五福了,而五福除了加十个好友获得外,最直接的途径就是支付宝的咻一咻了。那么咻一咻具体有哪些实现方式呢?下面我们将一一介
- Spring Security和Shiro的区别相同点1、认证功能2、授权功能3、加密功能4、会话管理5、缓存支持6、rememberMe功
- 本文实例为大家分享了C#使用Socket实现本地多人聊天室的具体代码,供大家参考,具体内容如下【脚本一:Server端】使用本机地址:127
- 对于Android平台上的线程优先级设置来说可以处理很多并发线程的阻塞问题,比如很多无关紧要的线程会占用大量的CPU时间,虽然通过了Mult
- 业务场景:调用同步接口获取当前全部有效账户,数据库已存在部分账户信息,因此需要筛选同步接口中已存在本地的帐户。调用接口获取的数据集合List
- 本文实例为大家分享了flutter实现倒计时加载页面的具体代码,供大家参考,具体内容如下效果图实现步骤1、pubspec.yaml中添加依赖