struts2拦截器的配置[转]

今天我们开始学习拦截器,虽然一直没有学习拦截器,但事实上我们已经使用拦截器很久了。
  
不知道大家还记不记得,在《Struts2之服务器端验证》里我说过这样一句话“在到达Login Action之前,验证已经完成了”。我很希望有人能提出这是为什么,这样我就可以说,这是拦截器的功劳,我们就可以研究拦截器了。可能大家都没有在意,或者提出了疑问,怕杨老师不知道,怪尴尬的^_^没关系的,不会我们可以一起学嘛。
  
其实,拦截器并不难,也不是十分难懂的东西。

打开帮助文档(struts-2.0.6//docs//docs//interceptors.html)的拦截器部分。
  
能读懂英文技术文档是程序员必备的基本素质之一,慢慢来吧,只要静下心来逐字逐句的推敲,没有什么理解不了的。实在看不懂,那就看看[Action Lifecyle]这张图吧。Action生命周期,Action被一些拦截器包围着,也就是说在Action执行之前或之后,拦截器会被执行。
  
这就是拦截器,把程序看作是一个顺序执行的流,在执行Action的代码之前或之后,拦截器会打断Action的执行,让程序先执行拦截器的代码,这也许就是为什么把它叫做拦截器的原因。有的时候,拦截器还会阻止Action的执行,比如说在验证失败的情况下,应该让程序返回到输入界面让用户重新输入。
  
从图上还可以看出,一个Action之外不是只有一个拦截器,那么先执行哪个拦截器呢?Struts2把多个拦截器放在了一个栈中,我们把它叫做拦截器栈。一方面,栈可以解决拦截器的执行顺序问题,另一方面,把相关的拦截器放在一个栈中,管理起来也比较方便。
  
Struts2的一个优点是它的可配置性,我们可以根据实际情况选择需要的功能。当然也给我们带来了一些麻烦,就拿拦截器来说吧,要想让拦截器起作用,先要对它进行配置。配置拦截器,需要在struts.xml中加入相关配置:
<package name="default" extends="struts-default">
     <interceptors>
         <interceptor name="timer" class=".."/>
         <interceptor name="logger" class=".."/>
     </interceptors>
     <action name="login"
        class="tutorial.Login">
          <interceptor-ref name="timer"/>
          <interceptor-ref name="logger"/>
           <result name="input">login.jsp</result>
           <result name="success"
              type="redirect-action">/secure/home</result>
     </action>
</package>
=====================================================================
<interceptors>和</interceptors>标记对表示要配置一些拦截器,里面的每一条是一个拦截器。

<interceptor name="timer" class=".."/>
interceptor表示这是一个拦截器,name属性是给它起一个名字,class属性是指出它的实现类,也是代码的实际位置。
  
拦截器是拦截Action的,当然也要在Action的配置里加入对它的引用,指出这个Action要使用哪个拦截器。

<interceptor-ref name="timer"/>这句话是告诉Struts框架,login Action需要使用前面的timer拦截器。
  
有人也许会说,我们之前并没有配置拦截器,但刚才好像说过,不是也使用到拦截器了么?的确,可能是Struts2的开发者怕配置起来太麻烦了,没有人用吧:P,所以给我预先配置好了一些默认的拦截器和拦截器栈。
  
在struts-default.xml(struts-default.xml在struts2-core-2.0.6.jar包中)里面定义了很多拦截器:
<interceptor name="alias" class="com.opensymphony.xwork.interceptor.AliasInterceptor"/>
......
里面的validation和i18n就是我们之前用的验证和国际化功能。
  
还有很多拦截器栈:
<!-- Basic stack -->
<interceptor-stack name="basicStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="servlet-config"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="static-params"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
</interceptor-stack>
...
<interceptor-stack name="defaultStack">
      <interceptor-ref name="exception"/>
      <interceptor-ref name="alias"/>
      <interceptor-ref name="prepare"/>
      <interceptor-ref name="servlet-config"/>
      <interceptor-ref name="i18n"/>
      <interceptor-ref name="chain"/>
      <interceptor-ref name="model-driven"/>
      <interceptor-ref name="fileUpload"/>
      <interceptor-ref name="static-params"/>
      <interceptor-ref name="params"/>
      <interceptor-ref name="conversionError"/>
      <interceptor-ref name="validation"/>
      <interceptor-ref name="workflow"/>
</interceptor-stack>

<default-interceptor-ref name="defaultStack"/>
最后这条比较主要,是框架默认使用的拦截器栈,也就是说,defaultStack栈中的拦截器会默认起作用。

这也是我们没有配置validation和i18n,它们就起作用的原因。
  
顺便说一下,拦截器应该属于AOP(面向方面编程)思想的一种实现,它的确给开发带来了很多好处,一方面可以把一个大的问题分解成多个小问题分别处理,另一方面可以使Action专注与处理自己的事情,把相关的功能分散给各个拦截器处理。

在《Struts2之服务器端验证》中我们详细讨论了关于登陆验证的问题,只有通过登陆验证,拿到令牌的用户才能进入我们的系统。为此我们建立了登陆验证页面和相应的Action类,登陆验证(Login.jsp)负责提供给用户输入帐号和密码的机会,Login Action负责验证用户输入的帐号和密码是否正确,验证通过的情况下把帐号和密码保存到Session中,就相当于用户拿到了一块令牌,就是一个合法用户了。
  
我们的目的是限制非法用户,也就是没有拿到令牌的用户,不能访问我们的系统。但是我们只进行了登陆验证和保存令牌的工作,并没有做限制非法用户的工作。现在不守规矩的用户就可以直接在浏览器的地址栏里输入:http://localhost:8080/Success.jsp
访问我们的Success.jsp页面,这当然是不能容忍的。
  
在没有学习拦截器之前,我们当然可以在Success.jsp页面里加代码进行限制,先从Session中取出用户名和密码,如果取到了则说明用户已经登陆系统了,否则让浏览器显示Login.jsp让用户登陆系统,这样做一点问题也没有,就相当于我们在每一个房间门口都安排了一个检查令牌的人一样,万无一失。不过,如果系统的受限制资源多起来的时候,比如说像Success.jsp或Action很多,几十个,几百个的时候,这样的代码我们就要写很多遍,这当然也是聪明的我们所不能容忍的:P
  
显然,让拦截器来做这项工作再合适不过了。我们可以添加一个拦截器,让它在这些受限制的资源被执行之前先运行,在拦截器里我们检查用户是否登陆了系统,如果登陆了才让他们访问,否则送给用户一个Login.jsp让用户登陆。这样我们的检查代码只需要写一次就一劳永逸了。
  
明白了原理之后还需要做几项具体的工作:
1,自己写一个拦截器,实现检查用户是否登陆的功能。
2,添加拦截器的配置,让我们自己写的拦截器起作用。
  
首先我们来完成第一个任务,打开:
struts-2.0.6docsdocsguides.html里面的
struts-2.0.6docsdocswriting-interceptors.html帮助。
从这个帮助里我们可以看出,拦截器必须实现com.opensymphony.xwork2.interceptor.Interceptor接口。根据经验,init()方法应该是初始化拦截器的方法,可以把一些初始化工作的代码放在它里面,destroy()方法与之相反,在拦截器被销毁之前,让我们有机会执行一些善后工作。

显然intercept()方法,是添加真正执行拦截工作的代码的地方,如果我们不需要初始化和清理的操作,可以直接继承com.opensymphony.xwork2.interceptor.AbstractInterceptor类,覆盖它的intercept()方法。这个方法有个ActionInvocation类型的参数,可以用它取得Session或转发请求等操作。
  
先在src下建立一个包:tutorial.interceptor
在这个包下建立一个类LogonInterceptor继承于AbstractInterceptor,覆盖intercept()方法:
/**
* 工程: tutorial
* 文件: LogonInterceptor.java
* 包:    tutorial.interceptor
* 单位: 新东方一搏职业教育培训中心
* 版权: Copyright (c) 2007 NIT-PRO
* 版本: 1.0
* 变更历史: Jun 24, 2007 11:51:07 PM (coombe) 创建
*/
package tutorial.interceptor;
import java.util.Map;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
/**
* 登陆验证拦截器,如果用户没有登陆系统则让用户到登陆验证页面进行登陆
* 当用户请求网站资源的时候,例如某个Action,在Action被执行之前,检
* 查用户是否登陆了系统.
* 不足之处是该拦截器只能拦截Action,不能拦截jsp和servlet,所以不能
* 完全限制用户对未授权资源的访问,可以配合filter或将jsp页面放在
* WEB-INF目录下解决这个问题.
*
* @author coombe
*/
public class LogonInterceptor extends AbstractInterceptor {
      public String intercept(ActionInvocation invocation) throws Exception {
          // 取得请求的Action名
          String    name = invocation.getInvocationContext().getName();
  
          if (name.equals("Login")) {
              // 如果用户想登录,则使之通过
              return invocation.invoke();
          } else {
              // 取得Session。
              ActionContext ac = invocation.getInvocationContext();
              Map session =    (Map)ac.get(ServletActionContext.SESSION);
   
              if (session == null) {
                  // 如果Session为空,则让用户登陆。
                  return "login";
              } else {
                  String username = (String)session.get("username");
                  if (username == null) {
                      // Session不为空,但Session中没有用户信息,
                      // 则让用户登陆
                      return "login";
                  } else {
                      // 用户已经登陆,放行~
                      return invocation.invoke();
                  }
              }
          }
      }
}

今天的内容有点多,接下来还要对这个拦截器进行配置:
关于怎样配置一个拦截器使之对所有的Action起作用请参考:
struts-2.0.6docsdocshow-do-we-configure-an-interceptor-to-be-used-with-every-action.html
修改struts.xml,
1,自定义拦截器
2,重定义默认拦截器堆栈
3,添加一个global-results,用户在验证失败的情况下跳转到登陆验证页面
struts.xml的完整内容:
<!DOCTYPE struts PUBLIC
      "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
      "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts><!-- Configuration for the default package. -->
<constant name="struts.custom.i18n.resources" value="globalMessages" />

<include file="struts-validation.xml" />
<package name="default" extends="struts-default">
  
    <!-- 自定义拦截器 -->
    <interceptors>
     <interceptor name="logon" class="tutorial.interceptor.LogonInterceptor"/>
        <!-- 自定义拦截器堆栈 -->
        <interceptor-stack name="myStack">
        <interceptor-ref name="logon"/>
        <!-- 引用默认的拦截器堆栈

      如果不用defaultStack,则表单值将会被页面跳转后返回-->
        <interceptor-ref name="defaultStack"/>
     </interceptor-stack>
    </interceptors>
  
    <!-- 重定义默认拦截器堆栈 -->
    <default-interceptor-ref name="myStack"/>
  
    <global-results>
     <result name="login" type="redirect-action">Login!input.action</result>
    </global-results>
  
        <action name="HelloWorld" class="tutorial.HelloWorld">
               <result>/HelloWorld.jsp</result>
           </action>
         
           <action name="Login" class="tutorial.Login">
              <result>/Success.jsp</result>
              <result name="input">/Login.jsp</result>
           </action>  
</package>
</struts>
  
保存修改并布署项目到Tomcat下,启动Tomcat
在浏览器的地址栏中输入:
http://localhost:8080/tutorial/HelloWorld.action
系统会自动转到Login页面。
  
当然,现在只能限制未授权用户访问Action,不能限制用户非法访问jsp文件~
Struts2的拦截器实际上还是使用了filter的功能,当然可以直接使用filter
解决这个问题,不过如果使用了filter,我又何必使用拦截器呢-_-

 

 

转自:http://chinajava.blog.tom.com,感谢原创作者。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值