spring boot拦截器

    拦截器都需要实现 HandIerInterceptor 接口

    HandlerInterceptor 源码

public interface HandlerInterceptor {
    
    // 处理器执行前方法
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        return true;
    }

    // 处理器处理后方法
    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            @Nullable ModelAndView modelAndView) throws Exception {
    }
    
    // 处理器完成后方法
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
            @Nullable Exception ex) throws Exception {
    }
}

  Interceptor 基于Java的反射机制,属于AOP的一种运用

优点

  由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用
缺点:

  只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。

拦截器中方法的执行流程

  

  

  请求到达 DispatcherServlet,DispatcherServlet 发送至 Interceptor ,执行 preHandle 方法,该方法会返回一个布尔值。如果为 false ,则结束所有流程:如果为 true , 则执行下一步。
  请求达到 Controller,执行处理器逻辑,包含控制器的功能 。
  执行 postHandle 方法。
  执行视图解析和视图渲染 。
  执行 afterCompletion 方法。

Spring Boot2整合拦截器Interceptor 示例

  1、实现HandlerInterceptor接口编写拦截器,继承HandlerInterceptorAdapter也可以

package com.example.boot_interceptor.interceptor;

import org.springframework.lang.Nullable;
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 {

    /**
     * preHandle在执行Controller之前执行
     * 返回true:继续执行处理器逻辑,包含Controller的功能
     * 返回false:中断请求
     *
     * 处理器执行前方法
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandler");
        return true;
    }

    /**
     * postHandle在请求执行完之后 渲染ModelAndView返回之前执行
     * 处理器处理后方法
     */
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        System.out.println("postHandler");
    }
    /**
     * afterCompletion在整个请求执行完毕后执行,无论是否发生异常都会执行
     *
     * 处理器完成后方法
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
}

  2、实现WebMvcConfigurer接口注册拦截器

  可以用来注册拦截器的类和接口

  • WebMvcConfigurationSupport: 不需要返回逻辑视图,可以选择继承此类
  • WebMvcConfigurer:返回逻辑视图,可以选择实现此方法,重写addInterceptor方法

  

package com.example.boot_interceptor.config;

import com.example.boot_interceptor.interceptor.MyInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
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) {
        //  注册拦截器到 Spring MVC 机制, 然后 它会返 回 一个拦截器注册
        InterceptorRegistration regist =  registry.addInterceptor(new MyInterceptor());
        // 指定拦截匹配模式,限制拦截器拦截请求
        regist.addPathPatterns("/interceptor/*");
        // 不拦截的路径
        regist.excludePathPatterns("/interceptor/exclude/*");
    }
}

 

       3、验证

package com.example.boot_interceptor.controller;

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

@RestController
@RequestMapping("/interceptor")
public class TestController {

    @GetMapping("/test")
    public String testInterceptor() {
        System.out.println("执行处理器逻辑testInterceptor....");
        return "请观察控制台中拦截器的日志输出";
    }


    @GetMapping("/exclude/test")
    public String testExcludeInterceptor() {
        System.out.println("执行处理器逻辑testExcludeInterceptor....");
        return "exclude排除,不会被拦截器拦截";
    }
}

Filter 过滤器

  既然是配置在web.xml中,那肯定是依赖于servlet容器.

优点:

  • 在实现上Filter是基于函数回调,可以对几乎所有请求进行过滤

缺点:

  • 一个过滤器实例只能在容器初始化时调用一次 . 当容器第一次加载该过滤器时,init() 方法将被调用

使用场景:

  • 比如设置编码、过滤敏感词汇、禁止浏览器缓存所有动态页面、实现用户自动登陆、实现URL级别的权限认证等等 

传统的JavaEE项目开发filter的主要2个步骤

  实现Filter接口,并实现其doFilter方法。
  在 web.xml 文件中使用<filter>和<filter-mapping>元素对编写的filter类进行注册,并设置它所能拦截的资源
  可以开发编写多个Filter,组成一个Filter链,根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter

方式一 FilterRegistrationBean注册

Step1 实现Filter接口 开发过滤器

package com.example.filter;

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.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HttpFilter implements Filter {
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("HttpFilter  init");
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("HttpFilter  doFilter begin");
        
        HttpServletRequest req =(HttpServletRequest) request;
        HttpServletResponse res =(HttpServletResponse) response;
        System.out.println("HttpFilter name:" + request.getParameter("name"));
        
        // 将请求转发给过滤器链上下一个对象。这里的下一个指的是下一个filter,如果没有filter那就是请求的资源。
        chain.doFilter(request, response);
        System.out.println("HttpFilter  doFilter end");
    }

    @Override
    public void destroy() {
        System.out.println("HttpFilter  destroy");
        Filter.super.destroy();
    }
}

  在配置类中注册该过滤器

package com.example.conf;

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

import com.artisan.filter.HttpFilter;

@Configuration
public class FilterConfig {
    
    @Bean
    public FilterRegistrationBean<HttpFilter> httpFilter(){
        FilterRegistrationBean<HttpFilter> filterRegistrationBean = new FilterRegistrationBean<HttpFilter>();
        // 设置filter
        filterRegistrationBean.setFilter(new HttpFilter());
        // 拦截规则
        filterRegistrationBean.addUrlPatterns("/*");
        return filterRegistrationBean;
    }
}

方式二 @WebServlet+ @ServletComponentScan注解的方式

Step1 @WebFilter注解开发过滤器

  @WebFilter 用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器

 

package com.example.filter;

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;
import javax.servlet.http.HttpServletResponse;

@WebFilter(filterName = "HttpFilter", urlPatterns = "/*")
public class HttpFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("HttpFilter init");
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("HttpFilter  doFilter begin");

        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        System.out.println("HttpFilter name:" + request.getParameter("name"));

        // 将请求转发给过滤器链上下一个对象。这里的下一个指的是下一个filter,如果没有filter那就是请求的资源。
        chain.doFilter(request, response);
        System.out.println("HttpFilter  doFilter end");
    }

    @Override
    public void destroy() {
        System.out.println("HttpFilter2  destroy");
        Filter.super.destroy();
    }
}

 

  Step2 启动类增加@ServletComponentScan注解

  在 SpringBootApplication 上使用@ServletComponentScan 注解后,Servlet、Filter、Listener 可以直接通过 @WebServlet、@WebFilter、@WebListener 注解自动注册

@SpringBootApplication
@ServletComponentScan
public class BootInterceptorApplication {

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

总结:

  Filter的执行顺序在Interceptor之前 。 拦截器(Interceptor)是基于Java的反射机制,而过滤器(Filter)是基于函数回调。从灵活性上说拦截器功能更强大些,Filter能做的事情,Interceptor都能做,而且可以在请求前,请求后执行,比较灵活。

 

 

 

posted on 2019-03-17 22:51  溪水静幽  阅读(428)  评论(0)    收藏  举报