• 过滤器(Filter)与拦截器


    过滤器(Filter)与拦截器

    https://www.yuque.com/bigbeardhk/java/glico7


    一、过滤器(Filter)

    1.概念

    • 什么是过滤器

    过滤器(Filter)是处于客户端与服务器目标资源之间的一道过滤技术。

    • 过滤器作用

    在访问目标资源文件之前,通过一系列的过滤器对请求进行修改、判断等,把不符合规则的请求在中途拦截或修改。也可以对响应进行过滤,拦截或修改响应。例如:实现权限访问控制、过滤敏感词汇、压缩响应信息功能、简单登录认证、ip黑名单封禁请求等。

    2.过滤的过程

    3.代码实现

    存在注解与配置类实现两种方法,推荐配置类实现

    • 简单的登录认证过滤
    /**
     * Copyright (c) bigbeardhk@163.com Corporation 2022. All Rights Reserved.
     */
    
    package com.hk.study.config;
    
    import com.hk.study.filter.LoginFilter;
    import com.hk.study.filter.TestFilter;
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 过滤器配置类
     *
     * @Author : bigbeardhk
     * @Date : 2022/05/03 15:51
     **/
    @Configuration
    public class FilterConfig {
        @Bean
        public FilterRegistrationBean authFilterRegistation(){
            FilterRegistrationBean registrationBean = new FilterRegistrationBean();
            //注册bean
            registrationBean.setFilter(new LoginFilter());
            //设置bean name
            registrationBean.setName("LoginFilter");
            //设置属性值
            Map<String, String> initParameters = new HashMap<>(2);
            initParameters.put("includeUrls","/hello/login,/swagger-ui.html");
            registrationBean.setInitParameters(initParameters);
            //拦截所有请求
            registrationBean.addUrlPatterns("/*");
            //执行顺序,数字越小优先级越高
            registrationBean.setOrder(1);
            return registrationBean;
        }
    
        @Bean
        public FilterRegistrationBean testFilterRegistation(){
            System.out.println("=========过滤器配置Bean方法testFilterRegistation===========");
            FilterRegistrationBean registrationBean = new FilterRegistrationBean();
            //注册bean
            registrationBean.setFilter(new TestFilter());
            //设置bean name
            registrationBean.setName("TestFilter");
            //拦截所有请求
            registrationBean.addUrlPatterns("/*");
            //执行顺序,数字越小优先级越高
            registrationBean.setOrder(9);
            return registrationBean;
        }
    }
    
    
    /**
     * Copyright (c) bigbeardhk@163.com Corporation 2022. All Rights Reserved.
     */
    
    package com.hk.study.filter;
    
    import com.hk.study.util.StringUtil;
    import lombok.extern.slf4j.Slf4j;
    
    import javax.servlet.*;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    import java.io.IOException;
    
    /**
     * 登录认证
     *
     * @Author : bigbeardhk
     * @Date : 2022/05/03 15:35
     **/
    @Slf4j
    public class LoginFilter implements Filter {
        /**
         * 不需要登录就可以访问的路径(比如:注册登录等)
         */
        private String includeUrls;
    
        /**
         * 只在tomcat容器启动时执行一次
         *
         * @param filterConfig
         * @throws ServletException
         */
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            //获取初始化filter的参数
    //        this.includeUrls = filterConfig.getInitParameter("includeUrls");
            this.includeUrls = "/hello/login,/swagger-ui.html";
        }
    
        /**
         * 客服端发生请求时doFilter前置执行,服务端返回请求时doFilter后置执行
         * 模拟登录认证
         * 1.拦截使用/*(但登录地址/hello/login放行)
         * 2.所以到达/hello/login接口后,验证密码,
         * 密码正确就会在服务器的session中进行setAttribute("user", name + pass)操作;
         * 3.然后请求其它地址中,通过cooking中sessionId,我们在服务器中发现它对应的
         * session.getAttribute("user")是存在的,说明他登录过,所以放行这次请求
         *
         * @param servletRequest
         * @param servletResponse
         * @param filterChain
         * @throws IOException
         * @throws ServletException
         */
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            HttpSession session = request.getSession();
            String uri = request.getRequestURI();
            log.info("filter url:"+uri);
    
            //不需要过滤直接传给下一个过滤器
            if (!StringUtil.isEmpty(includeUrls) && includeUrls.contains(uri)) {
                filterChain.doFilter(servletRequest, servletResponse);
            } else {
                //需要过滤器
                // session中包含user对象,则是登录状态
                if(session!=null&&session.getAttribute("user") != null){
                    System.out.println("user:"+session.getAttribute("user"));
                    filterChain.doFilter(request, response);
                }else{
                    response.setContentType("Application/json;charset=UTF-8");
                    response.getWriter().write("您还未登录");
                    // 重定向到登录页(需要在static文件夹下建立此html文件)
                    // response.sendRedirect(request.getContextPath()+"/user/login.html");
                    return;
                }
            }
        }
    
        @Override
        public void destroy() {
        }
    }
    

    二、拦截器(HandlerInterceptor)

    执行顺序
    image.png
    代码实现

    /**
     * Copyright (c) bigbeardhk@163.com Corporation 2022. All Rights Reserved.
     */
    
    package com.hk.study.intercept;
    
    import lombok.extern.slf4j.Slf4j;
    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;
    
    /**
     * 日志拦截器实现
     * @Author : bigbeardhk
     * @Date : 2022/05/03 19:30
     **/
    @Slf4j
    public class LogInterceptor implements HandlerInterceptor{
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            log.info("日志拦截器preHandle方法执行");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
            log.info("日志拦截器postHandle方法执行");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
            log.info("日志拦截器afterCompletion方法执行");
        }
    }
    
    /**
     * Copyright (c) bigbeardhk@163.com Corporation 2022. All Rights Reserved.
     */
    
    package com.hk.study.config;
    
    import com.hk.study.intercept.LogInterceptor;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    /**
     * 拦截器全局配置
     *
     * @Author : bigbeardhk
     * @Date : 2022/05/03 19:32
     **/
    @Configuration
    public class InterceptorConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            //需要拦截的路径,/**表示拦截所有请求
    //        String[] addPathPatterns={"/**"};
            String[] addPathPatterns={"/sdgdfgf"};
            //不需要拦截的路径
            String[] excludePathPatterns={"/boot/login","/boot/exit"};
            //新注册的过滤器
            registry.addInterceptor(new LogInterceptor())
                    .addPathPatterns(addPathPatterns)
                    .excludePathPatterns(excludePathPatterns);
    
            /*registry.addInterceptor(new AuthIntercepter())
                    .addPathPatterns(addPathPatterns)
                    .excludePathPatterns(excludePathPatterns);*/
        }
    }
    

    三、切面编程(Aspect)

    详见SpringAOP的实现


    四、拦截器,过滤器,Aspect的区别

    • 共同点

    三者都是AOP思想体现

    都可以对HttpServletRequest对象进行处理,日志、权限控制等

    • 区别

    Filter属于Servlet规范,Intercepter、Spring AOP属于Spring框架

    实现AOP的方式不同,Filter用回调函数实现,一般情况下拿不到Spring bean对象,Intercepter用责任链实现,Spring AOP基于动态代理

    • 执行顺序

    image.png

    clipboard.png


    五、常见问题

    1. 过滤器各方法的执行时机?
    • init()与destroy()方法只会在tomcat(项目)启动或关闭时执行一次(一定会执行,不受配置URL影响),不会在客服端请求后再次执行
    • doFilter()在客服端请求(根据配置判断是否拦截)时执行,request请求时,执行doFilter上面代码;response响应时,执行doFilter下面代码;
    1. 过滤器,拦截器的执行顺序?

    image.png


    资料学习与引用

  • 相关阅读:
    jprofiler监控分析
    实现loadrunner的IP欺骗
    dump内存和线程栈
    jprofiler监控tomcat
    nginx+tomcat负载均衡搭建及梦林博客http://www.limlhome.cn/blog/?p=298
    jconsole和jvisualvm监控tomcat配置
    apache+tomcat实现session共享
    性能测试流程
    AcWing101 最高的牛 (差分)
    AcWing100 增减序列 (差分)
  • 原文地址:https://www.cnblogs.com/bigbeardhk/p/16220506.html
Copyright © 2020-2023  润新知