struts2中拦截器的简介与配置使用
拦截器是struts2框架的核心,struts2很多的功能都是构建在拦截器基础之上的,它是动态拦截Action调用的对象,提供了一种机制,使得开发者能够在一个Action前后执行需要的代码,可以在一个Action执行前组织他的执行,也能在Action执行后做一些相应的工作。同时他也提供了一种可以提取Action中可重用部分的方式。
拦截器
struts2拦截器是在访问某个Action或它的某个方法 、字段之前或之后实施拦截,struts2拦截器是可插拔的,是AOP的一种实现(AOP是OOP(Object-Oriented Programming,面向对象程序设计)的一种完善和补充,是软件技术和设计思想发展到一定阶段的自然产物)
一般情况下,拦截器都是通过代理的方式进行调用,当请求到达Struts2的ServletDispatcher(Web HTTP请求的调度器,所有对Action的请求都将通过ServletDispatcher调用)时,struts2会查找配置文件,并且根据配置文件的配置实例化相对的拦截器对象,并形成一个列表。每个Action请求都包装在一系列的拦截器内部。拦截器可以在Action执行之前做准备操作。也可以在之后进行操作,每个Action即可以将操作转交给下面的拦截器,也可以直接退出操作。拦截器的执行过程是一个递归的过程
拦截器栈
从结构上看,拦截器栈相当于多个拦截器的组合
在功能上看,拦截器栈也是拦截器
在功能上看,拦截器栈也是拦截器
自定义拦截器
1 实现Interceptor接口
void init():初始化拦截器所需资源
void destroy():释放在init()中分配的资源
String intercept(ActionInvocation ai)throws Exception
实现拦截器功能
利用ActionInvocation参数获取Action动态
返回result字符串作为逻辑视图
2 继承BSTRACTiNTERCEPTOR类
提供了init()和的destroy()方法的空实现
只需要实现intercept方法即可
void init():初始化拦截器所需资源
void destroy():释放在init()中分配的资源
String intercept(ActionInvocation ai)throws Exception
实现拦截器功能
利用ActionInvocation参数获取Action动态
返回result字符串作为逻辑视图
2 继承BSTRACTiNTERCEPTOR类
提供了init()和的destroy()方法的空实现
只需要实现intercept方法即可
实例:计算Action执行时间
Action:
public String execute() throws Exception {
for(int i = 0; i < 10000; i++){
System.out.println("Hello World!");
}
return SUCCESS;
}
拦截器:
@Override
public String intercept(ActionInvocation invocation) throws Exception {
//执行Action之前
long start = System.currentTimeMillis();
//执行下一个拦截器,如果已经是最后一个拦截器,则执行目标Action
String result = invocation.invoke();
//执行Action之后
long end = System.currentTimeMillis();
System.out.println("执行Action花费的时间:" + (end - start) + "ms");
return result;
}
struts.xml配置:
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="false"/>
<constant name="struts.devMode" value="true"/>
<package name="default" namespace="/" extends="struts-default">
<!-- 注册拦截器 -->
<interceptors>
<interceptor name="mytimer" class="com.hpu.interceptor.TimerInterceptor"/>
</interceptors>
<action name="timer" class="com.hpu.action.TimerAction">
<result>/success.jsp</result>
<!--为Action显示引用拦截器后,默认的拦截器defaultStack不再生效,需要手工引用 -->
<interceptor-ref name="defaultStack"/>
<!--引用拦截器 -->
<interceptor-ref name="mytimer"/>
</action>
</package>
</struts>
前端页面比较简单,这里不再添加。
内建拦截器
params拦截器
负责将请求参数设置为Action属性
staticParams拦截器
将配置文件中action元素的子元素param参数设置为Action属性
servletConfig拦截器
将源于Servlet API的各种对象注入到Action,必须实现对应接口
fileUpload拦截器
对文件上传提供支持,将文件和元数据设置到对应的Action属性
exception拦截器
捕获异常,并且将异常映射到用户自定义的错误页面
validation拦截器
调用验证框架进行数据验证
负责将请求参数设置为Action属性
staticParams拦截器
将配置文件中action元素的子元素param参数设置为Action属性
servletConfig拦截器
将源于Servlet API的各种对象注入到Action,必须实现对应接口
fileUpload拦截器
对文件上传提供支持,将文件和元数据设置到对应的Action属性
exception拦截器
捕获异常,并且将异常映射到用户自定义的错误页面
validation拦截器
调用验证框架进行数据验证
默认拦截器栈
在Struts-default.xml中定义一个defaultStack拦截器栈,并将其指定为默认拦截器
只要在定义包的过程中继承Struts-default包,那么defaultStack将是默认的拦截器
当为包中的某个action显示指定了某个拦截器,则默认拦截器不会起作用。
拦截器栈中的各个拦截器的顺序很重要。
只要在定义包的过程中继承Struts-default包,那么defaultStack将是默认的拦截器
当为包中的某个action显示指定了某个拦截器,则默认拦截器不会起作用。
拦截器栈中的各个拦截器的顺序很重要。
拦截器的配置
在Web应用中引入拦截器机制之后,就能够实现对Action通用操作的可插拔管理方式,这样的可插拔管理是基于struts.xml文件的配置来实现的。
定义拦截器的语法格式如下:
<interceptor name="拦截器名字" class="拦截器对应的java类型"/>
拦截器栈的配置
<interceptors>
<interceptor-stack name="拦截器栈的名字">
<interceptor-ref name="拦截器的名字"/>
</interceptor>
</interceptors>
拦截器的实例:
能够实现文字过滤的拦截器
Action:
public class ContentAction extends ActionSupport{
private String name;//评论人
private String content;//评论内容
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String execute() throws Exception {
return SUCCESS;
}
}
拦截器类:
public class ContentInterceptor extends AbstractInterceptor{
@Override
public String intercept(ActionInvocation arg0) throws Exception {
Object obj = arg0.getAction();//获取Action的实例
if(obj != null){
if(obj instanceof ContentAction){
ContentAction ca = (ContentAction)obj;//实例化ContentAction类
String content = ca.getContent();//获得用户提交的评论信息
int startIndex = content.indexOf('人');//检测字符人出现的位置
//截取从人开始往后的三个字符串
String str = content.substring(startIndex,startIndex + 3);
//如果用户发表的评论中包含有要过滤的文字
if(str.equals("人品差")){
content = content.replaceAll("人品差", "*");//以*替换要过滤的文字
ca.setContent(content);//将替换后的内容赋值给content属性
}
return arg0.invoke();
}else{
return Action.LOGIN;
}
}
return Action.LOGIN;
}
}
重要的一步,在struts.xml中的配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.i18n.encoding" value="UTF-8"/>
<package name="default" extends="struts-default" namespace="/">
<interceptors>
<interceptor name="contentItp" class="com.mxl.interceptor.ContentInterceptor"/>
</interceptors>
<action name="content" class="com.mxl.actions.ContentAction">
<result>/content_success.jsp</result>
<result name="login">/content_send.jsp</result>
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="contentItp"/>
</action>
</package>
</struts>
两个简单的页面:
content_send.xml:
<s:form action="content.action" method="post">
<s:textfield name="name" label="评论人" size="81"/>
<s:textfield name="content" label="评论正文" cols="180" rows="120"/>
<s:checkbox name="arr" label="我已阅读并同意当当网社区条款"/>
<s:submit type="button" align="center"/>
</s:form>
content_success.jsp:
<table cellpadding="0" cellspacing="0" border="0" align="left">
<tr style="line-height:30px;">
<td style="font-size:14px;font-weight:bold;" align="left">
对Spring入门经典的评论
</td></tr>
<tr>
<td style="font-size:12px;">
评论人:<s:property value="name"/>
</td>
</tr>
<tr>
<td style="font-size:12px">
评论正文:<s:property value="content"/>
</td>
</tr>
</table>
不要忘了在开头的地方加上,<%@ taglib prefix="s" uri="/struts-tags" %>,
拦截器的方法过滤实例:
拦截器类:
public class LoginInterceptor extends MethodFilterInterceptor{
@Override
protected String doIntercept(ActionInvocation arg0) throws Exception {
Map session=arg0.getInvocationContext().getSession();//获取Session对象
String uname = (String)session.get("username");//获取session中的username对象,并赋值给uname变量
System.out.println(uname + "XXXXXXXXXXXXX");
if(uname != null && !uname.equals("")){//检测uname变量的值,如果不为NULL或不为"",则进行后续操作
return arg0.invoke();
}else{//否则,重新登陆
session.put("errorMsg", "您还未登录,请登录!");
return Action.LOGIN;
}
}
}
Action类:
public class UserAction extends ActionSupport{
private String username;
private String pwd;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String execute() throws Exception {
return SUCCESS;
}
public String login(){
if("admin".equals(username.trim())){
ActionContext ac = ActionContext.getContext();
ac.getSession().put("username", username);
return SUCCESS;
}else{
this.addFieldError("username", "用户名/密码错误");
return LOGIN;
}
}
}
struts.xml中的配置:
<interceptors>
<interceptor name="myitp" class="com.mxl.interceptor.LoginInterceptor"/>
</interceptors>
<action name="timer" class="com.mxl.actions.TimerAction">
<result>/index.jsp</result>
<interceptor-ref name="timer"/>
</action>
<action name="login" class="com.mxl.actions.UserAction">
<result>/success.jsp</result>
<result name="login">/login.jsp</result>
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="myitp">
<param name="excludeMethods">login</param>
</interceptor-ref>
</action>
两个页面:
login.jsp:
<font color="red" style="font-size:12px"><s:property value="#session.errorMsg"/></font>
<s:form action="login!login.action" method="post">
<s:textfield name="username" label="用户名" size="20"/>
<s:password name="pwd" label="密码" size="20"/>
<s:submit type="button" value="登录"/>
</s:form>
success.jsp:
<s:if test="#session.username==null">
<font color="red">您还未登录,不能对本站进行任何操作,请<s:a href="login.action"
namespace="/">登录</s:a>!</font>
</s:if>
<s:else>
欢迎您:<s:property value="#session.username"/>
</s:else>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理