《研磨struts2》 第六章 拦截器 之 6.4 两个有用的拦截器

6.4  两个有用的拦截器

6.4.1  更强大的logger拦截器

在学习了这么多拦截器的理论知识过后,来示范两个真实项目中用得到的拦截器。先来看看更强大的logger拦截器。

Struts2自带的logger拦截器只是打印出了Action所对应的URL以及执行的方法名称,这对实际开发来说是肯定不够的。

       实际开发中为了调试方便,要记录的信息比较多,通常需要把这次请求相关的几乎所有信息都打印出来,比如:

  • 要访问哪个Action类
  • 要访问这个Action类的哪个方法
  • 打印出这次请求中所有的request中的parameter参数
  • 这次请求最后跳转到哪个页面。

       如果我们现在就要在拦截器中实现这样的功能,该怎么实现呢?

1:ActionInvocation接口

       在实现拦截器的功能的时候,需要使用ActionInvocation接口,这个接口有很多的功能,这里并不打算全部讲到,只描述一下接下来我们要用到的功能,更多的功能请参见Struts2的API文档。

  • getAction方法:返回这次请求准备执行的Action对象。
  • getProxy方法:返回这次请求的ActionProxy对象,可以在这个对象上获得要运行Action的哪个方法。
  • getInvocationContext方法:返回这个Action执行的上下文(ActionContext),可以在这个上下文对象中获取到大量的数据,比如请求的parameter值、session的值等等。
        在ActionContext中取到的parameter值是一个Map<String,Object>,其中以String为key,以String[]为value。这个Map中记录了所有的request参数。
  • getResult方法:返回Result运行之后代表结果的Result对象。

2:具体的LoggerInterceptor,示例代码如下:

 

java代码:
  1. package cn.javass.action.action;  
  2.   
  3. import java.util.Map;  
  4. import org.apache.struts2.dispatcher.ServletDispatcherResult;  
  5. import com.opensymphony.xwork2.ActionInvocation;  
  6. import com.opensymphony.xwork2.Result;  
  7. import com.opensymphony.xwork2.interceptor.Interceptor;  
  8.   
  9. public class LoggerInterceptor implements Interceptor{  
  10.     public void destroy() {  
  11.     }  
  12.     public void init() {  
  13.     }     
  14.     public String intercept(ActionInvocation invocation) throws Exception {  
  15.         System.out.println("begin-------------------------------");  
  16.         //找到运行的Action对象,并打印其类名  
  17.         System.out.println("Action:"+invocation.getAction().getClass().getName());  
  18.         //找到运行的ActionProxy对象,并打印其要运行的方法名  
  19.         System.out.println("Method:"+invocation.getProxy().getMethod());  
  20.         //找到这次请求的request中的parameter参数,并打印  
  21.         Map<String, Object> params = invocation.getInvocationContext().getParameters();  
  22.         for (String key:params.keySet()){  
  23.             Object obj = params.get(key);  
  24.               
  25.             if(obj instanceof String[]){  
  26.                 String[] arr = (String[]) obj;  
  27.                 System.out.println("Param:"+key);  
  28.                 for (String value:arr){  
  29.                     System.out.println(value);  
  30.                 }  
  31.             }  
  32.         }  
  33.           
  34.         //运行后续的拦截器、Action和Result  
  35.         String resultCode = invocation.invoke();  
  36.           
  37.         //在Action和Result运行之后,得到Result对象  
  38.         //并且可以强制转换成ServletDispatcherResult,打印其下一个JSP的位置  
  39.         Result rresult = invocation.getResult();  
  40.         if (rresult instanceof ServletDispatcherResult){  
  41.             ServletDispatcherResult result = (ServletDispatcherResult) rresult;  
  42.             System.out.println("JSP:"+result.getLastFinalLocation());  
  43.         }  
  44.           
  45.         System.out.println("end-------------------------------");           return resultCode;  
  46.     }  
  47. }  

3:在struts.xml中配置和使用这个拦截器,示例如下:

 

java代码:
  1. <package name="helloworld"  extends="struts-default">  
  2.         <interceptors>  
  3.             <interceptor name="MyLogger" class="cn.javass.action.action.LoggerInterceptor"/>  
  4.         </interceptors>  
  5.                   
  6.         <action name="helloworldAction" class="cn.javass.action.action.HelloWorldAction">  
  7.             <result name="toWelcome">/s2impl/welcome.jsp</result>  
  8.             <interceptor-ref name="MyLogger"/>  
  9.             <interceptor-ref name="defaultStack"/>  
  10.         </action>  
  11. </package>  

4:测试一下,运行登录页面,填入用户名和密码,点击提交按钮。然后查看后台的输出,示例如下:

 

java代码:
  1. begin-------------------------------  
  2. Action:cn.javass.action.action.HelloWorldAction  
  3. Method:execute  
  4. Param:submitFlag  
  5. login  
  6. Param:account  
  7. test  
  8. Param:password  
  9. test  
  10. 用户输入的参数为===account=test,password=test,submitFlag=login  
  11. JSP:/s2impl/welcome.jsp  
  12. end-------------------------------  

上面加粗的那句话,是Action运行的时候输出的信息,其余信息就是由我们的拦截器来输出的了。

基本实现了前面提出的四个要求,分别输出了如下信息:运行哪个Action类,运行哪个方法,请求的参数,Action运行完要跳转到哪个JSP。

这些信息对我们进行调试是非常有用的。

6.4.2  登录检查拦截器

在实际开发中,一个常见的功能要求是:有很多操作都需要登录后才能操作,如果操作的时候还没有登录,那么通常情况下会要求跳转回到登录页面。

1:如何实现这样的功能呢?

在具体实现之前,先来考虑几个问题:

1)这个功能应该在哪里实现?

要实现登录检查的功能,很明显是在Action运行之前,就要判断用户是否登陆了,判断方式是看session里面是否有相关信息,如果有,则继续操作;如果没有,则要跳转到预先制定好的登录页面。

简单点说,登录检查应该写在“invocation.invoke();”语句之前。

       2)是否需要参数?

要判断是否需要参数,其实就是判断这个拦截器有没有什么可变的量,可以把这些可变量从程序中分离出来,通过struts.xml来配置。经过分析,可以抽出两个参数:

  • 代表登陆页面的Result
  • 判断session中哪个attribute,也就是attribute的名称

       3)如何引用呢?

现在的情况是只有部分Action需要登陆录检查,另外一些Action不需要,这就需要权衡了。对于大多数Action都要进行登录检查的包,可以在包的默认拦截器引用上设置登录检查,而对于少数不需要登陆检查的Action,可以让它们直接引用默认的defaultStack拦截器栈。

2:接下来,就来实现满足要求的拦截器,示例代码如下:

 

java代码:
  1. package cn.javass.action.action;  
  2.   
  3. import java.util.Map;  
  4. import com.opensymphony.xwork2.ActionContext;  
  5. import com.opensymphony.xwork2.ActionInvocation;  
  6. import com.opensymphony.xwork2.interceptor.Interceptor;  
  7.   
  8. public class SessionCheckInterceptor implements Interceptor{  
  9.     //设置参数  
  10.     private String sessionAttribute;  
  11.     private String reloginResult;  
  12.     public void setSessionAttribute(String sessionAttribute) {  
  13.         this.sessionAttribute = sessionAttribute;  
  14.     }  
  15.     public void setReloginResult(String reloginResult) {  
  16.         this.reloginResult = reloginResult;  
  17.     }  
  18.     public void destroy() { }  
  19.     public void init() {    }  
  20.     public String intercept(ActionInvocation invocation) throws Exception {  
  21.         //读取Session  
  22.         Map<String, Object> session = invocation.getInvocationContext().getSession();  
  23.         //判断Session中是否有相应的attribute  
  24.         if (session.containsKey(sessionAttribute)){  
  25.             String resultCode = invocation.invoke();  
  26.             return resultCode;  
  27.         }else{  
  28.             return reloginResult;  
  29.         }         
  30.     }  
  31. }  

在intercept方法中,先读取session中指定的attribute,具体读取哪个attribute由参数从外界传进来,然后判断Session中是否存在这个attribute,如果有则继续执行后续的拦截器、Action和Result,如果没有则跳转到指定的Result所对应的页面,具体跳转到哪个Result也是由参数从外界传进来的。

3:写好了拦截器,该来写配置了,配置示例如下:

 

java代码:
  1. <package name="helloworld"  extends="struts-default">  
  2.         <interceptors>  
  3.             <interceptor name="LoginChecker" class="cn.javass.action.action.SessionCheckInterceptor"/>  
  4.             <interceptor-stack name="myStack">  
  5.                 <interceptor-ref name="LoginChecker">  
  6.                     <param name="sessionAttribute">login_user</param>  
  7.                     <param name="reloginResult">login</param>  
  8.                 </interceptor-ref>  
  9.                 <interceptor-ref name="defaultStack"/>  
  10.             </interceptor-stack>  
  11.         </interceptors>  
  12.           
  13.         <default-interceptor-ref name="myStack"/>  
  14.           
  15.         <global-results>  
  16.             <result name="login">/login.jsp</result>  
  17.         </global-results>  
  18.                   
  19.         <action name="helloworldAction" class="cn.javass.action.action.HelloWorldAction">  
  20.             <result name="toWelcome">/s2impl/welcome.jsp</result>  
  21.         </action>  
  22.         <action name="secondAction" class="cn.javass.action.action.SecondAction">  
  23.             <result name="toWelcome">/s2impl/welcome.jsp</result>  
  24.             <interceptor-ref name="defaultStack"/>  
  25.         </action>  
  26. </package>  

配置比较多,分解说明一下:

(1)上面的配置声明了一个叫LoginChecker的自定义拦截器,如下:

 

java代码:
  1. <interceptor name="LoginChecker" class="cn.javass.action.action.SessionCheckInterceptor"/>  

2)声明了一个myStack拦截器栈,在这个栈里面引用了LoginChecker拦截器和defaultStack拦截器,在引用LoginChecker拦截器的时候,还传入了两个自定义的参数,其中sessionAttribute传入login_user,reloginResult传入login,以备在拦截器中使用,如下:

 

java代码:
  1. <interceptor-stack name="myStack">  
  2.                 <interceptor-ref name="LoginChecker">  
  3.                     <param name="sessionAttribute">login_user</param>  
  4.                     <param name="reloginResult">login</param>  
  5.                 </interceptor-ref>  
  6.                 <interceptor-ref name="defaultStack"/>  
  7.             </interceptor-stack>  

(3)将myStack拦截器栈指定为这个包的默认拦截器引用,如下:

 

java代码:
  1. <default-interceptor-ref name="myStack"/>  

(4)声明了一个全局Result,作为所有需要登录检查的Action在没有登陆的时候,跳转到的登陆页面。这个Result的命名,要与引用LoginChecker拦截器时注入的reloginResult参数一致,如下:

 

java代码:
  1. <global-results>  
  2.             <result name="login">/login.jsp</result>  
  3.         </global-results>  

(5)这时,在整个包中,没有自己声明<interceptor-ref>的Action,都会采用包声明的默认拦截器引用,比如已经可以对helloworldAction执行登录检查了。

       为了测试需要,对于secondAction,配置了引用defaultStack,这样它就不会进行登录检查。

(6)去测试看看,是否能满足功能要求。

 

私塾在线网站原创《研磨struts2》系列

转自请注明出处:【http://sishuok.com/forum/blogPost/list/0/4060.html

欢迎访问http://sishuok.com获取更多内容

猜你喜欢

转载自rubbing-struts2.iteye.com/blog/1510653