SpringBoot中的Filter与Interceptor

SpringBoot中的Filter与Interceptor

(2018.03.22)

一、项目环境

  • 开发工具:IDEA
  • JDK:1.8
  • 项目框架:SpringBoot 1.0.4 + Maven

二、过滤器配置及使用

用log4j记录Filter的处理过程

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

//urlPatterns中填入你想过滤的请求地址
@WebFilter(filterName = "userFilter" , urlPatterns = "/*")
public class UserFilter implements Filter {

    private static Logger logger = LoggerFactory.getLogger(UserFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        logger.info("----------------过滤器正在启动-----------------");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String requestURI = request.getRequestURI();
        logger.info("----------------过滤器正在处理-----------------");
        logger.info("该请求为:"+requestURI);
        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

别忘了在Springboot的启动类中添加注解扫描@ServletComponentScan

启动的时候可以看到SpringBoot的后台日志输出

2018-03-22 11:15:31.916  INFO 1032 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'userFilter' to urls: [/*]
2018-03-22 11:15:31.937  INFO 1032 --- [ost-startStop-1] com.example.app.web.filter.UserFilter    : ----------------过滤器正在启动-----------------

访问指定路径后端控制台日志如下:

2018-03-22 14:16:22.965  INFO 10208 --- [nio-8080-exec-2] com.example.app.web.filter.UserFilter    : ----------------过滤器正在处理-----------------
2018-03-22 14:16:22.966  INFO 10208 --- [nio-8080-exec-2] com.example.app.web.filter.UserFilter    : 过滤的该请求为:/user/login.do
2018-03-22 14:16:23.677  INFO 10208 --- [nio-8080-exec-4] com.example.app.web.filter.UserFilter    : ----------------过滤器正在处理-----------------
2018-03-22 14:16:23.678  INFO 10208 --- [nio-8080-exec-4] com.example.app.web.filter.UserFilter    : 过滤的该请求为:/user/getManager

还可以指定Filter过滤异步ajax请求,可以通过requst.getHeader(),判断请求头是否为”XMLHttpRequest“,若是的话则为异步ajax请求。

private static String ajaxHeader = "XMLHttpRequest";

//在doFilter方法中:
if (StringUtils.equals(request.getHeader("X-Requested-With"),ajaxHeader)) {
            logger.info("接收到ajax异步请求");
        }

上面一段代码中有StringUtils,那个是apache提供的字符串工具类,其中的.equals方法可以避免常规equals方法抛出空指针异常的错误,是个非常好用的工具类。

页面发送一个/user/login.do的登录ajax请求到后端,可以看到控制台打印出日志:

2018-03-22 14:29:18.210  INFO 11716 --- [nio-8080-exec-1] com.example.app.web.filter.UserFilter    : ----------------过滤器正在处理-----------------
2018-03-22 14:29:18.210  INFO 11716 --- [nio-8080-exec-1] com.example.app.web.filter.UserFilter    : 过滤的该请求为:/user/login.do
2018-03-22 14:29:18.212  INFO 11716 --- [nio-8080-exec-1] com.example.app.web.filter.UserFilter    : 接收到ajax异步请求

三、拦截器的配置及使用

使用拦截器的时候要明白,拦截器是Spring提供的,

需要新建两个类,分别是UserInterceptor拦截器类,与WebConfig配置类。

首先是拦截器类,需要实现HandlerInterceptor的接口。在preHandle方法中可以进行判断,return true放行该请求,false则拦截阻止该请求。

public class UserInterceptor implements HandlerInterceptor {

    private static Logger logger = LoggerFactory.getLogger(UserInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        logger.info("---------------拦截器正在处理----------------");
        logger.info("拦截的该请求为:"+httpServletRequest.getRequestURI());

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }
}

接下来是第二个类,WebConfig配置类,注意需要添加@Configuration注解:

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        super.addInterceptors(registry);

        //添加拦截器
        registry.addInterceptor(new UserInterceptor()).
            addPathPatterns("/**").excludePathPatterns("/user/login.do");
    }

}

可以不断添加addPathPatterns()来指定要拦截的请求地址,excludePathPatterns()是指定忽略拦截的请求。

访问指定请求地址后,可见后端控制台日志输出:

2018-03-22 15:10:31.768  INFO 2432 --- [nio-8080-exec-3] c.e.app.web.interceptor.UserInterceptor  : ---------------拦截器正在处理----------------
2018-03-22 15:10:31.768  INFO 2432 --- [nio-8080-exec-3] c.e.app.web.interceptor.UserInterceptor  : 拦截的该请求为:/user/getManager

四、过滤器Filter与拦截器Interceptor的区别

就个人目前来看,最大的区别是Filter过滤器可以作用于Servlet及Controller。而拦截器无法拦截到发送至Servlet中的请求,只能拦截到Controller中的。

从后端控制台日志可以看出:

2018-03-22 15:27:23.208  INFO 5824 --- [nio-8080-exec-5] com.example.app.web.filter.UserFilter    : ----------------过滤器正在处理-----------------
2018-03-22 15:27:23.208  INFO 5824 --- [nio-8080-exec-5] com.example.app.web.filter.UserFilter    : 过滤的该请求为:/user/login.do
2018-03-22 15:27:23.372  INFO 5824 --- [nio-8080-exec-4] com.example.app.web.filter.UserFilter    : ----------------过滤器正在处理-----------------
2018-03-22 15:27:23.372  INFO 5824 --- [nio-8080-exec-6] com.example.app.web.filter.UserFilter    : ----------------过滤器正在处理-----------------
2018-03-22 15:27:23.372  INFO 5824 --- [nio-8080-exec-4] com.example.app.web.filter.UserFilter    : 过滤的该请求为:/userSevlet
2018-03-22 15:27:23.372  INFO 5824 --- [nio-8080-exec-6] com.example.app.web.filter.UserFilter    : 过滤的该请求为:/user/getManager
2018-03-22 15:27:23.372  INFO 5824 --- [nio-8080-exec-6] c.e.app.web.interceptor.UserInterceptor  : ---------------拦截器正在处理----------------
2018-03-22 15:27:23.373  INFO 5824 --- [nio-8080-exec-6] c.e.app.web.interceptor.UserInterceptor  : 拦截的该请求为:/user/getManager

可见拦截器并没有拦截到发送到UserServlet的请求,且过滤前执行全都在拦截器之前。

说明我们在搭建项目的时候就应该考虑应该使用Servlet还是使用Controller去处理请求。不过建议在Spring的框架下尽量使用拦截器。


以下是我在别处找到的过滤器与拦截器的不同之处,可供参考:
1. 拦截器是基于动态代理的,而过滤器是基于函数回调。
2. 拦截器不依赖于servlet容器,通过动态代理实现,过滤器依赖于servlet容器。
3. 拦截器可以在方法前后,异常前后等调用,而过滤器只能在请求前和请求后各调用一次。
4. 拦截器可以利用依赖注入,因此在Spring框架程序中,优先拦截器。

[注]:动态代理,学过python的朋友知道装饰器的话,动态代理就与python中的装饰器相类似。都是为了提高代码的可维护性。如果没学过,只能跟你解释说类似于游戏中的装备附魔,可以给它附加上额外的功能。比如给方法中加入日志,权限的功能,而不用去修改源代码。

过滤器与拦截器的执行顺序

如图:
这里写图片描述

你可能感兴趣的:(实习)