SSM项目遇到的问题(六)——拦截器和过滤器

471 阅读3分钟

过滤器

  1. 实现

    implements javax.servlet.Filter、XML中配置filter信息。

    重写init、doFilter、destroy三个方法

    • void init(FilterConfig var1) throws ServletException:初始化Filter,在servlet容器启动时执行且只在此时启动一次。(后续 不过滤指定请求 会用到)

    • void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException:实现过滤功能,可以在请求前预处理,也可以请求后处理,分界线是chain.doFilter()

    • void destroy():用于Filter销毁前,可用于资源回收。

  2. 使用

    public class TestFilter implements Filter {
        private String excluded;
        private String[] excludedPages;
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            excluded = filterConfig.getInitParameter("excluded");
            //System.out.println(excluded);
            if (excluded!=null && excluded.length()>0){
                excludedPages = excluded.split(",");
            }
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
            HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
            boolean flag = false;
            for (String page : excludedPages){
                if (httpServletRequest.getRequestURI().equals(page)){
                    flag = true;
                }
            }
    
            if (flag){
                filterChain.doFilter(servletRequest, servletResponse);
            }else {
                HttpSession session = httpServletRequest.getSession();
                Object curUser = session.getAttribute("curUser");
                if (curUser==null){
                    httpServletResponse.sendRedirect("/user/login");
                }else {
                    filterChain.doFilter(servletRequest, servletResponse);
                }
            }
        }
    
        @Override
        public void destroy() {
        }
    }
    

拦截器

  1. 实现

    implements org.springframework.web.servlet.HandlerInterceptor、spring-mvc.xml配置

    重写3个方法

    • boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception:如果返回true,则继续后续Interceptor的preHandle方法和controller;如果返回false,则后面的都不会执行。
    • void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception:如果preHandle返回false,这个方法不会执行。该方法执行在preHandle之后,视图渲染之前。多个Interceptor的postHandle的执行顺序,是:先声明的后执行。
    • void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception:该方法执行前提也是preHandle返回true。执行在请求结束之后,也就是渲染了视图之后才执行,可用于资源清理。类似于Filter的destroy。
  2. 使用

    public class TestInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            Object user = request.getSession().getAttribute("member");
            if (user==null){
                response.sendRedirect("/user/login");
                return false;
            }
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request,     HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        }
    }
    

拦截器和过滤器对比

对比 拦截器 过滤器
处理的目标 所有web请求 Action-部分web请求
实现原理 函数回调 Java反射(动态代理)
应用场景 字符编码 拦截未登录用户
URL级别的权限访问 审计日志
过滤敏感词
压缩响应信息
执行顺序 根据filter-mapping配置的先后 按配置的顺序,可通过order控制
规范 在Servlet规范中定义,servlet容器支持 spring容器内,spring框架支持
使用范围 只能用于Web程序 不仅Web程序,Application、swing都可以。
深度 只能在servlet前后使用 可以深入到方法前后,抛出异常前后。

Filter使用更加方便,Interceptor功能可以更细致的处理需求。

举例:计算请求响应时间。

Filter:

```
void doFilter() throw Exception{    
    long time = System.currentTimeMillis();    
    chain.doFilter();
    System.out.println("请求时间为:"+ (System.currentTimeMillis()-time));
}
```

interceptor:

```
long time = System.currentTimeMillis();  
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
   time = System.currentTimeMillis();
   return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    System.out.println("Interceptor cost="+(System.currentTimeMillis()-start));
}
```

Interceptor需要一个提前声明全局变量来存值,这就有可能引起线程问题。可以通过TreadLocal解决。


相关