Filter

1)SpringBoot 启动时默认加载四个 Filter

characterEncodingFilter、hiddenHttpMethodFilter、httpPutFormContentFilter、requestContextFilter

2)Filter 优先级

Ordered.HIGHEST_PRECEDENCE 表示最高的优先级,对应最小的整数值;Ordered.LOWEST_PRECEDENCE 表示最低的优先级,对应最大的整数值。

低位值意味着更高的优先级。自定义 Filter 避免和默认的 Filter 优先级一样,不然会冲突

3)在 SpringBoot 中使用 Servlet3.0 配置自定义 Filter

步骤1:使用 @WebFilter 注解来标记一个类为 Filter,当然这个类还需实现 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(urlPatterns = "/api/*", filterName = "loginFilter")
public class LoginFilter  implements Filter{

     /**
      * 容器加载的时候调用
      */
      @Override
      public void init(FilterConfig filterConfig) throws ServletException {
          System.out.println("init loginFilter");
      }

      /**
       * 请求被拦截的时候进行调用
       */
      @Override
      public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
          System.out.println("doFilter loginFilter");
          
          HttpServletRequest req = (HttpServletRequest) servletRequest;
          HttpServletResponse resp = (HttpServletResponse) servletResponse;
          String username = req.getParameter("username");
          
          if ("xdclass".equals(username)) {
              filterChain.doFilter(servletRequest,servletResponse);
          } else {
              resp.sendRedirect("/index.html");
              return;
          }
      }

      /**
       * 容器被销毁的时候被调用
       */
      @Override
      public void destroy() {
          System.out.println("destroy loginFilter");
      }
}

步骤2:启动类需要添加 @ServletComponentScan 注解,用于扫描到 Filter。

如果想要返回Json字符串

private void renderJson(HttpServletResponse response,String json){
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");

        try(PrintWriter writer = response.getWriter()){
            writer.print(json);
        }catch (Exception e){
            e.printStackTrace();
        }
}

过滤器一般用于非前后分离场景(如:权限控制、用户登录),如果校验不通过,可以使用 resp.sendRedirect("/index.html"); 跳转到错误页面等。

官网地址:https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/reference/htmlsingle/#boot-features-embedded-container-servlets-filters-listeners

 

Servlet

1)在 SpringBoot 中使用 Servlet3.0 的注解自定义原生 Servlet

步骤1:使用 @WebServlet 注解来标记一个类为 servlet,当然这个类还需实现 HttpServlet 接口

@WebServlet(name = "userServlet",urlPatterns = "/test/customs")
public class UserServlet extends HttpServlet{

     @Override
     public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         resp.getWriter().print("custom sevlet");
         resp.getWriter().flush();
         resp.getWriter().close();
     }

     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         this.doGet(req, resp);
     }
}

步骤2:启动类需要添加 @ServletComponentScan 注解,用于扫描到 Servlet。

 

Listener

1)在 SpringBoot 中使用 Servlet3.0 的注解自定义原生 Listener

步骤1:使用 @WebListener 注解来标记一个类为 Listener,当然这个类还需实现对应的 Listener 接口。常用的监听器 servletContextListener、httpSessionListener、servletRequestListener。

@WebListener
public class RequestListener implements ServletRequestListener {
  @Override
  public void requestDestroyed(ServletRequestEvent sre) {
    System.out.println("======requestDestroyed========");
  }

  @Override
  public void requestInitialized(ServletRequestEvent sre) {
    System.out.println("======requestInitialized========");  
  }
}

步骤2:启动类需要添加 @ServletComponentScan 注解,用于扫描到 Servlet。 

Interceptor

1)在 SpringBoot 中使用 Interceptor

步骤1:新建自定义的 Interceptor 类,实现 HandlerInterceptor 接口

public class LoginIntercepter implements HandlerInterceptor{

    /**
     * 进入controller方法之前
     */
    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        System.out.println("LoginIntercepter------->preHandle");
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    /**
     * 调用完controller之后,视图渲染之前
     */
    @Override
    public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        
        System.out.println("LoginIntercepter------->postHandle");
        
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    /**
     * 整个完成之后,通常用于资源清理
     */
    @Override
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("LoginIntercepter------->afterCompletion");
        
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

步骤2:Spring Boot 2.0 的实现方式:新建一个配置类(实现 WebMvcConfigurer 接口),使用 @Configuration 注解

@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer  {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(new LoginIntercepter()).addPathPatterns("/api2/*/**");
        registry.addInterceptor(new TwoIntercepter()).addPathPatterns("/api2/*/**");

        WebMvcConfigurer.super.addInterceptors(registry);
    }
}

老的实现方式:新建一个配置类(继承 WebMvcConfigurerAdapter 父类),使用 @Configuration 注解

@Configuration
public class CustomOldWebMvcConfigurer extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginIntercepter()).addPathPatterns("/api/");
        
        super.addInterceptors(registry);
    }
}

拦截器几个方法的含义: 

2)拦截器不生效常见问题:

① 是否有加@Configuration

② 拦截路径是否有问题 ** 和 *

③ 拦截器最后路径一定要 “/**”, 如果是目录的话则是 /*/

3)过滤器(Filter)和拦截器(Interceptor)的区别

① Filter 是基于函数回调  doFilter(),而 Interceptor 则是基于 AOP 思想

② Filter 在只在 Servlet 前后起作用,而 Interceptor 够深入到方法前后、异常抛出前后等

③ 依赖于 Servlet 容器即 Web 应用中,而 Interceptor 不依赖于 Servlet 容器所以可以运行在多种环境。

④ 在接口调用的生命周期里,Interceptor 可以被多次调用,而 Filter 只能在容器初始化时调用一次。

⑤ Filter 和 Interceptor 的执行顺序:过滤前->拦截前->action执行->拦截后->过滤后