1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Spring Boot 如何使用攔截器、過濾器、監(jiān)聽器?

        共 9388字,需瀏覽 19分鐘

         ·

        2022-03-06 04:42


        作者:海向
        出處:www.cnblogs.com/haixiang/p/12000685.html

        過濾器

        過濾器的英文名稱為 Filter, 是 Servlet 技術中最實用的技術。

        如同它的名字一樣,過濾器是處于客戶端和服務器資源文件之間的一道過濾網,幫助我們過濾掉一些不符合要求的請求,通常用作 Session 校驗,判斷用戶權限,如果不符合設定條件,則會被攔截到特殊的地址或者基于特殊的響應。

        過濾器的使用

        首先需要實現 Filter接口然后重寫它的三個方法

        • init 方法:在容器中創(chuàng)建當前過濾器的時候自動調用

        • destory 方法:在容器中銷毀當前過濾器的時候自動調用

        • doFilter 方法:過濾的具體操作

        我們先引入 Maven 依賴,其中 lombok 是用來避免每個文件創(chuàng)建 Logger 來打印日志


        ????org.projectlombok
        ????lombok



        ????org.springframework.boot
        ????spring-boot-starter-web

        我們首先實現接口,重寫三個方法,對包含我們要求的四個請求予以放行,將其它請求攔截重定向至/online,只要在將MyFilter實例化后即可,我們在后面整合代碼中一起給出。

        import?lombok.extern.log4j.Log4j2;
        import?org.springframework.stereotype.Component;

        import?javax.servlet.*;
        import?javax.servlet.http.HttpServletRequest;
        import?javax.servlet.http.HttpServletResponse;
        import?javax.servlet.http.HttpServletResponseWrapper;
        import?java.io.IOException;

        @Log4j2
        public?class?MyFilter?implements?Filter?{

        ????@Override
        ????public?void?init(FilterConfig?filterConfig)?throws?ServletException?{
        ????????log.info("初始化過濾器");
        ????}
        ??
        ????@Override
        ????public?void?doFilter(ServletRequest?servletRequest,?ServletResponse?response,?FilterChain?filterChain)?throws?IOException,?ServletException?{
        ????????HttpServletRequest?request?=?(HttpServletRequest)servletRequest;
        ????????HttpServletResponseWrapper?wrapper?=?new?HttpServletResponseWrapper((HttpServletResponse)?response);
        ????????String?requestUri?=?request.getRequestURI();
        ????????log.info("請求地址是:"+requestUri);
        ????????if?(requestUri.contains("/addSession")
        ????????????||?requestUri.contains("/removeSession")
        ????????????||?requestUri.contains("/online")
        ????????????||?requestUri.contains("/favicon.ico"))?{
        ????????????filterChain.doFilter(servletRequest,?response);
        ????????}?else?{
        ????????????wrapper.sendRedirect("/online");
        ????????}
        ????}
        ??
        ????@Override
        ????public?void?destroy()?{
        ????????//在服務關閉時銷毀
        ????????log.info("銷毀過濾器");
        ????}
        }

        攔截器

        Java中的攔截器是動態(tài)攔截 action 調用的對象,然后提供了可以在 action 執(zhí)行前后增加一些操作,也可以在 action 執(zhí)行前停止操作,功能與過濾器類似,但是標準和實現方式不同。

        • 登錄認證:在一些應用中,可能會通過攔截器來驗證用戶的登錄狀態(tài),如果沒有登錄或者登錄失敗,就會給用戶一個友好的提示或者返回登錄頁面,當然大型項目中都不采用這種方式,都是調單點登錄系統接口來驗證用戶。

        • 記錄系統日志:我們在常見應用中,通常要記錄用戶的請求信息,比如請求 ip,方法執(zhí)行時間等,通過這些記錄可以監(jiān)控系統的狀況,以便于對系統進行信息監(jiān)控、信息統計、計算 PV、性能調優(yōu)等。

        • 通用處理:在應用程序中可能存在所有方法都要返回的信息,這是可以利用攔截器來實現,省去每個方法冗余重復的代碼實現。

        使用攔截器

        我們需要實現 HandlerInterceptor 類,并且重寫三個方法:

        • preHandle:在 Controoler 處理請求之前被調用,返回值是 boolean類型,如果是true就進行下一步操作;若返回false,則證明不符合攔截條件,在失敗的時候不會包含任何響應,此時需要調用對應的response返回對應響應。

        • postHandler:在 Controoler 處理請求執(zhí)行完成后、生成視圖前執(zhí)行,可以通過ModelAndView對視圖進行處理,當然ModelAndView也可以設置為 null。

        • afterCompletion:在 DispatcherServlet 完全處理請求后被調用,通常用于記錄消耗時間,也可以對一些資源進行處理。

        import?lombok.extern.log4j.Log4j2;
        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;
        import?javax.servlet.http.HttpSession;

        @Log4j2
        @Component
        public?class?MyInterceptor?implements?HandlerInterceptor?{
        ????@Override
        ????public?boolean?preHandle(HttpServletRequest?request,?HttpServletResponse?response,?Object?handler)?throws?Exception?{
        ????????log.info("【MyInterceptor】調用了:{}",?request.getRequestURI());
        ????????request.setAttribute("requestTime",?System.currentTimeMillis());
        ????????return?true;
        ????}

        ????@Override
        ????public?void?postHandle(HttpServletRequest?request,?HttpServletResponse?response,
        ???????????????????????????Object?handler,?ModelAndView?modelAndView)?throws?Exception?{
        ????????if?(!request.getRequestURI().contains("/online"))?{
        ????????????HttpSession?session?=?request.getSession();
        ????????????String?sessionName?=?(String)?session.getAttribute("name");
        ????????????if?("haixiang".equals(sessionName))?{
        ????????????????log.info("【MyInterceptor】當前瀏覽器存在?session:{}",sessionName);
        ????????????}
        ????????}
        ????}

        ????@Override
        ????public?void?afterCompletion(HttpServletRequest?request,?HttpServletResponse?response,
        ????????????????????????????????Object?handler,?Exception?ex)?throws?Exception?{
        ????????long?duration?=?(System.currentTimeMillis()?-?(Long)request.getAttribute("requestTime"));
        ????????log.info("【MyInterceptor】[{}]調用耗時:{}ms",request.getRequestURI(),?duration);
        ????}
        }

        監(jiān)聽器

        監(jiān)聽器通常用于監(jiān)聽 Web 應用程序中對象的創(chuàng)建、銷毀等動作的發(fā)送,同時對監(jiān)聽的情況作出相應的處理,最常用于統計網站的在線人數、訪問量等。關注公眾號Java技術?;貜蚥oot可以獲取更多系列 Spring Boot 教程。

        監(jiān)聽器大概分為以下幾種:

        • ServletContextListener:用來監(jiān)聽 ServletContext 屬性的操作,比如新增、修改、刪除。

        • HttpSessionListener:用來監(jiān)聽 Web 應用種的 Session 對象,通常用于統計在線情況。

        • ServletRequestListener:用來監(jiān)聽 Request 對象的屬性操作。

        監(jiān)聽器的使用

        我們通過 HttpSessionListener來統計當前在線人數、ip等信息,為了避免并發(fā)問題我們使用原子int來計數。

        ServletContext,是一個全局的儲存信息的空間,它的生命周期與Servlet容器也就是服務器保持一致,服務器關閉才銷毀。

        request,一個用戶可有多個;

        session,一個用戶一個;而servletContext,所有用戶共用一個。所以,為了節(jié)省空間,提高效率,ServletContext中,要放必須的、重要的、所有用戶需要共享的線程又是安全的一些信息。

        因此我們這里用ServletContext來存儲在線人數sessionCount最為合適。

        我們下面來統計當前在線人數:

        import?lombok.extern.log4j.Log4j2;

        import?javax.servlet.http.HttpSessionEvent;
        import?javax.servlet.http.HttpSessionListener;
        import?java.util.concurrent.atomic.AtomicInteger;

        @Log4j2
        public?class?MyHttpSessionListener?implements?HttpSessionListener?{

        ????public?static?AtomicInteger?userCount?=?new?AtomicInteger(0);

        ????@Override
        ????public?synchronized?void?sessionCreated(HttpSessionEvent?se)?{
        ????????userCount.getAndIncrement();
        ????????se.getSession().getServletContext().setAttribute("sessionCount",?userCount.get());
        ????????log.info("【在線人數】人數增加為:{}",userCount.get());
        ??????
        ????????//此處可以在ServletContext域對象中為訪問量計數,然后傳入過濾器的銷毀方法
        ????????//在銷毀方法中調用數據庫入庫,因為過濾器生命周期與容器一致
        ????}

        ????@Override
        ????public?synchronized?void?sessionDestroyed(HttpSessionEvent?se)?{
        ????????userCount.getAndDecrement();
        ????????se.getSession().getServletContext().setAttribute("sessionCount",?userCount.get());
        ????????log.info("【在線人數】人數減少為:{}",userCount.get());
        ????}
        }

        過濾器、攔截器、監(jiān)聽器注冊

        實例化三器

        import?com.anqi.tool.sanqi.filter.MyFilter;
        import?com.anqi.tool.sanqi.interceptor.MyInterceptor;
        import?com.anqi.tool.sanqi.listener.MyHttpRequestListener;
        import?com.anqi.tool.sanqi.listener.MyHttpSessionListener;
        import?org.springframework.beans.factory.annotation.Autowired;
        import?org.springframework.boot.web.servlet.FilterRegistrationBean;
        import?org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
        import?org.springframework.context.annotation.Bean;
        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?{
        ????@Autowired
        ????MyInterceptor?myInterceptor;

        ????@Override
        ????public?void?addInterceptors(InterceptorRegistry?registry)?{
        ????????registry.addInterceptor(myInterceptor);
        ????}

        ????/**
        ?????*?注冊過濾器
        ?????*?@return
        ?????*/
        ????@Bean
        ????public?FilterRegistrationBean?filterRegistrationBean(){
        ????????FilterRegistrationBean?filterRegistration?=?new?FilterRegistrationBean();
        ????????filterRegistration.setFilter(new?MyFilter());
        ????????filterRegistration.addUrlPatterns("/*");
        ????????return?filterRegistration;
        ????}

        ????/**
        ?????*?注冊監(jiān)聽器
        ?????*?@return
        ?????*/
        ????@Bean
        ????public?ServletListenerRegistrationBean?registrationBean(){
        ????????ServletListenerRegistrationBean?registrationBean?=?new?ServletListenerRegistrationBean();
        ????????registrationBean.setListener(new?MyHttpRequestListener());
        ????????registrationBean.setListener(new?MyHttpSessionListener());
        ????????return?registrationBean;
        ????}
        }

        測試

        import?com.anqi.tool.sanqi.listener.MyHttpSessionListener;
        import?org.springframework.web.bind.annotation.GetMapping;
        import?org.springframework.web.bind.annotation.RestController;

        import?javax.servlet.http.HttpServletRequest;
        import?javax.servlet.http.HttpSession;

        @RestController
        public?class?TestController?{

        ????@GetMapping("addSession")
        ????public?String?addSession(HttpServletRequest?request)?{
        ????????HttpSession?session?=?request.getSession();
        ????????session.setAttribute("name",?"haixiang");
        ????????return?"當前在線人數"?+?session.getServletContext().getAttribute("sessionCount")?+?"人";
        ????}

        ????@GetMapping("removeSession")
        ????public?String?removeSession(HttpServletRequest?request)?{
        ????????HttpSession?session?=?request.getSession();
        ????????session.invalidate();
        ????????return?"當前在線人數"?+?session.getServletContext().getAttribute("sessionCount")?+?"人";
        ????}

        ????@GetMapping("online")
        ????public?String?online()?{
        ????????return?"當前在線人數"?+?MyHttpSessionListener.userCount.get()?+?"人";
        ????}

        }

        以下是監(jiān)聽請求的監(jiān)聽器

        import?javax.servlet.ServletRequestEvent;
        import?javax.servlet.ServletRequestListener;
        import?javax.servlet.http.HttpServletRequest;

        public?class?MyHttpRequestListener?implements?ServletRequestListener?{

        ????@Override
        ????public?void?requestDestroyed(ServletRequestEvent?sre)?{
        ????????System.out.println("request?監(jiān)聽器被銷毀");
        ????}

        ????@Override
        ????public?void?requestInitialized(ServletRequestEvent?sre)?{
        ????????HttpServletRequest?req?=?(HttpServletRequest)?sre.getServletRequest();
        ????????String?requestURI?=?req.getRequestURI();
        ????????System.out.println(requestURI+"--"+"被調用");
        ????}
        }

        攔截器與過濾器的區(qū)別

        1.參考標準

        • 過濾器是 JavaEE 的標準,依賴于 Servlet 容器,生命周期也與容器一致,利用這一特性可以在銷毀時釋放資源或者數據入庫。

        • 攔截器是SpringMVC中的內容,依賴于web框架,通常用于驗證用戶權限或者記錄日志,但是這些功能也可以利用 AOP 來代替。

        2.實現方式

        • 過濾器是基于回調函數實現,無法注入 ioc 容器中的 bean。

        • 攔截器是基于反射來實現,因此攔截器中可以注入 ioc 容器中的 bean,例如注入 Redis 的業(yè)務層來驗證用戶是否已經登錄。


        程序汪資料鏈接

        程序汪接的7個私活都在這里,經驗整理

        Java項目分享 最新整理全集,找項目不累啦 06版

        堪稱神級的Spring Boot手冊,從基礎入門到實戰(zhàn)進階

        臥槽!字節(jié)跳動《算法中文手冊》火了,完整版 PDF 開放下載!

        臥槽!阿里大佬總結的《圖解Java》火了,完整版PDF開放下載!

        字節(jié)跳動總結的設計模式 PDF 火了,完整版開放下載!


        歡迎添加程序汪個人微信 itwang009? 進粉絲群或圍觀朋友圈

        瀏覽 41
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            双性恋男女通吃h文 | 发情淫色精品网 | 北条麻妃无码在线观看 | 蜜桃视频18 | 午夜福利免费视频 | 欧洲男女操逼精品 | 俺要去操东京热 | 五月丁香婷婷爱 | 小情侣第一次啪啪全程偷拍 | 日日撸日日色 |