• 从struts2拦截器到自定义拦截器


    拦截器可谓struts2的核心了,最基本的bean的注入就是通过默认的拦截器实现的,一般在struts2.xml的配置中,package内直接或间接继承了struts-default.xml,这样struts2默认的拦截器就会作用.下面详细的说明一下:

    Interceptor拦截器类似于过滤器,是可以在action执行前后执行的代码。是我们做web开发时经常用的技术。比如:权限控制、日志等。我们也可以将多个Interceptor连在一起组成Interceptor栈。

    Struts2拦截器,每个拦截器类只有一个对象实例,即采用单例模式,所以引用这个拦截器的Action都共享这一拦截器类的实例,因此,在拦截器中如果使用类变量,要注意同步问题。

    实现原理 : Struts2拦截器的实现原理相对简单,当请求struts2的action时,Struts 2会查找配置文件,并根据其配置实例化相对应拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器。

    拦截器和过滤器的区别:

    1. 拦截器和过滤器的概念非常类似。 

    2. 过滤器隶属于web容器,可以过滤一切请求(包括action、servletjsphtml等等)。

    3. 而拦截器隶属于struts2框架,只能拦截action(无法拦截对jsp的请求)。 

    4. 过滤器内部采用函数回调来实现。拦截器采用动态代理来实现!

     

    拦截器在struts2中的应用:

     

     

    对于Struts2框架而言,正是大量的内置拦截器完成了大部分操作。比如: 

     

    – 像params拦截器将http请求中参数解析出来赋值给Action中对应的属性。 

     

    – Servlet-config拦截器负责把请求中HttpServletRequest实例和HttpServletResponse实例传递给Action

     

    – …

     

    struts-default.xml中有一个默认的引用,在默认情况下(也就是<action>中未引用拦截器时)会自动引用一些拦截器。

    常用拦截器:token

    作用:防止表单重复提交拦截器

    使用方法:配置struts2.xml+重复提交处理+jsp页面表单内插入<s:token></s:token>标签;其中struts.xml的配置是核心

    (1)先来看一下最基本的struts.xml的配置:

     

    1 <package name="test" namespace="/" extends="struts-default">
    2         <action name="testValidate" class="com.bjsxt.struts.test.TestValidateAction">
    3          <interceptor-ref name="token"></interceptor-ref>
    4              <result name="success">/ok.jsp</result>
    5              <result name="input">/testFormLabel.jsp</result>
    6              <result name="invalid.token">/tokenInvalid.jsp</result>
    7         </action>
    8 </package>

     

    说明:

    1.代码第三行代表引入一个struts2自带的拦截器token,此操作会使默认的拦截器失效,即无法使用其他功能,自定义拦截器再详细说明;

    2.代码第六行为基本固定的格式,result的name属性值是固定的,后面的/tokenInvalid.jsp可以根据需求自己定义

    3.此token拦截器会对该action下的所有请求作用,最关键的一点!即:所有该action的请求都会经过token的拦截处理,自定义拦截器时再说明;

    (2)form表单中需加入<s:token></s:token>标签:

    1 <s:form action="testValidate" >
    2         <s:textfield name="uname" ></s:textfield>
    3         <s:token></s:token>        
    4         <s:submit></s:submit>
    5 </s:form>    

    说明:不一定是s标签的表单,普通表单中插入<s:token></s:token>也可以实现拦截的效果.

    (3)处理措施,我的是跳到一个错误页面:testFormLabel.jsp

    1 <%@ page language="java" import="java.util.*" pageEncoding="gbk"%>
    2 <h1>表单不能重复提交!!</h1>

    --------------------------------------------------------------------------------------------------------------------------------------------------------

     自定义拦截器:

     

          作为“框架(framework)”,可扩展性是不可或缺的,因为世上没有放之四海而皆准的东西。虽然,Struts 2为我们提供如此丰富的拦截器实现,但是这并不意味我们失去创建自定义拦截器的能力,恰恰相反,在Struts 2自定义拦截器是相当容易的一件事。

          大家在开始着手创建自定义拦截器前,切记以下原则:
      拦截器必须是无状态的,不要使用在API提供的ActionInvocation之外的任何东西。要求拦截器是无状态的原因是Struts 2不能保证为每一个请求或者action创建一个实例,所    以如果拦截器带有状态,会引发并发问题。

     条件:

      1. 直接或间接实现接口com.opensymphony.xwork2.interceptor.Interceptor或者继承类com.opensymphony.xwork2.interceptor.AbstractInterceptor 

      2.通过<interceptor>元素来定义拦截器 

         3.通过<interceptor-ref>元素来使用拦截器

       4.自定拦截器的java类并重写public String intercept(ActionInvocation ai) throws Exception

    注意:如果为Action指定了一个拦截器,则系统默认的拦截器栈将会失去作用。为了继续使用默认拦截器,所以上面配置文件中手动引入了默认拦截器

     步骤:

      1.新建一个class,用于实现自定义拦截器功能,这儿就实现最为普遍的登陆验证,即防止未经登陆的情况下,访问action;先说一下原理:

      首先,用户登陆后,经过action验证用户名和密码是否正确,如果正确则在session作用域内存放user对象,否则跳到登陆页面并提示用户名或密码不正确,而且session作用域中user的值是没有设置的.然后,由于在该action下使用了自定义的拦截器(struts.xml配置),访问该action的所有请求都会被拦截,验证session中user属性的值,如果值不存在,则跳到登陆页面并提示无权操作,否则执行invoke方法,即请求会被action正常响应,并返回相应的结果.

    代码体现如下:

    自定义拦截器类:

     1 package com.bjsxt.struts2.exercise.interceptor;
     2 
     3 import java.util.Map;
     4 
     5 import com.bjsxt.struts2.exercise.vo.Users;
     6 import com.opensymphony.xwork2.Action;
     7 import com.opensymphony.xwork2.ActionContext;
     8 import com.opensymphony.xwork2.ActionInvocation;
     9 import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
    10 
    11 public class LoginInterceptor extends MethodFilterInterceptor{
    12     @Override
    13     protected String doIntercept(ActionInvocation invocation) throws Exception {
    14         //获取session对象(经过struts2包装过)
    15         Map session = ActionContext.getContext().getSession();
    16         //获取session作用域内是否有值
    17         Users user = (Users) session.get("user");
    18         if(user!=null){//合法访问
    19             return invocation.invoke();
    20         }else{//user为空说明未经过登陆,保存错误提示信息,跳到登陆页面
    21             ActionContext.getContext().put("noright", "请先登陆再进行操作!");
    22             return Action.LOGIN;
    23         }
    24     }
    25 }

    user类:

     1 package com.bjsxt.struts2.exercise.vo;
     2 
     3 public class Users {
     4     private Integer id;
     5     private String name;
     6     private String password;
     7     public Integer getId() {
     8         return id;
     9     }
    10     public void setId(Integer id) {
    11         this.id = id;
    12     }
    13     public String getName() {
    14         return name;
    15     }
    16     public void setName(String name) {
    17         this.name = name;
    18     }
    19     public String getPassword() {
    20         return password;
    21     }
    22     public void setPassword(String password) {
    23         this.password = password;
    24     }
    25 } 

    2.配置struts.xml,使自定义拦截器作用:

     1 <package name="move" namespace="/move" extends="struts-default">
     2         <interceptors>
     3             <interceptor name="loginInteceptor" class="com.bjsxt.struts2.exercise.interceptor.LoginInterceptor"></interceptor>
     4         </interceptors>
     5         <global-results>
     6             <result name="login" >/jsp/movebooking/login.jsp</result>
     7         </global-results>
     8         <action name="moveBookingAction" class="com.bjsxt.struts2.exercise.action.MoveBookingAction" >
     9             <interceptor-ref name="loginInteceptor">
    10                 <param name="excludeMethods">addMoveInfo</param>
    11             </interceptor-ref>
    12             <interceptor-ref name="token">
    13                 <param name="includeMethods">addMoveInfo</param>
    14             </interceptor-ref>
    15             <interceptor-ref name="defaultStack"></interceptor-ref>
    16             <result name="queryList" >/jsp/movebooking/movelist.jsp</result>
    17             <result name="queryInfo" >/jsp/movebooking/moveinfo.jsp</result>
    18             <result name="update" >/jsp/movebooking/updateinfo.jsp</result>
    19             <result name="afterupdate" type="redirectAction" >moveBookingAction!queryMoveList</result>
    20             <result name="success">/jsp/movebooking/success.jsp</result>
    21             <result name="invalid.token">/jsp/movebooking/tokenInvalid.jsp</result>
    22         </action>
    23         
    24         <action name="userAction" class="com.bjsxt.struts2.exercise.action.UserAction">
    25             <result name="success" type="redirectAction" >moveBookingAction!queryMoveList</result>
    26             <result name="failed" type="redirect">/jsp/movebooking/login.jsp
    27             </result>
    28         </action>
    29     </package>

    说明:

      (1)使用自定义拦截器会使默认拦截器失效,所以需要手动引入:代码第15行;当然上述代码引入拦截器的方式也可以采用拦截器栈的方式,就不贴了;

      (2)注意拦截器的顺序,一般情况下,默认拦截器都是放在最后面的,权限验证与token相比较,我觉得先验证是否登陆更加必要;

      (3)interceptor-ref内可以定义param元素,即实现对特定方法的拦截;但是注意,使用方法拦截器必须直接或间接实现AbstractInerceptor接口或者继承

    MethodFilterInterceptor类,并重写doIntercept方法.param标签内有两个属性:

          excludeMethods:排除的方法

          includeMethods:包含的方法

    在本配置文件中,由于token拦截器的作用范围为moveBookingAction下所有请求,而我在测试的时候就发现,该action下的所有请求都会被拦截到重复提交的错误页面,原理尚不明白,有高手敬请指导(只有需要被作用的请求对应的jsp页面的form表单内加入了token标签),所以被逼无奈对token拦截的方法只限定在addMoveInfo方法中!

     

    3.使用的action类和几个jsp页面:

    UserAction:

     1 package com.bjsxt.struts2.exercise.action;
     2 
     3 import com.bjsxt.struts2.exercise.service.UserService;
     4 import com.bjsxt.struts2.exercise.vo.Users;
     5 import com.opensymphony.xwork2.Action;
     6 import com.opensymphony.xwork2.ActionContext;
     7 import com.opensymphony.xwork2.ActionSupport;
     8 
     9 public class UserAction extends ActionSupport{
    10     private UserService userService  =new UserService();
    11     private Users user;
    12     public String queryUser() throws Exception{
    13         user = userService.queryUser(user);
    14 //        将user存到session中,实现拦截器拦截未经登陆直接请求的url的功能
    15         ActionContext.getContext().getSession().put("user", user);
    16         if(user!=null){
    17             return Action.SUCCESS;
    18         }else{
    19             ActionContext.getContext().getSession().put("wrong", "用户名或密码错误!");
    20             return "failed";
    21         }
    22     }
    23     
    24     public Users getUser() {
    25         return user;
    26     }
    27 
    28     public void setUser(Users user) {
    29         this.user = user;
    30     }
    31 
    32 }    

    MoveBookingAction:

     1 package com.bjsxt.struts2.exercise.action;
     2 
     3 import com.bjsxt.struts2.exercise.service.MoveBookingService;
     4 import com.bjsxt.struts2.exercise.util.MyPageUtil;
     5 import com.bjsxt.struts2.exercise.vo.MoveBookingVo;
     6 import com.opensymphony.xwork2.ActionSupport;
     7 
     8 public class MoveBookingAction extends ActionSupport{
     9     private MoveBookingService moveBookingService = new MoveBookingService();
    10     private MyPageUtil pu;
    11     private Integer pageNum;
    12     private MoveBookingVo moveBookingVo;
    13     private String[] phone;
    14     /**
    15      * 搬家列表
    16      * @return
    17      * @throws Exception
    18      */
    19     public String queryMoveList() throws Exception{
    20         pu = moveBookingService.queryMoveList(pageNum);
    21         return "queryList";
    22     }
    23     
    24     /**
    25      * 搬家信息详情
    26      * @return
    27      * @throws Exception
    28      */
    29     public String queryMoveInfo() throws Exception{
    30         moveBookingVo = moveBookingService.queryMoveInfo(moveBookingVo);
    31         return "queryInfo";
    32     }
    33     
    34     /**
    35      * 搬家详情,跳到update页面
    36      * @return
    37      * @throws Exception
    38      */
    39     public String queryForUpdate() throws Exception{
    40         moveBookingVo = moveBookingService.queryMoveInfo(moveBookingVo);
    41         return "update";
    42     }
    43     
    44     /**
    45      * 修改搬家信息
    46      * @return
    47      * @throws Exception
    48      */
    49     public String updateMoveInfo() throws Exception{
    50         moveBookingService.updateMoveInfo(moveBookingVo);
    51         return "afterupdate";
    52     }
    53     /**
    54      * 搬家预约
    55      * @return
    56      * @throws Exception
    57      */
    58     public String addMoveInfo() throws Exception{
    59         moveBookingVo.setStatus("0");
    60         moveBookingVo.setPhone(phone[0]+phone[1]);
    61         moveBookingService.addMoveInfo(moveBookingVo);
    62         return "success";
    63     }
    64     
    65     public MyPageUtil getPu() {
    66         return pu;
    67     }
    68     public void setPu(MyPageUtil pu) {
    69         this.pu = pu;
    70     }
    71     public Integer getPageNum() {
    72         return pageNum;
    73     }
    74     public void setPageNum(Integer pageNum) {
    75         this.pageNum = pageNum;
    76     }
    77     public MoveBookingVo getMoveBookingVo() {
    78         return moveBookingVo;
    79     }
    80     public void setMoveBookingVo(MoveBookingVo moveBookingVo) {
    81         this.moveBookingVo = moveBookingVo;
    82     }
    83 
    84     public String[] getPhone() {
    85         return phone;
    86     }
    87 
    88     public void setPhone(String[] phone) {
    89         this.phone = phone;
    90     }
    91 }

    login.jsp:

     1 <body>
     2           <font size="5"><b>管理员登陆</b></font><br>
     3           <form id="f1" action="move/userAction!queryUser">
     4               <input type="hidden" id="flag" name="flag" value="${flag }"/>
     5               用户名:
     6                   <input id="uname" name="user.name" onclick="clearMsg()" />
     7               密码:
     8                   <input id="pwd" type="password" name="user.password" onclick="clearMsg()" />
     9               <input type="button" style="background-color: lightgray; 100px;" value="登陆" onclick="submit_form()"/>
    10           </form>
    11           <div id="div" style="color: red">${wrong }${noright }</div>
    12   </body>

    tokenInvalid.jsp:

    1  <body>
    2     <h1>请勿重新提交</h1>
    3   </body>

     

     

     

  • 相关阅读:
    .NET Interop 工具集
    关于正弦波的算法
    Windows Phone 系列 本地数据存储
    Xaml cannot create an instance of “X”
    Windows Phone 系列 使用 MVVM绑定时无法获取当前值
    Windows Phone 系列 应用程序图标无法显示
    Windows Phone 系列 WPConnect无法上网的问题
    Windows Phone 系列 使用 Windows Phone 保存铃声任务
    WP7.5提交应用
    Windows Phone 系列 动态删除ObservableCollection
  • 原文地址:https://www.cnblogs.com/withyou/p/3170440.html
Copyright © 2020-2023  润新知