Spring Boot 整合过滤器拦截器

Spring Boot 整合过滤器

1. 简介

在Spring Boot应用中,我们可以使用Servlet API中的Filter来实现一些全局的功能,比如日志记录、跨域处理、权限验证等。

2. 创建自定义过滤器

创建一个类,实现javax.servlet.Filter接口,并重写其中的方法。

package com.example.filter;

import javax.servlet.*;
import java.io.IOException;

public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化过滤器时可以做一些准备工作
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 在这里对请求进行预处理,或者对响应进行后处理
        System.out.println("MyFilter is running");
        
        // 调用FilterChain对象的doFilter方法,将请求传递给下一个过滤器或Servlet
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        // 过滤器被销毁前可以做一些清理工作
    }
}

3. 注册过滤器到Spring Boot容器

在Spring Boot的配置类中,通过FilterRegistrationBean将过滤器注册到Spring Boot的IoC容器中。

package com.example.config;

import com.example.filter.MyFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<MyFilter> filterRegistration() {
        FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new MyFilter());
        registration.addUrlPatterns("/*"); // 设置过滤器作用的URL路径
        return registration;
    }
}

4. 配置过滤器顺序和优先级

可以通过FilterRegistrationBeansetOrder()方法设置过滤器的排序值。排序值越小,优先级越高,会先执行。

registration.setOrder(0); // 设置排序值为0,表示最高优先级

也可以通过过滤器的名字约定排序,如LogFilter和AuthFilter,字母A比L前面,所以AuthFilter会比LogFilter先执行。

5. 多个过滤器的应用

一个URL可以配置多个过滤器,使用逗号分隔。当设置多个过滤器时,全部验证通过,才视为通过。

registration.addUrlPatterns("/path1", "/path2");

部分过滤器可以指定参数,如perms、roles等。

6. 总结

通过上述步骤,我们成功地在Spring Boot应用中整合了自定义的过滤器。这个过滤器会在所有请求进入Controller之前运行,提供了灵活的扩展点来添加全局功能。
以下是一个Spring Boot整合拦截器的详细文档,包括最新的概念和示例代码:

Spring Boot 整合拦截器

1. 简介

在Spring MVC框架中,我们可以使用Interceptor(拦截器)来实现一些全局的功能,比如日志记录、权限验证等。

2. 创建自定义拦截器

创建一个类,实现org.springframework.web.servlet.HandlerInterceptor接口,并重写其中的方法。

package com.example.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod method = (HandlerMethod) handler;
            System.out.println("MyInterceptor is running for method: " + method.getMethod().getName());
        }
        return true; // 如果返回false,则中断后续流程
    }
//Object handler: 这个参数代表了将要被调用的处理器。
//通常情况下,它是一个实现了HandlerMethod接口的对象,包含了目标方法的信息。
//你可以通过((HandlerMethod) handler).getMethod().getName()来获取目标方法的名字,
//或者通过((HandlerMethod) handler).getBean()来获取目标方法所在的bean。
    @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 {
        // 这个方法会在整个请求完成以后被调用,无论是否有异常抛出
    }
}

3. 注册拦截器到Spring Boot容器

在Spring Boot的配置类中,通过实现org.springframework.web.servlet.config.annotation.WebMvcConfigurer接口并重写其addInterceptors()方法,将拦截器注册到Spring Boot的IoC容器中。

package com.example.config;

import com.example.interceptor.MyInterceptor;
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 InterceptorConfig implements WebMvcConfigurer {

    @Autowired
    private MyInterceptor myInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor).addPathPatterns("/**"); // 设置拦截器作用的URL路径
    }
}

4. 配置拦截器顺序和优先级

可以通过InterceptorRegistryorder()方法设置拦截器的排序值。排序值越小,优先级越高,会先执行。

registry.addInterceptor(myInterceptor).order(0); // 设置排序值为0,表示最高优先级

也可以通过拦截器的名字约定排序,如LogInterceptor和AuthInterceptor,字母A比L前面,所以AuthInterceptor会比LogInterceptor先执行。

5. 多个拦截器的应用

一个URL可以配置多个拦截器,它们按照添加的顺序依次执行。如果前一个拦截器返回false,则后续的拦截器不会执行。

以下是一个Spring Boot整合拦截器的实战应用,该示例演示了如何使用拦截器来实现用户登录验证功能:

6. preHandle、postHandle、afterCompletion三者的区别

preHandlepostHandleafterCompletion是Spring MVC中的拦截器(Interceptor)接口org.springframework.web.servlet.HandlerInterceptor的三个方法,它们在请求处理的不同阶段执行,分别用于实现预处理逻辑、后处理逻辑和清理工作。

  1. preHandle:

    • 执行时机:在目标Controller方法调用之前。
    • 返回值:布尔值。如果返回true,则允许请求继续进行;如果返回false,则中断请求流程,后续的拦截器和目标方法都不会被执行。
    • 用途:通常用于权限检查、登录验证等操作,决定是否允许请求到达Controller。
  2. postHandle:

    • 执行时机:在目标Controller方法调用之后,视图渲染之前。
    • 返回值:无。
    • 用途:可以修改ModelAndView对象,添加或修改模型数据,但不能改变响应状态码和头信息。常用于对处理器方法的后处理,比如修改返回给客户端的数据。
  3. afterCompletion:

    • 执行时机:在整个请求处理完成之后,包括视图渲染。
    • 返回值:无。
    • 用途:主要用于资源清理等收尾工作,如关闭数据库连接、清除缓存等。类似于try-catch-finally中的finally块。

这三个方法的关系可以用下面这张简化的时序图来表示:

+---------+      +----------+      +-------------+
| preHandle | ---> | Controller Method |
+---------+      +----------+      +-------------+
        |                      |                  |
        |                      V                  V
        |         +------------+      +--------------+
        +-------->| postHandle | ---> | afterCompletion |
                   +------------+      +--------------+

总结来说,preHandle主要负责前期的权限控制和决策,postHandle用于对处理器方法返回的结果进行加工,而afterCompletion则是用来做一些善后的工作。这三者共同构成了一个完整的请求处理链,在不同的阶段为应用提供了扩展点。

1. 拦截器实际应用

在这个实战应用中,我们将创建一个拦截器,用于检查每个请求是否已经通过了登录验证。如果没有通过验证,将返回401 Unauthorized响应。

2. 创建自定义拦截器

首先,我们创建一个名为LoginInterceptor的类,实现org.springframework.web.servlet.HandlerInterceptor接口,并重写其中的方法。

package com.example.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

            HandlerMethod method = (HandlerMethod) handler;
            // 检查当前请求是否需要登录验证
            if (method.getMethodAnnotation(LoginRequired.class) != null) {
                // 获取当前登录用户的ID(这里假设已存在从session或token中获取用户ID的方法)
                Object o = getUserId(request);
                if (o == null) {
                    // 如果未登录,返回401 Unauthorized响应
                    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Please log in first.");
                    return false; // 中断后续流程
                }
            }

        return true;
    }

    private Object getUserId(HttpServletRequest request) {
        // 这里只是一个示例,实际项目中应根据实际情况从session或token中获取用户ID
        return request.getSession().getAttribute("userId");
    }

    // 可以选择性地实现postHandle和afterCompletion方法
}

在上述代码中,我们定义了一个LoginInterceptor类,它会在每个请求到达Controller之前运行。如果请求的方法上标记了@LoginRequired注解,那么我们就检查当前用户是否已经登录。如果没有登录,就返回401 Unauthorized响应。

3. 注册拦截器到Spring Boot容器

接下来,在Spring Boot的配置类中,通过实现org.springframework.web.servlet.config.annotation.WebMvcConfigurer接口并重写其addInterceptors()方法,将拦截器注册到Spring Boot的IoC容器中。

package com.example.config;

import com.example.interceptor.LoginInterceptor;
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 InterceptorConfig implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor).addPathPatterns("/**"); // 设置拦截器作用的URL路径
    }
}

4. 创建登录验证注解

为了方便地为需要登录验证的Controller方法添加注解,我们可以创建一个名为LoginRequired的注解。

package com.example.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginRequired {
}

5. 使用登录验证注解

现在,我们可以在Controller类的方法上使用@LoginRequired注解,表示这个方法需要登录验证。

package com.example.controller;

import com.example.annotation.LoginRequired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
    @GetMapping("/user/profile")
    @LoginRequired
    public String getUserProfile() {
        return "This is your profile.";
    }
}

在上述代码中,getUserProfile方法被标记了@LoginRequired注解,所以只有登录用户才能访问这个方法。

6. 示例代码

完整的示例代码可以在GitHub上找到:https://github.com/yourusername/spring-boot-interceptor-login-example

7. 总结

通过上述步骤,我们成功地在Spring Boot应用中整合了一个自定义的拦截器,实现了用户登录验证功能。这个拦截器可以在全局范围内控制哪些请求需要登录验证,增强了应用的安全性。

6. 总结

通过上述步骤,我们成功地在Spring Boot应用中整合了自定义的拦截器。这个拦截器会在所有请求进入Controller之前运行,提供了灵活的扩展点来添加全局功能。

过滤器和拦截器执行的先后顺序

创建一个简单的过滤器(Filter):

import javax.servlet.*;
import java.io.IOException;

public class MyFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("Filter is running");
        chain.doFilter(request, response);
    }
}

然后在Spring Boot的配置类中注册这个过滤器:

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<MyFilter> filterRegistration() {
        FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new MyFilter());
        registration.addUrlPatterns("/*");
        return registration;
    }
}

接下来,我们创建一个拦截器(Interceptor):

import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod method = (HandlerMethod) handler;
            System.out.println("Interceptor is running for method: " + method.getMethod().getName());
        }
        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 {
        // ...
    }
}

最后,在Spring Boot的配置类中添加对拦截器的支持:

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 InterceptorConfig implements WebMvcConfigurer {

    @Autowired
    private MyInterceptor myInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor).addPathPatterns("/**");
    }
}

现在,当你发送一个HTTP请求到你的应用时,你会看到这样的输出:

Filter is running
Interceptor is running for method: yourControllerMethodName

这说明过滤器先执行,然后才是拦截器。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
乘风的头像乘风管理团队
上一篇 2023年12月14日
下一篇 2023年12月14日

相关推荐