Skip to content

Commit 635b269

Browse files
authored
Merge pull request #5 from fr35wo/feature/board
feat: Redis 연동 & 조회수 중복 증가 방지 기능 구현
2 parents 9925055 + 30a35d3 commit 635b269

File tree

5 files changed

+108
-2
lines changed

5 files changed

+108
-2
lines changed

build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ dependencies {
6262
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
6363
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
6464
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
65+
66+
// Redis
67+
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
6568
}
6669

6770
jar {

src/main/java/com/example/copro/board/application/BoardService.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.example.copro.board.exception.NotBoardOwnerException;
2222
import com.example.copro.board.exception.ScrapNotFoundException;
2323
import com.example.copro.comment.domain.repository.CommentRepository;
24+
import com.example.copro.global.redis.application.RedisService;
2425
import com.example.copro.image.domain.Image;
2526
import com.example.copro.image.domain.repository.ImageRepository;
2627
import com.example.copro.member.domain.Member;
@@ -51,6 +52,8 @@ public class BoardService {
5152

5253
private final NotificationRepository notificationRepository;
5354

55+
private final RedisService redisService;
56+
5457
public BoardListRspDto findAll(String category, Pageable pageable) {
5558
//Page<Board> boards = boardRepository.findAllByCategory(Category.valueOf(category), pageable);
5659
Page<BoardDto> boards = boardRepository.findAllWithCommentCount(Category.valueOf(category), pageable);
@@ -163,7 +166,13 @@ public BoardListRspDto findByTitleContaining(String query, Pageable pageable) {
163166
public BoardResDto getBoard(Member member, Long boardId) {
164167
Member getMember = memberRepository.findById(member.getMemberId()).orElseThrow(MemberNotFoundException::new);
165168
Board board = boardRepository.findById(boardId).orElseThrow(() -> new BoardNotFoundException(boardId));
166-
board.updateViewCount();
169+
170+
if (!board.getMember().getMemberId().equals(getMember.getMemberId())) {
171+
boolean isFirstView = redisService.checkAndAddViewByMember(getMember.getMemberId(), boardId);
172+
if (isFirstView) {
173+
board.updateViewCount();
174+
}
175+
}
167176

168177
boolean isHeart = memberHeartBoardRepository.existsByMemberAndBoard(getMember, board);
169178
boolean isScrap = memberScrapBoardRepository.existsByMemberAndBoard(getMember, board);
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.example.copro.global.config;
2+
3+
import org.springframework.beans.factory.annotation.Value;
4+
import org.springframework.context.annotation.Bean;
5+
import org.springframework.context.annotation.Configuration;
6+
import org.springframework.data.redis.connection.RedisConnectionFactory;
7+
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
8+
import org.springframework.data.redis.core.RedisTemplate;
9+
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
10+
import org.springframework.data.redis.serializer.StringRedisSerializer;
11+
12+
@Configuration
13+
@EnableRedisRepositories
14+
public class RedisConfig {
15+
@Value("${spring.data.redis.host}")
16+
private String host;
17+
18+
@Value("${spring.data.redis.port}")
19+
private int port;
20+
21+
@Value("${spring.profiles.active}")
22+
private String namespace;
23+
24+
@Bean
25+
public RedisConnectionFactory redisConnectionFactory() {
26+
return new LettuceConnectionFactory(host, port);
27+
}
28+
29+
@Bean
30+
public RedisTemplate<String, String> redisTemplate() {
31+
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
32+
redisTemplate.setKeySerializer(new StringRedisSerializer());
33+
redisTemplate.setValueSerializer(new StringRedisSerializer());
34+
redisTemplate.setConnectionFactory(redisConnectionFactory());
35+
return redisTemplate;
36+
}
37+
38+
public String getNamespace() {
39+
return namespace;
40+
}
41+
42+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.example.copro.global.redis.application;
2+
3+
import com.example.copro.global.config.RedisConfig;
4+
import org.springframework.data.redis.core.RedisTemplate;
5+
import org.springframework.stereotype.Service;
6+
import java.time.Duration;
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
10+
@Service
11+
public class RedisService {
12+
private final RedisTemplate<String, String> redisTemplate;
13+
private final RedisConfig redisConfig;
14+
15+
public RedisService(RedisTemplate<String, String> redisTemplate, RedisConfig redisConfig) {
16+
this.redisTemplate = redisTemplate;
17+
this.redisConfig = redisConfig;
18+
}
19+
20+
public boolean checkAndAddViewByMember(Long memberId, Long boardId) {
21+
String namespace = redisConfig.getNamespace();
22+
String redisKey = namespace + ":boardView:" + boardId;
23+
String redisMemberKey = namespace + ":memberView:" + memberId;
24+
25+
List<String> memberViewList = getValuesList(redisMemberKey);
26+
27+
if (!memberViewList.contains(redisKey)) {
28+
setValuesListWithExpire(redisMemberKey, redisKey, Duration.ofHours(24));
29+
return true;
30+
}
31+
return false;
32+
}
33+
34+
public void setValuesListWithExpire(String key, String data, Duration duration) {
35+
redisTemplate.opsForList().rightPush(key, data);
36+
redisTemplate.expire(key, duration);
37+
}
38+
39+
public List<String> getValuesList(String key) {
40+
Long len = redisTemplate.opsForList().size(key);
41+
return len == 0 ? new ArrayList<>() : redisTemplate.opsForList().range(key, 0, len-1);
42+
}
43+
44+
}

src/main/resources/application.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ FIREBASE_KEY: ${FIREBASE_KEY}
4949
spring:
5050
profiles:
5151
active: prod
52+
data:
53+
redis:
54+
host: ${spring.data.redis.host}
55+
port: ${spring.data.redis.port}
5256

5357
datasource:
5458
url: ${spring.datasource.url}
@@ -78,6 +82,10 @@ admin:
7882
spring:
7983
profiles:
8084
active: dev
85+
data:
86+
redis:
87+
host: ${spring.data.redis.host}
88+
port: ${spring.data.redis.port}
8189

8290
datasource:
8391
url: ${spring.datasource.url}
@@ -97,4 +105,4 @@ logging:
97105

98106
myapp:
99107
api-url: ${myapp.api-url}
100-
local-url: ${myapp.local-url}
108+
local-url: ${myapp.local-url}

0 commit comments

Comments
 (0)