Spring Boot Filter(过滤器)& Interceptor(拦截器)

Spring Boot 2.2.4.RELEASE

准备

新建 Spring Boot 项目,引入依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

新建控制器类:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IndexController {

    @GetMapping({"/"})
    public String index() {
        return "index";
    }

    @GetMapping({"/hello"})
    public String hello() {
        return "hello";
    }
}

过滤器

基于注解

新建过滤器类,并在类上使用 @WebFilter 注解:

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;

@WebFilter(urlPatterns = {"/hello"})
public class IpFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器初始化...");
    }
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("TimeFilter.doFilter() 过滤器开始执行...");
        String ip = request.getRemoteAddr();
        System.out.println(ip);
        chain.doFilter(request, response);
        System.out.println("TimeFilter.doFilter() 过滤器结束执行...");
    }

    @Override
    public void destroy() {
        System.out.println("过滤器被销毁...");
    }
}

在启动类上添加 @ServletComponentScan 注解:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@ServletComponentScan
@SpringBootApplication
public class SpringBootFilterApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootFilterApplication.class, args);
    }
}

启动项目,可以看到控制台输出 过滤器初始化...

因为配置 IpFilter 过滤器时,只对 /hello 进行过滤。所以,访问 http://localhost:8080/,是不会经过 IpFilter.doFilter 方法的。

当我们访问 http://localhost:8080/hello,控制台输出:

TimeFilter.doFilter() 过滤器开始执行...
0:0:0:0:0:0:0:1
TimeFilter.doFilter() 过滤器结束执行...

注意:如果直接在过滤器类上使用 @Component 注解,而不是使用 @WebFilter 注解,则默认会过滤所有请求。

基于编程式配置

新建配置类:

import javax.servlet.Filter;

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

import com.mk.filter.IpFilter;

@Configuration
public class WebConfig {

    @Bean
    public FilterRegistrationBean<Filter> ipFilter() {
        FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<Filter>();
        IpFilter ipFilter = new IpFilter();
        filterRegistrationBean.setFilter(ipFilter);
        filterRegistrationBean.addUrlPatterns("/hello");
        return filterRegistrationBean;
    }
}

取消 IpFilter 过滤器类上的 @WebFilter 注解,以及启动类上的 @ServletComponentScan 注解。重启项目,访问 http://localhost:8080/http://localhost:8080/hello,可以在控制台看到和上面一样的效果。

拦截器

新建一个拦截器类,实现 HandlerInterceptor 接口:

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

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

@Component
public class HelloInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("HelloInterceptor.preHandle() 开始...");
        System.out.println("方法:" + ((HandlerMethod) handler).getBean().getClass().getName()
                + "." + ((HandlerMethod) handler).getMethod().getName());
        System.out.println("HelloInterceptor.preHandle() 结束...");
        return true;
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("HelloInterceptor.postHandle() 开始...");
        System.out.println("HelloInterceptor.postHandle() 结束...");
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("HelloInterceptor.afterCompletion() 开始...");
        System.out.println("异常信息:" + ex);
        System.out.println("HelloInterceptor.afterCompletion() 结束...");
    }
}

HelloInterceptor 拦截器实现了 HandlerInterceptor 接口的三个方法。preHandle 方法在处理拦截之前执行,postHandle 方法只有当被拦截的方法没有抛出异常才会执行,afterCompletion 方法无论被拦截的方法抛出异常与否都会执行。

修改 WebConfig 配置类,实现 WebMvcConfigurer 接口,重写 addInterceptors 方法,添加拦截器(第 26 ~ 29 行):

package com.mk.config;

import javax.servlet.Filter;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.mk.filter.IpFilter;
import com.mk.interceptor.HelloInterceptor;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Autowired
    private HelloInterceptor helloInterceptor;

    @Bean
    public FilterRegistrationBean<Filter> ipFilter() {
        ...
    }
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(this.helloInterceptor);
    }
}

修改 IndexController 控制器类,新建 exception 方法,手动抛出异常:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IndexController {

    @GetMapping({"/"})
    public String index() {
        return "index";
    }

    @GetMapping({"/hello"})
    public String hello() {
        System.out.println("IndexController.hello()");
        return "hello";
    }
    
    @GetMapping("/ex")
    public void exception() {
        throw new RuntimeException("异常!");
    }
}

重启项目,访问 http://localhost:8080/hello,控制台输出:

TimeFilter.doFilter() 过滤器开始执行...
127.0.0.1
HelloInterceptor.preHandle() 开始...
方法:com.mk.controller.IndexController.hello
HelloInterceptor.preHandle() 结束...
IndexController.hello()
HelloInterceptor.postHandle() 开始...
HelloInterceptor.postHandle() 结束...
HelloInterceptor.afterCompletion() 开始...
异常信息:null
HelloInterceptor.afterCompletion() 结束...
TimeFilter.doFilter() 过滤器结束执行...

从输出中我们可以了解到三个方法的执行顺序,并且三个方法都被执行了。并且,过滤器要先于拦截器执行,晚于拦截器结束。

访问 http://127.0.0.1:8080/ex,控制台输出:

HelloInterceptor.preHandle() 开始...
方法:com.mk.controller.IndexController.exception
HelloInterceptor.preHandle() 结束...
HelloInterceptor.afterCompletion() 开始...
异常信息:java.lang.RuntimeException: 异常!
HelloInterceptor.afterCompletion() 结束...

可看到,postHandle 方法并没有被执行。

发布了36 篇原创文章 · 获赞 0 · 访问量 1852

猜你喜欢

转载自blog.csdn.net/qq_29761395/article/details/104066662