스프링 세션 값 가져오기 - seupeuling sesyeon gabs gajyeoogi

보통 Spring에서 로그인 정보는 session에 저장하는 방식을 사용한다.

session 저장 방식은 주로 다음과 같은 3가지 방식 중 하나를 사용한다.

1. 톰캣 내장메모리 session 사용

session은 톰캣의 내장 메모리에 저장이 되므로 서버를 재시작할 때마다 세션이 초기화된다는 특징이 있다.

  보통 1대의 was를 사용하는 프로젝트에서 주로 사용하는 방식이다. (2대 이상의 was를 사용할 경우 추가적인 설정 필요)

2. DBMS에 session 저장

: 여러 was에서 공용으로 세션을 사용할 수 있다.

  로그인/로그아웃 시마다 DB I/O가 발생하여 성능에 영향을 준다는 단점이 있다.

  로그인/로그아웃 요청이 많지 않은 프로젝트에서 주로 사용된다.

3. Redis, Elastic cache 등의 메모리 DB에 session 저장

: 가장 많이 사용되는 방식이다.

  실제 서비스로 배포하려면 embedded redis 방식이 아닌 외부 메모리 서버를 구축하여 사용해야 한다.

  사용료를 지불해야 한다. (유료)

이 중에서 나는 2번 방식을 선택하기로 했다.

구글링을 해보면 죄다 Spring boot 기준으로 설명이 되어 있고, Legacy Spring 셋팅 관련 문서가 많이 없어서 설정하는 데 애먹었다.

이 글이 나처럼 옛날 프로젝트 유지보수를 맡게 된 개발자들에게 도움이 됐으면 좋겠다.

과정

1. spring-session, spring-session-jdbc 의존성 추가

: pom.xml에 다음과 같이 추가하거나 해당 jar파일을 다운로드 받아서 lib에 추가한다.

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session</artifactId>
    <version>1.3.5.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-jdbc</artifactId>
    <version>2.5.3</version>
</dependency>

2. context-*.xml 파일에 다음과 같은 코드 추가

<!-- sqlSession 정의하는 곳에 아래와 같이 추가 -->
<context:annotation-config/>
<bean class="org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessionConfiguration"/>

3. web.xml에 다음과 같은 코드 추가

<filter>
  <filter-name>springSessionRepositoryFilter</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
  <filter-name>springSessionRepositoryFilter</filter-name>
  <url-pattern>/*</url-pattern>
  <dispatcher>REQUEST</dispatcher>
  <dispatcher>ERROR</dispatcher>
</filter-mapping>

4. SpringHttpSessionConfiguration.java 추가

: 이 부분은 Spring Http Session Configuration.class cannot be opened because it does not exist 에러가 나는 분들만 추가하면 된다.

package egovframework.com.cmm;

import java.io.IOException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.MapSessionRepository;
import org.springframework.session.config.annotation.web.http.EnableSpringHttpSession;

@Configuration
@EnableSpringHttpSession
public class SpringHttpSessionConfiguration {
   @Bean
   public MapSessionRepository sessionRepository() {
       return new MapSessionRepository();
   }
}

오류 해결 Q&A

Q.
SPRING_SESSION 테이블이 자동으로 생성되지 않아서 SQL 오류가 떠요!

=>

수작업으로 테이블을 생성해주는 방법밖에 없는 듯하다. boot에서는 application.properties에 딱 한 줄만 추가해주면 되던데...

-- spring_session 1.3 버전 이상부터는 primary_id라는 컬럼이 사라졌음

CREATE TABLE SPRING_SESSION (
	SESSION_ID CHAR(36),
	CREATION_TIME BIGINT NOT NULL,
	LAST_ACCESS_TIME BIGINT NOT NULL,
	MAX_INACTIVE_INTERVAL INT NOT NULL,
	PRINCIPAL_NAME VARCHAR(100),
	CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID)
);

CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);

CREATE TABLE SPRING_SESSION_ATTRIBUTES (
	SESSION_ID CHAR(36),
	ATTRIBUTE_NAME VARCHAR(200),
	ATTRIBUTE_BYTES BYTEA,
	CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
	CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE
);

CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID);

여기서도 주의할 사항이 있다.

DBMS마다 데이터 타입이 다르기 때문에 CREATE문 실행시 오류가 뜬다면 해당 DBMS에 맞는 데이터 타입으로 변경하면 된다.

참고로 난 Cubrid 기준으로 BYTEA(바이트형 배열) 데이터 타입이 없다고 나와서 BLOB 타입으로 수정하여 실행했다.

Q.
다중 DB를 사용중인데 세션을 저장하는 DB 외에 다른 Datasource로 세션 DB가 연결돼요!

=>

JdbcHttpSessionConfiguration에 datasource를 어떻게 설정하는 지 2시간동안 구글링 해봤는데 결국 못찾았습니다.

(알고 계신 분들은 댓글로 알려주시면 감사드리겠습니다.)

대신 야매법으로 해결했습니다. bean id가 dataSource인 경우 JdbcHttpSessionConfiguration에서 default datasource로 인식하기 때문에 세션 DB로 사용할 datasource의 id를 dataSource로 설정하면 됩니다.

참고자료

https://www.docs4dev.com/docs/en/spring-session/2.1.2.RELEASE/reference/httpsession.html