过滤器、监听器、拦截器

目录

[一、 主要内容](#一、 主要内容)

[二、 过滤器](#二、 过滤器)

[2.1 介绍](#2.1 介绍)

[2.2 实现](#2.2 实现)

MyFilter01

MyFilter02

MyServlet01

MyServlet02

[2.3 说明](#2.3 说明)

[2.4 执行顺序](#2.4 执行顺序)

[1. 使用 web.xml](#1. 使用 web.xml)

[2. 使用注解和@Order](#2. 使用注解和@Order)

[3. 使用FilterRegistrationBean](#3. 使用FilterRegistrationBean)

2.5字符乱码

三、监听器

3.1介绍

3.2实现

3.3在线人数统计

OnlineListener

OnlineServlet2

四、拦截器

4.1介绍

4.2实现方式

1.实现HandlerInterceptor接口

2.实现WebRequestInterceptor接口

3.继承HandlerInterceptorAdapter类

4.注册拦截器

4.3解决的问题

[4.4与Spring Boot的集成](#4.4与Spring Boot的集成)

4.4执行顺序控制

4.5身份验证实例

步骤一:创建拦截器

步骤二:配置拦截器

步骤三:测试

注意事项

五、过滤器和拦截器区别 (面试常问)

六、如何理解"拦截器只能拦截部分web请求"

1.拦截器的作用范围

2.为什么拦截器不能拦截所有Web请求?

3.如何拦截所有Web请求?


一、 主要内容

过滤器(Filter) 监听器(Listener) 拦截器(Interceptor)
关注点 web请求 系统级别参数、对象 Action(部分Web请求)
实现方式 函数回调 事件 Java反射机制
应用场景 设置字符编码 统计网站在线人数 拦截未登录用户
URL级别的权限访问控制 清楚过期session 审计日志
过滤敏感词汇
压缩响应信息
是否依赖Servlet容器
Servlet提供的支持 Filter接口 ServletRequestListener HttpSessionListener ServletContextListener
Spring提供的支持 HandlerInterceptor WebRequestInterceptor HandlerInterceptorAdapter
级别 系统级别 系统级别 非系统级别

二、 过滤器

2.1 介绍

  • Filter 即为过滤,用于在 Servlet 之外对 Request或者 Response 进行修改。

  • 它主要用于对用户请求进行预处 ,也可以对 HtpServletResponse 进行后处理

  • 使用 Filter 的完整流程: Filter 对用户请求进行预处理,接着将请求交给 Servlet 进行处理并生成响应,最后 Filter 再对服务器响应进行后处理。

  • 在一个 web 应用中,可以开发编写多个 Filter ,这些 Filter 组合起来 称之为一个 Filter 链

若是一个过滤器链:先配置先执行(请求时的执行顺序);响应时:以相反的顺序执行

在 HttpServletRequest 到达 Servlet 之前拦截客户的HttpServletRequest 。根据需要检查 HttpServletRequest,也可修改 HttpServletRequest 头和数据。 在HttpServletResponse 到达客户端之前 ,拦截 HttpServletResponse。 根据需要检查 HttpServletResponse,也可修改 HttpServletResponse头和数据

2.2 实现

  • 通过实现javax.servlet.Fileter的接口来实现一个过滤器。

  • 其中定义了 三个方法:init(),doFilter(),destroy() ,分别在相应的时机执行。后期观察生命周期。

  • Filter 的实现只需要两步:

    • 1:编写 java 类实现 Filter接口,并实现其 doFilter 方法

    • 2:通过@WebFilter注解设置它所能拦截的资源。

    • filterChain.doFilter(servletRequest, servletResponse); 放行

/*/**

在Spring MVC框架中,配置拦截器(Interceptor)的路径模式时,/*/**这两个通配符有以下区别:

  • /*

    • 匹配一级目录下的所有请求路径。

    • 只匹配直接跟在指定路径后面的第一级子路径。

    例如,如果配置为 /user/*,那么它会匹配 /user/john 或 /user/admin,但不会匹配 /user/profile/edit。

  • /**

    • 匹配任意多级目录下的所有请求路径。

    • 它可以匹配任何深度的子路径。

    例如,如果配置为 /user/,那么它会匹配 /user/john、/user/admin、/user/profile/edit 等等。

    总结来说,/*只匹配直接下一层的路径,而/**可以匹配所有层级的路径,包括直接下一层和更深层次的路径

    在实际应用中,如果你想要对整个应用程序的所有请求进行拦截,通常会选择使用 /** ,因为它提供了更全面的覆盖。而 /* 更适合需要精细控制某些特定一级目录下的请求的情况。

MyFilter01
java 复制代码
package com.dev.filter;
​
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
​
/**
 * 实现过滤器
 * 1. 实现javax.servlet.Filter接口
 * 2. 重写方法
 * 3. 在doFilter方法中编写过滤逻辑(控制资源访问)
 * 4,配置过滤器,设置拦截路径
 */
// 拦截所有资源
@WebFilter("/myServlet01")
public class MyFilter01 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
​
        // 处理请求数据
        System.out.println("filter01start ");
​
        filterChain.doFilter(servletRequest, servletResponse);
​
        // 处理响应数据
        System.out.println("filter01end");
    }
​
    @Override
    public void destroy() {
​
    }
}
复制代码
MyFilter02
java 复制代码
package com.dev.filter;
​
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
​
/**
 * 实现过滤器
 * 1. 实现javax.servlet.Filter接口
 * 2. 重写方法
 * 3. 在doFilter方法中编写过滤逻辑(控制资源访问)
 * 4,配置过滤器,设置拦截路径
 */
// 拦截所有资源
@WebFilter("/myServlet02")
public class MyFilter01 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
​
        // 处理请求数据
        System.out.println("filter02start ");
​
        filterChain.doFilter(servletRequest, servletResponse);
​
        // 处理响应数据
        System.out.println("filter02end");
    }
​
    @Override
    public void destroy() {
​
    }
}
​
MyServlet01
java 复制代码
package com.dev.filter;
​
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import java.io.IOException;
​
@WebServlet("/myServlet01")
public class MyServlet01 extends HttpServlet {
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        System.out.println("servlet01......");
    }
}
​
MyServlet02
java 复制代码
package com.dev.filter;
​
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import java.io.IOException;
​
@WebServlet("/myServlet02")
public class MyServlet02 extends HttpServlet {
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        System.out.println("servlet02......");
    }
}
复制代码

注意

  • 定义两个拦截器

    • MyFilter01 @WebFilter("/myServlet")

    • MyFilter02 @WebFilter("/*)

  • 定义两个Servlet:

    • MyServlet01 @WebServlet("/myServlet")

    • MyServlet02 @WebServlet("/myServlet02")

访问

  • /myServlet02 ------ filter02start ==>servlet02==>filter02end

  • /myServlet ------ filter01start ==>filter02start ==>servlet01==>filter02end==>filter01end

2.3 说明

  • 过滤器

    • 在请求到达资源之前,过滤器会进行预处理(处理request);在响应到达客户端之前,过滤器会进行后处理(处理response)
  • 过滤器链

    • 当存在多个过滤器时,先配置的先执行(如果没有配置文件,则按照字母排序)

      • 过滤器1、过滤器2、过滤器3

        • 当请求访问资源时,过滤器执行的顺序是1->2->3;

        • 到达资源后,响应的顺序为 3->2->1;

2.4 执行顺序

1. 使用 web.xml

过滤器的执行顺序就是它们在web.xml中声明的顺序。最先声明的过滤器将最先执行,而最后声明的过滤器将在响应阶段最后执行

复制代码
<!-- web.xml -->
<filter>
    <filter-name>AuthFilter</filter-name>
    <filter-class>com.example.AuthFilter</filter-class>
</filter>
​
<filter-mapping>
    <filter-name>AuthFilter</filter-name>
    <url-pattern>/secure/*</url-pattern>
</filter-mapping>
​
<filter>
    <filter-name>LoggingFilter</filter-name>
    <filter-class>com.example.LoggingFilter</filter-class>
</filter>
​
<filter-mapping>
    <filter-name>LoggingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
​

执行顺序说明

  • 对于所有请求,LoggingFilter都会被触发,因为它匹配所有URL模式。

  • 对于以/secure/开头的请求,除了LoggingFilter之外,AuthFilter也会被触发。

  • 因为AuthFilter在web.xml中先于LoggingFilter声明,所以对于匹配/secure/的请求,AuthFilter会先于LoggingFilter执行。

  • 对于非/secure/的请求,仅LoggingFilter会被执行。

因此,即使过滤器处理不同的URL模式,它们的执行顺序仍然基于配置文件中的声明顺序。

2. 使用注解和@Order

在Spring框架中,可以使用@WebFilter注解结合@Order注解来指定过滤器的执行顺序。@Order注解需要一个整数参数,数值越小的过滤器将越早执行

java 复制代码
@Order(1)
@WebFilter(urlPatterns = "/*")
public class FirstFilter implements Filter {
    // ...
}
​
@Order(2)
@WebFilter(urlPatterns = "/*")
public class SecondFilter implements Filter {
    // ...
}
3. 使用FilterRegistrationBean

在Spring Boot或Spring MVC中,你也可以通过FilterRegistrationBean在配置类中注册过滤器

java 复制代码
@Configuration
public class FilterConfig {
​
    @Bean
    public FilterRegistrationBean<FirstFilter> firstFilterRegistration() {
        FilterRegistrationBean<FirstFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new FirstFilter());
        registration.addUrlPatterns("/*");
        registration.setOrder(1);
        return registration;
    }
​
    @Bean
    public FilterRegistrationBean<SecondFilter> secondFilterRegistration() {
        FilterRegistrationBean<SecondFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new SecondFilter());
        registration.addUrlPatterns("/*");
        registration.setOrder(2);
        return registration;
    }
}
复制代码

2.5字符乱码

请求 Tomcat7及以下版本 Tomcat8及以上版本
POST 乱码,需要处理 乱码,需要处理
GET 乱码,需要处理 不会乱码,无需处理

处理

  • POST

    • request.setCharacterEncoding("UTF-8");
  • GET (服务器版本在 Tomcat7及以下版本)

    • 得到请求类习惯

    • 得到服务器版本信息

    • 判断请求为GET且版本小于8

    • 处理乱码

java 复制代码
package com.dev.filter;
​
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
​
/**
 * 请求乱码统一处理
 *  tomcat8及以上版本 POST请求乱码问题
 *  tomecat7以下版本 POST/GET请求乱码问题
 */
@WebFilter("/**")
public class AEncodingFilter implements Filter {
    
    public AEncodingFilter(){
    
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
    }
    
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 基于HTTP
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        
        // 处理请求乱码问题
        request.setCharacterEncoding("UTF-8");
        
        // 放行
        filterChain.doFilter(request, response);
        
    }
    
    @Override
    public void destroy() {
    
    }
}
复制代码

三、监听器

3.1介绍

web 监听器是Servlet 中一种的特殊的类,能帮助开发者监听 web 中的特定事件,比如 ServletcontextHttpSession,ServletRequest 的创建和销毁;变量的创建、销毁和修改等。 可以在某些动作前后增加处理,实现监控。例如可以用来统计在线人数等。

3.2实现

监听器有三类8种:

  • 监听生命周期

    • ServletRequestListener

    • HttpSessionListener

    • ServletContextListener

  • 监听值的变化

    • ServletRequestAttributeListener

    • HttpSessionAttributeListener

    • ServletContextAttributeListener

  • 针对 session 中的对象

    • 监听 session 中的 java 对象(javaBean),是javaBean 直接实现监听器 的接口

3.3在线人数统计

OnlineListener
java 复制代码
package com.dev.listener;
​
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
​
/**
 * 在线人数统计
 */
@WebListener
public class OnlineListener implements HttpSessionListener {
    
    // 得到在线人数
    public static int onlineCount = 0;
    
    /**
     * 当有新的session创建时,在线人数加一
     * @param httpSessionEvent
     */
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        onlineCount++;
        
        // 将在线人数放入session作用域中
        // httpSessionEvent.getSession().setAttribute("onlineCount", onlineCount);
        // 将在线任务放入application作用域中
        httpSessionEvent.getSession().getServletContext().setAttribute("onlineCount", onlineCount);
    }
    
    /**
     * 当session销毁时,在线人数减一
     * @param httpSessionEvent
     */
    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        onlineCount--;
        // 将在线人数放入session作用域中
        // httpSessionEvent.getSession().setAttribute("onlineCount", onlineCount);
        // 将在线任务放入application作用域中
        httpSessionEvent.getSession().getServletContext().setAttribute("onlineCount", onlineCount);
    }
}
​
OnlineServlet2
java 复制代码
package com.dev.listener;
​
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
​
/**
 * 在线任务统计
 */
@WebServlet("/online")
public class OnlineServlet2 extends HttpServlet {
    
    @Override
    public void service(HttpServletRequest req, HttpServletResponse res) throws IOException {
        
        //得到动作
        String action = req.getParameter("action");
        if ("logout".equals(action)) {
            // 退出
            req.getSession().invalidate();
            return;
        }
        
        // 得到当前访问的ip
        String ip = req.getRemoteAddr();
        System.out.println("当前访问的ip为:" + ip );
        
        
        // 获取session作用域中的在线人数
        // Integer onlineCount =(Integer) req.getSession().getAttribute("onlineCount");
        // 获取application作用域中的在线人数
        Integer onlineCount =(Integer) req.getSession().getServletContext().getAttribute("onlineCount");
        
        // 响应数据 在页面中显示人数
        res.setContentType("text/html;charset=utf-8");
        res.getWriter().write("当前在线人数为:" + onlineCount+"<a href='myServlet03?action=logout'>退出</a>");
        res.getWriter().flush();
        res.getWriter().close();
    }
}
复制代码

四、拦截器

4.1介绍

拦截器(Interceptor)是Java Web应用中的一种设计模式,主要用于在请求到达目标组件(如控制器)之前或响应离开目标组件之后执行一些特定的逻辑。在Spring框架中,拦截器是AOP(面向切面编程)的一个应用,可以用来实现诸如权限验证、日志记录、事务管理、性能监控等功能。

4.2实现方式

1.实现HandlerInterceptor接口

在Spring MVC中,拦截器可以通过实现HandlerInterceptor接口来创建

该接口包含三个方法:

  • preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception: 在请求处理之前 调用,可以用于权限验证、数据校验 等。如果返回false ,则请求处理停止,不会继续执行后续的拦截器或控制器方法。

  • postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception: 在请求处理之后, 但在视图渲染之前 调用,可以用于日志记录、缓存处理等。

  • afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception: 在视图渲染之后 调用,可以用于资源清理等操作。

复制代码
   
java 复制代码
import org.springframework.web.servlet.HandlerInterceptor;
   import org.springframework.web.servlet.ModelAndView;
​
   import javax.servlet.http.HttpServletRequest;
   import javax.servlet.http.HttpServletResponse;
​
   public class CustomInterceptor implements HandlerInterceptor {
​
       @Override
       public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
           // 在这里实现你的逻辑
           return true;
       }
​
       @Override
       public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
           // 在这里实现你的逻辑
       }
​
       @Override
       public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
           // 在这里实现你的逻辑
       }
   }
   
2.实现WebRequestInterceptor接口

这个接口与HandlerInterceptor类似,但是它在更早的阶段被调用,甚至在请求映射之前。这使得它适合做一些全局的初始化工作。实现WebRequestInterceptor接口需要重写以下方法:

  • preHandle(WebRequest request):在请求处理之前调用。

  • postHandle(WebRequest request, ModelMap model):在请求处理之后调用。

  • afterCompletion(WebRequest request, Exception ex):在请求处理完成之后调用。

3.继承HandlerInterceptorAdapter类

如果你不想实现HandlerInterceptor接口中的所有方法,可以继承HandlerInterceptorAdapter类,这是一个适配器类,它为HandlerInterceptor接口提供了默认实现,你只需要重写你感兴趣的方法即可。

复制代码
  
java 复制代码
 import org.springframework.web.servlet.HandlerInterceptorAdapter;
​
   public class CustomInterceptor extends HandlerInterceptorAdapter {
​
       @Override
       public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
           // 在这里实现你的逻辑
           return true;
       }
   }
复制代码
   
4.注册拦截器

一旦你创建了拦截器,就需要在Spring配置中注册它。这可以通过实现WebMvcConfigurer接口的addInterceptors方法来完成。

java 复制代码
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
​
@Configuration
public class WebConfig implements WebMvcConfigurer {
​
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CustomInterceptor())
                .addPathPatterns("/**"); // 指定拦截器应用的所有请求
    }
}
​

4.3解决的问题

拦截器可以解决多种问题:

  • 权限控制:在请求到达控制器之前验证用户权限。

  • 日志记录:记录请求和响应的详细信息,有助于调试和审计。

  • 性能监控:计算请求处理时间,监控应用性能。

  • 数据校验:检查请求参数的有效性,防止非法请求。

  • 资源清理:确保在请求处理完毕后释放资源。

4.4与Spring Boot的集成

在Spring Boot中使用拦截器,可以通过以下步骤:

  • 创建拦截器类并实现HandlerInterceptor接口。

  • 在Spring配置类中注册拦截器,通常通过实现WebMvcConfigurer接口的addInterceptors方法。

java 复制代码
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
​
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
​
public class MyInterceptor implements HandlerInterceptor {
​
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("Pre-handle logic...");
        return true; // 返回true表示继续处理请求
    }
​
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Post-handle logic...");
    }
​
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {java
        System.out.println("After completion logic...");
    }
}
​

接下来,在Spring配置类中注册这个拦截器

java 复制代码
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
​
@Configuration
public class WebConfig implements WebMvcConfigurer {
​
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**"); // 指定拦截器应用的所有请求
    }
}
​

4.4执行顺序控制

拦截器的执行顺序可以通过以下方式控制:

  • 配置顺序:在addInterceptors 方法中,拦截器的添加顺序决定了它们的执行顺序

  • 实现Ordered接口:让拦截器实现Ordered接口并重写getOrder()方法 ,返回一个整数,数值越小,优先级越高

java 复制代码
import org.springframework.core.Ordered;
import org.springframework.web.servlet.HandlerInterceptor;
​
public class MyInterceptor implements HandlerInterceptor, Ordered {
​
    @Override
    public int getOrder() {
        return 1; // 优先级高于其他返回值大于1的拦截器
    }
​
    // 其他方法...
}
复制代码

4.5身份验证实例

假设我们有一个Spring Boot应用,其中某些资源是受保护的,只有经过身份验证的用户才能访问。我们可以使用拦截器来检查用户的会话状态,确保只有已登录的用户才能访问这些资源。

步骤一:创建拦截器

首先,我们需要创建一个拦截器类,实现HandlerInterceptor接口,并覆盖preHandle方法来执行身份验证逻辑。

java 复制代码
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
​
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
​
@Component
public class AuthenticationInterceptor implements HandlerInterceptor {
​
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 从session中获取用户信息
        HttpSession session = request.getSession(false);
        if (session != null) {
            Object user = session.getAttribute("user");
            if (user != null) {
                // 用户已登录,允许请求继续
                return true;
            }
        }
        
        // 用户未登录,重定向到登录页面
        response.sendRedirect(request.getContextPath() + "/login");
        return false;
    }
​
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 这里可以处理请求后的逻辑,例如日志记录
    }
​
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 这里可以处理请求完成后的清理工作
    }
}

步骤二:配置拦截器

接下来,我们需要在Spring配置类中注册这个拦截器,并指定它应该应用于哪些URL。

java 复制代码
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
​
@Configuration
public class WebConfig implements WebMvcConfigurer {
​
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthenticationInterceptor())
                .addPathPatterns("/protected/*") // 指定拦截器应用于/protected下的所有请求
                .excludePathPatterns("/protected/login", "/protected/logout"); // 排除登录和登出路经
    }
}
​
步骤三:测试

现在,每当有请求尝试访问/protected/*下的资源时,AuthenticationInterceptor都会被调用。如果用户没有登录,他们将被重定向到登录页面。如果已经登录,则请求将继续正常处理。

注意事项
  • 确保登录和登出路由被排除在拦截器之外,否则用户将无法访问这些页面。

  • 考虑到安全性,可能还需要在拦截器中加入更复杂的认证逻辑,例如检查JWT令牌等。

  • 如果应用中有多个拦截器,它们的执行顺序可以通过实现Ordered接口并重写getOrder()方法来控制。

通过这种方式,拦截器可以帮助我们在Spring Boot应用中实现细粒度的访问控制,提高应用的安全性和健壮性。

五、过滤器和拦截器区别 (面试常问)

过滤器(Filter)和拦截器(Interceptor)在Java Web应用程序中扮演着重要的角色,它们用于在请求到达目标组件(如Servlet或JSP)之前或之后执行特定的逻辑。两者都可以在请求过程中介入并可能阻止请求。

尽管它们有相似的功能,但它们在实现机制、作用范围、依赖环境等方面存在显著差异。

  • 实现机制:

    • 过滤器 是基于函数回调的,通常通过实现javax.servlet.Filter接口来创建。过滤器会拦截所有进入Servlet容器的请求和响应,并且可以访问HttpServletRequest和HttpServletResponse对象。

    • 拦截器 是基于Java的反射机制(动态代理)实现的,通常与框架如Spring MVC一起使用。拦截器可以访问更广泛的上下文信息,比如Spring MVC的ModelAndView对象,以及控制器方法的参数和返回值。

  • 依赖环境:

    • 过滤器依赖于Servlet容器,如Tomcat、Jetty等,因此只能在Web环境中使用。

    • 拦截器不依赖于Servlet容器,可以在任何使用Spring MVC框架的应用中使用,即使是在非Web环境中也可以实现类似的功能。

  • 作用范围:

    • 过滤器可以拦截几乎所有的HTTP请求,包括对静态资源的请求。

    • 拦截器通常只拦截那些由控制器处理的请求,即所谓的"action"请求,不会拦截静态资源请求。

  • 生命周期:

    • 过滤器在Servlet容器启动时初始化,在容器关闭时销毁,每个请求只调用一次doFilter()方法。

    • 拦截器可以多次调用,取决于请求的路径和配置,每次请求可以调用多次拦截器的preHandle()、postHandle()和afterCompletion()方法。

  • 配置方式:

    • 过滤器通过web.xml文件或注解(如@WebFilter)配置。

    • 拦截器通常通过Spring的配置类或XML文件配置。

六、如何理解"拦截器只能拦截部分web请求"

截器主要用于拦截和处理由控制器(Controller)处理的请求,而不是所有的Web请求。

这是因为拦截器的设计初衷是为了处理业务逻辑层面的请求,如权限检查、日志记录、数据预处理等,这些通常与具体的业务操作相关联。

1.拦截器的作用范围

  • 控制器请求:拦截器主要针对由控制器处理的请求,即通过HTTP方法(GET、POST等)调用控制器方法的请求。拦截器可以访问控制器方法的参数、返回值、以及模型和视图对象。

  • 静态资源请求:拦截器通常不会拦截静态资源(如CSS、JavaScript、图片等)的请求,因为这些请求不涉及业务逻辑,而是直接由Web服务器或Servlet容器处理。

  • 非控制器路径:对于不通过控制器处理的请求,如直接指向特定资源或Servlet的请求,拦截器也不会进行拦截。

2.为什么拦截器不能拦截所有Web请求?

  • 设计目的:拦截器的设计目的是为了在业务逻辑层面上进行干预,而并非处理底层的网络通信或静态资源的分发。

  • 性能考虑:如果拦截器拦截所有请求,包括静态资源请求,可能会引入不必要的性能开销,因为静态资源的处理通常非常快速,而拦截器的介入可能会增加延迟。

  • 框架限制:Spring MVC的拦截器机制是基于控制器的,因此它天然不适合处理那些不由控制器处理的请求。

3.如何拦截所有Web请求?

  • 如果需要对所有Web请求进行处理,包括静态资源请求,那么应该使用过滤器(Filter)过滤器是Servlet容器级别的,它可以拦截所有进入容器的请求,无论这些请求是针对控制器还是静态资源。

  • 过滤器的实现和配置与拦截器不同,它通过实现javax.servlet.Filter接口来创建,并在web.xml文件或使用@WebFilter注解来配置。

总结来说,拦截器在Spring MVC中主要用于处理与业务逻辑相关的请求,而过滤器则可以用于处理所有类型的Web请求,包括静态资源请求。

相关推荐
跳动的梦想家h24 分钟前
黑马点评 秒杀下单出现的问题:服务器异常---java.lang.NullPointerException: null(已解决)
java·开发语言·redis
苹果醋326 分钟前
前端面试之九阴真经
java·运维·spring boot·mysql·nginx
哎呦没1 小时前
Spring Boot OA:企业办公自动化的高效路径
java·spring boot·后端
真心喜欢你吖1 小时前
Spring Boot与MyBatis-Plus的高效集成
java·spring boot·后端·spring·mybatis
2402_857589361 小时前
企业办公自动化:Spring Boot OA管理系统开发与实践
java·spring boot·后端
G丶AEOM1 小时前
JVM逃逸分析机制
java·jvm
无聊写博客1 小时前
JDK、JRE、JVM的区别
java·开发语言·jvm
message丶小和尚2 小时前
SpringBoot升级全纪录之项目启动
java·spring boot·mybatis
Allen Bright2 小时前
IDEA配置本地maven
java·maven·intellij-idea
总是学不会.2 小时前
【贪心算法】绿洲之旅:最少次数补给探索
java·算法·intellij-idea