如何将Spring Session与JDBC结合使用? | Java Development Journal


在本文中,我们将了解如何将Spring Session与JDBC结合使用。Spring Session  提供了一种解决HTTP会话限制的透明方法。它提供中央会话管理,而不依赖于特定于容器的解决方案(例如Tomcat,Jetty等)。它提供了存储和管理会话信息的不同选项。在本文中,我们将介绍将 JDBC与Spring Session集成的步骤。

如果您使用的是Spring Boot,则需要在应用程序的pom.xml文件中添加以下依赖项:

<dependencies>
    <dependency>
        <groupId>org.springframework.session</groupId>
        <artifactId>spring-session-jdbc</artifactId>
    </dependency>
    <!-- Adding this to  have datasource and other feature available to us -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

我们不需要为Spring会话添加依赖项,因为Spring Boot会对此进行处理。基于以上配置,Spring Boot自动配置将为我们处理其余配置。作为最后一步,我们需要通知Spring Boot使用jdbc来存储会话信息。在application.properties文件中添加以下属性:

spring.session.store-type=jdbc # Session store type.

如果您只使用单个会话模块,则可以从application.properties文件中省略上述属性。Spring Boot自动使用该存储实现。如果您有多个实现,则必须指定上述属性。

在我们使用JDBC支持的spring会话之前,我们需要在应用程序中添加一些属性。属性文件:

spring.datasource.url=jdbc:mysql://localhost:3306/spring-session-jdbc
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

为了使Spring会话能够使用我们的JDBC配置,它需要在DB中创建某个表,我们可以通过以下属性启用此功能:

spring.session.jdbc.initialize-schema=always

一旦我们启用这些属性如果我们指定spring.session.jdbc.initialize-schema=never,那么我们需要手动创建会话表。Spring会话JDBC jar包含用于创建所需模式的SQL脚本。您可以在org.springframework.session.jdbc包下看到。

MySQL数据库存储会话的模式:

CREATE TABLE SPRING_SESSION (
    PRIMARY_ID CHAR(36) NOT NULL,
    SESSION_ID CHAR(36) NOT NULL,
    CREATION_TIME BIGINT NOT NULL,
    LAST_ACCESS_TIME BIGINT NOT NULL,
    MAX_INACTIVE_INTERVAL INT NOT NULL,
    EXPIRY_TIME BIGINT NOT NULL,
    PRINCIPAL_NAME VARCHAR(100),
    CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID)
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;

CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID);
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME);
CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME);

CREATE TABLE SPRING_SESSION_ATTRIBUTES (
    SESSION_PRIMARY_ID CHAR(36) NOT NULL,
    ATTRIBUTE_NAME VARCHAR(200) NOT NULL,
    ATTRIBUTE_BYTES BLOB NOT NULL,
    CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
    CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;


Spring JDBC Session和@EnableJdbcHttpSession
如果您使用  @EnableJdbcHttpSession,以上配置将无法正常工作。spring.session.*不适合你的原因是因为你正在使用@EnableJdbcHttpSession。
这意味着我们正在明确自己来配置Spring Session,因此Spring Boot的自动配置会不起作用。为了处理这个情况,我们有以下两个选项:

  1. 不要用 @EnableJdbcHttpSession,让Spring Boot通过自动配置来处理它。
  2. 如果继续使用@EnableJdbcHttpSession注释,请手动创建架构  。

REST控制器
让我们创建一个简单的REST控制器来查看运行中的会话处理:

@RestController
public class GreetingController {

    @GetMapping("/")
    public @ResponseBody ResponseEntity<List> getMessage(Model model, HttpSession session) {
        List greetings = (List) session.getAttribute(
"GREETING_MESSAGES");
        if(greetings == null) {
            greetings = new ArrayList<>();
        }

        return new ResponseEntity<List>(greetings,HttpStatus.OK);
    }

    @PostMapping(
"/messages")
    public @ResponseBody ResponseEntity<List> saveMessage(@RequestParam(
"message") String greeting, HttpServletRequest request)
    {
        List greetings = (List) request.getSession().getAttribute(
"GREETING_MESSAGES");
        if(greetings == null) {
            greetings = new ArrayList<>();
            request.getSession().setAttribute(
"GREETING_MESSAGES", greetings);
        }
        greetings.add(greeting);
        return new ResponseEntity<List>(greetings,HttpStatus.OK);
    }
}

Spring Boot主类:

@SpringBootApplication
@EnableJdbcHttpSession
public class SpringSessionWithJdbcApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringSessionWithJdbcApplication.class, args);
    }
}

@EnableJdbcHttpSession注释创建一个名为的Spring bean springSessionRepositoryFilter实现Filter。过滤器负责替换由Spring Session支持的HttpSession实现。