기존 방법 : Session 이용. HttpSession을 여러 개 생성해서 이용해서 이메일을 검증했다.
문제점 : Key 값 중복 위험이 있음.
해결 방법 : Key, Value값의 맵을 사용하는 Redis를 이용한다.
이점 : 캐시 서버이기 때문에 빠름. DB의 부하를 줄여줌.
도커를 이용하면 간편하다.
docker run -p 6379:6379 --name redis -d redis
6379는 redis의 기본 포트 번호이다.
-p [내 서버 port] : [redis port] 로 내 서버 port에 접근하면 redis 포트로 접근한다는 의미이다.
docker ps
→ 현재 가동중인 컨테이너 리스트를 반환해주는 명령어.
docker exec -it abbf49a1cd90 bash
→ 가동중인 컨테이너 내부에 들어가는 명령어
저기 있는 abbf49 ~ 이건 CONTAINER ID이다. docker ps를 입력하면 알 수 있다.
redis-cli
→ 레디스 컨테이너 안에서 redis-cli를 입력하면 redis 클라이언트로 접속을 할 수 있다.
→ 여기서 레디스에 저장된 정보들을 보거나 삭제하거나, 입력하거나 등 작업을 할 수 있다.
도커를 이용해 redis 설치를 완료했다. 이 redis를 이제 WAS에 연동시켜보겠다.
스프링 부트는 redis에 대한 빈 설정들을 자동으로 제공해주고 우리가 하는 일은 classpath를 추가하고 bean을 가져다가 쓰기만 하면 된다.
gradle을 통해 redis 관련 라이브러리들을 다운받아 적용시킨다.
implementation 'org.springframework.boot:spring-boot-starter-data-redis
dependencies {
// spring data redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
}
application.properties 또는 yml에 가서 spring.redis에 관련된 설정을 해준다.
#application.properties
#redis
spring.redis.host=localhost
spring.redis.port=6379
Redis와 연결시킬 dao 생성
package com.example.testlocal.module.user.domain.repository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;
import java.time.Duration;
@RequiredArgsConstructor
@Repository
public class EmailCertificationDao {
private final String REDIS_EMAIl_PREFIX = "email:"; // Redis에 저장되는 Key값이 중복되지 않도록 상수 선언
private final int LIMIT_TIME = 10 * 60; // Redis에서 해당 데이터의 유효시간(TTL)을 설정
private final StringRedisTemplate stringRedisTemplate;
public void createCodeCertification(String email, String certificationNumber){
stringRedisTemplate.opsForValue()
.set(REDIS_EMAIl_PREFIX + email, certificationNumber, Duration.ofSeconds(LIMIT_TIME));
}
// 이메일에 해당하는 인증번호 가져오기
public String getCodeCertification(String email){
return stringRedisTemplate.opsForValue().get(REDIS_EMAIl_PREFIX + email);
}
// 인증이 완료되었을 경우 메모리 관리를 위해 인증번호 삭제
public void removeCodeCertification(String email){
stringRedisTemplate.delete(REDIS_EMAIl_PREFIX + email);
}
// Redis에 이메일(KEY)로 저장된 인증번호(VALUE)가 존재하는지 확인
public boolean hasKey(String email){
return stringRedisTemplate.hasKey(REDIS_EMAIl_PREFIX + email);
}
}
StringRedisTemplate를 주입 받음으로써 redis와 연동할 수 있다.
StringRedisTemplate에 대한 정보는 추후에 작성하겠다.
EmailService 부분 리팩토링
public SendEmailResponse sendSejongEmail(SendEmailRequest sendEmailRequest, HttpServletRequest request) throws MessagingException {
String authCode = getAuthCode();
sendEmail(sendEmailRequest.getEmail(), authCode);
createCodeInRedis(sendEmailRequest.getEmail() + "@sju.ac.kr", authCode);
//setSession(request, authCode);
return SendEmailResponse.of(sendEmailRequest.getEmail());
}
public void createCodeInRedis(String email, String authCode){
emailCertificationDao.createCodeCertification(email, authCode);
}
getAuthCode() 메소드로 인증번호 난수를 생성하고
controller에서 sendSejongEmail을 호출하면 sendEmail() 메소드를 통해 이메일을 보낸 후
setSession() 메소드를 통해 HttpSession을 만들어줘서 인증번호를 저장했었는데
setSession()을 지우고 createCodeInRedis()를 호출함으로써 이메일과 인증번호를 저장하게끔 설정했다.
테스트
package com.example.testlocal.module.user.domain.repository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;
import java.time.LocalDateTime;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
@WebAppConfiguration
@SpringBootTest
class EmailCertificationDaoTest {
@Autowired
private EmailCertificationDao emailCertificationDao;
private final String email = "tovbsvb@sju.ac.kr";
@AfterEach
public void tearDown() throws Exception {
emailCertificationDao.removeCodeCertification(email);
}
@DisplayName("기본_등록_조회기능")
@Test
public void createCodeCertification() {
//given
emailCertificationDao.createCodeCertification(email, "12345");
assertThat(emailCertificationDao.getCodeCertification(email)).isEqualTo("12345");
}
}
결과
성공한 모습을 볼 수 있다.