Spring Sessionを使う

Spring Sessionを使ってHttpSessionをRedisで管理してみる

セットアップ

build.gradle

  • dependenciesにspring-boot-starter-data-redisとspring-session-data-redisを追加する
plugins {
    id 'org.springframework.boot' version '2.5.0'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    compileOnly 'org.projectlombok:lombok'
    implementation 'org.slf4j:slf4j-api'
    implementation 'ch.qos.logback:logback-core'
    implementation 'ch.qos.logback:logback-classic'
    implementation 'com.google.guava:guava:30.1.1-jre'
    implementation 'org.apache.commons:commons-lang3'
    implementation 'commons-beanutils:commons-beanutils:1.9.2'
    implementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.9'
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.4'
    implementation 'org.springframework:springloaded:1.2.8.RELEASE'
    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
    implementation 'org.springframework.session:spring-session-data-redis'
    runtimeOnly 'mysql:mysql-connector-java' 
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
    useJUnitPlatform()
}

/src/main/resources/application.yml

  • spring.session.store-type、spring.redis.host=localhost、spring.redis.portの定義を追加
server:
  servlet:
    context-path: /sample
spring:
  messages:
    basename: "application-messages,ValidationMessages"
    encoding: "UTF-8"
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:33060/sample
    username: mysql-app
    password: mysql-app
  thymeleaf:
    cache: false
  session:
    store-type: redis    ←追加
  redis:
    host: localhost    ←追加
    port: 16379    ←追加
mybatis:
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    org:
      springframework: WARN
    com:
      example:
        demo:
          domain:
            mapper: DEBUG

/src/main/java/com/example/demo/web/controller/SessionCheckController.java

package com.example.demo.web.controller;

import java.net.UnknownHostException;
import java.time.LocalDateTime;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.web.dto.form.SessionInfo;

@RestController
public class SessionCheckController {

    private final SessionInfo sessionInfo;

    @Autowired
    public SessionCheckController(SessionInfo sessionInfo) {
        this.sessionInfo = sessionInfo;
    }

    @GetMapping("/session/accept")
    public String start(HttpServletRequest request) throws UnknownHostException {
        if (sessionInfo.getStartedAt() == null) {
            sessionInfo.setClientIp(request.getRemoteAddr());
            sessionInfo.setStartedAt(LocalDateTime.now());
            sessionInfo.setMessage("Session start.");
        } else {
            sessionInfo.setMessage("Session is continuing.");
        }
        return String.format("[Message: %s] [Host: %s] [Started At: %s]", sessionInfo.getMessage(),
                sessionInfo.getClientIp(), sessionInfo.getStartedAt());
    }

    @GetMapping("/session/invalidate")
    public String invalidate(HttpSession session) {
        session.invalidate();
        return "Session invalidate.";
    }
}

/src/main/java/com/example/demo/web/dto/form/SessionInfo.java

package com.example.demo.web.dto.form;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.SessionScope;

@Component
@SessionScope
public class SessionInfo implements Serializable {

    /**
    * SerialVersionUID.
    */
    private static final long serialVersionUID = -6228456085202936272L;

    private String clientIp;
    private String startedAt;
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getClientIp() {
        return clientIp;
    }

    public void setClientIp(String host) {
        this.clientIp = host;
    }

    public String getStartedAt() {
        return startedAt;
    }

    public void setStartedAt(String startedAt) {
        this.startedAt = startedAt;
    }

    public void setStartedAt(LocalDateTime startedAt) {
        this.startedAt = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").format(startedAt);
    }

}

/src/main/java/com/example/demo/WebConfiguration.java

  • springSessionDefaultRedisSerializerメソッドを追加。オブジェクトをJSON形式に変換してRedisに登録する
package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.example.demo.interceptor.RequestHandlerInterceptor;

@Configuration
public class WebConfiguration implements WebMvcConfigurer {

    @Autowired
    private RequestHandlerInterceptor requestHandlerInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(requestHandlerInterceptor);
    }

    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
        return new GenericJackson2JsonRedisSerializer();
    }
}

実行結果

f:id:samehada3:20210709141058p:plain
Another Redis Desktop