springmvc过滤器,拦截器,监听器作用与区别

Web开发中的过滤器、拦截器和监听器详解

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

1.过滤器

配置在web.xml中。依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等,最常用的过滤字符串的拦截器。

<filter><filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>utf-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
复制代码

1.自定义过滤器

我们还可以自定义过滤器,以下一个登陆过滤器。

@RequestMapping(value="/login",method=RequestMethod.GET)
    public String login(HttpServletRequest request,HttpServletResponse response){
        //获取Cookie
        Cookie[] cookies = request.getCookies();
        for(Cookie cookie : cookies){
            System.out.println("cookie>>"+cookie.getValue());
            //从数据库获取保存的cookie
            Session session = iSessionDAO.getSession(cookie.getValue());
            if(session!=null){
                //如果存在,就跳转到首页
                return "index";
            }
        }
        return "login";
    }
    
    @RequestMapping(value="/login",method=RequestMethod.POST)
    public String loginPOST(HttpServletRequest request, HttpServletResponse response,Model model){
        //用户名
        String username=request.getParameter("username");  
        System.out.println("username>>>"+username);
        //密码
        String password=request.getParameter("password"); 
        System.out.println("password>>>"+password);
        //先从数据库查找该账号信息
        User user = null;
        try {
            user = iUserDAO.queryForUser(username);
        } catch (NullPointerException e) {
            e.printStackTrace();
            model.addAttribute("message", "No account");
        }
        if(user==null){
            model.addAttribute("message", "No account");
        }else{
            // 匹配密码
            if (user.getPassword().equals(password)) {
                //登录成功,保存session
                request.getSession().setAttribute("user", user);
                // 保存cookie
                Cookie[] cookies = request.getCookies();
                Cookie cookie = cookies[0];//获得最新的那个cookie
                Session isSession = iSessionDAO.getSessionByUserId(user.getId());
                //没有session,就添加
                if(isSession==null){
                    Session session = new Session();
                    session.setId(UUID.randomUUID().toString());
                    session.setSession(cookie.getValue());
                    session.setUser_id(user.getId());
                    System.out.println("cookie>>" + cookie.getValue());
                    iSessionDAO.save(session);
                    System.out.println("==添加session==");
                }else{
                    //如果已经有session,就更新
                    isSession.setSession(cookie.getValue());
                    iSessionDAO.update(isSession);
                    System.out.println("==更新session==");
                }
                model.addAttribute("message", user.getUsername());
                return "index";
            }else{
                model.addAttribute("message", "Wrong password");
            }
        }
        return "login";
    }

    @RequestMapping(value="/sessionTest",method=RequestMethod.GET)
    public String sessionTest(HttpServletRequest request,HttpServletResponse response,Model model){
        System.out.println(">>>sessionTest");
        model.addAttribute("message", "sessionTest");
        return "index";

    }

复制代码

2.如何配置

在使用中,需要在web.xml中配置才生效。

<filter><description>session过滤器</description>
        <filter-name>sessionFilter</filter-name>
        <filter-class>com.mocha.filter.SessionFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>sessionFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

复制代码

2.拦截器

依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。

1.实现方式

  1. 通过实现HandlerInterceptor接口,或继承HandlerInterceptor接口的实现类(如HandlerInterceptorAdapter)来定义。
  2. 通过实现WebRequestInterceptor接口,或继承WebRequestInterceptor接口的实现类来定义。 以下是一个拦截器。

2.代码实现

@Component
public class HandlerInterceptor extends HandlerInterceptorAdapter {

	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {

		System.out.println("11111111");
	}
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {

		System.out.println("222222222");
	}

	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("44444");
		return true;
	}
}
复制代码

同时也需要在mvc的配置文件中加入配置。

<mvc:interceptors>
		<mvc:interceptor>
			<!--配置拦截器的作用路径 -->
			<mvc:mapping path="/**" />
			<!--定义在<mvc:interceptor>下面的表示匹配指定路径的请求才进行拦截 -->
			<bean class="com.HandlerInterceptor" />
		</mvc:interceptor>
	</mvc:interceptors>
复制代码

3.监听器

监听器是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或者属性改变,当被监听对象发生上述事件后,监听器某个方法将立即执行。 监听器用于监听web应用中某些对象、信息的创建、销毁、增加,修改,删除等动作的发生,然后作出相应的响应处理。当范围对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。常用于统计在线人数和在线用户,系统加载时进行信息初始化,统计网站的访问量等等。或者在开发工作中,会遇到一种场景,做完某一件事情以后,需要广播一些消息或者通知,告诉其他的模块进行一些事件处理,一般来说,可以一个一个发送请求去通知,但是有一种更好的方式,那就是事件监听,事件监听也是设计模式中 发布-订阅模式、观察者模式的一种实现。

1.代码实现

监听事件

import org.springframework.context.ApplicationEvent;
public class MyTestEvent extends ApplicationEvent{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private String msg ;
    public MyTestEvent(Object source,String msg) {
        super(source);
        this.msg = msg;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
}

复制代码

定义监听器

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

import com.mu.event.MyTestEvent;

@Component
public class MyNoAnnotationListener implements ApplicationListener<MyTestEvent>{

    @Override
    public void onApplicationEvent(MyTestEvent event) {
        System.out.println("非注解监听器:" + event.getMsg());
    }
}

复制代码

事件发布

package com.mu.event;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class MyTestEventPubLisher {
    @Autowired
    private ApplicationContext applicationContext;
    // 事件发布方法
    public void pushListener(String msg) {
        applicationContext.publishEvent(new MyTestEvent(this, msg));
    }
}

复制代码

调用

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.mu.event.MyTestEventPubLisher;
@Controller
public class TestEventListenerController {
    @Autowired
    private MyTestEventPubLisher publisher;
    @RequestMapping(value = "/test/testPublishEvent1" )
    public void testPublishEvent(){
        publisher.pushListener("我来了!");
    }
}

复制代码

也可以使用注解实现

import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import com.mu.event.MyTestEvent;

@Component
public class MyAnnotationListener {

    @EventListener
    public void listener1(MyTestEvent event) {
        System.out.println("注解监听器1:" + event.getMsg());
    }
}
复制代码

4.过滤器与拦截器的区别

过滤器可以简单的理解为“取你所想取”,过滤器关注的是web请求;拦截器可以简单的理解为“拒你所想拒”,拦截器关注的是方法调用,比如拦截敏感词汇。

  1. 拦截器是基于java反射机制来实现的,而过滤器是基于函数回调来实现的。(有人说,拦截器是基于动态代理来实现的)
  2. 拦截器不依赖servlet容器,过滤器依赖于servlet容器。
  3. 拦截器只对Action起作用,过滤器可以对所有请求起作用。
  4. 拦截器可以访问Action上下文和值栈中的对象,过滤器不能。
  5. 在Action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时调用一次。

5.AOP与拦截器的区别

Filter过滤器:拦截web访问url地址。 Interceptor拦截器:拦截以 .action结尾的url,拦截Action的访问。 Spring AOP拦截器:只能拦截Spring管理Bean的访问(业务层Service)

拦截顺序:监听器>filter—>Interceptor—->@Aspect

aop与拦截器的实现方式都是动态代理实现的。

来源:https://juejin.cn/post/7021684725018263583#heading-6
<think>嗯,用户问的是过滤器拦截器监听器区别。这个问题在Java Web开发中很基础,但也很重要。 用户提供的三个引用内容其实已经涵盖了主要区别点:引用1强调了技术实现差异(反射机制 vs 函数回调)、作用范围和生命周期;引用2解释了执行顺序;引用3补充了过滤器的触发时机。不过用户可能更想要系统化的对比。 考虑到用户可能是Java Web初学者,我应该用结构化表格呈现核心区别,但需要避免直接复制引用内容。重点突出四个维度:技术本质、作用范围、生命周期、典型场景。比如过滤器基于Servlet容器这个特点,直接影响它能否处理静态资源,这点很关键但引用里没明说。 监听器那块需要补充完整。引用里只提到拦截器过滤器的触发时机,但监听器响应事件的特点更值得说明。比如ServletRequestListener能感知请求创建/销毁,这对日志记录特别有用。 执行顺序的示意图很重要。引用2提到"过滤前-拦截前-Action处理-拦截后-过滤后",但需要明确"Action处理"在SpringMVC里对应Controller方法执行。这个顺序解释清楚能帮助用户理解为什么拦截器适合做权限检查。 用户没问但可能想知道的是实际应用组合。比如用过滤器解决全局编码问题,拦截器做登录验证,监听器统计在线人数。这个可以放在应用示例里,避免表格太抽象。 最后的相关问题设计要递进:从三者区别延伸到如何选择(场景驱动),再到框架集成(Spring里的实践),最后到执行顺序原理(源码级理解)。这样用户可以根据当前需求选择深入方向。 </think>以下是过滤器拦截器监听器的核心区别对比及详解: ### **一、核心区别对比表** | **维度** | **过滤器 (Filter)** | **拦截器 (Interceptor)** | **监听器 (Listener)** | |----------------|----------------------------------------|----------------------------------------|-------------------------------------| | **技术本质** | 基于函数回调 (Servlet规范) | 基于Java反射机制 (框架实现,如Spring) | 基于事件监听 (Servlet规范) | | **依赖关系** | 依赖Servlet容器 (如Tomcat) | 不依赖Servlet容器 | 依赖Servlet容器 | | **作用范围** | 所有请求(静态资源、Servlet、JSP等) | 仅对Controller/Action请求生效 | 特定事件(请求/会话/应用生命周期) | | **生命周期** | 容器初始化时创建,每次请求触发 | 随请求动态创建/销毁 | 事件触发时执行,单次或长期监听 | | **访问上下文** | 只能访问ServletRequest/Response | 可访问Action上下文、值栈对象等 | 可访问事件源对象(如HttpSession) | --- ### **二、执行顺序详解** 1. **请求阶段** `容器初始化 → 过滤器生效 → 拦截器生效 → Controller处理` ``` $ \text{请求流程: } \boxed{\text{过滤器前置}} \rightarrow \boxed{\text{拦截器前置}} \rightarrow \boxed{\text{Controller}} $ ``` 2. **响应阶段** `拦截器后置 → 过滤器后置 → 结果返回客户端` ``` $ \text{响应流程: } \boxed{\text{Controller}} \rightarrow \boxed{\text{拦截器后置}} \rightarrow \boxed{\text{过滤器后置}} $ ``` > **关键顺序**:过滤前 → 拦截前 → 业务处理 → 拦截后 → 过滤后 [^2] --- ### **三、典型应用场景** #### **1. 过滤器 (Filter)** - **全局请求处理** - 字符编码统一设置(`request.setCharacterEncoding("UTF-8")`) - 敏感词过滤(替换请求/响应内容) - 跨域请求处理(添加CORS响应头) ```java // 示例:登录验证过滤器 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) { HttpServletRequest request = (HttpServletRequest) req; if (request.getSession().getAttribute("user") == null) { // 未登录用户重定向到登录页 response.sendRedirect("/login"); } else { chain.doFilter(request, response); // 放行请求 } } ``` #### **2. 拦截器 (Interceptor)** - **Controller层定制** - 权限验证(检查用户角色) - 日志记录(记录请求参数、执行时间) - 数据预处理(参数校验、数据封装) ```java // Spring拦截器示例:记录请求耗时 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { request.setAttribute("startTime", System.currentTimeMillis()); return true; // 继续执行Controller } public void postHandle(...) { long startTime = (Long) request.getAttribute("startTime"); System.out.println("请求耗时:" + (System.currentTimeMillis() - startTime) + "ms"); } ``` #### **3. 监听器 (Listener)** - **系统事件响应** - 统计在线人数(`HttpSessionListener`监听会话创建/销毁) - 应用启动初始化(`ServletContextListener`加载全局配置) - 会话属性追踪(`HttpSessionAttributeListener`监听Session数据变化) ```java // 监听会话创建 public void sessionCreated(HttpSessionEvent se) { AtomicInteger onlineCount = (AtomicInteger) se.getSession().getServletContext().getAttribute("onlineCount"); onlineCount.incrementAndGet(); // 在线人数+1 } ``` --- ### **四、核心技术要点总结** 1. **过滤器** - 最早接触请求,最晚处理响应(类似“外包装”) - 可修改请求/响应内容(如压缩响应、加密数据) - **强制依赖Servlet容器** [^1][^3] 2. **拦截器** - 可获取Spring上下文(如自动注入Bean) - 能中断请求流程(`preHandle`返回`false`时终止) - **框架深度集成**(Spring MVC/Struts等) 3. **监听器** - 被动触发,不具体请求绑定 - 用于状态监控(如会话超时、应用异常) --- **相关问题** 1. 如何在Spring Boot中自定义拦截器实现JWT验证? 2. 过滤器中`chain.doFilter()`不放行请求会导致什么问题? 3. 监听器能否修改HTTP请求?为什么? 4. 三者在分布式架构中的应用有哪些变化? > 引用说明: > [^1]: 拦截器过滤器的核心差异(反射机制 vs 函数回调) > [^2]: 三者执行顺序的典型工作流程 > [^3]: 过滤器的触发时机(Servlet容器初始化后)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值