diff --git a/build.gradle b/build.gradle index 41dfddfd..af3385b8 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,6 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' -// implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation 'com.h2database:h2' @@ -72,6 +71,9 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect' + // cache + implementation 'org.springframework.boot:spring-boot-starter-cache' + // view implementation 'org.springframework.boot:spring-boot-starter-freemarker' developmentOnly 'org.springframework.boot:spring-boot-devtools' @@ -80,7 +82,6 @@ dependencies { implementation 'org.webjars.bower:axios:0.17.1' implementation 'com.google.code.gson:gson:2.8.0' - // WebSocket, Kafka, Stomp, MongoDB implementation 'org.springframework.boot:spring-boot-starter-websocket' implementation 'org.webjars:sockjs-client:1.1.2' diff --git a/src/main/java/com/example/waggle/domain/board/question/repository/QuestionRepository.java b/src/main/java/com/example/waggle/domain/board/question/repository/QuestionRepository.java index c55aabb0..c7b11400 100644 --- a/src/main/java/com/example/waggle/domain/board/question/repository/QuestionRepository.java +++ b/src/main/java/com/example/waggle/domain/board/question/repository/QuestionRepository.java @@ -1,11 +1,12 @@ package com.example.waggle.domain.board.question.repository; import com.example.waggle.domain.board.question.entity.Question; +import java.util.List; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; - -import java.util.List; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface QuestionRepository extends JpaRepository, QuestionQueryRepository { @@ -19,7 +20,10 @@ public interface QuestionRepository extends JpaRepository, Quest Page findPageByMemberId(Long memberId, Pageable pageable); + @Query("SELECT q.viewCount FROM Question q WHERE q.id = :boardId") + Long findViewCountByBoardId(@Param("boardId") Long boardId); - void deleteAllByMemberUsername(String username); + @Query("update Question q set q.viewCount = :viewCount where q.id = :boardId") + void applyViewCntToRDB(@Param("boardId") Long boardId, @Param("viewCount") Long viewCount); } \ No newline at end of file diff --git a/src/main/java/com/example/waggle/domain/board/question/service/QuestionCacheService.java b/src/main/java/com/example/waggle/domain/board/question/service/QuestionCacheService.java new file mode 100644 index 00000000..d2b6bfe3 --- /dev/null +++ b/src/main/java/com/example/waggle/domain/board/question/service/QuestionCacheService.java @@ -0,0 +1,54 @@ +package com.example.waggle.domain.board.question.service; + +import com.example.waggle.domain.board.question.repository.QuestionRepository; +import com.example.waggle.domain.member.service.RedisService; +import java.util.Objects; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CachePut; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Transactional +@RequiredArgsConstructor +@Service +public class QuestionCacheService { + + private final RedisService redisService; + private final QuestionRepository questionRepository; + private final String VIEW_COUNT_PREFIX = "viewCount::"; + private final String BOARD_PREFIX = "board::"; + + @CachePut(value = "viewCounts", key = "#boardId") + public Long applyViewCountToRedis(Long boardId) { + String viewCountKey = VIEW_COUNT_PREFIX + boardId; + String currentViewCount = redisService.getValue(viewCountKey); + if (currentViewCount != null) { + return redisService.increment(viewCountKey); + } else { + Long initialViewCount = questionRepository.findViewCountByBoardId(boardId); + return initialViewCount + 1; + } + } + + @Scheduled(fixedRate = 1000 * 60 * 3) + public void applyViewCountToRDB() { + Set viewCountKeys = redisService.getKeysByPattern(VIEW_COUNT_PREFIX + "*"); + if (Objects.requireNonNull(viewCountKeys).isEmpty()) { + return; + } + + for (String viewCntKey : viewCountKeys) { + Long boardId = extractBoardIdFromKey(viewCntKey); + Long viewCount = Long.parseLong(redisService.getValue(viewCntKey)); + questionRepository.applyViewCntToRDB(boardId, viewCount); + redisService.deleteData(viewCntKey); + redisService.deleteData(BOARD_PREFIX + boardId); + } + } + + private static Long extractBoardIdFromKey(String key) { + return Long.parseLong(key.split("::")[1]); + } +} diff --git a/src/main/java/com/example/waggle/domain/board/question/service/QuestionCommandService.java b/src/main/java/com/example/waggle/domain/board/question/service/QuestionCommandService.java index 0edc193b..6f09b9fd 100644 --- a/src/main/java/com/example/waggle/domain/board/question/service/QuestionCommandService.java +++ b/src/main/java/com/example/waggle/domain/board/question/service/QuestionCommandService.java @@ -16,6 +16,4 @@ Long updateQuestion(Long boardId, void deleteQuestion(Long boardId, Member member); - void increaseQuestionViewCount(Long boardId); - -} +} \ No newline at end of file diff --git a/src/main/java/com/example/waggle/domain/board/question/service/QuestionCommandServiceImpl.java b/src/main/java/com/example/waggle/domain/board/question/service/QuestionCommandServiceImpl.java index aed105fa..185208dc 100644 --- a/src/main/java/com/example/waggle/domain/board/question/service/QuestionCommandServiceImpl.java +++ b/src/main/java/com/example/waggle/domain/board/question/service/QuestionCommandServiceImpl.java @@ -1,5 +1,7 @@ package com.example.waggle.domain.board.question.service; +import static com.example.waggle.domain.board.service.BoardType.QUESTION; + import com.example.waggle.domain.board.ResolutionStatus; import com.example.waggle.domain.board.question.entity.Question; import com.example.waggle.domain.board.question.repository.QuestionRepository; @@ -10,13 +12,12 @@ import com.example.waggle.global.exception.handler.QuestionHandler; import com.example.waggle.global.payload.code.ErrorStatus; import com.example.waggle.web.dto.question.QuestionRequest; +import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import static com.example.waggle.domain.board.service.BoardType.QUESTION; - @Slf4j @RequiredArgsConstructor @Transactional @@ -88,13 +89,6 @@ public void deleteQuestion(Long boardId, Member member) { questionRepository.delete(question); } - @Override - public void increaseQuestionViewCount(Long boardId) { - Question question = questionRepository.findById(boardId) - .orElseThrow(() -> new QuestionHandler(ErrorStatus.BOARD_NOT_FOUND)); - question.increaseViewCount(); - } - private Question buildQuestion(QuestionRequest createQuestionRequest, Member member) { return Question.builder() .title(createQuestionRequest.getTitle()) diff --git a/src/main/java/com/example/waggle/domain/board/question/service/QuestionQueryServiceImpl.java b/src/main/java/com/example/waggle/domain/board/question/service/QuestionQueryServiceImpl.java index 4f46b5fe..b1e337d0 100644 --- a/src/main/java/com/example/waggle/domain/board/question/service/QuestionQueryServiceImpl.java +++ b/src/main/java/com/example/waggle/domain/board/question/service/QuestionQueryServiceImpl.java @@ -2,6 +2,7 @@ import com.example.waggle.domain.board.question.entity.Question; import com.example.waggle.domain.board.question.repository.QuestionRepository; +import com.example.waggle.domain.member.service.RedisService; import com.example.waggle.domain.recommend.repository.RecommendRepository; import com.example.waggle.global.exception.handler.QuestionHandler; import com.example.waggle.global.payload.code.ErrorStatus; @@ -26,6 +27,7 @@ public class QuestionQueryServiceImpl implements QuestionQueryService { private final QuestionRepository questionRepository; private final RecommendRepository recommendRepository; + private final RedisService redisService; @Override public List getAllQuestion() { diff --git a/src/main/java/com/example/waggle/domain/board/siren/repository/SirenRepository.java b/src/main/java/com/example/waggle/domain/board/siren/repository/SirenRepository.java index 2ad4721c..a921a8bd 100644 --- a/src/main/java/com/example/waggle/domain/board/siren/repository/SirenRepository.java +++ b/src/main/java/com/example/waggle/domain/board/siren/repository/SirenRepository.java @@ -7,6 +7,10 @@ import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.transaction.annotation.Transactional; public interface SirenRepository extends JpaRepository, SirenQueryRepository { @@ -28,4 +32,12 @@ public interface SirenRepository extends JpaRepository, SirenQueryR List findAllByOrderByStatusAsc(); + @Query("SELECT s.viewCount FROM Siren s WHERE s.id = :boardId") + Long findViewCountByBoardId(@Param("boardId") Long boardId); + + @Transactional + @Modifying + @Query("update Siren s set s.viewCount = :viewCount where s.id = :boardId") + void applyViewCntToRDB(@Param("boardId") Long boardId, @Param("viewCount") Long viewCount); + } diff --git a/src/main/java/com/example/waggle/domain/board/siren/service/SirenCacheService.java b/src/main/java/com/example/waggle/domain/board/siren/service/SirenCacheService.java new file mode 100644 index 00000000..8662506c --- /dev/null +++ b/src/main/java/com/example/waggle/domain/board/siren/service/SirenCacheService.java @@ -0,0 +1,56 @@ +package com.example.waggle.domain.board.siren.service; + +import com.example.waggle.domain.board.siren.repository.SirenRepository; +import com.example.waggle.domain.member.service.RedisService; +import java.util.Objects; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CachePut; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Transactional +@RequiredArgsConstructor +@Service +public class SirenCacheService { + + private final RedisService redisService; + private final SirenRepository sirenRepository; + private final String VIEW_COUNT_PREFIX = "viewCounts::"; + private final String BOARD_PREFIX = "board::"; + + @CachePut(value = "viewCounts", key = "#boardId") + public Long applyViewCountToRedis(Long boardId) { + String viewCountKey = VIEW_COUNT_PREFIX + boardId; + String currentViewCount = redisService.getValue(viewCountKey); + if (currentViewCount != null) { + return redisService.increment(viewCountKey); + } else { + Long initialViewCount = sirenRepository.findViewCountByBoardId(boardId); + return initialViewCount + 1; + } + } + + @Scheduled(fixedRate = 1000 * 60 * 3) + public void applyViewCountToRDB() { + Set viewCountKeys = redisService.getKeysByPattern(VIEW_COUNT_PREFIX + "*"); + if (Objects.requireNonNull(viewCountKeys).isEmpty()) { + return; + } + + for (String viewCntKey : viewCountKeys) { + Long boardId = extractBoardIdFromKey(viewCntKey); + Long viewCount = Long.parseLong(redisService.getValue(viewCntKey)); + sirenRepository.applyViewCntToRDB(boardId, viewCount); + redisService.deleteData(viewCntKey); + redisService.deleteData(BOARD_PREFIX + boardId); + } + } + + private static Long extractBoardIdFromKey(String key) { + return Long.parseLong(key.split("::")[1]); + } +} diff --git a/src/main/java/com/example/waggle/domain/board/siren/service/SirenCommandService.java b/src/main/java/com/example/waggle/domain/board/siren/service/SirenCommandService.java index 7d73ed2a..0c87921e 100644 --- a/src/main/java/com/example/waggle/domain/board/siren/service/SirenCommandService.java +++ b/src/main/java/com/example/waggle/domain/board/siren/service/SirenCommandService.java @@ -17,6 +17,4 @@ Long updateSiren(Long boardId, void deleteSiren(Long boardId, Member member); - void increaseSirenViewCount(Long boardId); - } \ No newline at end of file diff --git a/src/main/java/com/example/waggle/domain/board/siren/service/SirenCommandServiceImpl.java b/src/main/java/com/example/waggle/domain/board/siren/service/SirenCommandServiceImpl.java index ccb3262a..f7c69f7f 100644 --- a/src/main/java/com/example/waggle/domain/board/siren/service/SirenCommandServiceImpl.java +++ b/src/main/java/com/example/waggle/domain/board/siren/service/SirenCommandServiceImpl.java @@ -1,5 +1,7 @@ package com.example.waggle.domain.board.siren.service; +import static com.example.waggle.domain.board.service.BoardType.SIREN; + import com.example.waggle.domain.board.ResolutionStatus; import com.example.waggle.domain.board.service.BoardService; import com.example.waggle.domain.board.siren.entity.Siren; @@ -9,6 +11,7 @@ import com.example.waggle.domain.media.service.MediaCommandService; import com.example.waggle.domain.member.entity.Gender; import com.example.waggle.domain.member.entity.Member; +import com.example.waggle.domain.member.service.RedisService; import com.example.waggle.domain.recommend.repository.RecommendRepository; import com.example.waggle.global.exception.handler.QuestionHandler; import com.example.waggle.global.exception.handler.SirenHandler; @@ -19,8 +22,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import static com.example.waggle.domain.board.service.BoardType.SIREN; - @Slf4j @RequiredArgsConstructor @Transactional @@ -32,6 +33,7 @@ public class SirenCommandServiceImpl implements SirenCommandService { private final BoardService boardService; private final CommentCommandService commentCommandService; private final MediaCommandService mediaCommandService; + private final RedisService redisService; @Override public Long createSiren(SirenRequest createSirenRequest, Member member) { @@ -86,13 +88,6 @@ public void deleteSiren(Long boardId, Member member) { sirenRepository.delete(siren); } - @Override - public void increaseSirenViewCount(Long boardId) { - Siren siren = sirenRepository.findById(boardId) - .orElseThrow(() -> new SirenHandler(ErrorStatus.BOARD_NOT_FOUND)); - siren.increaseViewCount(); - } - private Siren buildSiren(SirenRequest createSirenRequest, Member member) { return Siren.builder() .title(createSirenRequest.getTitle()) diff --git a/src/main/java/com/example/waggle/domain/board/siren/service/SirenQueryService.java b/src/main/java/com/example/waggle/domain/board/siren/service/SirenQueryService.java index ff7d8ec2..4b36c757 100644 --- a/src/main/java/com/example/waggle/domain/board/siren/service/SirenQueryService.java +++ b/src/main/java/com/example/waggle/domain/board/siren/service/SirenQueryService.java @@ -26,4 +26,5 @@ public interface SirenQueryService { Page getPagedSirenListByCategory(SirenCategory category, Pageable pageable); Siren getSirenByBoardId(Long boardId); + } \ No newline at end of file diff --git a/src/main/java/com/example/waggle/domain/board/siren/service/SirenQueryServiceImpl.java b/src/main/java/com/example/waggle/domain/board/siren/service/SirenQueryServiceImpl.java index 90ecb2ac..819d3a29 100644 --- a/src/main/java/com/example/waggle/domain/board/siren/service/SirenQueryServiceImpl.java +++ b/src/main/java/com/example/waggle/domain/board/siren/service/SirenQueryServiceImpl.java @@ -4,6 +4,7 @@ import com.example.waggle.domain.board.siren.entity.Siren; import com.example.waggle.domain.board.siren.entity.SirenCategory; import com.example.waggle.domain.board.siren.repository.SirenRepository; +import com.example.waggle.domain.member.service.RedisService; import com.example.waggle.domain.recommend.repository.RecommendRepository; import com.example.waggle.global.exception.handler.SirenHandler; import com.example.waggle.global.payload.code.ErrorStatus; @@ -28,6 +29,7 @@ public class SirenQueryServiceImpl implements SirenQueryService { private final SirenRepository sirenRepository; private final RecommendRepository recommendRepository; + private final RedisService redisService; @Override public List getAllSiren() { @@ -83,4 +85,5 @@ public Siren getSirenByBoardId(Long boardId) { return sirenRepository.findById(boardId) .orElseThrow(() -> new SirenHandler(ErrorStatus.BOARD_NOT_FOUND)); } + } \ No newline at end of file diff --git a/src/main/java/com/example/waggle/domain/member/service/RedisService.java b/src/main/java/com/example/waggle/domain/member/service/RedisService.java index 69d80cee..a3df60a9 100644 --- a/src/main/java/com/example/waggle/domain/member/service/RedisService.java +++ b/src/main/java/com/example/waggle/domain/member/service/RedisService.java @@ -95,7 +95,6 @@ public void decrementRecommendCnt(Long boardId) { public Long getRecommendCnt(Long boardId) { HashOperations hashOperations = redisTemplate.opsForHash(); RecommendationHashKey recommendationHashKey = buildHashKey(boardId); - log.info("class = {}", hashOperations.get(recommendationHashKey.getKey(), recommendationHashKey.getHashKey()).getClass()); return hashOperations.get(recommendationHashKey.getKey(), recommendationHashKey.getHashKey()); } @@ -125,7 +124,7 @@ public void setRecommend(Long memberId, Long boardId) { // setOperations.add(boardSetKey.getKey(), boardSetKey.getValue()); } - private Set getKeysByPattern(String pattern) { + public Set getKeysByPattern(String pattern) { RedisConnection connection = redisTemplate.getConnectionFactory().getConnection(); ScanOptions scanOptions = ScanOptions.scanOptions().match(pattern).build(); Cursor cursor = connection.scan(scanOptions); @@ -215,4 +214,13 @@ private RecommendationSetKey buildMemberSetKey(Long memberId, Long boardId) { // .build(); // } + public Long increment(String key) { + ValueOperations valueOperations = redisTemplate.opsForValue(); + return valueOperations.increment(key); + } + + public void deleteData(String key) { + redisTemplate.delete(key); + } + } \ No newline at end of file diff --git a/src/main/java/com/example/waggle/global/config/CacheConfig.java b/src/main/java/com/example/waggle/global/config/CacheConfig.java new file mode 100644 index 00000000..ec56262b --- /dev/null +++ b/src/main/java/com/example/waggle/global/config/CacheConfig.java @@ -0,0 +1,48 @@ +package com.example.waggle.global.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator; +import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.time.Duration; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +@EnableCaching +@Configuration +public class CacheConfig { + + @Bean + public CacheManager cacheManager(RedisConnectionFactory connectionFactory) { + PolymorphicTypeValidator typeValidator = + BasicPolymorphicTypeValidator.builder().allowIfSubType(Object.class).build(); + + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.activateDefaultTyping(typeValidator, ObjectMapper.DefaultTyping.NON_FINAL); + + RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() + .entryTtl(Duration.ofMinutes(3)) + .disableCachingNullValues() + .serializeKeysWith( + SerializationPair.fromSerializer(new StringRedisSerializer()) + ) + .serializeValuesWith( + SerializationPair.fromSerializer( + new GenericJackson2JsonRedisSerializer()) + ); + + return RedisCacheManager.builder(connectionFactory) + .cacheDefaults(cacheConfiguration) + .build(); + } + +} diff --git a/src/main/java/com/example/waggle/web/controller/QuestionApiController.java b/src/main/java/com/example/waggle/web/controller/QuestionApiController.java index 0bb68d16..d9f3f5b9 100644 --- a/src/main/java/com/example/waggle/web/controller/QuestionApiController.java +++ b/src/main/java/com/example/waggle/web/controller/QuestionApiController.java @@ -1,6 +1,9 @@ package com.example.waggle.web.controller; +import static com.example.waggle.web.dto.question.QuestionResponse.QuestionDetailDto; + import com.example.waggle.domain.board.question.entity.Question; +import com.example.waggle.domain.board.question.service.QuestionCacheService; import com.example.waggle.domain.board.question.service.QuestionCommandService; import com.example.waggle.domain.board.question.service.QuestionQueryService; import com.example.waggle.domain.member.entity.Member; @@ -20,6 +23,8 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; @@ -28,12 +33,15 @@ import org.springframework.data.domain.Sort; import org.springframework.http.MediaType; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.List; -import java.util.stream.Collectors; - -import static com.example.waggle.web.dto.question.QuestionResponse.QuestionDetailDto; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; @Slf4j @RequiredArgsConstructor @@ -43,6 +51,7 @@ @Tag(name = "Question API", description = "질문 API") public class QuestionApiController { + private final QuestionCacheService questionCacheService; private final QuestionCommandService questionCommandService; private final QuestionQueryService questionQueryService; private final RecommendQueryService recommendQueryService; @@ -152,9 +161,9 @@ public ApiResponseDto getQuestionsByUsername(@PathVariab @GetMapping("/{questionId}") public ApiResponseDto getQuestionByBoardId( @PathVariable("questionId") Long questionId) { - questionCommandService.increaseQuestionViewCount(questionId); Question questionByBoardId = questionQueryService.getQuestionByBoardId(questionId); QuestionDetailDto detailDto = QuestionConverter.toDetailDto(questionByBoardId); + detailDto.setViewCount(questionCacheService.applyViewCountToRedis(questionId)); detailDto.setRecommendCount(recommendQueryService.countRecommend(questionId)); return ApiResponseDto.onSuccess(detailDto); } diff --git a/src/main/java/com/example/waggle/web/controller/SirenApiController.java b/src/main/java/com/example/waggle/web/controller/SirenApiController.java index dcaecd2f..cd02ea83 100644 --- a/src/main/java/com/example/waggle/web/controller/SirenApiController.java +++ b/src/main/java/com/example/waggle/web/controller/SirenApiController.java @@ -1,6 +1,7 @@ package com.example.waggle.web.controller; import com.example.waggle.domain.board.siren.entity.Siren; +import com.example.waggle.domain.board.siren.service.SirenCacheService; import com.example.waggle.domain.board.siren.entity.SirenCategory; import com.example.waggle.domain.board.siren.service.SirenCommandService; import com.example.waggle.domain.board.siren.service.SirenQueryService; @@ -44,6 +45,7 @@ @Tag(name = "Siren API", description = "사이렌 API") public class SirenApiController { + private final SirenCacheService sirenCacheService; private final SirenCommandService sirenCommandService; private final SirenQueryService sirenQueryService; private final RecommendQueryService recommendQueryService; @@ -166,11 +168,10 @@ public ApiResponseDto getSirenListByUsername(@PathVariable("userUr }) @GetMapping("/{sirenId}") public ApiResponseDto getSirenByBoardId(@PathVariable("sirenId") Long sirenId) { - sirenCommandService.increaseSirenViewCount(sirenId); Siren siren = sirenQueryService.getSirenByBoardId(sirenId); SirenDetailDto detailDto = SirenConverter.toSirenDetailDto(siren); + detailDto.setViewCount(sirenCacheService.applyViewCountToRedis(sirenId)); detailDto.setRecommendCount(recommendQueryService.countRecommend(sirenId)); - return ApiResponseDto.onSuccess(detailDto); } diff --git a/src/main/java/com/example/waggle/web/dto/question/QuestionResponse.java b/src/main/java/com/example/waggle/web/dto/question/QuestionResponse.java index 7b925086..d60a99e6 100644 --- a/src/main/java/com/example/waggle/web/dto/question/QuestionResponse.java +++ b/src/main/java/com/example/waggle/web/dto/question/QuestionResponse.java @@ -53,7 +53,7 @@ public static class QuestionDetailDto { private List hashtagList; private MemberSummaryDto member; private int recommendCount; - private int viewCount; + private long viewCount; } @Data diff --git a/src/main/java/com/example/waggle/web/dto/siren/SirenResponse.java b/src/main/java/com/example/waggle/web/dto/siren/SirenResponse.java index 067eed63..2ec1f7bf 100644 --- a/src/main/java/com/example/waggle/web/dto/siren/SirenResponse.java +++ b/src/main/java/com/example/waggle/web/dto/siren/SirenResponse.java @@ -53,7 +53,7 @@ public static class SirenDetailDto { private MemberSummaryDto member; private ResolutionStatus status; private int recommendCount; - private int viewCount; + private long viewCount; } @Data