Struts2之拦截器

article/2025/9/22 1:13:12

目录

    • 拦截器简介
    • 拦截器配置
    • 内建拦截器
    • 自定义拦截器
    • 使用拦截器实现权限控制
    • 拦截器工作原理

拦截器简介

拦截器(Interceptor)是Struts2的核心组成部分,它可以动态拦截Action调用的对象,类似于Servlet中的过滤器。 Struts2的拦截器是AOP(Aspect-Object-Programming,面向切面编程)的一种实现策略,是可插拔的。它可以任意地组合Action提供的附加功能,而不需要修改Action的代码,开发者只需要提供拦截器的实现类,并将其配置在struts.xml中即可。

每个拦截器可以完成单个功能。不同功能的拦截器按照一定的顺序排列在一起形成的链,就是拦截器链。拦截器链组成的集合就是拦截器栈。

拦截器配置

1.拦截器
要想拦截器起作用,首先要在struts.xml文件中进行配置

<interceptor  name="interceptorName"   class="interceptorClass"><param name="paramName">paramValue</param>
</interceptor>

name属性用来指定拦截器的名称,class属性用于指定拦截器的实现类。如果在定义拦截器时需要传入参数,这时需要使用<param>标签,其中name属性用来指定参数的名称,paramValue表示参数的值。

2.拦截栈
在实际开发中,经常需要在Action执行前同时执行多个拦截动作,如用户登录检查、登录日志记录以及权限检查等,这时,可以把多个拦截器组成一个拦截器栈。
在使用时,可以将栈内的多个拦截器当成个整体来引用。 当拦截器栈被附加到一个 Action上时,在执行Action之前必须先执行拦截器栈中的每一一 个拦截器。

<interceptors><interceptor-stack name="interceptorStackName"><interceptor-ref  name="interceptorName" />...</interceptor-stack>
</interceptors>

interceptorStackName值代表配置的拦截器栈的名称,interceptorName值代表拦截器的名称。

除此之外,一个拦截器栈也可以包含另外一个拦截器栈:

<struts><package name="xxx" extends="struts-default" ><!--声明拦截器--><interceptors><interceptor  name="interceptor1"   class="interceptorClass"/><interceptor  name="interceptor2"   class="interceptorClass"/><!--定义一个拦截器栈myStack,该拦截器栈中包含两个拦截器和一个拦截器栈--><interceptor-stack name="myStack"><interceptor-ref  name="defaultStack" /><interceptor-ref  name="interceptor1" /><interceptor-ref  name="interceptor2" /></interceptor-stack></interceptors>
</struts>

在定义的拦截栈myStack中,除了引用了两个自定义的拦截器interceptor1和interceptor2外,还引用了一个内置拦截器栈defaultStack,且该内置拦截器栈必不可少。

<struts><package name="xxx" extends="struts-default" ><interceptors><!--配置用户自定义的拦截器--><interceptor name="MyInterceptor" class="TestAction"/><!--自定义拦截器栈,我们配置了自定义的拦截器,默认的拦截器栈就不会被执行,因此,想要使用默认的拦截器功能,就要配置进来--><interceptor-stack name="mystack"><!--引用默认的拦截器栈,一定要放在第一行--><interceptor-ref name="defalutStack"/><!--引用自定义的拦截器--><interceptor-ref name="MyInterceptor"/></interceptor-stack></interceptors><!--上面配置了拦截器栈,但是没有被执行...下面配置执行拦截器--><default-interceptor-ref name="mystack"/><action name="TestAction" class="TestAction" method="execute"><result name="success">/index.jsp</result></action></package>
</struts>

内建拦截器

拦截器都继承AbstractInterceptor

Struts2 框架中内置了许多拦截器,这些拦截器以 name-class 对的形式配置在 struts-default.xml 文件中,其中,name 是拦截器的名称,也就是引用的名字;class 指定了该拦截器所对应的实现。

只要自定义的包继承了 Struts2 的 struts-default 包,就可以使用包中定义的内建拦截器,否则需要自行定义拦截器。

内建拦截器介绍:

名称说明
alias在不同请求之间将请求参数在不同名称间转换,请求内容不变
autowiring用于实现 Action 的自动装配
chain让前一个 Action 的属性可以被后一个 Action 访问,现在和 chain 类型的 result() 结合使用
conversionError将错误从 ActionContext 中添加到 Action 的属性字段中
cookies使用配置的 Name 和 Value 指定 Cookies
cookieProvider该类是一个 Cookie 工具,方便开发者向客户端写 Cookie
clearSession用于清除一个 HttpSession 实例
createSession自动创建 HttpSession,用于为需要使用
HttpSession的拦截器服务
debugging提供不同的调试用的页面展现内部的数据状况
execAndWait在后台执行 Action,同时将用户带到一个中间的等待页面
exception将异常定位到一个画面
fileUpload提供文件上传功能
il8n记录用户选择的 locale
logger输出 Action 的名称
model-driven如果一个类实现了 Model Driven,将 get Model 得到的结果放在 Value Slack 中
scoped-model-driven如果一个 Action 实现了
params将请求中的参数设置到 Action 中
actionMappingParams用于负责在 Action 配置中传递参数
prepare如果 Action 实现了 Preparable,则该拦截器调用 Action 类的 prepare 方法
staticParams将 struts.xml 文件中 标签的参数内容设置到对应的 Action 中
scope将 Action 状态存入 session 和 application 范围
servletConfig提供访问 HttpServletRequest 和 HttpServletResponse 方法,以 Map 方式访问
timer输岀 Action 执行的时间
token通过 Token 避免双击
tokenSession和 Token Interceptor 一样,不过双击时把请求的数据存储在 Session 中
validation使用 action-validation.xml 文件中定义的内容校验提交的数据
workflow调用 Action 的 validate 方法,一旦有错谋返回,则重新定位到 INPUT 画面
store存储或者访问实现 ValidalionAware 接口的 Action 类出现的消息、错误和字段错误等
checkbox添加了 checkbox 自动处理代码,将没有选中的 checkbox 的内容设定为 false,而 html 在默认情况下不提交没有选中的 checkbox
datetime日期拦截器
profiling通过参数激活 profile
roles确定用户是否具有 JAAS 指定的 Role,否则不予执行
annotationWorkflow利用注解代替 XML 配置
multiselect检测是否有像 标签一样被选中的多个值,然后添加一个空参数
deprecation当日志级别设置为调试模式(debug)并且没有特殊参数时,在 devMode

在 struts-core-2.3.24.jar 包中的根目录下找到 struts-default.xml 文件,打开后找到 元素下的内建拦截器和拦截器栈,其部分代码如下所示:

<package name="struts-default" abstract="true">...<interceptors><!--系统内建拦截器部分,上一部分介绍的内容--><interceptor name="alias"class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/><interceptor name="autowiring"class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/><interceptor name="chain"class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>...<!-- 定义Basic stack拦截器栈 --><interceptor-stack name="basicStack"><!--引用系统定义的exception拦截器--><interceptor-ref name="exception"/>...</interceptor-stack>...<!-- 定义Sample model -driven stack --><interceptor-stack name="modelDrivenStack"><!--引用系统定义的modelDriven拦截器--><interceptor-ref name="modelDriven"/><!--引用系统定义的basicStack拦截器栈--><interceptor-ref name="basicStack"/></interceptor-stack>...<!--定义defaultStack拦截器栈--><interceptor-stack name="defaultStack"><interceptor-ref name="exception"/><interceptor-ref name="alias"/><interceptor-ref name="il8n"/>...<interceptor-ref name="validation"><param name="excludeMethods">input,back,cancel,browse</param></interceptor-ref>...</interceptor-stack></interceptors><!--将defaulrStack拦截器栈配置为系统默认拦截器栈--><default-interceptor-ref name="defaultStack"/><!--默认action类是ActionSupport--><default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
</package>

在上述内建拦截器的配置代码中,defaultStack 拦截器组合了多个拦截器,这些拦截器可以满足大部分 Web 应用程序的需求。使用时,只要在 struts.xml 定义包的过程中继承 struts-default 包,那么 defaultStack 拦截器栈就是默认拦截器的引用。

自定义拦截器

在实际的项目开发中,Struts2的内置拦截器可以完成大部分的拦截任务,但是,一些与系统逻辑相关的通用功能(如权限的控制、用户登录控制等),则需要通过自定义拦截器来实现,自定义拦截器其实就是开发自己的拦截器类。

自定义的拦截器类,需要实现import com.opensymphony.xwork2.interceptor.Interceptor接口

public interface Interceptor extends Serializable {void destroy();void init();String intercept(ActionInvocation invocation) throws Exception;
}

该接口提供了以下三个方法:

  • void init():该方法在拦截器被创建后会立即被调用,它在拦截器的生命周期内只被调用一-次。可以在该方法中对相关资源进行必要的初始化。

  • void destroy():该方法与init()方法相对应,在拦截器实例被销毁之前,将调用该方法来释放与拦截器相关的资源。它在拦截器的生命周期内也只被调用一次。

  • 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() {System.out.println("我是拦截器的初始化方法");}public void destroy() {System.out.println("我是拦截器的销毁方法");}public abstract String intercept(ActionInvocation invocation) throws Exception{System.out.println("我是拦截器的拦截方法");//调用invoke()方法,代表着放行执行下一个拦截器,如果没有拦截器了,那么就执行Action的业务代码//可看成是过滤器的doFilter()方法actionInvocation.invoke();return null;
}

AbstractInterceptor类实现了Interceptor接口的所有方法,只需继承AbstractInterceptor类,实现interceptor()方法就可以创建自定义拦截器。

使用拦截器实现权限控制

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

  1. 自定义一个实现Interceptor接口(或者继承自AbstractInterceptor)的类。
  2. 在strutx.xml中注册上一步中定义的拦截器。
  3. 在需要使用的Action中引用上述定义的拦截器,为了方便也可将拦截器定义为默认的拦截器,这样在不加特殊声明的情况下所有的Action都被这个拦截器拦截。

源代码如下:

User.java

package cn.itcast.domain;
public class User {private String username; //用户名private String password; //密码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;}@Overridepublic String toString() {return "User [username=" + username + ", password=" + password + "]";}}

LoginAction.java

package cn.itcast.action;
import cn.itcast.domain.User;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class LoginAction extends ActionSupport implements ModelDriven<User> {private static final long serialVersionUID = 1L;private User user = new User();@Overridepublic User getModel() {return user;}@Overridepublic String execute() throws Exception {//获取ActionContextActionContext actionContext = ActionContext.getContext();System.out.println(user);if ("tom".equals(user.getUsername())&& "123".equals(user.getPassword())) {// 将用户存储在session中actionContext.getSession().put("user", user);return SUCCESS;} else {actionContext.put("msg", "用户名或密码不正确");return INPUT;}}
}

BookAction.java

package cn.itcast.action;
import com.opensymphony.xwork2.ActionSupport;
@SuppressWarnings("serial")
public class BookAction extends ActionSupport {public String add() {System.out.println("book add");return SUCCESS;}public String del() {System.out.println("book del");return SUCCESS;}public String update() {System.out.println("book update");return SUCCESS;}public String find() {System.out.println("book find");return SUCCESS;}
}

PrivilegeInterceptor.java

package cn.itcast.interceptor;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class PrivilegeInterceptor extends AbstractInterceptor {private static final long serialVersionUID = 1L;@Overridepublic String intercept(ActionInvocation invocation) throws Exception {ActionContext actionContext = invocation.getInvocationContext();// 得到ActionContext.Object user = actionContext.getSession().get("user");//获取user对象if (user != null) {return invocation.invoke(); // 继续向下执行} else {actionContext.put("msg", "您还未登录,请先登录");return Action.LOGIN; //如果用户不存在,返回login值}}
}

login.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>登录</title>
</head>
<body>
<center>
${requestScope.msg}<br><form action="login" method="post"><table><tr><td><label style="text-align: right;">用户名:</label></td><td><input type="text" name="username"></td></tr><tr><td><label style="text-align: right;">密码:</label></td><td><input type="password" name="password"></td></tr><tr><td align="right" colspan="2"><input type="submit" value="登录"></td></tr></table></form>
</center>
</body>
</html>

main.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>  <title>main.jsp</title></head><body><a href="/chapter03/book_del">book del</a><br><a href="/chapter03/book_add">book add</a><br><a href="/chapter03/book_update">book update</a><br><a href="/chapter03/book_find">book find</a><br></body>
</html>

success.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>成功页面</title>
</head>
<body>用户${user.username}操作成功
</body>
</html>

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><package name="struts2" namespace="/" extends="struts-default"><!-- 声明拦截器 --><interceptors><interceptor name="privilege" class="cn.itcast.interceptor.PrivilegeInterceptor"/><interceptor-stack name="myStack"><interceptor-ref name="defaultStack" /><interceptor-ref name="privilege"></interceptor-ref></interceptor-stack></interceptors><!-- 用户登录操作 --><action name="login" class="cn.itcast.action.LoginAction"><result>/main.jsp</result><result name="input">/login.jsp</result></action><!-- 关于book操作 --><action name="book_*" class="cn.itcast.action.BookAction"method="{1}"><result>/success.jsp</result><result name="login">/login.jsp</result><interceptor-ref name="myStack" /></action></package>
</struts>

发布项目,访问main.jsp
在这里插入图片描述
点击连接,由于没有登陆,所以没有权限,页面跳转到登录页面要求用户登录。
在这里插入图片描述
登陆成功后点击链接,跳转成功页面,提示用户操作成功。
在这里插入图片描述

对比可知拦截器成功执行

以上案例中,创建了一个方法过滤器PrivilegeInterceptor,在struts.xml中配置了该拦截器,如果用户没有登陆,将无法对页面链接进行相应操作,只有登陆后的用户才有权限操作页面相应功能。

拦截器工作原理

拦截器的执行顺序
invocation.invoke()方法是拦截器框架的实现核心,通过确定invocation.invoke()方法执行位置,来实现Action执行前后处理操作,在invocation.invoke()方法之前的代码将依据配置中拦截器顺序依次执行,直到走完拦截器后再执行invocation.invoke()方法调用Action,然后再依据配置中拦截器顺序反向执行invocation.invoke()方法后的代码,直到走完拦截器

拦截器的工作原理
如图所示
在这里插入图片描述
每一个Action请求都包装在一系列的拦截器的内部。拦截器可以在Action执行直线做相似的操作也可以在Action执行直后做回收操作。

每一个Action既可以将操作转交给下面的拦截器,Action也可以直接退出操作返回客户既定的画面。

https://www.cnblogs.com/yw-ah/p/5761235.html
https://www.cnblogs.com/wkrbky/p/5894315.html
https://blog.csdn.net/weixin_42529699/article/details/81354355
https://www.imooc.com/learn/450


http://chatgpt.dhexx.cn/article/R5uNM8XS.shtml

相关文章

struts2中拦截器

拦截器&#xff08;interceptor&#xff09;概念 拦截器是动态拦截action调用的对象&#xff0c;类似于servlet中的过滤器。在执行action中的业务逻辑处理方法之前&#xff0c;struts会首先执行struts.xml中引用的拦截器。烂拦截器是struts2中的中一个重要的特性&#xff0c;st…

struts2拦截器详解

一、拦截器概念 拦截器(Interceptor)是Struts2的一个重要特性&#xff0c;它可以在Action 执行前和执行后拦截调用。Struts2的拦截器和Servlet过滤器类似。在执行Action的execute方法之前&#xff0c;Struts2会首先执行在struts.xml中引用的拦截器&#xff0c;在执行完所有引用…

android教程 易百教程,Android RadioGroup

RadioGroup中使用类组单选按钮。如果我们选中一个单选按钮属于一个单选按钮组&#xff0c;它会自动取消选中同一组内的任何先前检查的单选按钮。 RadioGroup 属性 以下是RadioGroup中控件有关的重要属性。可以检查Android官方文档的属性和相关方法的完整列表&#xff0c;可以用…

android radiogroup 添加,如何在android中动态添加textview到radiogroup

大家好&#xff0c; 我们想动态地在radiogroup旁边添加textview。基于服务响应&#xff0c;我们需要在不使用xml的情况下将标签添加到radiogroup。 在某些情况下基于最长无线电如何在android中动态添加textview到radiogroup [ ] 这里下面的代码 final RadioGroup rg new Radi…

Android实现RadioGroup之间的互斥

Android实现RadioGroup之间的互斥 关于效果图实现准备工作&#xff0c;附上布局代码解决需求&#xff0c;附上类代码 关于 因为一个页面需求&#xff0c;需要有两个radio group共六个radio button来实现单选互斥&#xff08;为什么不用一个radio group来包裹是因为需要两行展示…

网格RadioGroup实现

RadioGroup只能横向和垂直展示RadioButton&#xff0c;然后设计师们就经常要求我们网格展示。比如要实现如下的效果&#xff1a; 那要怎么做呢&#xff0c;采用继承RadioGroup&#xff0c;重新绘制里面的内容&#xff0c;上代码&#xff1a; 定义所需属性 attrs&#xff1a;…

RadioGroup 使用

xml //布局 <RadioGroupandroid:id"id/rb"android:layout_width"match_parent"android:layout_height"44dp"android:orientation"horizontal"><RadioButtonandroid:id"id/rb_start"android:layout_width"0dp…

radiogroup多选_3.Android之单选按钮RadioGroup和复选框Checkbox学习

单选按钮和复选框在实际中经常看到&#xff0c;今天就简单梳理下。 首先&#xff0c;我们在工具中拖进单选按钮RadioGroup和复选框Checkbox&#xff0c;如图&#xff1a; xml对应的源码&#xff1a; android:layout_width"match_parent" android:layout_height"…

java radiogroup_android 菜单导航 (Fragment + RadioGroup)

网上有很多讲利用Fragment RadioGroup&#xff0c;actionbar viewPager和TabHost做菜单导航和切换的例子。对于第三种现在已经过时了。所以讲讲自己对第一个的理解和经验分享&#xff0c;不过在此也简单说说第二种。 1、actionbar viewpager 对于这种方式&#xff0c;其实在…

java radiogroup_Android基础控件RadioGroup使用方法详解

本文为大家分享了Android基础控件RadioGroup的使用&#xff0c;供大家参考&#xff0c;具体内容如下 1.简单介绍 RadioGroup可以提供几个选项供用户选择&#xff0c;但只能选择其中的一个。其下面可以横着或者竖着挂几个RadioButton&#xff0c;也可以挂载其他控件(如TextView)…

android自定义radiogroup,Android自定义RadioGroup

最近做项目时需要用到RadioGroup&#xff0c;发现Android原生的RadioGroup太丑了&#xff0c;所以自己写了一个&#xff0c;效果如下所示&#xff1a; 其实就是由4个Button组成的LinearLayout&#xff0c;只是为了方便点击效果的切换所以封装了一下。代码如下&#xff1a; pack…

RadioGroup

实现RadioButton由两部分组成,也就是RadioButton和RadioGroup配合使用.RadioGroup是单选组合框&#xff0c;可以容纳多个RadioButton的容器.在没有RadioGroup的情况下&#xff0c;RadioButton可以全部都选中&#xff1b;当多个RadioButton被RadioGroup包含的情况下&#xff0c;…

Android入门之路 - RadioGroup、RadioButton、CheckBox(单复选框)使用进阶

本文只为初级的Android新手而写&#xff0c;多掌握一份简单实用的技能&#xff0c;快速get吧&#xff0c;有问题就留言 2022&#xff1a;蓦然回首&#xff0c;已入行多年&#xff0c;人生的第二个迷茫阶段 初级 - 使用方式RadioGroup RadioButtonCheckBoxDemo示例 CheckBox 自…

Android RadioGroup 单选按钮控件

Android RadioGroup 单选按钮控件 RadioGroup 为单项选择按钮组&#xff0c;其中可以包含多个 RadioButton&#xff0c;即单选按钮&#xff0c;它们共同为用户提供一种多选一的选择方式。在多个 RadioButton 被同一个 RadioGroup 包含的情况下&#xff0c;多个 RadioButton 之间…

RadioGroup控件使用

在只能进行单选的选择上面可以通过&#xff32;adioGroup控件来实现&#xff0c;例如性别选择以及考试的单项选择题。 xml布局如下&#xff1a; <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xm…

RedHat9.0下载地址

RedHat下载&#xff1a;http://archive.download.redhat.com/pub/redhat/linux/9/en/iso/i386/ 转载于:https://www.cnblogs.com/XACOOL/p/5679613.html

下载redhat4.8的方法

一、背景 因为老软件需要安装&#xff0c;所以找个了老系统来安装。 二、上官网 https://www.redhat.com/zh/ 点开redhat最新版本&#xff0c;现在是8.0 下载 要求我登录账户&#xff0c;我就登录jhui163的 然后&#xff0c;看到7.0和更早期的超链接&#xff0c;点进去

vmware安装redhat 8

vmware安装redhat 8 1、下载镜像文件1.1 镜像文件 2、安装系统2.1、选择自定义安装2.2、兼容性选择2.3、选择镜像文件导入2.4、设置用户名密码2.5、选择虚拟机在磁盘上的位置2.6、选择处理器数量2.7、选择内存大小2.8、选择桥接或NAT2.9、选择SCSI控制器类型2.10、选择虚拟机磁…

RedHat 7.5 7.6下载磁力链分享

某度最近更新了一波&#xff0c;导致诸多屏蔽弹客户端应用直接显示直链下载的浏览器插件也失效&#xff0c;就连最强的下载神器也400、403报错 csdn的下载站里是有不少资源&#xff0c;但是苦于都要积分&#xff0c;出于服务大众、便利人民的心。 我终于找到了对应的下载磁力…

RedHat使用yum下载安装软件包

RedHat使用yum下载安装软件包 Red Hat Enterprise Linux Server&#xff08;RHEL&#xff09;的yum服务是收费的&#xff0c;如果没有付费&#xff0c;则无法使用yum安装软件包。通过删除RedHat自带的yum&#xff0c;安装CentOS版本的yum&#xff0c;并使用CentOS的yum源和epel…