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处理了请求,此时拦截器不处理)

    拦截器不处理。

  • 相关阅读:
    Android 按键消息处理Android 按键消息处理
    objcopy
    SQLite多线程读写实践及常见问题总结
    android动画坐标定义
    Android动画效果translate、scale、alpha、rotate
    Android公共库(缓存 下拉ListView 下载管理Pro 静默安装 root运行 Java公共类)
    Flatten Binary Tree to Linked List
    Distinct Subsequences
    Populating Next Right Pointers in Each Node II
    Populating Next Right Pointers in Each Node
  • 原文地址:https://www.cnblogs.com/mr-yang-localhost/p/7784607.html
Copyright © 2011-2022 走看看