J2EE中的过滤器和拦截器

过滤器和拦截器的相似之处就是拦截请求,做一些预处理或者后处理。

而过滤器和拦截器的区别在于过滤器是相对HTTP请求而言的,而拦截器是相对Action中的方法的。

过滤器:访问web服务器的时候,对一个请求,我们可以设置请求编码,设置请求参数,设置其是否能访问某个页面,设置相应编码等。

拦截器:访问web服务器的时候,在你调用的方法前做一个拦截,加上我想要的任意操作。比喻记录操作日志,加上某个特定业务(AOP)。

1、过滤器

过滤器需要做两部分的工作:Filter过滤类、web.xml配置

Filter类部分:

package com.chanshuyi.servlet;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
//import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;

/**
 * Test Servlet Filter
 * @author chenyr
 */
//@WebFilter(filterName = "myfilter", urlPatterns = {"/*.*"})
//你可以通过这段注释来声明这个Filter,从而不用在web.xml文件中配置,但你用的Servlet版本必须是3.0以上
public class MyServletFilter implements Filter {
    
    /** Filter Config Info **/
    private FilterConfig config;
    
    public void init(FilterConfig config) throws ServletException {
        this.config = config;
    }

    public void destroy() {
        this.config = null;
    }

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        //-------- Preprocess --------
        long before =  System.currentTimeMillis();
        System.out.println("Begin filtering...");
        HttpServletRequest hrequest = (HttpServletRequest)request;
        System.out.println("Intercept the user request address:" + hrequest.getServletPath());
        
        //-------- Do the Servlet --------
        chain.doFilter(request, response);
        
        //-------- afterprocess --------
        long after = System.currentTimeMillis();
        System.out.println("End filtering...");
        System.out.println("Redirect To:" + hrequest.getRequestURI() + "  Time Cost:" + (after - before));
    }
}

web.xml部分:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  <filter>
          <filter-name>myfilter</filter-name>
          <filter-class>com.chanshuyi.servlet.MyServletFilter</filter-class>
  </filter>
  
  <filter-mapping>
          <filter-name>myfilter</filter-name>
          <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

2、拦截器

Struts的拦截器本质上还是通过过滤器来实现的。

拦截器实现需要做两部分的工作:Interceptor过滤类、struts.xml配置

拦截器类:

package com.chanshuyi.interceptor;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

@SuppressWarnings("serial")
public class MyInterceptor extends AbstractInterceptor {
    
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        
        //get the target action
        //LoginAction action = (LoginAction)invocation.getAction();
        System.out.println(name + "Interceptor begin to work ...");
        long startMill = System.currentTimeMillis();
        
        //execute the target action method
        String result = invocation.invoke();
        
        long endMill = System.currentTimeMillis();
        System.out.println(name + "Interceptor ends, time cost:" + (endMill - startMill));
        System.out.println("result is : " + result);
        
        return result;
    }
}

你可以通过实现Interceptor接口来实现拦截器。但是Java为我们提供了AbstractInterceptor类,通过实现AbstractInterceptor类可以让我们减少编码(因为AbstractInterceptor已经帮我们实现了init()/destory()方法,我们只需再实现interceptor方法即可)

struts.xml配置部分:

<struts>
    <package name="default" namespace="/" extends="struts-default">
        <interceptors>
            <interceptor name="loginInter" class="com.chanshuyi.interceptor.MyInterceptor">
                <param name="name">[默认的拦截器名字]</param>
            </interceptor>
        </interceptors>
    
        <action name="login" class="com.chanshuyi.action.LoginAction" method="execute">
            <result name="success">/hello.jsp</result>
            <result name="login">/hello.jsp</result>
            
            <interceptor-ref name="defaultStack"/>
            <interceptor-ref name="loginInter">
                <param name="name">[修改后的拦截器名字]</param>
            </interceptor-ref>
        </action>
    </package>
</struts>

MARK CHENYR (这里需要补充)

3、只拦截部分Action部分方法的拦截器

通过继承AbstractInterceptor的子类:MethodFilterInterceptor类,可以实现对Action中方法级的过滤。

它与继承AbstractInterceptor实现过滤在代码上的不同在于:

1).需要继承的是MethodFilterInterceptor类

2).需要实现的是doInterceptor方法,而不是interceptor方法

3).可以通过setExcludeMethod/setIncludeMethod方法或配置文件的方式实现方法的过滤

拦截器部分代码(将intercept方法换成doIntercept即可):

@SuppressWarnings("serial")
public class CopyOfMyInterceptor extends MethodFilterInterceptor {
    
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String doIntercept(ActionInvocation invocation) throws Exception {
        
        //get the target action
        //LoginAction action = (LoginAction)invocation.getAction();
        System.out.println(name + "Interceptor begin to work ...");
        long startMill = System.currentTimeMillis();

     //直接调用setExcludeMethod/setIncludeMethod方法给excludeMethod/includeMethod属性赋值。这与用配置文件赋值是一样的
        
        //execute the target action method
        String result = invocation.invoke();
        
        long endMill = System.currentTimeMillis();
        System.out.println(name + "Interceptor ends, time cost:" + (endMill - startMill));
        System.out.println("result is : " + result);
        
        return result;
    }
}

通过配置文件实现对方法的过滤:

<struts>
    <package name="default" namespace="/" extends="struts-default">
          <interceptors>
            <interceptor name="loginInter" class="com.chanshuyi.interceptor.MyInterceptor">
                <param name="name">[默认的拦截器名字]</param>
            </interceptor>
        </interceptors>

        <action name="login" class="com.chanshuyi.action.LoginAction" method="execute">
                <result name="success">/hello.jsp</result>
                <result name="login">/hello.jsp</result>
            
                <interceptor-ref name="defaultStack"/>
                <interceptor-ref name="loginInter">
                    <param name="name">[修改后的拦截器名字]</param>
                    <!-- 多个方法用英文逗号隔开 -->
                    <param name="excludeMethods">execute</param>                
       <!-- 通过配置文件赋值,本质上是给继承了MethodFilterInterceptor的CopyOfMyInterceptor类的excludeMethods属性复制。所以你也可以不在这里复制,而直接在CopyOfMyInterceptor类中用setExcludedMethod/setIncludeMethod赋值 -->
                </interceptor-ref>
     </action>
  </package>
</struts>

4、关于过滤器和拦截器的执行顺序

在一般情况下,过滤器和拦截器都是先配置先执行的。

下面用过滤器的一个例子说明:

web.xml部分代码:

<!-- 第一个过滤器 -->
<filter>
    <filter-name>filter1</filter-name>
    <filter-class>filter.Filter1</filter-class>
</filter>
<filter-mapping>
    <filter-name>filter1</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 第二个过滤器 -->
<filter>
    <filter-name>filter2</filter-name>
    <filter-class>filter.Filter2</filter-class>
</filter>
<filter-mapping>
    <filter-name>filter2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Filter1类的关键代码:

public void doFilter(ServletRequest request, ServletResponse response,
		  FilterChain chain) throws IOException, ServletException {
		 try {
			 System.out.println("filter1");
			  chain.doFilter(request, response);
			  System.out.println("filter1   go back");
		 } catch (Exception e) {
		  e.printStackTrace();
		}
}

Filter2类与Filter1类一样,只是输出内容变成了“filter2”以及“filter2   go back”。

运行结果为:

filter1
filter2
filter2   go back
filter1  go back

可以看出,过滤器和拦截器的执行顺序是先定义先执行,并且执行是类似于堆栈的先进后出的执行顺序。  

5、关于过滤器和拦截器的思考

在说拦截器和过滤器之前,先说这两者的几点区别:

1.过滤器可以对所有HTTP请求进行拦截,但拦截器只能对Action请求进行拦截

2.过滤器是Servlet中的概念,拦截器是Struts中的概念

在Struts还没有出来的时候,拦截器这个概念是不存在的。在Struts出来之后,拦截器也来了。拦截器是通过Servlet来实现的,拦截器对过滤器进行了一层封装,使Struts框架更加好用。

在使用了Struts框架的项目中,更多人直接使用拦截器,过滤器的概念就被弱化了。这是我的一些理解。因此在使用了Struts的项目中,你可以直接使用拦截器对所有Action请求进行拦截,对他们进行权限控制。

但拦截器不能拦截直接访问的页面,那这些页面如何保障权限的控制呢?答案是将页面房在WEB-INF目录下(WEB-INF目录下的文件不能通过客户端直接访问),只将少数必要的文件放在Web-Root目录,这样就可以实现这些页面的安全。

总的来说,如果你的项目使用了Struts,那么你可以直接用Struts的拦截器实现权限控制等。

但如果你的项目是用纯Servlet写的,那么你只能用过滤器实现了。

===================== 相信美好的事情终会发生 ====================

struts.xml文件中拦截器配置集锦

<!-- 配置拦截器 -->
<interceptor name="interceptor1" class="classRoute"/>
<interceptor name="interceptor1" class="classRoute">
<param name="paraName">Param Value</param>
</interceptor>
<!-- 拦截器栈 -->
<interceptor-stack name="stackName">
<interceptor name="interceptor1" class="classRoute"/>
<interceptor-ref name="interceptorName">
<param name="paraName">Param Value</param>
</interceptor-ref>
</interceptor-stack>
<!-- 使用拦截器 -->
<action name="" class="" method="">
<result>...</result>
<!-- 一定要加上Struts的默认拦截器 -->
<interceptor-ref name="defaultStack"/>
<!-- 使用自己的拦截器 -->
<interceptor-ref name="myInterceptor"/>
</action>
<!-- 设置默认拦截器 -->
<package>
<interceptors>...</interceptors>
<!-- 设置默认拦截器 -->
<default-interceptor-ref name=""></default-interceptor-ref>
<action>...</action>
</package>

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏JackieZheng

RabbitMQ入门-Routing直连模式

Hello World模式,告诉我们如何一对一发送和接收消息; Work模式,告诉我们如何多管齐下高效的消费消息; Publish/Subscribe模式,告...

27410
来自专栏ChaMd5安全团队

CryptoShield勒索病毒分析

这篇文章主要分析一下Cryptoshield,来自于RITEST RIG EK的一个勒索病毒。病毒样本可以从这里得到: http://www.malware-t...

3785
来自专栏信安之路

pydictor 爆破字典生成指南

pydictor 是一个使用 python 语言开发,遵循 GPLv3 协议的开源命令行工具,主要用来帮助安全研究人员生成称心如意的暴力破解字典。

2680
来自专栏雨尘分享

2018 - iOS 面试题汇总一般面试题BAT面试题

4.3K3
来自专栏技术博客

Asp.Net Web API 2第十一课——在Web API中使用Dependency Resolver

阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.h...

1084
来自专栏信安之路

CTF 玩转 pwn 月度总结

自从加入 RTIS 交流群, 在 7o8v 师傅, gd 大佬 的帮助下, PWN 学习之路进入加速度. 下面是 8 周学习的总结, 基本上是按照how2hea...

1820
来自专栏扎心了老铁

django中间件Middleware

熟悉web开发的同学对hook钩子肯定不陌生,通过钩子可以方便的实现一些触发和回调,并且做一些过滤和拦截。 django中的中间件(middleware)就是类...

4037
来自专栏JavaEdge

Java并发编程实战系列10之避免活跃性危险

10.1 死锁 哲学家问题 有环 A等B,B等A 数据库往往可以检测和解决死锁//TODO JVM不行,一旦死锁只有停止重启。 下面分别介绍了几种典型的死锁情况...

3625
来自专栏Linux驱动

19.QT-事件发送函数sendEvent()、postEvent()

1043
来自专栏大内老A

Dora.Interception,为.NET Core度身打造的AOP框架 [3]:多样化拦截器应用方式

在《以约定的方式定义拦截器》中,我们通过对拦截器的介绍了Dora.Interception的两种拦截机制,即针对接口的“实例拦截”针对虚方法的“类型拦截”。我们...

954

扫码关注云+社区

领取腾讯云代金券