티스토리 뷰

0. Redis 설치 [EC2+Docker]

✔️redis 이미지 다운

docker pull redis 

✔️이미지 파일 확인

docker images

✔️ AWS 보안그룹 인바운드/아웃바인드 설정

✔️ docker를 사용하여 redis 이미지를 만들고 redis 비밀번호를 설정

 docker run -p 6379:6379 --name (redis 컨테이너 이름) -d redis:latest --requirepass "(비밀번호)"

ex) docker run -p 6379:6379 --name spring-redis -d redis:latest --requirepass "123456"

✔️ redis-cli에서 인증 후 접속 확인

docker exec -i -t (redis 컨테이너 이름) redis-cli
AUTH (비밀번호)

 

1. 환경 설정

✔️ 의존성

implementation 'org.springframework.boot:spring-boot-starter-data-redis'

✔️ application.yml 파일 수정

redis:
  host: SERVER_HOST
  port: 6379
  password: PASSWORD

❗ SERVER_HOST: EC2 퍼블릭 IP ❗
PASSWORD : Redis 계정 비밀번호  
 

✔️RedisConfig.java 

@Configuration
public class RedisConfig {

    @Value("${spring.redis.host}")
    private String redisHost;

    @Value("${spring.redis.port}")
    private String redisPort;

    @Value("${spring.redis.password}")
    private String redisPassword;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(redisHost);
        redisStandaloneConfiguration.setPort(Integer.parseInt(redisPort));
        redisStandaloneConfiguration.setPassword(redisPassword);
        LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration);
        return lettuceConnectionFactory;
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}

 

2. Login 처리

로그인을 하면 현재 로그인한 사용자의 email을 value로 저장하려고 한다.

@Override
    public LoginResponse login(LoginRequest loginRequest) {
        TokenInfoResponse tokenInfoResponse = this.validateLogin(loginRequest);
        return LoginResponse.from(tokenInfoResponse);
    }

    public TokenInfoResponse validateLogin(LoginRequest loginRequest) {
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginRequest.getEmail(), loginRequest.getPassword());
        Authentication authentication = this.authenticationManagerBuilder.getObject().authenticate(authenticationToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);

        TokenInfoResponse tokenInfoResponse = this.tokenProvider.createToken(authentication);

        //redis에 데이터 저장
        redisTemplate.opsForValue().set("RT:" + authentication.getName(),
                authentication.getName(),tokenInfoResponse.getRefreshTokenExpirationTime(), TimeUnit.MILLISECONDS);

        return tokenInfoResponse;
    }

❓왜 저장할 때 key앞에 RT를 붙여주는 걸까?

처음에는 그냥 유저의 이름을 저장했는데 내가 구하고 싶은 것은 현재 로그인 중인 전체 사용자이기 때문이다! 

 

+) 하나의 세션이 각각 string, set, hash로 총 3가지의 데이터 타입으로 저장이 된다.
실제로 이렇게 코드를 짜고 Postman으로 localhost:8080/user/login에 POST요청을 한 후, redis-cli로 확인하면 다음과 같이 데이터가 저장된 것을 확인할 수 있다.

✔️ RT: 사용자 email
     세션 Key. string타입
 
✔️ spring:session:sessions:(session id)
      세션 정보가 저장됨. hash타입
 
✔️ spring:session:sessions:expires:(session id)
     세션 만료 키. string타입
 
✔️ spring:session:expirations:(expire time)
     만료시간에 삭제될 세션 정보. set타입
 
만약 다른 데이터 타입인 'spring:session:sessions:717c7769-cb97-4c93-ab4b-41696b513443'에 get을 하면? 

이런 이유가 나오는 이유는 다음과 같다.
레디스는 기본적으로 5가지 타입을 제공하고 있으며 데이터베이스에 한번 타입이 결정된 상태에서 해당 타입과 상관없는 명령을 수행하려고 할때 위와 같은 에러 메시지가 출력된다. 꼭 수행해야되는 명령이라면 기존의 키를 지우면 된다.


Redis support 5 types of data types. You need to know what type of value that key maps to, as for each data type, the command to retrieve it is different.
Here are the commands to retrieve key value:

  • if value is of type string -> GET <key>
  • if value is of type hash -> HGETALL <key>
  • if value is of type lists -> lrange <key> <start> <end>
  • if value is of type sets -> smembers <key>
  • if value is of type sorted sets -> ZRANGEBYSCORE <key> <min> <max>

command to check the type of value a key mapping to:

  • type <key>

즉, 내가 입력한 value(email)를 보려면 get "RT:test003@naver.com" 로 조회해야 한다. 
-> RT:*형식인 것만 조회하면 된다!

 

3. 로그인 되어있는 다른 사용자 보기

public void getActiveUser(String email, List<UserDto.ActiveUserResponse> activeUserResponseList){
        // (1) RT:*형식인 Key를 모두 조회
        Set<String> redisSessionKeys = redisTemplate.keys("RT:*");

        // (2) Key Sets를 이용해 value를 하나씩 조회
        for (String redisSessionKey : redisSessionKeys) {
            String redisSessionValue = (String)redisTemplate.opsForValue().get(redisSessionKey);
            User user = validateEmail(redisSessionValue);
            if (user.getEmail().equals(email)) {
                continue;
            }
            UserDto.ActiveUserResponse dto = UserDto.ActiveUserResponse.builder()
                    .name(user.getName())
                    .email(user.getEmail())
                    .imgUrl(user.getUserImage().getImageUrl())
                    .build();
                    
            activeUserResponseList.add(dto);
        }
    }

redisTemplate.keys("RT:*") : RT:~인 key 모두 조회 
redisTemplate.opsForValue().get(redisSessionKey): 해당 key 의 value 데이터 조회
 
opsForValue()가 궁금해?

 

[Java + Redis] Spring Data Redis로 Redis와 연동하기 - RedisTemplate 편

[Redis] 캐시(Cache)와 Redis [Redis] Redis의 기본 명령어 [Java + Redis] Spring Data Redis로 Redis와 연동하기 - RedisTemplate 편 [Java + Redis] Spring Data Redis로 Redis와 연동하기 - RedisRepository 편 안녕하세요. 오늘은 Redis

sabarada.tistory.com

 


참고

더보기