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

        共 9256字,需瀏覽 19分鐘

         ·

        2020-10-07 01:32

        來(lái)源:cnblogs.com/haixiang/p/12000685.html

        • 過(guò)濾器
        • 攔截器
        • 監(jiān)聽器
        • 過(guò)濾器、攔截器、監(jiān)聽器注冊(cè)
        • 攔截器與過(guò)濾器的區(qū)別

        過(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)打印日志

        <dependency>
        ????<groupId>org.projectlombokgroupId>
        ????<artifactId>lombokartifactId>
        dependency>

        <dependency>
        ????<groupId>org.springframework.bootgroupId>
        ????<artifactId>spring-boot-starter-webartifactId>
        dependency>

        我們首先實(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姂?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)聽器

        監(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ù)、訪問(wèn)量等。

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

        • ServletContextListener:用來(lái)監(jiān)聽 ServletContext 屬性的操作,比如新增、修改、刪除。
        • HttpSessionListener:用來(lái)監(jiān)聽 Web 應(yīng)用種的 Session 對(duì)象,通常用于統(tǒng)計(jì)在線情況。
        • ServletRequestListener:用來(lái)監(jiān)聽 Request 對(duì)象的屬性操作。

        監(jiān)聽器的使用

        我們通過(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)聽器注冊(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)聽器
        ?????*?@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)聽請(qǐng)求的監(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)用");
        ????}
        }

        攔截器與過(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)登錄。
        推薦閱讀
        6 個(gè) Spring Boot 項(xiàng)目夠經(jīng)典,建議收藏!
        SQL判斷是否"存在",還在用 count 操作?
        你還不知道SpringBoot這些Starter?
        延遲隊(duì)列實(shí)現(xiàn),定時(shí)任務(wù),關(guān)閉訂單

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

        手機(jī)掃一掃分享

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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        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>
            精品二区在线 | 黄色国产在线播放 | 9.1人成人免费视频网站 | 在线免费观看黄片 | 久久久黄色 | 黄色片黄色片黄色片黄色片 | 高清无码在线观看18 | 91麻豆成人精品国产免费网站 | 国产igao为爱做激情国外 | 91无码人妻精品一区二区三区男 |