你好,游客 登录 注册 搜索
背景:
阅读新闻

Struts2 拦截器配置以及实现

[日期:2017-06-26] 来源:Linux社区  作者:jabnih [字体: ]

@(Java ThirdParty)[Struts|Interceptor]

Struts2 拦截器配置以及实现

Struts2的拦截器应用于Action,可以在执行Action的方法之前,之后或者两者。用于处理一些公共的方法,而不影响原有的代码,并且使得可以关注功能的实现,分离关注点。比如防止重复提交等。
如下图(图片来自Struts2文档Interceptor章节):

拦截器配置

注:以下配置均来自于Struts2官方的例子
Struts2内置了一些拦截器,也可以通过实现Interceptor接口来自定义拦截器。


如下,在struts.xml中配置自定义拦截器以及引用定义的拦截器:

<package name="default" extends="struts-default">
   <interceptors>
       <interceptor name="timer" class=".."/>
   </interceptors>
 
   <action name="login"
      class="tutorial.Login">
        <interceptor-ref name="timer"/>
         <result name="input">login.jsp</result>
   </action>
</package>

如果定义多个拦截器,像上面那样一个个引用显然是很费劲的,这里可以将多个打包为一个拦截器栈,直接引用该拦截器栈即可:

<package name="default" extends="struts-default">
   <interceptors>
        <interceptor name="timer" class=".."/>
        <interceptor name="logger" class=".."/>
        <interceptor-stack name="myStack">
           <interceptor-ref name="timer"/>
           <interceptor-ref name="logger"/>
        </interceptor-stack>
    </interceptors>
 
    <action name="login"
         class="tutuorial.Login">
             <interceptor-ref name="myStack"/>
             <result name="input">login.jsp</result>
    </action>
</package>

Struts2 拦截器实现

在先介绍Struts2拦截器实现时,需要先介绍一个设计模式,拦截过滤器,Struts2采用了该设计模式来实现,文档中注解了说明是使用Command设计模式,但是我觉得用Intercepting filter来理解比较好理解。

Intercepting filter pattern

在wiki中Intercepting Filter定义为:JavaEE设计模式,用于创建可插拔式过滤器,用于处理通用的服务,而不需要改变和兴请求的处理代码。这涉及了四个组件:Filter Manager,Filter chain,Filters,Target。如下:
在下图,可以看成FilterManager维护着一系列的Filter,并且知道Target,这里可以实现为:FilterManager内部维护一个List<Filter>,该List作为Filter Chain。
注:图片来自Wiki

处理流程如下:
注:图片来自Wiki

Struts2 拦截器实现

Struts2中DefaultActionInvocation可以看做一个FilterManager,其中有Iterator<InterceptorMapping>,可以看做FilterChain,即包含了所有需要拦截该Action的Interceptor,其中Object action为真正的Target。如下图:

Interceptor接口:

public interface Interceptor extends Serializable {
    void destroy();
    void init();
    String intercept(ActionInvocation invocation) throws Exception;
}

主要执行流程在DefaultActionInvocation.invoke方法中,该方法用递归来实现链式调用(和Tomcat中实现FIlter一样):

public String invoke() throws Exception {
        // 省略了部分代码...

        // 如果还有Interceptor,则继续(递归条件)
        if (interceptors.hasNext()) {
            try {
                // 获取拦截器,并将当前对象传递给拦截器,由拦截器决定是要需要继续执行,例如:invocation.invoke(),如果执行了,则继续递归,直到执行完所有的拦截器,如果没有调用该方法,即拦截了,则这里就终止递归了。
                resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
            }
            finally {
                UtilTimerStack.pop(interceptorMsg);
            }
        } else {
            // 只有执行完所有拦截器,才执行Action的方法
            resultCode = invokeActionOnly();
        }
    
}

Tomcat Filter实现

Tomcat中Filter的实现和上面差不多,不过其中的类名和概念的名称比较匹配。如下:

ApplicationDispatcher通过使用FilterChain来实现Filter链式调用。
其中ApplicationFIlterChain.internalDoFilter为核心的代码:

private void internalDoFilter(ServletRequest request, 
                              ServletResponse response)
    throws IOException, ServletException {

    // 通过pos来记录当前执行的Filter,只有到所有Filter执行完(递归终止条件之一)
    if (pos < n) {
        ApplicationFilterConfig filterConfig = filters[pos++];
        Filter filter = null;
        try {
            filter = filterConfig.getFilter();

            if (request.isAsyncSupported() && "false".equalsIgnoreCase(
                    filterConfig.getFilterDef().getAsyncSupported())) {
            // ...
                
            } else {  
                // Filter.doFilter,通过传入当前对象,来实现递归调用,将控制权传递给Filter,由Filter来决定是否需要继续执行下去
                filter.doFilter(request, response, this);
            }

        return;
    }
    
    try {

        if ((request instanceof HttpServletRequest) &&
            (response instanceof HttpServletResponse)) {
                
            if( Globals.IS_SECURITY_ENABLED ) {
                // ... 
            } else {  
                // 执行Target真正的方法
                servlet.service(request, response);
            }
        } else {
            servlet.service(request, response);
        }
   }
   // ...
}

参考文档:

Wiki:
https://en.wikipedia.org/wiki/Intercepting_filter_pattern
https://en.wikipedia.org/wiki/Interceptor_pattern
官方文档:
http://struts.apache.org/docs/interceptors.html

推荐阅读:

Struts中异步传送XML和JSON类型的数据 http://www.linuxidc.com/Linux/2013-08/88247.htm

Struts2的入门实例 http://www.linuxidc.com/Linux/2013-05/84618.htm

Struts2学习笔记-Value Stack(值栈)和OGNL表达式  http://www.linuxidc.com/Linux/2015-07/120529.htm 

struts2文件上传(保存为BLOB格式) http://www.linuxidc.com/Linux/2014-06/102905.htm

在Struts2中使用ModelDriven action http://www.linuxidc.com/Linux/2017-03/141203.htm

Struts2拦截器浅解  http://www.linuxidc.com/Linux/2017-03/141473.htm

Struts2数据验证机制  http://www.linuxidc.com/Linux/2016-10/135995.htm

struts2简单示例 http://www.linuxidc.com/Linux/2016-11/137146.htm

Struts2绑定对象数组  http://www.linuxidc.com/Linux/2017-01/139080.htm

Struts2 s:if标签以及 #,%{},%{#}的使用方法  http://www.linuxidc.com/Linux/2016-11/137188.htm

Struts 的详细介绍请点这里
Struts 的下载地址请点这里

本文永久更新链接地址http://www.linuxidc.com/Linux/2017-06/145200.htm

linux
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数

       

评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款