struts2 拦截器
Struts2中的拦截器(特别重要)
1、拦截器的重要性
Struts2中的很多功能都是由拦截器完成的。比如:servletConfig,staticParam,params,modelDriven等等。
是AOP编程思想的一种应用形式。
2、拦截器的执行时机:
3、自定义拦截器
3.1、拦截器的类试图(初级版本):
3.2、编写步骤:
a、编写一个类,继承AbstractInterceptor类或者实现Interceptor接口。重写intercept方法。
1 package com.itheima.web.interceptor; 2 3 import com.opensymphony.xwork2.ActionInvocation; 4 import com.opensymphony.xwork2.interceptor.AbstractInterceptor; 5 /** 6 * 自定义拦截器 7 * 第一步:创建一个普通类,继承AbstractInterceptor,实现抽象方法intercept 8 * 第二步:在struts.xml中配置拦截器 9 * 1.声明拦截器 10 * <interceptors> 11 <interceptor name="demo1Interceptor" class="com.itheima.web.interceptor.Demo1Interceptor" /> 12 </interceptors> 13 2.使用拦截器 14 <!-- 使用自定义拦截器:当配置了任何一个拦截器,默认的拦截器栈就不会在工作了 --> 15 <interceptor-ref name="demo1Interceptor"></interceptor-ref> 16 * @author zhy 17 * 18 */ 19 public class Demo1Interceptor extends AbstractInterceptor { 20 21 public String intercept(ActionInvocation invocation) throws Exception { 22 System.out.println("Demo1Interceptor拦截器:拦截了-执行动作方法之前"); 23 //放行:如果有下一个拦截器,就前往下一个拦截器,如果没有了,就到达动作方法 24 String rtValue = invocation.invoke();//就是结果视图的名称 25 System.out.println("Demo1Interceptor拦截器:拦截了-执行动作方法之后"); 26 return rtValue; 27 } 28 29 }
b、配置拦截器:注意拦截器必须先声明再使用
注意: 在xml中配置了任何一个拦截器,默认的拦截器就不会再给我们工作了,要重新配置
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE struts PUBLIC 3 "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" 4 "http://struts.apache.org/dtds/struts-2.3.dtd"> 5 <struts> 6 <constant name="struts.devMode" value="true" /> 7 <package name="p1" extends="struts-default"> 8 <!-- 声明自定义拦截器 --> 9 <interceptors> 10 <interceptor name="demo1Interceptor" class="com.itheima.web.interceptor.Demo1Interceptor"></interceptor> 11 <interceptor name="demo2Interceptor" class="com.itheima.web.interceptor.Demo2Interceptor"></interceptor> 12 </interceptors> 13 <action name="action1" class="com.itheima.web.action.Demo1Action" method="save"> 14 <!-- 使用自定义拦截器:当配置了任何一个拦截器,默认的拦截器栈就不会在工作了 . 15 当有多个拦截器的时候,是由引用配置决定执行的顺序 。 注意:执行顺序与声明无关--> 16 <interceptor-ref name="demo2Interceptor"></interceptor-ref> 17 <interceptor-ref name="demo1Interceptor"></interceptor-ref> 18 <result name="success">/demo1.jsp</result> 19 </action> 20 </package>
3.3、执行顺序
见前面的执行时机图
3.4、多个拦截器的执行顺序
在动作方法执行之前, 拦截器执行顺序与配置(不是声明)顺序正相关
在动作方法执行之后, 拦截器执行顺序与配置(不是声明 )顺序负相关
3.5、intercept方法的返回值
return invocation.invoke(); 返回的就是 结果视图(seccess,input,error等)
4、拦截器的应用:
4.1、检查登录的拦截器案例
配置文件:
1 <!-- 使用自定义拦截器,检查登录。最基本的配置方式。 2 其中存在的问题: 3 当我们使用了自定义拦截器之后,默认的拦截器栈就不再工作了 --> 4 <package name="p2" extends="struts-default"> 5 <interceptors>声明拦截器 6 <interceptor name="checkLoginInterceptor" class="com.itheima.web.interceptor.CheckLoginInterceptor" /> 7 </interceptors> 8 <global-results>全局结果视图 9 <result name="input">/login.jsp</result>数据回显的结果视图 10 </global-results> 11 用户登录时,不需要检查登录的拦截器工作 12 <action name="login" class="com.itheima.web.action.Demo2Action" method="login"> 13 <result type="redirectAction">showMain</result> 14 </action> 15 前往主页的动作名称,需要检查登录的拦截器工作 16 <action name="showMain" class="com.itheima.web.action.Demo2Action" > 17 <interceptor-ref name="checkLoginInterceptor"></interceptor-ref> 18 <result>/main.jsp</result> 19 </action> 20 前往另一个页面的动作名称,需要检查登录的拦截器工作 21 <action name="showOther" class="com.itheima.web.action.Demo2Action" > 22 <interceptor-ref name="checkLoginInterceptor"></interceptor-ref> 23 <result>/otherpage.jsp</result> 24 </action> 25 </package>
动作类:
1 package com.itheima.web.action; 2 3 import javax.servlet.http.HttpSession; 4 5 import org.apache.struts2.ServletActionContext; 6 7 import com.opensymphony.xwork2.ActionSupport; 8 9 public class Demo2Action extends ActionSupport { 10 11 12 /** 13 * 用户登录的方法 14 * @return 15 */ 16 public String login(){ 17 HttpSession session = ServletActionContext.getRequest().getSession(); 18 session.setAttribute("user", "test"); 19 return SUCCESS; 20 } 21 22 23 24 /** 25 * 无论是显示主页还是显示另一个页面都执行此方法, 26 * 返回成功 27 */ 28 public String execute(){ 29 return SUCCESS; 30 } 31 }
拦截器:
1 package com.itheima.web.interceptor; 2 3 import javax.servlet.http.HttpSession; 4 5 import org.apache.struts2.ServletActionContext; 6 7 import com.opensymphony.xwork2.ActionInvocation; 8 import com.opensymphony.xwork2.interceptor.AbstractInterceptor; 9 /** 10 * 检查登录的拦截器,初级版本 11 * @author zhy 12 * 13 */ 14 public class CheckLoginInterceptor extends AbstractInterceptor { 15 16 public String intercept(ActionInvocation invocation) throws Exception { 17 //1.获取HttpSession 18 HttpSession session = ServletActionContext.getRequest().getSession(); 19 //2.获取session域中的登录标记 20 Object obj = session.getAttribute("user"); 21 //3.判断是否有登录标记 22 if(obj == null){ 23 //用户没有登录 24 return "input"; 25 } 26 //4.用户登录了,放行 27 String rtValue = invocation.invoke(); 28 return rtValue; 29 } 30 31 }
页面:
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>主页:检查登录的拦截器</title> 7 </head> 8 <body> 9 <%--要想来到本页面(主页),必须得先登录 --%> 10 主页<hr/> 11 <a href="${pageContext.request.contextPath}/showOther.action">访问另一个页面</a> 12 </body> 13 </html>
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>用户登录</title> 7 </head> 8 <body> 9 <form action="${pageContext.request.contextPath}/login.action" method="post"> 10 用户名:<input type="text" name="username"/><br/> 11 密码:<input type="password" name="password"/><br/> 12 <input type="submit" value="登录"/> 13 </form> 14 </body> 15 </html>
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>另一个页面</title> 7 </head> 8 <body> 9 另一个页面 10 </body> 11 </html>
4.2、案例中的问题
问题:由于我们写了自己的拦截器,默认的拦截器不起作用了。
解决办法:
a、把默认拦截器加入到配置文件中
1 <!-- a.针对上面的问题,我们的解决办法是,把默认的拦截器栈也配置进来. 2 <package name="p2" extends="struts-default"> 3 <interceptors> 4 <interceptor name="checkLoginInterceptor" class="com.itheima.web.interceptor.CheckLoginInterceptor" /> 5 </interceptors> 6 <global-results> 7 <result name="input">/login.jsp</result> 8 </global-results> 9 <action name="login" class="com.itheima.web.action.Demo2Action" method="login"> 10 <result type="redirectAction">showMain</result> 11 </action> 12 <action name="showMain" class="com.itheima.web.action.Demo2Action" > 13 加入自定义拦截器,和默认的拦截器栈 14 <interceptor-ref name="defaultStack"></interceptor-ref> 15 <interceptor-ref name="checkLoginInterceptor"></interceptor-ref> 16 <result>/main.jsp</result> 17 </action> 18 <action name="showOther" class="com.itheima.web.action.Demo2Action" > 19 加入自定义拦截器,和默认的拦截器栈 20 <interceptor-ref name="defaultStack"></interceptor-ref> 21 <interceptor-ref name="checkLoginInterceptor"></interceptor-ref> 22 <result>/otherpage.jsp</result> 23 </action> 24 </package>-->
b、a中暴露的问题:当有多个拦截器时,需要改写的地方非常多。
解决办法:抽取公共的包,把全局配置放入公共包中。
1 <!-- b. a中存在的弊端,当如果需要拦截的动作很多时,写起来很繁琐 2 <package name="p2" extends="struts-default"> 3 <interceptors> 4 <interceptor name="checkLoginInterceptor" class="com.itheima.web.interceptor.CheckLoginInterceptor" /> 5 定义一个拦截器栈,把我们自定义的拦截器和默认的拦截器栈放到一起. 6 <interceptor-stack name="myDefaultStack"> 7 <interceptor-ref name="defaultStack"></interceptor-ref> 8 <interceptor-ref name="checkLoginInterceptor"></interceptor-ref> 9 </interceptor-stack> 10 </interceptors> 11 <global-results> 12 <result name="input">/login.jsp</result> 13 </global-results> 14 <action name="login" class="com.itheima.web.action.Demo2Action" method="login"> 15 <result type="redirectAction">showMain</result> 16 </action> 17 <action name="showMain" class="com.itheima.web.action.Demo2Action" > 18 直接引入我们自己定义的拦截器栈,里面已经包含了默认的拦截器栈 19 <interceptor-ref name="myDefaultStack"></interceptor-ref> 20 <result>/main.jsp</result> 21 </action> 22 <action name="showOther" class="com.itheima.web.action.Demo2Action" > 23 直接引入我们自己定义的拦截器栈,里面已经包含了默认的拦截器栈 24 <interceptor-ref name="myDefaultStack"></interceptor-ref> 25 <result>/otherpage.jsp</result> 26 </action> 27 </package> --> 28 29 <!-- c. b中存在的问题,还需要在每个要用到地方使用拦截器引用。 30 解决办法:使用覆盖struts-default.xml配置文件中的默认拦截器栈,让我们的这个称为默认的--> 31 32 <package name="p2" extends="struts-default"> 33 <interceptors> 34 <interceptor name="checkLoginInterceptor" class="com.itheima.web.interceptor.CheckLoginInterceptor" /> 35 <interceptor-stack name="myDefaultStack"> 36 <interceptor-ref name="defaultStack"></interceptor-ref> 37 <interceptor-ref name="checkLoginInterceptor"></interceptor-ref> 38 </interceptor-stack> 39 </interceptors> 40 覆盖了struts-default.xml中定义的默认拦截器栈。由myDefaultStack把defaultStack给替换了 41 <default-interceptor-ref name="myDefaultStack"></default-interceptor-ref> 42 <global-results> 43 <result name="input">/login.jsp</result> 44 </global-results> 45 <action name="login" class="com.itheima.web.action.Demo2Action" method="login"> 46 <result type="redirectAction">showMain</result> 47 </action> 48 <action name="showMain" class="com.itheima.web.action.Demo2Action" > 49 <result>/main.jsp</result> 50 </action> 51 <action name="showOther" class="com.itheima.web.action.Demo2Action" > 52 <result>/otherpage.jsp</result> 53 </action> 54 </package>
c、b中的问题:还要再每个动作方法中引入拦截器。能不能不写呢?
思路:我们在设置【开发模式】时,覆盖掉了一个default.properties中的常量,能不能把struts-default.xml中的默认拦截器栈的设置给覆盖掉呢?答案是可以的。
解决办法:
1 <!-- c. b中存在的问题,还需要在每个要用到地方使用拦截器引用。 2 解决办法:使用覆盖struts-default.xml配置文件中的默认拦截器栈,让我们的这个称为默认的 --> 3 4 5 <package name="p2" extends="struts-default"> 6 <interceptors> 7 <interceptor name="checkLoginInterceptor" class="com.itheima.web.interceptor.CheckLoginInterceptor" /> 8 <interceptor-stack name="myDefaultStack"> 9 <interceptor-ref name="defaultStack"></interceptor-ref> 10 <interceptor-ref name="checkLoginInterceptor"></interceptor-ref> 11 </interceptor-stack> 12 </interceptors> 13 覆盖了struts-default.xml中定义的默认拦截器栈。由myDefaultStack把defaultStack给替换了 14 <default-interceptor-ref name="myDefaultStack"></default-interceptor-ref> 15 <global-results> 16 <result name="input">/login.jsp</result> 17 </global-results> 18 <action name="login" class="com.itheima.web.action.Demo2Action" method="login"> 19 <result type="redirectAction">showMain</result> 20 </action> 21 <action name="showMain" class="com.itheima.web.action.Demo2Action" > 22 <result>/main.jsp</result> 23 </action> 24 <action name="showOther" class="com.itheima.web.action.Demo2Action" > 25 <result>/otherpage.jsp</result> 26 </action> 27 </package>
d、c中出现的问题:当使用了默认拦截器栈,这时候三个动作login,showIndex和show1Action都将被检查登录的拦截器拦截。
解决办法:
需要通过AbstractInterceptor类的子类入手,通过查看发现,该类还有一个子类是抽象的:
所以我们在自定义拦截器时,还可以继承MethodFilterInterceptor并且重写doIntercept方法。
1 package com.itheima.web.interceptor; 2 3 import javax.servlet.http.HttpSession; 4 5 import org.apache.struts2.ServletActionContext; 6 7 import com.opensymphony.xwork2.ActionInvocation; 8 import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; 9 /** 10 * 检查登录的拦截器,最终版本 11 * @author zhy 12 * 13 */ 14 public class CheckLoginInterceptor1 extends MethodFilterInterceptor { 15 16 public String doIntercept(ActionInvocation invocation) throws Exception { 17 //1.获取HttpSession 18 HttpSession session = ServletActionContext.getRequest().getSession(); 19 //2.获取session域中的登录标记 20 Object obj = session.getAttribute("user"); 21 //3.判断是否有登录标记 22 if(obj == null){ 23 //用户没有登录 24 return "input"; 25 } 26 //4.用户登录了,放行 27 String rtValue = invocation.invoke(); 28 return rtValue; 29 } 30 31 }
并且在struts的配置文件中,配置需要拦截哪些方法,和需要放过哪些方法。
<!-- d. c中存在的问题,当我们配置了默认的拦截器栈时,连登陆都被拦截了。 解决办法: 在AbstractInterceptor的子类中,还有一个抽象类MethodFilterInterceptor,它里面提供了两个属性。 excludeMethods:哪些方法不需要拦截 includeMethods:哪些方法需要拦截 --> <package name="p2" extends="struts-default"> <interceptors> <interceptor name="checkLoginInterceptor1" class="com.itheima.web.interceptor.CheckLoginInterceptor1" /> <interceptor-stack name="myDefaultStack"> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="checkLoginInterceptor1"> 给自定义拦截器注入参数,告知他哪些方法不需要拦截 <param name="excludeMethods">login</param> </interceptor-ref> </interceptor-stack> </interceptors> <default-interceptor-ref name="myDefaultStack"></default-interceptor-ref> <global-results> <result name="input">/login.jsp</result> </global-results> <action name="login" class="com.itheima.web.action.Demo2Action" method="login"> <result type="redirectAction">showMain</result> </action> <action name="showMain" class="com.itheima.web.action.Demo2Action" > <result>/main.jsp</result> </action> <action name="showOther" class="com.itheima.web.action.Demo2Action" > <result>/otherpage.jsp</result> </action> </package>
e、d中遗留的问题:我们在声明时配置了哪些方法需要拦截,哪些方法不需要拦截。但是在没有写动作类和动作方法之前,不确定方法名叫什么。
解决办法:我们需要在使用拦截器的时候给它注入参数。
1 <!-- e. d中的问题,我们在声明拦截器和定义拦截器栈的时候,可能根本不知道哪些方法需要拦截,哪些不需要 2 解决办法:在使用拦截器的时候,注入参数,告诉拦截器哪些需要拦截,哪些不需要 3 --> 4 <package name="p2" extends="struts-default"> 5 <interceptors> 6 <interceptor name="checkLoginInterceptor1" class="com.itheima.web.interceptor.CheckLoginInterceptor1" /> 7 <interceptor-stack name="myDefaultStack"> 8 <interceptor-ref name="defaultStack"></interceptor-ref> 9 <interceptor-ref name="checkLoginInterceptor1"></interceptor-ref> 10 </interceptor-stack> 11 </interceptors> 12 <default-interceptor-ref name="myDefaultStack"></default-interceptor-ref> 13 <global-results> 14 <result name="input">/login.jsp</result> 15 </global-results> 16 17 <action name="login" class="com.itheima.web.action.Demo2Action" method="login"> 18 <interceptor-ref name="myDefaultStack"> 19 <!-- 在引用自定义拦截器栈的时候,给指定的拦截器注入参数。方式就是:拦截器名称.属性名称 --> 20 <param name="checkLoginInterceptor1.excludeMethods">login</param> 21 </interceptor-ref> 22 <result type="redirectAction">showMain</result> 23 </action> 24 <action name="showMain" class="com.itheima.web.action.Demo2Action" > 25 <result>/main.jsp</result> 26 </action> 27 <action name="showOther" class="com.itheima.web.action.Demo2Action" > 28 <result>/otherpage.jsp</result> 29 </action> 30 </package>
4.3、拦截器类视图(全):
lanjieqi