<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 如何使用攔截器、過(guò)濾器、監(jiān)聽(tīng)器?

          共 9401字,需瀏覽 19分鐘

           ·

          2022-03-10 22:11

          程序員的成長(zhǎng)之路
          互聯(lián)網(wǎng)/程序員/技術(shù)/資料共享?
          關(guān)注


          閱讀本文大概需要 7 分鐘。

          作者:海向

          出處:www.cnblogs.com/haixiang/p/12000685.html


          過(guò)濾器

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

          過(guò)濾器的使用

          首先需要實(shí)現(xiàn)?Filter接口然后重寫它的三個(gè)方法
          • init 方法:在容器中創(chuàng)建當(dāng)前過(guò)濾器的時(shí)候自動(dòng)調(diào)用

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

          • doFilter 方法:過(guò)濾的具體操作

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


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



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

          我們首先實(shí)現(xiàn)接口,重寫三個(gè)方法,對(duì)包含我們要求的四個(gè)請(qǐng)求予以放行,將其它請(qǐng)求攔截重定向至/online,只要在將MyFilter實(shí)例化后即可,我們?cè)诤竺嬲洗a中一起給出。

          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("初始化過(guò)濾器");
          ????}
          ??
          ????@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("請(qǐng)求地址是:"+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("銷毀過(guò)濾器");
          ????}
          }

          攔截器

          Java中的攔截器是動(dòng)態(tài)攔截 action 調(diào)用的對(duì)象,然后提供了可以在 action 執(zhí)行前后增加一些操作,也可以在 action 執(zhí)行前停止操作,功能與過(guò)濾器類似,但是標(biāo)準(zhǔn)和實(shí)現(xiàn)方式不同。
          • 登錄認(rèn)證:在一些應(yīng)用中,可能會(huì)通過(guò)攔截器來(lái)驗(yàn)證用戶的登錄狀態(tài),如果沒(méi)有登錄或者登錄失敗,就會(huì)給用戶一個(gè)友好的提示或者返回登錄頁(yè)面,當(dāng)然大型項(xiàng)目中都不采用這種方式,都是調(diào)單點(diǎn)登錄系統(tǒng)接口來(lái)驗(yàn)證用戶。

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

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

          使用攔截器

          我們需要實(shí)現(xiàn) HandlerInterceptor 類,并且重寫三個(gè)方法:
          • preHandle:在 Controoler 處理請(qǐng)求之前被調(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 處理請(qǐng)求執(zhí)行完成后、生成視圖前執(zhí)行,可以通過(guò)ModelAndView對(duì)視圖進(jìn)行處理,當(dāng)然ModelAndView也可以設(shè)置為 null。

          • afterCompletion:在 DispatcherServlet 完全處理請(qǐng)求后被調(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)聽(tīng)器

          監(jiān)聽(tīng)器通常用于監(jiān)聽(tīng) Web 應(yīng)用程序中對(duì)象的創(chuàng)建、銷毀等動(dòng)作的發(fā)送,同時(shí)對(duì)監(jiān)聽(tīng)的情況作出相應(yīng)的處理,最常用于統(tǒng)計(jì)網(wǎng)站的在線人數(shù)、訪問(wèn)量等。
          監(jiān)聽(tīng)器大概分為以下幾種:
          • ServletContextListener:用來(lái)監(jiān)聽(tīng) ServletContext 屬性的操作,比如新增、修改、刪除。

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

          • ServletRequestListener:用來(lái)監(jiān)聽(tīng) Request 對(duì)象的屬性操作。

          監(jiān)聽(tīng)器的使用

          我們通過(guò)?HttpSessionListener來(lái)統(tǒng)計(jì)當(dāng)前在線人數(shù)、ip等信息,為了避免并發(fā)問(wèn)題我們使用原子int來(lái)計(jì)數(shù)。
          ServletContext,是一個(gè)全局的儲(chǔ)存信息的空間,它的生命周期與Servlet容器也就是服務(wù)器保持一致,服務(wù)器關(guān)閉才銷毀。
          request,一個(gè)用戶可有多個(gè);
          session,一個(gè)用戶一個(gè);而servletContext,所有用戶共用一個(gè)。所以,為了節(jié)省空間,提高效率,ServletContext中,要放必須的、重要的、所有用戶需要共享的線程又是安全的一些信息。
          因此我們這里用ServletContext來(lái)存儲(chǔ)在線人數(shù)sessionCount最為合適。
          我們下面來(lái)統(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問(wèn)量計(jì)數(shù),然后傳入過(guò)濾器的銷毀方法
          ????????//在銷毀方法中調(diào)用數(shù)據(jù)庫(kù)入庫(kù),因?yàn)檫^(guò)濾器生命周期與容器一致
          ????}

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

          過(guò)濾器、攔截器、監(jiān)聽(tīng)器注冊(cè)

          實(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);
          ????}

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

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

          測(cè)試

          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)聽(tīng)請(qǐng)求的監(jiān)聽(tīng)器

          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)聽(tīng)器被銷毀");
          ????}

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

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

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

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

          2.實(shí)現(xiàn)方式
          • 過(guò)濾器是基于回調(diào)函數(shù)實(shí)現(xiàn),無(wú)法注入?ioc?容器中的 bean。

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

          推薦閱讀:

          IDEA 完美支持多人遠(yuǎn)程編程!

          MySQL中,當(dāng)update修改數(shù)據(jù)與原數(shù)據(jù)相同時(shí)會(huì)再次執(zhí)行嗎

          互聯(lián)網(wǎng)初中高級(jí)大廠面試題(9個(gè)G)

          內(nèi)容包含Java基礎(chǔ)、JavaWeb、MySQL性能優(yōu)化、JVM、鎖、百萬(wàn)并發(fā)、消息隊(duì)列、高性能緩存、反射、Spring全家桶原理、微服務(wù)、Zookeeper、數(shù)據(jù)結(jié)構(gòu)、限流熔斷降級(jí)......等技術(shù)棧!

          ?戳閱讀原文領(lǐng)取!? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??朕已閱?

          瀏覽 30
          點(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>
                  国产精品内射视频免费 | 欧美成人午夜无码A片秀色直播 | 日韩一区二区三区三四区视频在线观看 | 青青草成人无码视频 | 日韩三级电影网址 |