<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 9388字,需瀏覽 19分鐘

           ·

          2022-03-06 04:42


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

          過濾器

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

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

          過濾器的使用

          首先需要實(shí)現(xiàn) Filter接口然后重寫它的三個(gè)方法

          • init 方法:在容器中創(chuàng)建當(dāng)前過濾器的時(shí)候自動(dòng)調(diào)用

          • destory 方法:在容器中銷毀當(dāng)前過濾器的時(shí)候自動(dòng)調(diào)用

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

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


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



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

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

          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()?{
          ????????//在服務(wù)關(guān)閉時(shí)銷毀
          ????????log.info("銷毀過濾器");
          ????}
          }

          攔截器

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

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

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

          • 通用處理:在應(yīng)用程序中可能存在所有方法都要返回的信息,這是可以利用攔截器來實(shí)現(xiàn),省去每個(gè)方法冗余重復(fù)的代碼實(shí)現(xiàn)。

          使用攔截器

          我們需要實(shí)現(xiàn) HandlerInterceptor 類,并且重寫三個(gè)方法:

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

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

          • afterCompletion:在 DispatcherServlet 完全處理請求后被調(diào)用,通常用于記錄消耗時(shí)間,也可以對(duì)一些資源進(jìn)行處理。

          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】調(diào)用了:{}",?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】當(dāng)前瀏覽器存在?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】[{}]調(diào)用耗時(shí):{}ms",request.getRequestURI(),?duration);
          ????}
          }

          監(jiān)聽器

          監(jiān)聽器通常用于監(jiān)聽 Web 應(yīng)用程序中對(duì)象的創(chuàng)建、銷毀等動(dòng)作的發(fā)送,同時(shí)對(duì)監(jiān)聽的情況作出相應(yīng)的處理,最常用于統(tǒng)計(jì)網(wǎng)站的在線人數(shù)、訪問量等。關(guān)注公眾號(hào)Java技術(shù)棧回復(fù)boot可以獲取更多系列 Spring Boot 教程。

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

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

          • HttpSessionListener:用來監(jiān)聽 Web 應(yīng)用種的 Session 對(duì)象,通常用于統(tǒng)計(jì)在線情況。

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

          監(jiān)聽器的使用

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

          ServletContext,是一個(gè)全局的儲(chǔ)存信息的空間,它的生命周期與Servlet容器也就是服務(wù)器保持一致,服務(wù)器關(guān)閉才銷毀。

          request,一個(gè)用戶可有多個(gè);

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

          因此我們這里用ServletContext來存儲(chǔ)在線人數(shù)sessionCount最為合適。

          我們下面來統(tǒng)計(jì)當(dāng)前在線人數(shù):

          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("【在線人數(shù)】人數(shù)增加為:{}",userCount.get());
          ??????
          ????????//此處可以在ServletContext域?qū)ο笾袨樵L問量計(jì)數(shù),然后傳入過濾器的銷毀方法
          ????????//在銷毀方法中調(diào)用數(shù)據(jù)庫入庫,因?yàn)檫^濾器生命周期與容器一致
          ????}

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

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

          實(shí)例化三器

          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?"當(dāng)前在線人數(shù)"?+?session.getServletContext().getAttribute("sessionCount")?+?"人";
          ????}

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

          ????@GetMapping("online")
          ????public?String?online()?{
          ????????return?"當(dāng)前在線人數(shù)"?+?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+"--"+"被調(diào)用");
          ????}
          }

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

          1.參考標(biāo)準(zhǔn)

          • 過濾器是 JavaEE 的標(biāo)準(zhǔn),依賴于 Servlet 容器,生命周期也與容器一致,利用這一特性可以在銷毀時(shí)釋放資源或者數(shù)據(jù)入庫。

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

          2.實(shí)現(xiàn)方式

          • 過濾器是基于回調(diào)函數(shù)實(shí)現(xiàn),無法注入 ioc 容器中的 bean。

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


          程序汪資料鏈接

          程序汪接的7個(gè)私活都在這里,經(jīng)驗(yàn)整理

          Java項(xiàng)目分享 最新整理全集,找項(xiàng)目不累啦 06版

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

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

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

          字節(jié)跳動(dòng)總結(jié)的設(shè)計(jì)模式 PDF 火了,完整版開放下載!


          歡迎添加程序汪個(gè)人微信 itwang009? 進(jìn)粉絲群或圍觀朋友圈

          瀏覽 41
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美色爽| 99精品在这里 | 视频播放一区 | 色播综合 | 黄色视频A片 |