• 从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>

     

     

     

  • 相关阅读:
    vue使用CDN全局安装百度地图
    vue cli3使用webpack4打包优化
    vue使用axios提交formdata格式的数据
    windows、linux使用查看、杀死进程
    分离vue文件,方便后期维护
    vue:使用element-ui制作动态表格
    《从0到1学习Flink》—— Data Sink 介绍
    《从0到1学习Flink》—— Mac 上搭建 Flink 1.6.0 环境并构建运行简单程序入门
    《从0到1学习Flink》—— Flink 配置文件详解
    《从0到1学习Flink》—— Flink Data transformation(转换)
  • 原文地址:https://www.cnblogs.com/withyou/p/3170440.html
Copyright © 2020-2023  润新知