(2018.03.22)
用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过滤器可以作用于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中的装饰器相类似。都是为了提高代码的可维护性。如果没学过,只能跟你解释说类似于游戏中的装备附魔,可以给它附加上额外的功能。比如给方法中加入日志,权限的功能,而不用去修改源代码。
如图: