1. 概述
在本快速教程中,我們將探討如何使用 Spring Session 與 MongoDB 集成,無論使用 Spring Boot 還是不使用。
Spring Session 也可以與 Redis 和 JDBC 等其他存儲後端集成。
2. Spring Boot 配置
首先,讓我們看一下 Spring Boot 所需的依賴項和配置。首先,讓我們將最新版本的 spring-session-data-mongodb 和 spring-boot-starter-data-mongodb 添加到我們的項目中:
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-mongodb</artifactId>
<version>3.1.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>3.1.5</version>
</dependency>如果使用了多個 Spring Session 模塊,則需要通過設置 Spring Session 的 store-type 屬性來定義我們想要使用的模塊。例如,在這種情況下,我們會在 application.properties 中將 store-type 設置為 mongodb:
spring.session.store-type=mongodb從 Spring Boot 3.0.0 開始,不再支持存儲類型的屬性,而是通過註解配置來管理會話。
3. 在 Spring Boot 環境之外的 Spring 配置
現在,讓我們來查看在 MongoDB 中存儲 Spring 會話所需的依賴項和配置,而無需使用 Spring Boot。
類似於 Spring Boot 配置,我們需要 spring-session-data-mongodb 依賴項。但是,在這裏,我們將使用 spring-data-mongodb 依賴項來訪問我們的 MongoDB 數據庫:
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-mongodb</artifactId>
<version>3.1.5</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>3.1.5</version>
</dependency>最後,讓我們看看如何配置應用程序:
@EnableMongoHttpSession
public class HttpSessionConfig {
@Bean
public JdkMongoSessionConverter jdkMongoSessionConverter() {
return new JdkMongoSessionConverter(Duration.ofMinutes(30));
}
}使用 @EnableMongoHttpSession 註解可以配置將會話數據存儲在 MongoDB 中
此外,請注意,JdkMongoSessionConverter 負責序列化和反序列化會話數據。
4. 示例應用程序
讓我們創建一個應用程序來測試配置。我們將使用 Spring Boot,因為它速度更快,並且需要更少的配置。
我們將首先創建一個控制器來處理請求:
@RestController
public class SpringSessionMongoDBController {
@GetMapping("/")
public ResponseEntity<Integer> count(HttpSession session) {
Integer counter = (Integer) session.getAttribute("count");
if (counter == null) {
counter = 1;
} else {
counter++;
}
session.setAttribute("count", counter);
return ResponseEntity.ok(counter);
}
}如本示例所示,我們每次對端點進行調用時都會遞增 counter,並將其值存儲在名為 count 的會話屬性中。
5. 測試應用程序
讓我們測試應用程序,以確認我們是否能夠將會話數據存儲在 MongoDB 中。
為此,我們將訪問端點並檢查我們收到的 cookie。該 cookie 將包含會話 ID。
之後,我們將查詢 MongoDB 集合,使用會話 ID 檢索會話數據:
@Test
public void
givenEndpointIsCalledTwiceAndResponseIsReturned_whenMongoDBIsQueriedForCount_thenCountMustBeSame() {
HttpEntity<String> response = restTemplate
.exchange("http://localhost:" + 8080, HttpMethod.GET, null, String.class);
HttpHeaders headers = response.getHeaders();
String set_cookie = headers.getFirst(HttpHeaders.SET_COOKIE);
Assert.assertEquals(response.getBody(),
repository.findById(getSessionId(set_cookie)).getAttribute("count").toString());
}
private String getSessionId(String cookie) {
return new String(Base64.getDecoder().decode(cookie.split(";")[0].split("=")[1]));
}6. 工作原理
讓我們來了解一下 Spring 會話背後的運作機制。
SessionRepositoryFilter 負責大部分工作:
- 將HttpSession 轉換為MongoSession
- 檢查是否存在Cookie,如果存在,則從存儲中加載會話數據
- 保存更新後的會話數據到存儲
- 檢查會話的有效性
此外,SessionRepositoryFilter 會創建一個名為 SESSION 的 Cookie,該 Cookie 是 HttpOnly 和 secure 屬性。此 Cookie 包含會話 ID,該 ID 是 Base64 編碼的值。
要自定義 Cookie 的名稱或屬性,則必須創建一個類型為 DefaultCookieSerializer 的 Spring Bean。
例如,我們在這裏禁用了 Cookie 的 httponly 屬性:
@Bean
public DefaultCookieSerializer customCookieSerializer(){
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
cookieSerializer.setUseHttpOnlyCookie(false);
return cookieSerializer;
}7. 會話詳情存儲在 MongoDB 中
以下我們使用以下命令在 MongoDB 控制枱中查詢我們的會話集合:
db.sessions.findOne()因此,我們會得到一個類似於以下的 BSON 文檔:
{
"_id" : "5d985be4-217c-472c-ae02-d6fca454662b",
"created" : ISODate("2019-05-14T16:45:41.021Z"),
"accessed" : ISODate("2019-05-14T17:18:59.118Z"),
"interval" : "PT30M",
"principal" : null,
"expireAt" : ISODate("2019-05-14T17:48:59.118Z"),
"attr" : BinData(0,"rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABdAAFY291bnRzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAC3g=")
}id 是一個 UUID,將由 DefaultCookieSerializer 進行 Base64 編碼,並作為 SESSION 餅乾的值設置。 此外,請注意,attr 屬性包含我們計數器的實際值。
8. 結論
在本教程中,我們探討了使用 MongoDB 作為後端的 Spring Session——這是一種在分佈式系統中管理 HTTP 會話的強大工具。 考慮到這一點,它對於解決應用程序中多個實例之間會話複製的問題非常有幫助。