美文网首页web容器(nginx, tomcat等)
过滤器(Filter), 拦截器(Interceptor), 监

过滤器(Filter), 拦截器(Interceptor), 监

作者: suxin1932 | 来源:发表于2019-07-25 21:01 被阅读0次
    #SpringBoot中:
    ServletRegistrationBean --注册--> Servlet
    FilterRegistrationBean --注册--> Filter
    ServletListenerRegistrationBean --注册--> Listener
    

    1.Filter

    过滤器是服务端的一个组件,是基于servlet实现从客户端访问服务端web资源的一种拦截机制,
    对请求request和响应response都进行过滤,依赖于serverlet容器.
    使用时,实现Filter接口,在web.xml里配置对应的class还有mapping-url,
    springboot工程可以通FilterRegisteration配置后,设置要过滤的URL
    #注意  
    两种方式过滤器都是有序的!
    
    定义过滤器后会重写三个方法,分别是init(),doFilter(),和destory():
    #init方法
    是过滤器的初始化方法,当web容器创建这个bean的时候就会执行,
    这个方法可以读取web.xml里面的参数
    
    #doFilter方法
    是执行过滤的请求的核心,当客户端请求访问web资源时,
    这个时候我们可以拿到request里面的参数,对数据进行处理后,
    通过filterChain方法将请求将请求放行,
    也可以通过response对响应进行处理(比如压缩响应),然后会传递到下一个过滤器
    
    #destory方法
    是当web容器中的过滤器实例被销毁时,会被执行,释放资源
    
    #summary
    过滤器的生命周期为:
    实例化(web.xml) --> 初始化(init) --> 过滤(doFilter) --> 销毁(destroy)
    
    Filter.png

    2.拦截器Interceptor

    过滤器依赖serverlet容器,获取request和response处理,是基于函数回调,简单说就是“去取你想取的”;
    拦截器是通过java反射机制,动态代理来拦截web请求,是“拒你想拒绝的”,他只拦截web请求,但不拦截静态资源
    
    #拦截器的三个方法,preHandler(),postHandler(),afterCompletion()
    #preHandler(): 
    这个方法是在controller调用之前调用,通过返回true或者false决定是否进入Controller层
    
    #postHandler():
    在请求进入控制层之后调用,但是在处理请求抛出异常时不会调用
    
    #afterCompletion(): 
    在请求处理完成之后,也就是在DispatherServlet渲染了视图之后执行,
    也就是说这个方法必定是执行,包含异常信息,它的主要作用就是清理资源
    
    Interceptor.png

    示例代码

    Interceptor.png
    package com.zy.netty.config;
    
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    @Component
    public class MyInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println(">>>>>>>>> preHandle");
            // 如果请求URI是c1, 返回false进行拦截, 否则不拦截
            return !"/c1".equals(request.getRequestURI());
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println(">>>>>>>>> postHandle");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println(">>>>>>>>> afterCompletion");
        }
    }
    
    package com.zy.netty.config;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration
    public class WebConfig implements WebMvcConfigurer {
    
        private final MyInterceptor myInterceptor;
    
        @Autowired
        public WebConfig(MyInterceptor myInterceptor) {
            this.myInterceptor = myInterceptor;
        }
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(myInterceptor);
        }
    }
    
    package com.zy.netty.controller;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HelloController {
    
        @RequestMapping("c1")
        public Object c1() {
            System.out.println(".......c1..........");
            return "c1";
        }
        @RequestMapping("c2")
        public Object c2() {
            System.out.println(".......c2..........");
            return "c2";
        }
    
    }
    
    #访问http://localhost:8080/c1, 被拦截, 打印信息为:
    >>>>>>>>> preHandle
    
    #访问http://localhost:8080/c2, 未被拦截, 打印信息为:
    >>>>>>>>> preHandle
    .......c2..........
    >>>>>>>>> postHandle
    >>>>>>>>> afterCompletion
    

    summary

    >> 拦截器是基于Java反射机制的, 过滤器是基于接口回调的
    >> 过滤器依赖于servlet容器, 而拦截器不依赖servlet容器
    >> 过滤器可以对所有请求起作用, 拦截器只对Action请求起作用
    >> 拦截器可以访问Action上下文, 值栈里的对象, 过滤器不能
    

    3.Listener

    参考:
    https://www.jianshu.com/p/a766267be3c6

    java.util.EventListener
    javax.servlet.http.HttpSessionListener
    javax.servlet.ServletRequestListener
    javax.servlet.ServletContextListener
    
    package com.zy.netty.listener;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    /**
     * 自定义事件
     */
    @Data
    @AllArgsConstructor
    public class OrderEvent {
        private String msg;
    }
    
    package com.zy.netty.listener;
    
    import org.springframework.context.event.EventListener;
    import org.springframework.stereotype.Component;
    /**
     * 事件处理程序: 监听器
     */
    @Component
    public class OrderEventListener {
        @EventListener
        public void handlerOrderEvent(OrderEvent event) {
            System.out.println("监听到orderEvent, 开始处理msg: " + event.getMsg());
        }
    }
    
    package com.zy.netty.listener;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.stereotype.Service;
    /**
     * 事件触发
     */
    @Service
    public class OrderService {
        @Autowired
        private ApplicationContext context;
        public void publishOrder(OrderEvent event) {
            context.publishEvent(event);
        }
    }
    
    package com.zy.netty;
    import com.zy.netty.listener.OrderEvent;
    import com.zy.netty.listener.OrderService;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SpringBootNettyDemoApplicationTests {
        @Autowired
        private OrderService orderService;
        @Test
        public void fn01() {
            orderService.publishOrder(new OrderEvent("order01"));
        }
    }
    

    4.Filter

    package com.zy.eureka.filter;
    
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import javax.servlet.DispatcherType;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Objects;
    
    /**
     * SpringMVC 中自定义 Filter, 并设置 Filter 的执行顺序 (优先级)
     */
    @SuppressWarnings("all")
    @Configuration
    public class FilterConfiguration {
    
        @Bean
        public FilterRegistrationBean xssFilterRegistration() {
            FilterRegistrationBean xssFilterRegistration = new FilterRegistrationBean();
            xssFilterRegistration.setFilter(new XssFilter());
            xssFilterRegistration.setName("xssFilter");
            // order数字越小越先执行
            xssFilterRegistration.setOrder(2);
            xssFilterRegistration.addUrlPatterns("/*");
            xssFilterRegistration.setDispatcherTypes(DispatcherType.REQUEST);
            return xssFilterRegistration;
        }
    
        @Bean
        public FilterRegistrationBean csrfFilterRegistration() {
            FilterRegistrationBean csrfFilterRegistration = new FilterRegistrationBean();
            csrfFilterRegistration.setFilter(new CsrfFilter());
            csrfFilterRegistration.setName("csrfFilter");
            csrfFilterRegistration.setOrder(1);
            csrfFilterRegistration.addUrlPatterns("/*");
            csrfFilterRegistration.setDispatcherTypes(DispatcherType.REQUEST);
            return csrfFilterRegistration;
        }
    
        private static class XssFilter implements Filter {
            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
                HttpServletRequest request1 = (HttpServletRequest) request;
                if ((Objects.isNull(request1.getHeader("reqHeader01")))) {
                    return;
                }
                HttpServletResponse response1 = (HttpServletResponse) response;
                response1.setHeader("xssHeader", "xss");
                chain.doFilter(request, response);
            }
        }
    
        private static class CsrfFilter implements Filter {
            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
                HttpServletResponse response1 = (HttpServletResponse) response;
                response1.setHeader("csrfHeader", "csrf");
                chain.doFilter(request, response);
            }
        }
    }
    

    当访问一个 controller 时, 其调用堆栈信息为:

    FilterChain.png FilterChain中的filters.png

    https://blog.csdn.net/jjkang_/article/details/88548120
    https://blog.csdn.net/WoddenFish/article/details/84836824 (filter)

    相关文章

      网友评论

        本文标题:过滤器(Filter), 拦截器(Interceptor), 监

        本文链接:https://www.haomeiwen.com/subject/vavkrctx.html