JAVA中的拦截器、过滤器

慈云数据 1年前 (2024-03-15) 技术支持 55 0

JAVA变成拦截器、过滤器

  • 一、拦截器
    • 1、简介说明
    • 2、源码及方法说明
    • 3、拦截器自定义应用
    • 二、过滤器
      • 1、简介说明
      • 2、源码及方法说明
      • 3、过滤器的自定义应用
      • 三、Springboot中的WebMvcConfigurer
        • 1、简介
        • 2、主要方法
        • 3、添加拦截器
        • 四、区别
          • 1、原理
          • 2、触发
          • 3、其他

            一、拦截器

            1、简介说明

            相关解释:拦截器依赖于页面有访问controller的操作,且属于SpringMVC体系的动态拦截调用机制,是java中AOP思想的运用。

            来看看源码作者的注释:

            在这里插入图片描述

            其中倒数第二段话,描述其类似于过滤器,但其特点只允许使用自定义预处理,不能处理程序本身。此处可体现AOP思想。

            过滤器是在web.xml中配置,web.xml是应用程序上下文中的HandlerInterceptor。

            最后一段话,则体现了拦截器常用情况,如常见处理程序代码和授权检查。

            而过滤器非常适合请求内容和视图内容处理,如多部分表单和GZIP压缩。

            2、源码及方法说明

            HandlerInterceptor

            在这里插入图片描述

            HandlerInterceptor接口中有3个方法:

            preHandler():该方法会在控制器方法前执行,其返回值表示是否中断后续操作。当其返回值为true时,表示继续向下执行;当其返回值为false时,会中断后续的所有操作。

            postHandle():该方法会在控制器方法调用之后,且解析视图之前执行。可以通过此方法对请求域中的模型和视图做出进一步的修改。

            afterCompletion():该方法会在整个请求完成,即视图渲染结束之后执行。可以通过此方法实现一些资源清理、记录日志信息等工作。

            3、拦截器自定义应用

            实现 org.springframework.web.servlet.HandlerInterceptor 接口

            如常见的白名单控制

            package com.framework;
            import com.alibaba.fastjson.JSON;
            import org.springframework.stereotype.Component;
            import org.springframework.web.servlet.HandlerInterceptor;
            import javax.servlet.http.HttpServletRequest;
            import javax.servlet.http.HttpServletResponse;
            @Component
            public class WhiteRosterInterceptor implements HandlerInterceptor {
                @Override
                public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                    if(checkWhiteList()){
                        return true;
                    }
                    response.setContentType("application/json; charset=utf-8");
                    response.setCharacterEncoding("UTF-8");
                    response.getWriter().append(JSON.toJSONString("白名单暂未设置"));
                    return false;
                }
                private Boolean checkWhiteList(){
                    //业务处理
                    return true;
                }
            }
            

            二、过滤器

            1、简介说明

            相关解释:java过滤器能够对目标资源的请求和响应进行截取。

            来看看源码作者的注释:

            在这里插入图片描述

            其描述中说明该过滤器为基于(a servlet or static content)。

            同时也将其现有应用场景进行了说明,如权限过滤,加密过滤,图像转换过滤等等。

            2、源码及方法说明

            Filter

            在这里插入图片描述

            Filter接口中有3个方法:

            init():初始化参数,在创建Filter时自动调用,如需要设置初始化参数,可写到该方法中。

            doFilter():拦截到要执行的请求时,doFilter就会执行。写对请求和响应的预处理。

            destroy():销毁时Filter自动调用。

            init()和destroy(),为default方法,可不实现,但doFilter()必须实现,且方法中传进来的FilterChain对象用来调用下一个过滤器。

            3、过滤器的自定义应用

            实现javax.servlet.Filter 接口

            如常见的加解密过滤器

            package com.framework;
            import com.AesUtil;
            import com.response.ResponseWrapper;
            import org.springframework.stereotype.Component;
            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.http.HttpServletResponse;
            import java.io.IOException;
            import java.io.PrintWriter;
            @Component
            public class EncryptFilter implements Filter{
                @Override
                public void init(FilterConfig filterConfig) throws ServletException {
                }
                @Override
                public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
                    if(isExcept(request)){
                        chain.doFilter(request, response);
                        return;
                    }
                    response.setContentType("application/json; charset=utf-8");
                    response.setCharacterEncoding("UTF-8");
                    ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) response);
                    chain.doFilter(request, responseWrapper);
                    byte[] resData = responseWrapper.getResponseData();
                    String encrypt = AesUtil.encrypt(new String(resData, "utf-8"), "AesKey");
                    PrintWriter out = response.getWriter();
                    out.print(encrypt.replaceAll("[\\s*\t\n\r]", ""));
                    out.flush();
                    out.close();
                }
                private Boolean isExcept(ServletRequest HttpRequest){
                    //业务处理,是否不加密
                    return true;
                }
                @Override
                public void destroy() {
                }
            }
            

            依赖的 ResponseWrapper.java

            package com.response;
            import javax.servlet.ServletOutputStream;
            import javax.servlet.WriteListener;
            import javax.servlet.http.HttpServletResponse;
            import javax.servlet.http.HttpServletResponseWrapper;
            import java.io.ByteArrayOutputStream;
            import java.io.IOException;
            import java.io.OutputStreamWriter;
            import java.io.PrintWriter;
            public class ResponseWrapper extends HttpServletResponseWrapper {
                private ByteArrayOutputStream byteArrayOutputStream = null;
                private ServletOutputStream servletOutputStream = null;
                private PrintWriter printWriter = null;
                public ResponseWrapper(HttpServletResponse response) throws IOException {
                    super(response);
                    byteArrayOutputStream = new ByteArrayOutputStream();
                    servletOutputStream = new WrapperOutputStream(byteArrayOutputStream);
                    printWriter = new PrintWriter(new OutputStreamWriter(byteArrayOutputStream,this.getCharacterEncoding()));
                }
                private class WrapperOutputStream extends ServletOutputStream {
                    private ByteArrayOutputStream bos = null;
                    public WrapperOutputStream(ByteArrayOutputStream stream) throws IOException {
                        bos = stream;
                    }
                    @Override
                    public void write(int b) throws IOException {
                        bos.write(b);
                    }
                    @Override
                    public void write(byte[] b) throws IOException {
                        bos.write(b, 0, b.length);
                    }
                    @Override
                    public boolean isReady() {
                        return false;
                    }
                    @Override
                    public void setWriteListener(WriteListener writeListener) {
                    }
                }
            }
            

            当需要使用多个过滤器时,需要设置过滤器先后顺序。

            即在EncryptFilter类中使用 @Order() 注解,数值越小,优先级越高,执行顺序越靠前。

            加密相关链接:

            Springboot项目报文加密(采用AES、RSA动态加密策略):

            https://blog.csdn.net/qq_38254635/article/details/129275971

            Springboot集成AES加密:

            https://blog.csdn.net/qq_38254635/article/details/129622075

            三、Springboot中的WebMvcConfigurer

            1、简介

            为Spring内部的配置方式,通过JavaBean的方式来替代传统的xml配置文件形式,可自定义一些Handler,Interceptor,ViewResolver,MessageConverter,需创建配置类并实现WebMvcConfigurer接口

            2、主要方法

            addViewControllers:将一个请求转到一个页面。

            addResourceHandlers:静态资源的地址映射。

            configureMessageConverters:将@ResponseBody实体转FastJson字符串返回,可以返回实体进行重写。

            addCorsMappings:实现ajax跨域请求。

            addInterceptors:添加拦截器。

            3、添加拦截器

            1、自定义一个注解,用作手动单个接口忽略拦截

            package com.annotation;
            import java.lang.annotation.ElementType;
            import java.lang.annotation.Retention;
            import java.lang.annotation.RetentionPolicy;
            import java.lang.annotation.Target;
            @Target(ElementType.METHOD)
            @Retention(RetentionPolicy.RUNTIME)
            public @interface IgnoreInterceptor {
            }
            

            2、自定义配置,用作某路径下的请求批量忽略拦截

            放置在yml配置文件中。

            SpringBoot加载自定义yml中的配置参数:https://blog.csdn.net/qq_38254635/article/details/112033193

            3、编写拦截器类 WebMvcConfig.java

            package com.config;
            import com.alibaba.fastjson.JSON;
            import com.annotation.IgnoreInterceptor;
            import com.framework.WhiteRosterInterceptor;
            import org.springframework.beans.factory.annotation.Value;
            import org.springframework.context.annotation.Configuration;
            import org.springframework.web.method.HandlerMethod;
            import org.springframework.web.servlet.HandlerInterceptor;
            import org.springframework.web.servlet.ModelAndView;
            import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
            import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
            import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
            import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
            import javax.annotation.Resource;
            import javax.servlet.http.HttpServletRequest;
            import javax.servlet.http.HttpServletResponse;
            import java.util.List;
            @Configuration
            public class WebMvcConfig implements WebMvcConfigurer {
                @Value("#{'${spring.excludePath}'.split(',')}")
                private List excludePath;
                @Resource
                private WhiteRosterInterceptor whiteRosterInterceptor;
                @Override
                public void addViewControllers(ViewControllerRegistry registry) {
                    registry.addViewController("/").setViewName("index");
                }
                @Override
                public void addResourceHandlers(ResourceHandlerRegistry registry) {
                    registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
                }
                @Override
                public void addInterceptors(InterceptorRegistry registry) {
                    registry.addInterceptor(new HandlerInterceptor() {
                        @Override
                        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                            if (handler instanceof HandlerMethod) {
                                HandlerMethod method = (HandlerMethod) handler;
                                IgnoreInterceptor methodAnnotation = method.getMethodAnnotation(IgnoreInterceptor.class);
                                if(null != methodAnnotation) return true;
                                if (!isLogin(request)) {
                                    response.setContentType("application/json; charset=utf-8");
                                    response.setCharacterEncoding("UTF-8");
                                    response.getWriter().append(JSON.toJSONString("未登录"));
                                    return false;
                                }
                                refreshLogin(request);
                                return true;
                            }
                            return true;
                        }
                        private Boolean isLogin(HttpServletRequest request) {
                            //判断用户是否登录
                            return true;
                        }
                        private void refreshLogin(HttpServletRequest request) {
                            //刷新登录信息
                        }
                        @Override
                        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
                            //处理完业务后,清除用户的登录相关信息,永远放在最后处理
                        }
                    }).addPathPatterns("/**").excludePathPatterns(excludePath);
                    registry.addInterceptor(whiteRosterInterceptor).addPathPatterns("/api/**");
                }
            }
            

            4、说明

            拦截器方式addInterceptors中,可实现多个拦截器。

            可通过 registry.addInterceptor()增加拦截器,如上接口,增加了文中白名单拦截器。

            addPathPatterns:拦截路径,**表示匹配后续所有路径

            excludePathPatterns:忽略路径,接口中excludePath使用yml配置的路径,进行忽略操作。

            IgnoreInterceptor:自定义注解,手动忽略某请求,在拦截器做了单独处理。

            如自定义拦截器,可通过注入的方式添加。

            执行顺序也根据配置的顺序,依次执行。

            四、区别

            1、原理

            拦截器方法都是通过代理的方式来调用的,是基于反射机制实现的,依赖于web框架。

            过滤器的实现是基于回调函数的。依赖于Servlet容器

            2、触发

            如1.1中源码注释所说。

            拦截器:对请求在handler【Controller】前后进行处理,属于应用上下文。

            过滤器:对请求在进入后Servlet之前或之后进行处理,允许交换请求和响应对象,使用web.xml配置。

            在这里插入图片描述

            拦截器和过滤器执行顺序:

            1、Filter.init();

            2、Filter.doFilter(); before doFilter

            3、HandlerInterceptor.preHandle();

            4、Controller方法执行

            5、HandlerInterceptor.postHandle();

            6、DispatcherServlet视图渲染

            7、HandlerInterceptor.afterCompletion();

            8、Filter.doFilter(); after doFilter

            9、Filter.destroy();

            在这里插入图片描述

            3、其他

            过滤器:每一次都传入FilterChain对象,达到最后接口回调的效果。

            拦截器:任何一个拦截器的preHandle为false,则其后的所有拦截器都不会执行。只有所有的拦截器preHandler都为true,postHandle才会执行。

            多个过滤器设置执行顺序:增加 @Order() 注解,数值越小,优先级越高,执行顺序越靠前。

            在这里插入图片描述

            多个拦截器设置执行顺序:可通过实现Ordered接口来实现。

            在这里插入图片描述

            相关链接:

            SpringBoot过滤器获取请求的参数:https://blog.csdn.net/qq_38254635/article/details/136041159

            SpringBoot过滤器获取响应的参数:https://blog.csdn.net/qq_38254635/article/details/136041183

            参考链接:

            https://baijiahao.baidu.com/s?id=1677716748772601748

            https://blog.csdn.net/m0_53123540/article/details/124924596

            https://blog.csdn.net/king101125s/article/details/104372380

微信扫一扫加客服

微信扫一扫加客服