什么是拦截器
拦截器是Struts2的核心组成部分,它可以动态的拦截Action调用的对象,类似与Servlet中的过滤器。Struts2的拦截器是AOP(Aspect-Object-Programming,面向切面编程)的一种实现策略,是可插拔的,需要某一个功能时就“插入”这个功能的拦截器,不需要这个功能就“拔出”拦截器。开发者只需要提供拦截器的实现类,并将其配置在Struts.xml中即可。
工作流程为请求-过滤前 – 拦截前 – Action处理 – 拦截后 -过滤后-响应
滤器器、拦截器的区别:
滤器器与截器非常相似,都是面向切面编程,具体的区别如下:
1、拦截器是基于java反射机制的,而过滤器是基于函数回调的。
2、过滤器依赖于servlet容器,而拦截器不依赖于servlet容器。
3、拦截器只能对Action请求起作用,而过滤器则可以对几乎所有请求起作用。
4、拦截器可以访问Action上下文、值栈里的对象,而过滤器不能。
5、在Action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时被调用一次。
6、过滤器:取你需要的东西,忽视那些不需要的东西!在程序中,你希望选择中一篇文章中的所有数字,你就可以针对性的挑选数字!
7、拦截器:针对你不要的东西进行拦截,比如说,在一个BBS里面你希望人家不要留“小乌鸦”的这个词,那你就可能采用拦截器!
8、过滤器,是在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts2的 action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者 struts2的action前统一设置字符集,或者去除掉一些非法字符
9、拦截器,是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。
10、执行顺序 :过滤前 – 拦截前 – Action处理 – 拦截后 -过滤后。个人认为过滤是一个横向的过程,首先把客户端提交的内容进行过滤(例如未登录用户不能访问内部页面的处理);过滤通过后,拦截器将检查用户提交数据的验证,做一些前期的数据处理,接着把处理后的数据发给对应的Action;Action处理完成返回后,拦截器还可以做其他过程,再向上返回到过滤器的后续操作。
拦截器的配置
1、拦截器配置
拦截器的配置在struts.xml文件中完成的,它通常以
<interceptors>
<interceptor name="interceptorName" class="interceptorClass">
<param name="paramName">paramValue</param>
</interceptor>
</interceptors>
2、拦截器栈
在实际开发中,在Action执行前同时执行多个拦截动作,如用户登陆检查等,这时可以把多个拦截器组成拦截器栈。在使用时,可以将栈内的多个拦截器当成一个整体来引用。当拦截器栈被附加到一个Action上时,在执行Action之前必须先执行拦截器栈中的每一个拦截器。
定义拦截器栈使用
<interceptors>
<interceptor-stack name="interceptorStackName">
<interceptor-ref name="interceptorName"/>
...
</interceptor-stack>
</interceptors>
上述语法中,interceptorStackName值表示配置的拦截器栈的名称,interceptorName值表示拦截器的名称。除此之外,在一个拦截器栈中还可以包含另一个拦截器栈
3、默认拦截器
默认拦截器可以对其指定包中的所有Action起到拦截的作用。一旦为某个包指定了默认拦截器,并且该包中的Action未显式地指定拦截器,则会使用默认拦截器。默认拦截器需要使用
<default-interceptor-ref name="拦截器(栈)的名称"/>
Notice:一个包下只能定义一个默认拦截器,如果需要多个拦截器作为默认拦截器,则可以将这些拦截器定义为一个拦截器栈,再将这个拦截器栈作为默认拦截器即可。
自定义拦截器
struts2的内置拦截器可以实现大部分的拦截任务,但是一些与系统逻辑相关的通用功能(如权限的控制、用户登陆控制等),则需要通过自定义拦截器来实现。
在程序开发过程中,如果需要开发自己的拦截器类,就需要直接或间接地实现com.opensymphony.xwork2. interceptor. Interceptor接口在程序开发过程中,如果需要开发自己的拦截器类,就需要直接或间接地实现com.opensymphony.xwork2. interceptor. Interceptor接口.
该接口提供一下三个方法:
- void init():该方法在拦截器被创建后会立即被调用,它在拦截器的生命周期只有内只被调用一次。可以在该方法中对相关的资源进行必要的初始化;
- void destroy():该方法与init()方法相对应,在拦截器实例被销毁之前,将调用该方法来释放与拦截器相关的资源。它在拦截器的生命周期内也只被调用一次。
- Spring intercept(ActionInvocation invocation)throws Exception:该方法是拦截器的核心方法,用来真正执行拦截工作的代码,实现具体的拦截工作。
自定义拦截器的使用分为一下三个步骤:
- 用户自定义拦截器类,必须实现Interceptor接口或者继承AbstractInterceptor类;
- 需要在struts.xml中,定义自定义拦截器;
- 在struts.xml中的Action中使用拦截器。
自定义权限拦截器
简单介绍一个登陆权限下的图书管理
1、登陆页面login.jsp,提交用户名密码到LoginAction处理
2、登陆成功后跳转到书本管理页面bookM.jsp,将用户对象放在session域中
3、失败会将失败信息放在actionContext中后继续登陆,在login.jsp页面通过 ${requestScope.msg}获取失败的登陆信息
4、在bookM.jsp页面操作图书,信息提交到BookAction处理
5、BookAction有过滤器,检测session域中是否有用户对象,有的话继续,没有跳转到登陆页面
6、BookAction操作book,将信息放在ActionMessage中
7、操作完成,返回bookM.jsp页面,<s:actionmessage/>
返回操作图书的信息
8、bookM.jsp有注销,动作提交给LoginAction处理
9、LoginAction删除在session中用户对象
10、删除后跳转到登陆页面login.jsp
struts.xml配置
<package name="myPackage" extends="struts-default" namespace="/">
<interceptors>
<interceptor name="login_interceptor" class="interceptor.PrivilegeInterceptor">
<param name="userName">刘病已</param>
<param name="password">123456</param>
</interceptor>
<interceptor-stack name="mystack">
<interceptor-ref name="login_interceptor"/>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<action name="login_*" class="action.LoginAction" method="login_{1}">
<result>/bookM.jsp</result>
<result name="input">login.jsp</result>
</action>
<!--关于book操作-->
<action name="book_*" class="action.BookAction" method="{1}">
<result>/bookM.jsp</result>
<result name="login">/login.jsp</result>
<!--在action中使用自定义拦截器-->
<interceptor-ref name="mystack"/>
</action>
</package>
注意:一旦在Action中使用了自定义拦截器或拦截器栈则defaultStack就不起作用了。
使用自定义的拦截器配置在struts配置文件的action中,还要引入defaultStack,否则使用了modelDriven的formBean将不能获取到form表单中字段的值。
每一个拦截器都有两个默认的参数:
excludeMethods – 过滤掉不使用拦截器的方法和
includeMethods – 使用拦截器的方法。
拦截器需要有name属性(定义了setXxx方法)即可注入。
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>登陆</title>
</head>
<body>
<center>
${requestScope.msg}<br>
<form action="login_in.action" 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>
bookM.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<title>书本管理页面</title>
<style type="text/css">
.actionMessage {
list-style: none;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<s:actionmessage/>
<a href="book_del.action">book del</a><br>
<a href="book_add.action">book add</a><br>
<a href="book_update.action">book update</a><br>
<a href="book_find.action">book find</a><br>
<a href="login_out.action">注销</a><br>
<s:debug></s:debug>
</body>
</html>
LoginAction.java
/**
*
*/
package action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import entity.Users;
/**
* @author Administrator
*
*/
public class LoginAction extends ActionSupport implements ModelDriven<Users>{
private static final long serialVersionUID = 1L;
private Users user;
public Users getModel() {
if(user==null){
user = new Users();
}
return user;
}
public String login_in() throws Exception {
//获取ActionContext
ActionContext actionContext = ActionContext.getContext();
if ("shadow".equals(user.getUsername()) && "123".equals(user.getPassword())) {
actionContext.getSession().put("user", user);
return SUCCESS;
} else {
actionContext.put("msg", "用户名或者密码不正确");
return INPUT;
}
}
public String login_out() throws Exception {
//获取ActionContext
ActionContext actionContext = ActionContext.getContext();
actionContext.getSession().remove("user");
return INPUT;
}
}
BooKAction.java
/**
*
*/
package action;
import com.opensymphony.xwork2.ActionSupport;
/**
* @author Administrator
*
*/
public class BookAction extends ActionSupport{
public String add(){
addActionMessage("添加书本成功");
return SUCCESS;
}
public String del(){
addActionMessage("删除书本成功");
return SUCCESS;
}
public String update(){
addActionMessage("更新书本成功");
return SUCCESS;
}
public String find(){
addActionMessage("查找书本成功");
return SUCCESS;
}
}
PrivilegeInterceptor.java
/**
*
*/
package interceptor;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.util.TextParseUtil;
import lombok.Getter;
import lombok.Setter;
/**
* @author Administrator
*
*/
public class PrivilegeInterceptor extends AbstractInterceptor{
@Getter
@Setter
private String userName;
@Getter
@Setter
private String password;
@Override
public String intercept(ActionInvocation invocation) throws Exception {
//得到ActionContext
ActionContext actionContext = invocation.getInvocationContext();
System.out.println("获取到拦截器定义参数"+userName);
System.out.println("获取到拦截器定义参数"+password);
//获取user对象
Object user = actionContext.getSession().get("user");
if(user != null){
return invocation.invoke();
}else {
actionContext.put("msg","您还未登录,请先登陆");
return Action.LOGIN; //用户如果不存在,返回login直
}
}
}
使用拦截器注解
Struts2在com.opensymphony.xwork2.interceptor.annotations包中定义了3个拦截器注解类型,让你可以不用编写拦截器类,直接通过注解的方式指定action执行之前和之后需要调用的方法。
Struts2提供的3个拦截器注解类型都只能应用到方法级别。如下:
- Before
标注一个action方法,该方法将在action的主要方法(如execute方法)调用之前调用。如果标注的方法有返回值,并且不为空,那么它的返回值将作为Action的结果代码。 -
After
标注一个action方法,该方法将在action的主要方法以及result执行之后调用,如果标注的方法有返回值,那么这个返回值将被忽略。 -
BeforeResult
标注一个action方法,该方法将在action的主要方法调用之后,在result执行之前调用,如果标注的方法有返回值,那么这个返回值将被忽略。
Before After 和BeforeResult注解的同名参数
参数 | 类型 | 是否必要 | 默认值 | 描述 |
---|---|---|---|---|
priority | int | 否 | 10 | 指定方法执行的优先级别 |
同一个注解可以用来标注多个方法,方法执行的先后顺序可以通过priority参数来指定,优先级越高,方法越先执行。在相同的优先级的情况下,方法执行的先后顺序无法保证。不过有继承关系的action类,在基类上标注的方法将先于在派生类上标注的方法执行。
要使用拦截器注解,需要配置
<interceptor name="annotationInterceptor" class="com.opensymphony.xwork2.interceptor.annotations. AnnotationWorkflowInterceptor"/>
使用注解拦截器案例
<package name="myPackage" extends="struts-default" namespace="/">
<interceptors>
<interceptor name="annotationInterceptor" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor"/>
<interceptor name="login_interceptor" class="interceptor.PrivilegeInterceptor">
<param name="userName">刘病已</param>
<param name="password">123456</param>
</interceptor>
<interceptor-stack name="mystack">
<interceptor-ref name="login_interceptor"/>
<interceptor-ref name="annotationInterceptor"/>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
BookAction.java
/**
*
*/
package action;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.interceptor.annotations.After;
import com.opensymphony.xwork2.interceptor.annotations.Before;
import com.opensymphony.xwork2.interceptor.annotations.BeforeResult;
/**
* @author Administrator
*
*/
public class BookAction extends ActionSupport{
/**
*
*/
private static final long serialVersionUID = -8082685884945619946L;
public String add(){
addActionMessage("添加书本成功");
return SUCCESS;
}
public String del(){
addActionMessage("删除书本成功");
return SUCCESS;
}
public String update(){
addActionMessage("更新书本成功");
return SUCCESS;
}
public String find(){
addActionMessage("查找书本成功");
return SUCCESS;
}
@Before
public void before(){
System.out.println("before");
}
@After(priority=1)
public void after(){
System.out.println("after1");
}
@After(priority=2)
public void after2(){
System.out.println("after2");
}
@BeforeResult
public void beforeResult(){
System.out.println("beforeResult");
}
}
结果为:
before
beforeResult
after2
after1
系统自带的拦截器
<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"/>
<interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
<interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
<interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
<interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
<interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
<interceptor name="externalRef" class="com.opensymphony.xwork2.interceptor.ExternalReferencesInterceptor"/>
<interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
<interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
<interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
<interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
<interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
<interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>
<interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
<interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
<interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
<interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
<interceptor name="sessionAutowiring" class="org.apache.struts2.spring.interceptor.SessionContextAutowiringInterceptor"/>
<interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
<interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
<interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
<interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
<interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
<interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
<interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
<interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
<interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
<interceptor name="jsonValidation" class="org.apache.struts2.interceptor.validation.JSONValidationInterceptor" />
<interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />
<interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />
- alias:对于HTTP请求包含的参数设置别名。
- autowiring:将某些JavaBean实例自动绑定到其他Bean对应的属性中。有点类似Spring的自动绑定,在Spring部分会详细说明。
- Chain:在Web项目开发中,以前使用Struts开发时候经常碰到两个Action互相传递参数或属性的情况。该拦 截器就是让前一Action的参数可以在现有Action中使用。
- conversionError:从ActionContext中将转化类型时候发生的错误添加到Action的值域错误中,在校验时候 经常被使用到来显示类型转化错误的信息。
- cookie:从Struts2.0.7版本开始,可以把cookie注入Action中可设置的名字或值中。
- createSession:自动创建一个HTTP的Session,尤其是对需要HTTP的Session的拦截器特别有用。比如下面 介绍的TokenInterceptor。
- debugging:用来对在视图间传递的数据进行调试。
- ExecAndWait:不显式执行Action,在视图上显示给用户的是一个正在等待的页面,但是Action其实是在 “背后”正在执行着。该拦截器尤其在对进度条进行开发的时候特别有用。
- exception:将异常和Action返回的result相映射。
- fileUpload:支持文件上传功能的拦截器。
- i18n:支持国际化的拦截器。
- logger:拥有日志功能的拦截器。
- modelDriven:Action执行该拦截器时候,可以将getModel方法得到的result值放入值栈中。
- scopedModelDriven:执行该拦截器时候,它可以从一个scope范围检索和存储model值,通过调用
setModel:方法去设置model值。 - params:将HTTP请求中包含的参数值设置到Action中。
- prepare:假如Action继承了Preparable接口,则会调用prepare方法。
- staticParams:对于在struts.xml文件中Action中设置的参数设置到对应的Action中。
- scope:在session或者application范围中设置Action的状态。
- servletConfig:该拦截器提供访问包含HttpServletResquest和HttpServletResponse对象的Map的方法。
- timer:输出Action的执行时间。
- token:避免重复提交的校验拦截器。
- tokenSession:和token拦截器类似,但它还能存储提交的数据到session里。
- validation:运行在action-validation.xml(校验章节将介绍)文件中定义的校验规则。
- workflow:在Action中调用validate校验方法。如果Action有错误则返回到input视图。
- store:执行校验功能时候,该拦截器提供存储和检索Action的所有错误和正确信息的功能。
- checkbox:视图中如果有checkbox存在的情况,该拦截器自动将unchecked的checkbox当作一个参数(通常值为“false”)记录下来。这样可以用一个隐藏的表单值来记录所有未提交的checkbox,而且缺省
- unchecked:的checkbox值是布尔类型的,如果视图中checkbox的值设置的不是布尔类型,它就会被覆盖成布 尔类型的值。
- profiling:通过参数来激活或不激活分析检测功能,前提是Web项目是在开发模式下。(涉及到调试和性能 检验时使用)
- roles:进行权限配置的拦截器,如果登录用户拥有相应权限才去执行某一特定Action
defaultStack
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
参考
https://www.cnblogs.com/Mairr/p/7906086.html
https://blog.csdn.net/yy008871/article/details/7671395
https://blog.csdn.net/hao2244/article/details/50426693
https://www.cnblogs.com/zxl/archive/2008/11/21/1338096.html