Skip to content

Commit

Permalink
#508 [feat] 글 인기 글 / 작가 도메인 캐시 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
sohyundoh committed Sep 7, 2024
1 parent 04e1cd9 commit 8ea14a0
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 40 deletions.
2 changes: 2 additions & 0 deletions module-domain/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ dependencies {

//Swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
implementation 'org.springframework.boot:spring-boot-starter-cache'
implementation 'com.github.ben-manes.caffeine:caffeine:3.1.2'

// QueryDSL Implementation
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.mile.common.config;

import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Scheduler;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(caffeineConfig());
return cacheManager;
}

private Scheduler getScheduler() {
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
Scheduler scheduler;
scheduler = Scheduler.forScheduledExecutorService(executor);
return scheduler;
}

private Caffeine<Object, Object> caffeineConfig() {
return Caffeine.newBuilder()
.maximumSize(200)
.expireAfterAccess(5, TimeUnit.DAYS)
.scheduler(getScheduler());
}
}
47 changes: 7 additions & 40 deletions module-domain/src/main/java/com/mile/moim/service/MoimService.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package com.mile.moim.service;

import com.mile.curious.repository.dto.PostAndCuriousCountInLastWeek;
import com.mile.common.utils.DateUtil;
import com.mile.common.utils.SecureUrlUtil;
import com.mile.curious.service.CuriousRetriever;
import com.mile.exception.message.ErrorMessage;
import com.mile.exception.model.BadRequestException;
import com.mile.exception.model.ForbiddenException;
import com.mile.moim.domain.Moim;
import com.mile.moim.domain.popular.MoimCuriousPost;
import com.mile.moim.domain.popular.MoimCuriousWriter;
import com.mile.moim.domain.popular.MoimPopularInfo;
import com.mile.moim.repository.MoimPopularInfoRepository;
import com.mile.moim.service.dto.request.MoimCreateRequest;
import com.mile.moim.service.dto.request.MoimInfoModifyRequest;
import com.mile.moim.service.dto.request.TopicCreateRequest;
Expand All @@ -35,15 +34,14 @@
import com.mile.moim.service.dto.response.TopicListResponse;
import com.mile.moim.service.dto.response.WriterNameConflictCheckResponse;
import com.mile.moim.service.lock.AtomicValidateUniqueMoimName;
import com.mile.moim.service.popular.MoimPopularInfoService;
import com.mile.post.domain.Post;
import com.mile.post.service.PostRetriever;
import com.mile.topic.service.TopicCreator;
import com.mile.topic.service.TopicRemover;
import com.mile.topic.service.TopicRetriever;
import com.mile.user.domain.User;
import com.mile.user.service.UserRetriever;
import com.mile.common.utils.DateUtil;
import com.mile.common.utils.SecureUrlUtil;
import com.mile.writername.domain.WriterName;
import com.mile.writername.service.WriterNameRemover;
import com.mile.writername.service.WriterNameRetriever;
Expand Down Expand Up @@ -73,7 +71,7 @@ public class MoimService {
private final TopicRemover topicRemover;
private final TopicRetriever topicRetriever;
private final TopicCreator topicCreator;
private final MoimPopularInfoRepository moimPopularInfoRepository;
private final MoimPopularInfoService moimPopularInfoService;

private static final int WRITER_NAME_MAX_VALUE = 8;
private static final int MOIM_NAME_MAX_VALUE = 10;
Expand Down Expand Up @@ -144,35 +142,6 @@ public MoimMostCuriousWriterResponse getMostCuriousWritersOfMoim(
}


private MoimPopularInfo setMostPopularInfoOfMoim(final Moim moim) {
List<PostAndCuriousCountInLastWeek> mostCuriousPostsInLastWeek = curiousRetriever.findMostCuriousPostsInLastWeek(moim);

List<MoimCuriousPost> moimCuriousPosts = getMoimCuriousPost(mostCuriousPostsInLastWeek);

List<MoimCuriousWriter> moimCuriousWriters = getMoimCuriousWriter(mostCuriousPostsInLastWeek);

MoimPopularInfo moimPopularInfo = MoimPopularInfo.of(moim.getId(), moimCuriousPosts, moimCuriousWriters);

return moimPopularInfoRepository.save(moimPopularInfo);
}

private List<MoimCuriousPost> getMoimCuriousPost(final List<PostAndCuriousCountInLastWeek> mostCuriousPostsInLastWeek) {
return mostCuriousPostsInLastWeek.stream().map(p ->
MoimCuriousPost.of(p.getPost())).limit(2).toList();
}

private List<MoimCuriousWriter> getMoimCuriousWriter(final List<PostAndCuriousCountInLastWeek> mostCuriousPostsInLastWeek) {
Map<WriterName, Long> writerNameCount = mostCuriousPostsInLastWeek.stream()
.collect(Collectors.groupingBy(p -> p.getPost().getWriterName(), Collectors.summingLong(PostAndCuriousCountInLastWeek::getCount)));

List<WriterName> topTwoWriters = writerNameCount.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.limit(2)
.map(Map.Entry::getKey).toList();

return topTwoWriters.stream().map(MoimCuriousWriter::of).toList();
}

public MoimTopicResponse getTopicFromMoim(
final Long moimId
) {
Expand All @@ -193,13 +162,11 @@ public MoimInfoResponse getMoimInfo(
);
}


public MoimOverallInfoResponse getMoimTotalInformation(final Long moimId) {
Moim moim = moimRetriever.findById(moimId);
MoimInfoResponse moimInfoResponse = moimRetriever.getMoimInfoForTotal(moim,
writerNameRetriever.findNumbersOfWritersByMoim(moim));
MoimPopularInfo moimPopularInfo = moimPopularInfoRepository.findByMoimId(moimId).orElseGet(
() -> setMostPopularInfoOfMoim(moim)
);
MoimInfoResponse moimInfoResponse = moimRetriever.getMoimInfoForTotal(moim, writerNameRetriever.findNumbersOfWritersByMoim(moim));
MoimPopularInfo moimPopularInfo = moimPopularInfoService.getMoimPopularInfo(moim);
MoimMostCuriousWriterResponse mostCuriousWriterResponse = MoimMostCuriousWriterResponse.of(moimPopularInfo.getWriters());
MoimCuriousPostListResponse moimCuriousPostListResponse = MoimCuriousPostListResponse.of(
moimPopularInfo.getPosts().stream().map(MoimMostCuriousPostResponse::of).toList()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.mile.moim.service.popular;

import com.mile.curious.repository.dto.PostAndCuriousCountInLastWeek;
import com.mile.curious.service.CuriousRetriever;
import com.mile.moim.domain.Moim;
import com.mile.moim.domain.popular.MoimCuriousPost;
import com.mile.moim.domain.popular.MoimCuriousWriter;
import com.mile.moim.domain.popular.MoimPopularInfo;
import com.mile.moim.repository.MoimPopularInfoRepository;
import com.mile.writername.domain.WriterName;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
public class MoimPopularInfoService {
private final MoimPopularInfoRepository moimPopularInfoRepository;
private final CuriousRetriever curiousRetriever;

@CachePut(value = "moimPopularInfo", key = "#moim.id")
public MoimPopularInfo setMostPopularInfoOfMoim(final Moim moim) {
List<PostAndCuriousCountInLastWeek> mostCuriousPostsInLastWeek = curiousRetriever.findMostCuriousPostsInLastWeek(moim);

List<MoimCuriousPost> moimCuriousPosts = getMoimCuriousPost(mostCuriousPostsInLastWeek);

List<MoimCuriousWriter> moimCuriousWriters = getMoimCuriousWriter(mostCuriousPostsInLastWeek);

MoimPopularInfo moimPopularInfo = MoimPopularInfo.of(moim.getId(), moimCuriousPosts, moimCuriousWriters);

return moimPopularInfoRepository.save(moimPopularInfo);
}

private List<MoimCuriousPost> getMoimCuriousPost(final List<PostAndCuriousCountInLastWeek> mostCuriousPostsInLastWeek) {
return mostCuriousPostsInLastWeek.stream().map(p ->
MoimCuriousPost.of(p.getPost())).limit(2).toList();
}

private List<MoimCuriousWriter> getMoimCuriousWriter(final List<PostAndCuriousCountInLastWeek> mostCuriousPostsInLastWeek) {
Map<WriterName, Long> writerNameCount = mostCuriousPostsInLastWeek.stream()
.collect(Collectors.groupingBy(p -> p.getPost().getWriterName(), Collectors.summingLong(PostAndCuriousCountInLastWeek::getCount)));

List<WriterName> topTwoWriters = writerNameCount.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.limit(2)
.map(Map.Entry::getKey).toList();

return topTwoWriters.stream().map(MoimCuriousWriter::of).toList();
}

@Cacheable(value = "moimPopularInfo", key = "#moim.id")
public MoimPopularInfo getMoimPopularInfo(final Moim moim) {
return moimPopularInfoRepository.findByMoimId(moim.getId()).orElseGet(
() -> setMostPopularInfoOfMoim(moim)
);
}

}

0 comments on commit 8ea14a0

Please sign in to comment.