Spring Boot 解決方案 - 會話

鏈接無狀態

使用 HTTP 的鏈接是無狀態的,所以爲了應對須要狀態的服務例如用戶登陸,誕生了適合保存狀態的設計-會話(session),本文就來探討一下會話。html

會話的使用

Spring Mvc 中使用會話很簡單,在控制器類的方法參數列表中,直接編寫 HttpSession 類型的參數,或者參數列表中編寫 HttpServletRequest 類,而後使用 getSession() 方法獲取會話。redis

下面是使用會話的簡單例子,第一次訪問時會建立一個無數據的會話,所以獲取到的 access 屬性爲 null ,而當不是第一次訪問時,因爲屬性不爲 null 會獲得 "NOT THE FIRST TIME ACCESS" 。spring

@RestController
public class DemoController {
    private static final String ACCESS = "access";
    @RequestMapping("/")
    public String index(HttpSession session) { // or `index(HttpServletRequest req)`
        // then `HttpSession session = request.getSession();`
        if (session.getAttribute(ACCESS) == null) {
            session.setAttribute(ACCESS, true);
            return "FIRST TIME ACCESS";
        }
        return "NOT THE FIRST TIME ACCESS";
    }
}

注意:因爲用 Mock Mvc 測試獲取不到第一次請求 Cookies,所以沒法模擬獲得正確結果,請使用瀏覽器或者請求工具測試。數據庫

經常使用方法

上面例子展現了會話的簡單使用,其中 HttpSession 接口是 servlet 的標準,而 Spring Mvc 中的會話默認使用 Tomcat 的實現。下面來介紹幾個經常使用方法,更多方法使用請參考這篇文章瀏覽器

  • Object getAttribute(String) 方法用來獲取會話的屬性,若不存在則返回 null
  • void setAttribute(String, Object) 方法用來設置會話的屬性
  • void removeAttribute(String) 方法用來刪除會話的屬性
  • void setMaxInactiveInterval(int) 方法用來設置會話失效時間,單位爲秒,設置小於等於零的數則會話永不過時
  • void invalidate() 手動使會話失效並清理會話數據

會話監聽器

會話的生命週期分別爲建立、失效和建立與失效之間,而會話監聽器是爲了知足會話生命週期中觸發相應事件的須要,HttpSessionListenerHttpSessionAttributeListener 兩個監聽器接口分別知足了會話的各個生命週期。使用監聽器只需實現這些接口而後標註 @WebListener 註解便可,下面會有實現的例子。安全

針對會話的監聽器

HttpSessionListener 接口能夠算是針對會話的監聽器接口,由於它的兩個方法分別在會話建立和失效時調用,下面爲一個簡單的例子,參數列表中 HttpSessionEvent 類能夠用 getSession 獲取會話。服務器

@WebListener
public class SessionListener implements HttpSessionListener {
    public void sessionCreated(HttpSessionEvent event) {
        // ...
    }
    public void sessionDestroyed(HttpSessionEvent event) {
        // ...
    }
}

針對會話屬性的監聽器

HttpSessionListener 監聽器接口接管會話生命週期的建立與失效不一樣,HttpSessionAttributeListener 監聽器接口負責會話屬性的建立、銷燬與替換,下面爲該監聽器的簡單例子,參數列表中 HttpSessionBindingEvent 類除了能夠用 getSession 獲取會話,最主要的是可用 getNamegetValue 分別獲取屬性的名字和值。session

@WebListener
public class SessionListener implements HttpSessionBindingListener {
    public void attributeAdded(HttpSessionBindingEvent event) {
        // ...
    }
    
    public void attributeRemoved(HttpSessionBindingEvent event) {
        // ...
    }
    
    public void attributeReplaced(HttpSessionBindingEvent event) {
        // ...
    }
}

使監聽器生效

上面的例子只是編寫了監聽器的實現,爲了使得監聽器在項目裏生效,還必須在啓動類或者配置類上標註 @ServletComponentScan 來掃描這些屬於 servlet 組件的監聽器,例以下面在配置類上啓動 servlet 組件掃描。app

@Configuration
@ServletComponentScan  // enable scan servlet component
public class ApplicationConf {
    // ...
}

分佈式會話

如果有多臺 Web 服務器提供不一樣的服務,且要求屬於同一會話,上面的單機會話例子就沒法知足要求,因而就有了分佈式會話便可以共享會話數據。分佈式

利用 Spring Session 就能夠實現分佈式會話,而 Spring Session 的實現可依賴關係數據庫或內存數據庫,下面例子爲 Spring Boot 中導入基於 Redis 實現的 Spring Session 的依賴。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>

接着在 Spring Boot 的屬性配置文件中,添加以下的屬性便可,而對於會話的使用和單機會話操做是同樣的

spring:
  session:
    store-type: redis
  redis:
    host: 127.0.0.1
    port: 6379

會話安全問題

關於會話安全問題,因爲了解知識尚淺,暫且不作探討,後續會補充該部分。

相關文章
相關標籤/搜索