[이전글]
https://yooseong12.tistory.com/47
이전의 글에서는 왜 Redis를 사용해서 중복방지를 해야하는지와 Redis 가 무엇인지 간단하게 설명드렸습니다.
이 포스팅에서는 실제로 Redis를 통해 중복방지를 구현해보려고합니다.
우선 Redis-server 가 설치 되어 있어야 합니다.
Reids-server 설치
[Mac]
https://herojoon-dev.tistory.com/170
설치 방법은 위의 블로그를 참고하시고,
저는 Reids의 활용 방법에 대해서 설명드리겠습니다.
저는 Mac을 사용하기 때문에 Mac 기준으로 설명드리겠습니다.
우선, dependency를 추가해야합니다.
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
위의 dependency를 추가하고, reids 내부 메서드를 구현해야합니다.
우선 저희가 필요한 기능은 총 2가지 입니다.
- key에 데이터를 추가한다
- key를 기준으로 데이터를 가져온다.
이 두가지의 기능만 있다면 redis로 중복방지 구현이 가능합니다.
우선 RedisUtil.class 를 생성합시다.
Redis 구현
ReidsUtil.class
@Service
@RequiredArgsConstructor
public class RedisUtil {
private final StringRedisTemplate stringRedisTemplate;
public String getData(String key) {
ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();
return valueOperations.get(key);
}
public void setDateExpire(String key, String value, long duration) {
ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();
Duration expireDuration = Duration.ofSeconds(duration);
valueOperations.set(key, value, expireDuration);
}
}
하나씩 설명드리겠습니다.
- getData
- key 값을 받으면 ValueOperations 객체를 생성합니다.
- 그 후, 생서자로 주입받은 stringRedisTemplate 안에 있는 내부메서드인 opsForValue(); 기능을 사용합니다.
- 그 후, 생성한 valueOperations 객체를 통해 .get() 메서드로 데이터를 가져옵니다.
- setDateExpire
- 데이터를 가져오는 로직은 동일하지만 Duration 객체를 생성해서 해당 키의 만료 일자를 구현했습니다.
- 현재 보고계신 tistory 블로그 또한, 하루 접속자를 기준으로 조회수를 증가 시키기 때문에 만료일자를 만들어서 그날 하루동안만 데이터를 보관하는 형식으로 구현했습니다.
- 그 후, set() 메서드로 데이터를 저장합니다.
기본적인 두가지의 메서드를 설명드렸는데, 여기서 그냥 넘어가면 개발자라고 할 수 없습니다. stringRedisTemplate가 어떻게 데이터를 가져오는지 확인해봐야합니다.
String-focused extension of RedisTemplate. Since most operations against Redis are String based, this class provides a dedicated class that minimizes configuration of its more generic template especially in terms of serializers.
RedisTemplate의 문자열 중심 확장입니다. Redis에 대한 대부분의 작업은 문자열 기반이므로 이 클래스는 특히 직렬화기 측면에서 더 일반적인 템플릿의 구성을 최소화하는 전용 클래스를 제공합니다.쉽게 이야기하면 문자열 기준으로 확장된 클래스입니다.
- 그래서 위의 코드에서 사용한 .opsForValue() 메서드 또한 RedisTemplate의 메서드입니다. StringRedisTemplate는 확장클래스이고요.
그렇다면 계속 사용된 ValueOperations 객체는 무엇일까요? 🤔
- 위의 설명에서 보면 redis를 문자열 형식으로 변경하는 클래스입니다.
- 그중에서도 구현체인 AbstractOperations 가 Redis의 값을 가져오는 로직인 raw(key)를 실행해서 데이터를 가져옵니다.
이제 어떻게 데이터를 가져왔는지 확인해봤으니 어떻게 구현해야할지 알아봅시다.
밑에는 예시 코드입니다.
redisUtil은 생성자로 주입받아서 사용중입니다
구현 class
String viewCount = redisUtil.getData(String.valueOf(memberId));
if (viewCount == null) {
redisUtil.setDateExpire(String.valueOf(memberId), portfolioId + "_", calculateTimeUntilMidnight());
portfolio.increaseView();
} else {
String[] strArray = viewCount.split("_");
List<String> redisPortfolioList = Arrays.asList(strArray);
boolean isView = false;
if (!redisPortfolioList.isEmpty()) {
for (String redisPortfolioId : redisPortfolioList) {
if (String.valueOf(portfolioId).equals(redisPortfolioId)) {
isView = true;
break;
}
}
if (!isView) {
viewCount += portfolioId + "_";
redisUtil.setDateExpire(String.valueOf(memberId), viewCount, calculateTimeUntilMidnight());
portfolio.updateView();
}
}
}
이 위에 코드를 설명드리자면
- 우선 viewCount 변수를 생성해서 key를 기준으로 데이터를 가져옵니다.
근데, 여기서 key는 memberId가 되어야 합니다. 왜냐하면 사용자가 어떤 게시물을 확인했는지 알아야 하기 때문입니다. - if문을 통해서 만약 null 이라면 현재 한번도 조회를 하지 않았다고 판단이 되기 때문에 현재 상세조회한 게시글 id를 저장합니다.
"_" 언더바를 넣은 이유는 구분을 위해서 넣어놓았습니다.나중에 10과 101 이 있을때 그냥 쭉 저장된다면 10100 이런식으로 저장되기 때문에 구분이 어려워 언더바로 표현했습니다. - 이제 이미 오늘 게시글을 조회한적이 있다면 방금 설명드린대로 언더바를 기준으로 데이터를 나누고 List 객체를 생성합니다.
- isView 논리형을 생성해서 이미 확인한 적이 있는지 체크합니다.
for문을 돌려서 확인합니다. - 만약 한번도 확인한 적이 없다면 받아온 data값에 추가해서 넣습니다.
그리고 이제야 게시글의 조회수를 증가시켜줍니다.
위의 코드를 간단하게 설명드렸는데, 직접 코드를 작성해보시면서 이해하시면 더 이해하시기 편하실겁니다.
아마 여기서 calculateTimeUntilMidnight() 메서드가 눈에 띄실텐데 이 메서드는 현재 시간을 기준으로 00시까지의 시간을 계산하는 메서드입니다.
public static long calculateTimeUntilMidnight() {
LocalDateTime now = LocalDateTime.now();
LocalDateTime midnight = now.truncatedTo(ChronoUnit.DAYS).plusDays(1);
return ChronoUnit.SECONDS.between(now, midnight);
}
이렇게 구현해서 API를 테스트해보신다면 값이 잘 나오는 것을 확인하실 수 있습니다.
회고록
사실 1판 글을 올릴 당시에는 너무 어려워서 이걸 구현이 정말 가능한 걸까 생각하면서 당시에는 쿠키로 중복방지를 구현했는데, 현재는 reids로도 중복방지를 구현할 만한 실력이 올라와서 구현을 진행했습니다.
안되는것이 있으면 댓글 달아주시면 최선을 다해 알려드리겠습니다 (꾸벅)
'오류 > 트러블슈팅' 카테고리의 다른 글
SpringBoot+Redis 를 사용해서 조회수 중복방지 구현해보기 -1 (0) | 2023.04.24 |
---|