最新亚洲精品福利在线,欧美一区二区三区大片,久久91无码一区二区三区,色哟哟免费观看视频入口,美女裸露双奶头屁股无裸体

Spring Boot中使用監(jiān)聽(tīng)器

時(shí)間:2022-10-11 09:07:51 類型:JAVA
字號(hào):    
  1.  什么是 web 監(jiān)聽(tīng)器?web 監(jiān)聽(tīng)器是一種 Servlet 中特殊的類,它們能幫助開(kāi)發(fā)者監(jiān)聽(tīng) web 中特定的事件,比如 ServletContext, HttpSession, ServletRequest 的創(chuàng)建和銷毀;變量的創(chuàng)建、銷毀和修改等。可以在某些動(dòng)作前后增加處理,實(shí)現(xiàn)監(jiān)控。

  2. Spring Boot中監(jiān)聽(tīng)器的使用

    web 監(jiān)聽(tīng)器的使用場(chǎng)景很多,比如監(jiān)聽(tīng) servlet 上下文用來(lái)初始化一些數(shù)據(jù)、監(jiān)聽(tīng) http session 用來(lái)獲取當(dāng)前在線的人數(shù)、監(jiān)聽(tīng)客戶端請(qǐng)求的 servlet request 對(duì)象來(lái)獲取用戶的訪問(wèn)信息等等。


    2.1 監(jiān)聽(tīng)Servlet上下文對(duì)象

        監(jiān)聽(tīng) servlet 上下文對(duì)象可以用來(lái)初始化數(shù)據(jù),用于緩存。什么意思呢?

        比如用戶在點(diǎn)擊某個(gè)站點(diǎn)的首頁(yè)時(shí),一般都會(huì)展現(xiàn)出首頁(yè)的一些信息,而這些信息基本上或者大部分時(shí)間都保持不變的,但是這些信息都是來(lái)自數(shù)據(jù)庫(kù)。如果用戶的每次點(diǎn)擊,都要從數(shù)據(jù)庫(kù)中去獲取數(shù)據(jù)的話,用戶量少還可以接受,如果用戶量非常大的話,這對(duì)數(shù)據(jù)庫(kù)也是一筆很大的開(kāi)銷。針對(duì)這種首頁(yè)數(shù)據(jù),大部分都不常更新的話,我們完全可以把它們緩存起來(lái),每次用戶點(diǎn)擊的時(shí)候,我們都直接從緩存中拿,這樣既可以提高首頁(yè)的訪問(wèn)速度,又可以降低服務(wù)器的壓力。如果做的更加靈活一點(diǎn),可以再加個(gè)定時(shí)器,定期的來(lái)更新這個(gè)首頁(yè)緩存。就類似與 CSDN 個(gè)人博客首頁(yè)中排名的變化一樣。

  針對(duì)這個(gè)功能,接下來(lái)我們寫(xiě)一個(gè) demo,在實(shí)際中,大家可以完全套用該代碼,來(lái)實(shí)現(xiàn)自己項(xiàng)目中的相關(guān)邏輯。首先寫(xiě)一個(gè) Mapper,模擬一下從數(shù)據(jù)庫(kù)查詢數(shù)據(jù):

@Repository
public interface UserMapper {
    public User getUserById(Integer id);
}

然后寫(xiě)一個(gè)監(jiān)聽(tīng)器,實(shí)現(xiàn) ApplicationListener接口,重寫(xiě)onApplicationEvent 方法,將 ContextRefreshedEvent 對(duì)象傳進(jìn)去。

如果我們想在加載或刷新應(yīng)用上下文時(shí),也重新刷新下我們預(yù)加載的資源,就可以通過(guò)監(jiān)聽(tīng) ContextRefreshedEvent 來(lái)做這樣的事情。

如下:

/*使用ApplicationListener來(lái)初始化一些數(shù)據(jù)到application域中的監(jiān)聽(tīng)器*/
@Component
public class MyServletContextListener implements
        ApplicationListener<ContextRefreshedEvent> {
    @Resource
    private UserMapper userMapper;
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent)
    {
        // 先獲取到application上下文
        ApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext();
        // 獲取對(duì)應(yīng)的service
        UserService userService = applicationContext.getBean(UserService.class);
        User user = userMapper.getUserById(1);
        // 獲取application域?qū)ο?,將查到的信息放到application域中
        ServletContext application = applicationContext.getBean(ServletContext.class);
        application.setAttribute("user", user);
    }

}

  正如注釋中描述的一樣,首先通過(guò) contextRefreshedEvent 來(lái)獲取 application 上下文,再通過(guò) application 上下文來(lái)獲取 UserService 這個(gè) bean,項(xiàng)目中可以根據(jù)實(shí)際業(yè)務(wù)場(chǎng)景,也可以獲取其他的bean,然后再調(diào)用自己的業(yè)務(wù)代碼獲取相應(yīng)的數(shù)據(jù),最后存儲(chǔ)到 application 域中,這樣前端在請(qǐng)求相應(yīng)數(shù)據(jù)的時(shí)候,我們就可以直接從 application 域中獲取信息,減少數(shù)據(jù)庫(kù)的壓力。下面寫(xiě)一個(gè)Controller 直接從 application 域中獲取 user 信息來(lái)測(cè)試一下。

@RestController
@RequestMapping("/listener")
public class TestController {
    @RequestMapping
            ("/user")
    public User getUser(HttpServletRequest request) {
        ServletContext application = request.getServletContext();
        return (User) application.getAttribute("user");
    }

}

通過(guò)PostMan訪問(wèn)如下:

1.jpg

  說(shuō)明數(shù)據(jù)已經(jīng)緩存成功

然后,直接在數(shù)據(jù)庫(kù)修改用戶名,密碼, 再次訪問(wèn),得到的依然是之前的結(jié)果, 證明沒(méi)有再次訪問(wèn)數(shù)據(jù)庫(kù),用的是之前 緩存內(nèi)存中的數(shù)據(jù)

  監(jiān)聽(tīng)HTTP會(huì)話 Session對(duì)象

  監(jiān)聽(tīng)器還有一個(gè)比較常用的地方就是用來(lái)監(jiān)聽(tīng) session 對(duì)象,來(lái)獲取在線用戶數(shù)量,現(xiàn)在有很多開(kāi)發(fā)者都有自己的網(wǎng)站,監(jiān)聽(tīng) session 來(lái)獲取當(dāng)前在下用戶數(shù)量是個(gè)很常見(jiàn)的使用場(chǎng)景,下面來(lái)介紹一下如何來(lái)使用。

  問(wèn)題:

  訪問(wèn)HTML是否創(chuàng)建Session?:不會(huì)。

  訪問(wèn)JSP是否創(chuàng)建Session? :會(huì)

  訪問(wèn)Servlet是否創(chuàng)建Session?:不會(huì)(默認(rèn)沒(méi)有調(diào)用getSession方法)

        只有調(diào)用了getSession方法,才會(huì)創(chuàng)建Session, 觸發(fā)sessionCreated方法

@Component
public class MyHttpSessionListener implements HttpSessionListener {
    private static final Logger logger =
            LoggerFactory.getLogger(MyHttpSessionListener.class);
            /* 記錄在線的用戶數(shù)量*/
    public Integer count = 0;
    @Override
    public synchronized void sessionCreated(HttpSessionEvent httpSessionEvent) {
                                //Notification that a session was created.
        logger.info("新用戶上線了");
        count++;
        httpSessionEvent.getSession().getServletContext().setAttribute("count", count);
    }
    @Override
    public synchronized void sessionDestroyed(HttpSessionEvent httpSessionEvent)
    {                            //Notification that a session is about to be invalidated.
        logger.info("用戶下線了");
        count--;
        httpSessionEvent.getSession().getServletContext().setAttribute("count",
                count);
    }

}

  可以看出,首先該監(jiān)聽(tīng)器需要實(shí)現(xiàn) HttpSessionListener 接口,然后重寫(xiě) sessionCreated 和 sessionDestroyed 方法,在 sessionCreated 方法中傳遞一個(gè) HttpSessionEvent 對(duì)象,然后將當(dāng)  前 session 中的用戶數(shù)量加1, sessionDestroyed 方法剛好相反,不再贅述。然后我們寫(xiě)一個(gè) Controller 來(lái)測(cè)試一下。

@GetMapping("/total2")
    public String getTotalUser(HttpServletRequest request, HttpServletResponse
            response) {
        Cookie cookie;
        try {
// 把sessionId記錄在瀏覽器中
            cookie = new Cookie("JSESSIONID",
                    URLEncoder.encode(request.getSession().getId(), "utf-8"));
            cookie.setPath("/");
//設(shè)置cookie有效期為2天,設(shè)置長(zhǎng)一點(diǎn)
            cookie.setMaxAge( 48*60 * 60);
            response.addCookie(cookie);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        Integer count = (Integer)
                request.getSession().getServletContext().getAttribute("count");
        return "當(dāng)前在線人數(shù):" + count;
    }

  監(jiān)聽(tīng)客戶端請(qǐng)求Servlet Request對(duì)象

  使用監(jiān)聽(tīng)器獲取用戶的訪問(wèn)信息比較簡(jiǎn)單,實(shí)現(xiàn) ServletRequestListener 接口即可,然后通過(guò) request

  對(duì)象獲取一些信息。如下

@Component
public class MyServletRequestListener implements ServletRequestListener {
        private static final Logger logger =
                LoggerFactory.getLogger(MyServletRequestListener.class);
        @Override
        public void requestInitialized(ServletRequestEvent servletRequestEvent) {
            HttpServletRequest request = (HttpServletRequest)
                    servletRequestEvent.getServletRequest();
            logger.info("session id為:{}", request.getRequestedSessionId());
            logger.info("request url為:{}", request.getRequestURL());
            request.setAttribute("name", "莊子");
        }
        @Override
        public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
            logger.info("request end");
            HttpServletRequest request = (HttpServletRequest)
                    servletRequestEvent.getServletRequest();
            logger.info("request域中保存的name值為:{}", request.getAttribute("name"));
        }
}

接下來(lái)寫(xiě)一個(gè) Controller 測(cè)試一下即可。

@GetMapping("/request")
public String getRequestInfo(HttpServletRequest request) {
    System.out.println("requestListener中的初始化的name數(shù)據(jù):" +
            request.getAttribute("name"));
    return "success";
}

其實(shí)訪問(wèn)任意的控制器都會(huì)觸發(fā)ServletRequestListener監(jiān)聽(tīng)事件

<