zoukankan      html  css  js  c++  java
  • Java的Servlet、Filter、Interceptor、Listener

    写在前面:

    使用Spring-Boot时,嵌入式Servlet容器可以通过扫描注解(@ServletComponentScan)的方式注册Servlet、Filter和Servlet规范的所有监听器(如HttpSessionListener监听器)。 

    Spring boot 的主 Servlet 为 DispatcherServlet,其默认的url-pattern为“/”。一般情况系统默认的Servlet就够用了,如果需要自定义Servlet,可以继承系统抽象类HttpServlet,重写方法来实现自己的Servlet。关于Servlet、过滤器、拦截器、监听器可以参考:(转)servlet、filter、listener、interceptor之间的区别和联系

    Spring-Boot有两种方法注册Servlet、Filter和Listener :

    1、代码注册:通过ServletRegistrationBean、 FilterRegistrationBean 和 ServletListenerRegistrationBean 获得控制。

    2、在 SpringBootApplication 上使用@ServletComponentScan 注解后,Servlet、Filter、Listener 可以直接通过 @WebServlet、@WebFilter、@WebListener 注解自动注册,无需其他代码。

    一、Servlet

    Servlet匹配规则:匹配的优先级是从精确到模糊,复合条件的Servlet并不会都执行。

    1、通过@ServletComponentScan自动扫描

    a、springboot的启动入口添加注解:@ServletComponentScan;

    @SpringBootApplication
    @ServletComponentScan
    public class ApplicationMain {
        public static void main(String[] args) {
            SpringApplication.run(ApplicationMain.class, args);
        }
    }

    b、@WebServlet 自定义Servlet,配置处理请求路径 /demo/myServlet 

    @WebServlet(name = "myServletDemo1",urlPatterns = "/demo/myServlet",description = "自定义的servlet")
    public class MyServletDemo1 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("==========myServletDemo Get Method==========");
    
            resp.getWriter().println("my myServletDemo1 process request");
            super.doGet(req, resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("==========myServletDemo1 POST Method==========");
            super.doPost(req, resp);
        }
    }

    2、使用@ServletRegistrationBean注解

    a、@ServletRegistrationBean注入自定义的Servlet,配置处理的路径为 /demo/servletDemo2 

    @Configuration
    public class ServletConfiguration {
        /**
         * 代码注入
         */
        @Bean
        public ServletRegistrationBean myServletDemo() {
            return new ServletRegistrationBean(new MyServletDemo2(), "/demo/servletDemo2");
        }
    }

    b、自定义的Servlet

    public class MyServletDemo2 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("==========myServletDemo2 Get Method==========");
    
            resp.getWriter().println("my myServletDemo2 process request");
            super.doGet(req, resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("==========myServletDemo2 POST Method==========");
            super.doPost(req, resp);
        }
    }

    二、Filter

    完整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。

    Filter有如下几个用处。

    • 在HttpServletRequest到达Servlet之前,拦截客户的HttpServletRequest。
    • 根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据。
    • 在HttpServletResponse到达客户端之前,拦截HttpServletResponse。
    • 根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。

    多个FIlter可以组成过滤器调用链,按设置的顺序逐一进行处理,形成Filter调用链。

    1、通过@ServletComponentScan自动扫描

    a、springboot的启动入口添加注解:@ServletComponentScan;

    b、@WebFilter 配置处理全部url的Filter

    @WebFilter(filterName = "myFilter",urlPatterns = "/*")
    public class MyFilter implements Filter {
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println(">>>>>>myFilter init ……");
        }
    
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println(">>>>>>执行过滤操作");
            filterChain.doFilter(servletRequest, servletResponse);
        }
    
        public void destroy() {
            System.out.println(">>>>>>myFilter destroy ……");
        }
    }

     * doFilter()方法是过滤器的核心方法,实现该方法就可实现对用户请求进行预处理,也可实现对服务器响应进行后处理——它们的分界线为是否调用了filterChain.doFilter(),执行该方法之前,即对用户请求进行预处理;执行该方法之后,即对服务器响应进行后处理。

    2、通过@FilterRegistrationBean注册

    a、@Bean注入自定义的Filter

    @Configuration
    public class ServletConfiguration {
        @Bean
        public FilterRegistrationBean myFilterDemo(){
            FilterRegistrationBean registration = new FilterRegistrationBean();
            registration.setFilter(new MyFilter2());
            registration.addUrlPatterns("/demo/myFilter2");
            registration.addInitParameter("paramName", "paramValue");
            registration.setName("myFilter2");
            registration.setOrder(2);//指定filter的顺序
            return registration;
        }
    }

    b、自定义的Filter

    public class MyFilter2 implements Filter {
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("======MyFilter2 init ……");
        }
    
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("======MyFilter2执行过滤操作");
            filterChain.doFilter(servletRequest, servletResponse);
        }
    
        public void destroy() {
            System.out.println("======MyFilter2 destroy ……");
        }
    }

    三、Listener

    目前 Servlet 中提供了 6 种两类事件的观察者接口,它们分别是:4 个 EventListeners 类型的,ServletContextAttributeListener、ServletRequestAttributeListener、ServletRequestListener、HttpSessionAttributeListener 和 2 个 LifecycleListeners 类型的,ServletContextListener、HttpSessionListener。

    • ServletContextAttributeListener监听对ServletContext属性的操作,比如增加、删除、修改属性。
    • ServletContextListener监听ServletContext。当创建ServletContext时,激发contextInitialized(ServletContextEvent sce)方法;当销毁ServletContext时,激发contextDestroyed(ServletContextEvent sce)方法。
    • HttpSessionListener监听HttpSession的操作。当创建一个Session时,激发session Created(HttpSessionEvent se)方法;当销毁一个Session时,激发sessionDestroyed (HttpSessionEvent se)方法。
    • HttpSessionAttributeListener监听HttpSession中的属性的操作。当在Session增加一个属性时,激发attributeAdded(HttpSessionBindingEvent se) 方法;当在Session删除一个属性时,激发attributeRemoved(HttpSessionBindingEvent se)方法;当在Session属性被重新设置时,激发attributeReplaced(HttpSessionBindingEvent se) 方法。

    1、通过@ServletComponentScan自动扫描

    a、ServletListenerRegistrationBean 注入自定义的Listener;

    b、自定义的Listener

    @WebListener
    public class MyLisener implements ServletContextListener {
        public void contextInitialized(ServletContextEvent servletContextEvent) {
            System.out.println("MyLisener contextInitialized method");
        }
    
        public void contextDestroyed(ServletContextEvent servletContextEvent) {
            System.out.println("MyLisener contextDestroyed method");
        }
    }

    2、通过@ServletListenerRegistrationBean 注册

    a、@Bean注入自定义的Listener;

    @Configuration
    public class ServletConfiguration {
        @Bean
        public ServletListenerRegistrationBean myListener(){
            return new ServletListenerRegistrationBean(new MyLisener());
        }
    }

    b、自定义的Listener

    public class MyLisener implements ServletContextListener {
        public void contextInitialized(ServletContextEvent servletContextEvent) {
            System.out.println("MyLisener contextInitialized method");
        }
    
        public void contextDestroyed(ServletContextEvent servletContextEvent) {
            System.out.println("MyLisener contextDestroyed method");
        }
    } 

    四、验证servlet、filter、listener的顺序

    a、使用MyServletDemo2、MyFilter2、MyFilter3、MyLisener做测试;

    b、设置servlet处理url格式为 /demo/*;设置MyFilter2顺序为2;MyFilter3的顺序为3;

    @Configuration
    public class ServletConfiguration {
        /**代码注入*/
        @Bean
        public ServletRegistrationBean myServletDemo(){
            return new ServletRegistrationBean(new MyServletDemo2(),"/demo/*");
        }
    
        @Bean
        public FilterRegistrationBean myFilterDemo(){
            FilterRegistrationBean registration = new FilterRegistrationBean();
            registration.setFilter(new MyFilter2());
            registration.addUrlPatterns("/demo/myFilter");
            registration.addInitParameter("paramName", "paramValue");
            registration.setName("myFilter2");
            registration.setOrder(2);//指定filter的顺序
            return registration;
        }
    
        @Bean
        public FilterRegistrationBean myFilterDemo2(){
            FilterRegistrationBean registration = new FilterRegistrationBean();
            registration.setFilter(new MyFilter3());
            registration.addUrlPatterns("/demo/*");
            registration.addInitParameter("paramName", "paramValue");
            registration.setName("myFilter3");
            registration.setOrder(1);
            return registration;
        }
    
        @Bean
        public ServletListenerRegistrationBean myListener(){
            return new ServletListenerRegistrationBean(new MyLisener());
        }
    }
    View Code

    c、启动项目后输出:(FIlter2先执行init,因为@Ben在前)

    MyLisener contextInitialized method
    ======MyFilter2 init ……
    ======MyFilter3 init ……

    d、浏览器输入地址地址:http://localhost:8080/demo/myFilter,输出:

    ======MyFilter3执行过滤操作
    ======MyFilter2执行过滤操作
    >>>>>>>>>>test Get Method==========

    可以看出:

    1. Filter3比Filter2先执行;
    2. Filter可以匹配上的url都会执行,并且按顺序执行(Filter的调用链);
    3. Filter比servlet先执行。
    4. servlet先按具体匹配,然后模糊匹配,并且只能有一个servlet匹配上,没有servlet调用链。

    执行顺序是:Listener》Filter》Servlet

    五、ApplicationListener自定义侦听器类

    参考:http://blog.csdn.net/liaokailin/article/details/48186331

    六、Interceptor

    拦截器只会处理DispatcherServlet处理的url

    a、自定义拦截器

    public class MyInterceptor implements HandlerInterceptor {
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
            System.out.println(">>>>MyInterceptor preHandle");
            return true;
        }
    
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
            System.out.println(">>>>MyInterceptor postHandle");
    
        }
    
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
            System.out.println(">>>>MyInterceptor afterCompletion");
    
        }
    }

    b、注册拦截器

    @Configuration
    public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
            super.addInterceptors(registry);
        }
    }

    c、拦截器验证

    输入地址:http://localhost:8080/home/test

    >>>>MyInterceptor preHandle
    >>>>MyInterceptor postHandle
    >>>>MyInterceptor afterCompletion

    输入地址:http://localhost:8080/demo/myFilter (自定义的Servlet处理了请求,此时拦截器不处理)

    拦截器不处理。

  • 相关阅读:
    pidgin的未认证解决办法
    题解【洛谷P1074】[NOIP2009]靶形数独
    题解【洛谷P1315】[NOIP2011]观光公交
    题解【BZOJ4145】「AMPPZ2014」The Prices
    题解【洛谷P4588】[TJOI2018]数学计算
    题解【洛谷P3884】[JLOI2009]二叉树问题
    题解【SP8002】HORRIBLE
    树链剖分学习笔记
    题解【洛谷P1807】最长路_NOI导刊2010提高(07)
    题解【洛谷P1995】口袋的天空
  • 原文地址:https://www.cnblogs.com/mr-yang-localhost/p/7784607.html
Copyright © 2011-2022 走看看