struts2中的拦截器使用
一、拦截器简介
拦截器的功能类似于web.xml文件中的Filter,能对用户的请求进行拦截,通过拦截用户的请求来实现对页面的控制。拦截器是在Struts-core-2.2.3.jar中进行配置的,原始的拦截器是在struts-default.xml中配置的,里面封存了拦截器的基本使用方法。
Struts2拦截器功能类似于Servlet过滤器。在Action执行execute方法前,Struts2会首先执行struts.xml中引用的拦截器,如果有多个拦截器则会按照上下顺序依次执行,在执行完所有的拦截器的interceptor方法后,会执行Action的execute方法。
Struts2的拦截器必须从com.opensymphoy.xwork2.interceptor.Interceptor中实现该接口,在被定义的拦截器中有下面三个方法需要被实现:
void destroy();
void init();
String intercept(ActionInvocation invocation) throws Exception;
自定义的拦截器需要重写上面三个方法。另外Struts2的拦截器配置文件struts.xml它是继承了原始文件struts-default.xml文件的,这样在相应的<package>中就会自动拥有struts-default.xml中的所有配置信息了。具体代码如下:
<package name="demo" extends="struts-default" > ... </package>
二、添加拦截器
格式如下:
<interceptor name="拦截器的名字" class="拦截器的实现类">
<param name="参数名">参数值</param>
</interceptor>
其中<param 是可选的。
想要使用拦截器必须要经过配置,struts2采用的是映射的方法,所以想用使用某一个功能就必须在配置文件中配置,拦截器也不例外。所以必须在package中添加相应的拦截器元素,同时将拦截器关联相应的class文件,这样在执行action前才会执行相应的拦截器,具体使用方法如下。
(1)添加配置文件struts.xml,并在该文件中添加拦截器
<package name="testLogin" namespace="/" extends="struts-default">
<!-- 拦截器 -->
<interceptors>
<interceptor name="myInterceptor" class="com.interceptor.MyInterceptor"></interceptor>
</interceptors>
<action name="LoginAction" class="com.action.LoginAction">
<result name="error" type="redirect">/error.jsp</result>
<result name="success">/success.jsp</result>
<result name="checkError">/checkSession.jsp</result>
<interceptor-ref name="myInterceptor"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
</package>
上面的package中添加了一个名为myInterceptor的拦截器,并为该拦截器注册了一个java类,该类名称为MyInterceptor,并被封存在com.interceptor包中。另外还在该package中添加了相应的action,在执行该action前会首先执行myInterceptor拦截器。
(2)编写被注册的拦截器类MyInterceptor,该类必须实现com.opensymphoy.xwork2.interceptor.Interceptor接口,并重写相应的方法
package com.interceptor;
import java.util.Map;
import com.entity.User;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
public class MyInterceptor implements Interceptor{
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public void destroy() {
// TODO Auto-generated method stub
System.out.println("----destroy()----");
}
@Override
public void init() {
// TODO Auto-generated method stub
System.out.println("-----Init()-------");
}
@Override
public String intercept(ActionInvocation invocation) throws Exception {
// TODO Auto-generated method stub
System.out.println("----intercept()------");
Map<String, Object> session= invocation.getInvocationContext().getSession();
if(session.get("username")!=null){
System.out.println("登陆成功!");
//session.put("username",user.getUsername());
return invocation.invoke();
}else{
System.out.println("登陆失败!");
return "checkError";
}
}
}
(3)经过前面两步后,拦截器已经配置完成,最后一部就是使用拦截器了,在显示页面上添加相应的标签,并为标签指定上面创建的名为demo的action,然后执行页面即可在控制台中打印出相应的拦截器内容。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="demo">
用户名:<input type="text" name="username"><br>
密 码:<input type="text" name="password"><br>
<input type="submit" name="ok" value="提交">
</form>
</body>
</html>
程序编译阶段首先会去读取配置文件struts.xml,在该配置文件action中顺序查找是否添加了拦截器,如果添加了拦截器则根据拦截器名称在<interceptors>中查找是否定义了该拦截器或者拦截器栈,如果发现定义的是拦截器则根据拦截器查找对应的注册的class,最后在包内查找注册的class并执行相应的init()方法;程序运行阶段的大致流程和编译阶段类似,用户在前台提交请求后,会按照注册的action在struts.xml中查找与之相对应的,如果查找到将会查找拦截器,没有查找到的话会相应的抛错,最后执行拦截器注册类的intercept方法。
三、拦截器栈
格式如下:
<interceptors>
<interceptor name="拦截器的名字" class="拦截器的实现类">
<param name="参数名">参数值</param>
</interceptor>
<interceptor name="拦截器1" class="interceptor1"/>
<interceptor name="拦截器2" class="interceptor2"/>
<interceptor name="拦截器3" class="interceptor3"/>
<interceptor-stack name="拦截器栈名">
<interceptor-ref name="拦截器1"/>
<interceptor-ref name="拦截器2"/>
<interceptor-ref name="拦截器3"/>
</interceptor-stack>
</interceptors>
由上面的代码可以看出拦截器栈是由<interceptor-stack 定义的,然后使用<interceptor-ref 来引用已成在的拦截器,组成一个拦截器栈。它其实就是一个大的拦截器。和拦截器一样,它们都会在Action的execute方法之前自动执行。
拦截器同样有栈的概念,它是将使用的拦截器定义到共有的状态下来实现统一管理,这样在package中就可以做到拦截器的共享了,大大便利了拦截器的使用。在一个package中往往会用到重复的interceptor,如果每次都在Action中添加interceptor-ref的话就会很麻烦,那么拦截器栈就是为了解决这个问题而产生的,具体配置如下:
<package name="testLogin" namespace="/" extends="struts-default">
<!-- 拦截器 -->
<interceptors>
<interceptor name="myInterceptor" class="com.interceptor.MyInterceptor"></interceptor>
<!-- 定义公共的拦截器链,在action标签中只需要引用拦截器链 -->
<interceptor-stack name="defaultstack1">
<interceptor-ref name="myInterceptor"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<action name="demo" class="com.action.LoginAction">
<result name="error" type="redirect">/error.jsp</result>
<result name="success">/success.jsp</result>
<result name="checkError">/checkSession.jsp</result>
<interceptor-ref name="defaultstack1"></interceptor-ref>
</action>
</package>
实例中使用了interceptor-stack来定义了一个名称为defaultstack1的拦截器栈,在该栈中添加了要执行的拦截器,把拦截器做了封装,在Action中直接调用该拦截器栈即可,实现了拦截器栈的共享。
拦截器栈就是一个大的拦截器。这说明拦截器栈中可以包含其他拦截器栈:
<interceptors>
<interceptor name="拦截器的名字" class="拦截器的实现类">
<param name="参数名">参数值</param>
</interceptor>
<interceptor name="拦截器1" class="interceptor1"/>
<interceptor name="拦截器2" class="interceptor2"/>
<interceptor name="拦截器3" class="interceptor3"/>
<interceptor name="拦截器4" class="interceptor4"/>
<interceptor-stack name="拦截器栈1">
<interceptor-ref name="拦截器1"/>
<interceptor-ref name="拦截器2"/>
<interceptor-ref name="拦截器3"/>
</interceptor-stack>
<interceptor-stack name="拦截器栈2">
<interceptor-ref name="拦截器4"/>
<interceptor-ref name="拦截器栈1"/>
</interceptor-stack>
</interceptors>
系统为拦截器指定参数有如下两个时机:
定义拦截器时(即通过<interceptor 元素来定义拦截器)指定参数值:这种参数值将作为拦截器参数的默认参数值。
使用拦截器时(即通过<interceptor-ref 元素来使用拦截器)指定参数:在配置Action时为拦截器参数指定值,用于覆盖拦截器的默认参数值。
通过为<interceptor-ref 元素增加<param 子元素,就可以在使用拦截器时为参数指定值。
四、默认拦截器栈
另外可以定义默认的拦截器栈,即:如果某个Action中没有定义拦截器,那么它会默认执行该公共的拦截器。它和interceptors标签属于同一等级的,使用default-interceptor-ref定义。
<package name="testLogin" namespace="/" extends="struts-default">
<!-- 拦截器 -->
<interceptors>
<interceptor name="myInterceptor" class="com.interceptor.MyInterceptor"></interceptor>
<!-- 定义公共的拦截器链,在action标签中只需要引用拦截器链 -->
<interceptor-stack name="defaultinter">
<interceptor-ref name="myInterceptor"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 定义默认的拦截器栈,会自动注册到action中 -->
<default-interceptor-ref name="defaultinter"></default-interceptor-ref>
<action name="demo" class="com.action.LoginAction">
<result name="error" type="redirect">/error.jsp</result>
<result name="success">/success.jsp</result>
<result name="checkError">/checkSession.jsp</result>
</action>
</package>
定义的默认的拦截器栈只是在Action没有指定拦截器的情况下才执行自定义默认的拦截器栈的,如果在Action中重定义了拦截器,那么它会覆盖自定义默认的拦截器栈的。
五、不执行任何拦截器
还有一种情况是一个package中定义了默认的拦截器,但是在编写的某个Action中并不需要执行任何拦截器,那么此时可以在相应的Action中添加一个名称为defaultStack的拦截器即可,它是系统默认的拦截器,不会有任何操作。
<package name="testLogin" namespace="/" extends="struts-default">
<!-- 拦截器 -->
<interceptors>
<interceptor name="myInterceptor" class="com.interceptor.MyInterceptor"></interceptor>
<!-- 定义公共的拦截器链,在action标签中只需要引用拦截器链 -->
<interceptor-stack name="defaultinter">
<interceptor-ref name="myInterceptor"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 定义默认的拦截器栈,会自动注册到action中 -->
<default-interceptor-ref name="defaultinter"></default-interceptor-ref>
<action name="demo" class="com.action.LoginAction">
<result name="error" type="redirect">/error.jsp</result>
<result name="success">/success.jsp</result>
<result name="checkError">/checkSession.jsp</result>
<!-- 添加defaultStack保证不执行拦截器 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
</package>
六、拦截方法
上面的拦截器只是实现了对Action的拦截,其实拦截器的功能很强大,它也可以拦截相应Action方法。和拦截Action不同的是想要拦截方法就必须继承类MethodFilterInterceptor,该类封存在xwork-core.jar中,又一次证明了WebWork是Struts2的核心。另外还需要在配置文件中添加相应的属性来确定拦截的方法和不拦截的方法,具体配置方法如下:
<package name="testLogin" namespace="/" extends="struts-default">
<!-- 拦截器 -->
<interceptors>
<interceptor name="myInterceptor" class="com.interceptor.MyInterceptor"></interceptor>
<!-- 定义公共的拦截器链,在action标签中只需要引用拦截器链 -->
<interceptor-stack name="defaultinter">
<interceptor-ref name="myInterceptor"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<action name="demo" class="com.action.LoginAction">
<result name="error" type="redirect">/error.jsp</result>
<result name="success">/success.jsp</result>
<result name="checkError">/checkSession.jsp</result>
<!-- 在defaultStack中配置拦截方法,参数includeMethods中添加被拦截的方法名称,excludeMethods中添加不需要拦截的名称 -->
<interceptor-ref name="defaultStack">
<param name="includeMethods">添加要拦截的方法名称</param><!-- 需要拦截的方法 -->
<param name="excludeMethods">添加不需要拦截的方法名称</param><!-- 不需要拦截的方法 -->
</interceptor-ref>
</action>
</package>
继承MethodFilterInterceptor类的相应拦截方法的类中的代码:
package com.interceptor;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
public class inter extends MethodFilterInterceptor {
@Override
public String doIntercept(ActionInvocation invocation) throws Exception {
System.out.println("--intercept()--");
//获取相应的Session
Map<String,Object> session=invocation.getInvocationContext().getSession();
Map request=(Map)ActionContext.getContext().get("request");
String username=(String)request.get("user.username");
if(session.get("username") != null){
String result=invocation.invoke();
System.out.println("--end()--");
return result;
}
}
}