• 7.Struts2拦截器及源码分析


    1.Struts2架构图

    2.Struts2 执行过程分析

      1.首先,因为使用 struts2 框架,请求被Struts2Filter 拦截

      2.Struts2Filter  调用 DisPatcher 的 serviceAction 方法

      3.在serviceAction 中,创建 ActionProxy对象,并调用其execute方法

      4.在ActionProxy的execute中,调用ActionInvocation的invoke方法,ActionInvocation对象中包含了众多的拦截器(ExceptionInterceptor等)

      5.ActionInvocation的invoke方法 会调用这些拦截器的intercept方法,

       每一个intercept方法都会回过头调用之前的ActionInvocation对象的invoke方法

      6.再次调用这个invkoe,会继续调用下一个拦截器,直到所有的拦截器都被调用一遍后,没有下一个拦截器了,此时就会调用Action的execute方法了

      7.调用了Action中的方法后,此时最后一个拦截器的invoke方法完成调用,

       最后一个拦截器执行invoke方法之后的代码,然后一直迭代回去,第一个拦截器的invoke方法也调用完毕

      8.所有的拦截器的intercept方法 结束后,ActionInvocation的invoke方法也结束,最后形成响应回去

     注:类似于 Filter 拦截WEB资源时的这种关系,doFileter方法和chain方法    

     调用chain方法时,会先看下后面是否还有Filter注册了,如果有,先执行后面Filter的 doFileter方法,等到判断到后面没有Filter了,

     最后一个Filter的chain方法才能被执行,最后一个Filter全部都执行完成之后,才会回调之前的Filter

     /*这种形式也有点类似AOP的感觉,一个又一个的拦截器,就是一个又一个的切面*/

    3.Interceptor 拦截过程模拟

     1 public class ActionInvocation {
     2     List<Interceptor> interceptors = new ArrayList<Interceptor>();
     3     Action a = new Action();
     4     int index = -1;
     5     
     6     public ActionInvocation() {
     7         this.interceptors.add(new FirstInterceptor());
     8         this.interceptors.add(new SecondInterceptor());
     9     }
    10     
    11     public void invoke() {
    12         index++;
    13         if(index >= this.interceptors.size()) {
    14             a.execute();
    15         }
    16         else {
    17             this.interceptors.get(index).interceptor(this);
    18         }
    19     }
    20 
    21 }

    4.定义自己的拦截器(一般没有必要去定义自己的拦截器,常见的拦截器通常已经做好了)

      1.编写拦截器(实现Interceptor接口)

     1 public class MyInterceptor implements Interceptor {
     2 
     3     public void destroy() {
     4         // TODO Auto-generated method stub
     5         
     6     }
     7 
     8     public void init() {
     9         // TODO Auto-generated method stub
    10         
    11     }
    12 
    13     public String intercept(ActionInvocation arg0) throws Exception {
    14         long t1 = System.currentTimeMillis();
    15         String r = arg0.invoke();
    16         long t2 = System.currentTimeMillis();
    17         System.out.println("time="+(t2-t1));
    18         return r;
    19     }
    20 
    21 }

      2.在struts.xml中注册(使用 interceptors标签 声明拦截器)<interceptor-ref>(使用这个拦截器)

     1 <package name="test" namespace="/" extends="struts-default">
     2         <interceptors>
     3             <interceptor name="my" class="com.bjsxt.interceptor.MyInterceptor"></interceptor>
     4         </interceptors>
     5 
     6 
     7         <action name="test" class="com.bjsxt.action.TestAction">
     8             <result>/test.jsp</result>
     9             <!-- 自定义拦截器在默认拦截器的前面,是为了先执行自定义拦截器,不然自定义拦截器 结束的会很快 -->
    10             <interceptor-ref name="my"></interceptor-ref>
    11             <!-- 这里必须要加上默认拦截器,不然自定义拦截器会把默认拦截器覆盖 -->
    12             <interceptor-ref name="defaultStack"></interceptor-ref>
    13         </action>
    14 </package>

    5.使用token拦截器(防止表单重复提交)(很少用 有其他方式)

      1.在form 表单中添加<s:token></s:token> (作用,生成一个唯一的识别码,用于验证是否重复提交)

      2.在struts.xml中添加 <result name="invalid.token">/error.jsp</result> (至于为什么是 'invalid.token',可以查看struts-default.xml)

                    <interceptor-ref name="token"></interceptor-ref>

    过程:1.使用token拦截器 会在服务器端生成一个 唯一标识码
       2.客户端通过 <s:token></s:token> 发送 标识码过来 和服务器端的进行对比,对比完成后,这个唯一标识码会删除,
         重复提交时,客户端再发送 标识码 ,服务端已经没有了,返回结果 'invalid.token'

    6.认识默认的拦截器(servletConfig)

    作用:取得Map类型request,session,application 等

    1.在Action中,让Action实现RequestAware,SessionAware,ApplicationAware 这种接口,

    2.实现这些接口,需要重写一些方法,如setRequest(Map<String, Object> request)

    这个过程的实现,就是通过  ServletConfigInterceptor  这个拦截器 实现的

    7.类型转换

      1.默认转换

        (将前台提交的String 类型的数据 转换成如int,List,Set(interests=math&interests=history),

         数组,Map(users['a']=usera&users['b']=userb))

        如果想转换成日期类型,需符合输入规范,也可以通过<s:date> 标签用指定的格式显示 日期

        http://localhost:8080/struts2_37_type_conversion/test?name=xzk&age=21&d=1996-07-29&interests=math&interests=history&users[%27a%27]=usera&users[%27b%27]=userb

      2.写自己的转换器

     1 public class MyPointConverter extends StrutsTypeConverter{
     2 
     3     @Override
     4     public Object convertFromString(Map context, String[] values, Class toClass) {
     5         
     6             Point p = new Point();
     7             String[] strs = (String[])values;
     8             String[] xy = strs[0].split(",");
     9             p.x = Integer.parseInt(xy[0]);
    10             p.y = Integer.parseInt(xy[1]);
    11             return p;    
    12     }
    13 
    14     @Override
    15     public String convertToString(Map context, Object o) {
    16         // TODO Auto-generated method stub
    17         return o.toString();
    18     }
    19 
    20 }

      3.三种注册方式(写好自己的转换器后,还需要完成注册)

        a) 局部(将注册文件(XXXAction-conversion.properties)放到和Action同级下)

        b) 全局:xwork-conversion.properties

           java.awt.Point=com.bjsxt.converter.MyPointConverter

        c) Annotation (注解)

    http://localhost:8080/struts2_37_type_conversion/test?p=2,3&ps=2,3&ps=3,4&points[%27a%27]=2,3&points[%27b%27]=3,4

  • 相关阅读:
    POJ3061(尺取法)
    POJ2739(尺取法)
    HDOJ4763(KMP原理理解)
    HDOJ5521(巧妙构建完全图)
    UVALive7261(2015ACM/ICPC北京赛区现场赛A)
    POJ1745动态规划
    POJ1273(最大流入门)
    HDOJ5883(欧拉路)
    HDOJ5437(优先队列)
    HDOJ5875(线段树)
  • 原文地址:https://www.cnblogs.com/xuzekun/p/7383006.html
Copyright © 2020-2023  润新知