From fef89cf9c1a540b2aba9b6a4105a409ba6ecf65b Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Thu, 29 Aug 2024 01:23:28 +0900 Subject: [PATCH 01/20] =?UTF-8?q?[config]:=20=EC=BA=90=EC=8B=9C=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=EC=9D=84=20=EC=9C=84=ED=95=B4=20CacheControl?= =?UTF-8?q?=20=ED=97=A4=EB=8D=94=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ETag 사용을 위해 `Cache-Control`헤더에 `no-cache`, `must-revalidate` 적용 --- .../recruit/api/config/WebMvcConfig.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/config/WebMvcConfig.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/config/WebMvcConfig.java index 04192b4e..e3e8d7b0 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/config/WebMvcConfig.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/config/WebMvcConfig.java @@ -2,7 +2,10 @@ import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; +import org.springframework.http.CacheControl; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.mvc.WebContentInterceptor; @Configuration @RequiredArgsConstructor @@ -23,4 +26,14 @@ public class WebMvcConfig implements WebMvcConfigurer { // // registrationBean.setUrlPatterns(Arrays.asList("/api/v1/*")); // return registrationBean;3 // } + + @Override + public void addInterceptors(final InterceptorRegistry registry) { + CacheControl cacheControl = CacheControl.noCache().mustRevalidate(); + + WebContentInterceptor webContentInterceptor = new WebContentInterceptor(); + webContentInterceptor.addCacheMapping(cacheControl, "/**"); + + registry.addInterceptor(webContentInterceptor); + } } From 4ca0c78273d9846d74462bd69aa5d067217d86fb Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Thu, 29 Aug 2024 01:25:26 +0900 Subject: [PATCH 02/20] =?UTF-8?q?[config]:=20ETag=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=ED=97=A4=EB=8D=94=EB=A5=BC=20=ED=8F=AC=ED=95=A8=EC=8B=9C?= =?UTF-8?q?=EC=BC=9C=EC=A3=BC=EB=8A=94=20=ED=95=84=ED=84=B0=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 응답을 받아 고유한 ETag를 생성하고 요청의 If-None-Match와 비교하여 값이 같다면 304 응답 반환 - 해당 필터를 로컬에서 사용하려면 `@Profile`에 `local` 추가하기 --- .../api/config/ServletFilterConfig.java | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/config/ServletFilterConfig.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/config/ServletFilterConfig.java index 47a24be8..9d8fd288 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/config/ServletFilterConfig.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/config/ServletFilterConfig.java @@ -9,6 +9,7 @@ import org.springframework.context.annotation.Profile; import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; import org.springframework.web.filter.ForwardedHeaderFilter; +import org.springframework.web.filter.ShallowEtagHeaderFilter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter; @@ -23,18 +24,18 @@ public class ServletFilterConfig implements WebMvcConfigurer { @Bean public FilterRegistrationBean securityFilterChain( @Qualifier(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) - Filter securityFilter) { - FilterRegistrationBean registration = new FilterRegistrationBean(securityFilter); - registration.setOrder(Integer.MAX_VALUE - 3); - registration.setName(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME); - return registration; + Filter securityFilter) { + FilterRegistrationBean registrationBean = new FilterRegistrationBean(securityFilter); + registrationBean.setOrder(Integer.MAX_VALUE - 5); + registrationBean.setName(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME); + return registrationBean; } @Bean public FilterRegistrationBean setResourceUrlEncodingFilter() { FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(new ResourceUrlEncodingFilter()); - registrationBean.setOrder(Integer.MAX_VALUE - 2); + registrationBean.setOrder(Integer.MAX_VALUE - 4); return registrationBean; } @@ -42,7 +43,7 @@ public FilterRegistrationBean setResourceUrlEncodingFilter() { public FilterRegistrationBean setForwardedHeaderFilterOrder() { FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(forwardedHeaderFilter); - registrationBean.setOrder(Integer.MAX_VALUE - 1); + registrationBean.setOrder(Integer.MAX_VALUE - 3); return registrationBean; } @@ -50,7 +51,16 @@ public FilterRegistrationBean setForwardedHeaderFilterOrder() { public FilterRegistrationBean setHttpContentCacheFilterOrder() { FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(httpContentCacheFilter); - registrationBean.setOrder(Integer.MAX_VALUE); + registrationBean.setOrder(Integer.MAX_VALUE - 2); + return registrationBean; + } + + @Bean + public FilterRegistrationBean shallowEtagHeaderFilter() { + FilterRegistrationBean registrationBean + = new FilterRegistrationBean<>(new ShallowEtagHeaderFilter()); + registrationBean.setOrder(Integer.MAX_VALUE - 1); + registrationBean.addUrlPatterns("/*"); return registrationBean; } } From 5a22e0300589108a495a1378d7a7050d046a2eab Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Thu, 29 Aug 2024 01:30:17 +0900 Subject: [PATCH 03/20] =?UTF-8?q?[config]:=20=EC=BA=90=EC=8B=B1=EC=9D=84?= =?UTF-8?q?=20=EC=9C=84=ED=95=9C=20CacheManager=20=EB=B9=88=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 사용할 캐시 저장소를 등록 --- .../recruit/api/config/CachingConfig.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 server/Recruit-Api/src/main/java/com/econovation/recruit/api/config/CachingConfig.java diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/config/CachingConfig.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/config/CachingConfig.java new file mode 100644 index 00000000..c7d8eb65 --- /dev/null +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/config/CachingConfig.java @@ -0,0 +1,26 @@ +package com.econovation.recruit.api.config; + +import java.util.List; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@EnableCaching +@Configuration +public class CachingConfig { + + @Bean + public CacheManager cacheManager() { + ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager(); + cacheManager.setCacheNames(List.of( + "boardsByColumnsIds", // BoardService::getBoardByColumnsIds + "columnsByNavigationId", // ColumnService::getByNavigationId + "boardCardsByNavigationId", // CardService::getByNavigationId + "recordsByPage" // RecordService::execute + )); + return cacheManager; + } + +} From 7b4fe05f9d7748b04cf3739aa5e982209fe37485 Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Thu, 29 Aug 2024 02:29:00 +0900 Subject: [PATCH 04/20] =?UTF-8?q?[feat]:=20Board=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=EC=BA=90=EC=8B=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `BoardService::getBoardByColumnsIds` 응답 캐싱 --- .../recruit/api/card/service/BoardService.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java index c815613f..4fc9dea9 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java @@ -25,6 +25,9 @@ import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -104,11 +107,16 @@ public Board findById(Integer id) { } @Override + @Caching(evict = { + @CacheEvict(value = "boardsByColumnsIds", allEntries = true), + @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) + }) public void execute(Board board) { boardRecordPort.save(board); } @Override + @CacheEvict(value = "boardsByColumnsIds", allEntries = true) public Board createWorkBoard(Integer columnId, Long cardId) { Columns column = columnLoadPort.findById(columnId); List boardByNavigationIdAndColumnId = @@ -160,6 +168,10 @@ public Columns createColumn(String title, Integer navigationId) { }*/ @Override + @Caching(evict = { + @CacheEvict(value = "boardsByColumnsIds", allEntries = true), + @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) + }) public void createApplicantBoard(String applicantId, String hopeField, Long cardId) { // \"hopeField\" -> hopeField 로 변경 hopeField = hopeField; @@ -243,6 +255,7 @@ public Navigation getNavigationByNavLoc(Integer navLoc) { } @Override + @Cacheable(value = "boardsByColumnsIds") public List getBoardByColumnsIds(List columnsIds) { return boardLoadPort.getBoardByColumnsIds(columnsIds); } @@ -275,6 +288,10 @@ public Result getBoardByNextBoardId(Integer boardId) { paramClassType = UpdateLocationBoardDto.class, leaseTime = 500, waitTime = 500) + @Caching(evict = { + @CacheEvict(value = "boardsByColumnsIds", allEntries = true), + @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) + }) public void relocateCard(UpdateLocationBoardDto updateLocationBoardDto) { List invisibleBoard = List.of(1, 2, 3); // 기준 보드는 이동이 불가하다. @@ -336,6 +353,7 @@ public void updateColumnLocation(UpdateLocationColumnDto updateLocationDto) { } @Override + @CacheEvict(value = "boardsByColumnsIds", allEntries = true) public void delete(Board board) { boardRecordPort.delete(board); } From 86a9d93173e94a53fc4f65dfda73e5cbbbac88ca Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Thu, 29 Aug 2024 02:30:02 +0900 Subject: [PATCH 05/20] =?UTF-8?q?[feat]:=20Column=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=EC=BA=90=EC=8B=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `ColumnService::getByNavigationId` 응답 캐싱 --- .../recruit/api/card/service/BoardService.java | 8 ++++++++ .../recruit/api/card/service/ColumnService.java | 2 ++ 2 files changed, 10 insertions(+) diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java index 4fc9dea9..7cb7b5fc 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java @@ -209,6 +209,10 @@ public void createApplicantBoard(String applicantId, String hopeField, Long card @Override @Transactional + @Caching(evict = { + @CacheEvict(value = "columnsByNavigationId", allEntries = true), + @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) + }) public Columns createColumn(String title, Integer navigationId) { Columns column = Columns.builder().title(title).navigationId(navigationId).build(); @@ -312,6 +316,10 @@ public void relocateCard(UpdateLocationBoardDto updateLocationBoardDto) { @Override @Transactional + @Caching(evict = { + @CacheEvict(value = "columnsByNavigationId", allEntries = true), + @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) + }) public void updateColumnLocation(UpdateLocationColumnDto updateLocationDto) { // 첫번째로 옮기는 경우 (nextColumnId == 0) if (updateLocationDto.getTargetColumnId().equals(0)) { diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/ColumnService.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/ColumnService.java index b38f14c9..ac2ff8be 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/ColumnService.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/ColumnService.java @@ -6,6 +6,7 @@ import com.econovation.recruitdomain.out.ColumnRecordPort; import java.util.List; import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; @Service @@ -14,6 +15,7 @@ public class ColumnService implements ColumnsUseCase { private final ColumnRecordPort columnRecordPort; private final ColumnLoadPort columnLoadPort; + @Cacheable(value = "columnsByNavigationId") public List getByNavigationId(Integer navigationId) { return columnLoadPort.getColumnByNavigationId(navigationId); } From 7ae01219073f6af74808b8d0ac66278c6d8bd927 Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Thu, 29 Aug 2024 02:30:51 +0900 Subject: [PATCH 06/20] =?UTF-8?q?[feat]:=20Card=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=EC=BA=90=EC=8B=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `CardService::getByNavigationId` 응답 캐싱 --- .../econovation/recruit/api/card/service/CardService.java | 5 +++++ .../recruit/api/comment/service/CommentService.java | 3 +++ .../econovation/recruit/api/label/service/LabelService.java | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/CardService.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/CardService.java index b8419cbb..91d21496 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/CardService.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/CardService.java @@ -32,6 +32,8 @@ import java.util.Optional; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -56,6 +58,7 @@ public List findAll() { @Override @Transactional(readOnly = true) + @Cacheable(value = "boardCardsByNavigationId", key = "#navigationId") public List getByNavigationId(Integer navigationId, Integer year) { Long userId = SecurityUtils.getCurrentUserId(); List columns = columnsUseCase.getByNavigationId(navigationId); @@ -153,6 +156,7 @@ public CardResponseDto findCardById(Long cardId) { @Override @Transactional + @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) public void deleteById(Long cardId) { Board board = boardLoadUseCase.getBoardByCardId(cardId); Result prevBoard = boardLoadUseCase.getBoardByNextBoardId(board.getId()); @@ -186,6 +190,7 @@ public void saveWorkCard(CreateWorkCardDto createWorkCardDto) { @Override @Transactional + @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) public void update(Long cardId, UpdateWorkCardDto updateWorkCardDto) { Card card = cardLoadPort.findById(cardId); // 단 title 이 null일 수도 있고, content가 null일 수도 있다. diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/comment/service/CommentService.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/comment/service/CommentService.java index 5e837349..23bd6dbb 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/comment/service/CommentService.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/comment/service/CommentService.java @@ -24,6 +24,7 @@ import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; +import org.springframework.cache.annotation.CacheEvict; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -39,6 +40,7 @@ public class CommentService implements CommentUseCase { @Override @Transactional + @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) public Comment saveComment(CommentRegisterDto commentDto) { Long userId = SecurityUtils.getCurrentUserId(); // applicantId null 이면 "" 으로 바꿔준다. cardId 가 null 이면 0 으로 바꿔준다. @@ -81,6 +83,7 @@ private Comment convertComment(CommentRegisterDto commentDto, Long userId) { @Override @Transactional + @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) public void deleteComment(Long commentId) { Long idpId = SecurityUtils.getCurrentUserId(); Comment comment = commentLoadPort.findById(commentId); diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/label/service/LabelService.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/label/service/LabelService.java index fe66249e..b6db61dc 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/label/service/LabelService.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/label/service/LabelService.java @@ -18,6 +18,7 @@ import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; +import org.springframework.cache.annotation.CacheEvict; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -36,6 +37,7 @@ public class LabelService implements LabelUseCase { waitTime = 1000L, leaseTime = 1000L) @Transactional + @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) public Boolean createLabel(String applicantId) { Long idpId = SecurityUtils.getCurrentUserId(); Card card = cardLoadPort.findByApplicantId(applicantId); @@ -67,6 +69,7 @@ public List findByApplicantId(String applicantId) { identifier = "applicantId", waitTime = 1000L, leaseTime = 1000L) + @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) public void deleteLabel(String applicantId) { Long idpId = SecurityUtils.getCurrentUserId(); Label label = labelLoadPort.loadLabelByApplicantIdAndIdpId(applicantId, idpId); @@ -87,6 +90,7 @@ public void deleteLabelByCardId(Long cardId) { @Override @Transactional + @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) public Boolean createLabelByCardId(Long cardId) { Long idpId = SecurityUtils.getCurrentUserId(); Card card = cardLoadPort.findById(cardId); From 60a8887ad6415a8742b64b0a1aac9c7c09064cfd Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Thu, 29 Aug 2024 02:32:03 +0900 Subject: [PATCH 07/20] =?UTF-8?q?[feat]:=20Record=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=EC=BA=90=EC=8B=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `RecordService::execute` 응답 캐싱 --- .../recruit/api/record/service/RecordService.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/record/service/RecordService.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/record/service/RecordService.java index 0ddab0ea..a8fccb9d 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/record/service/RecordService.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/record/service/RecordService.java @@ -20,6 +20,8 @@ import java.util.*; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -34,6 +36,7 @@ public class RecordService implements RecordUseCase { @Override @Transactional + @CacheEvict(value = "recordsByPage", allEntries = true) public Record createRecord(CreateRecordDto recordDto) { if (applicantQueryUseCase.execute(recordDto.getApplicantId()) == null) { throw ApplicantNotFoundException.EXCEPTION; @@ -57,6 +60,7 @@ public List findAll() { * Records를 모두 조회합니다 ) */ @Override + @Cacheable(value = "recordsByPage") public RecordsViewResponseDto execute(Integer page, Integer year, String sortType) { List result = recordLoadPort.findAll(page); PageInfo pageInfo = getPageInfo(page); @@ -145,6 +149,7 @@ public Record findByApplicantId(String applicantId) { @Override @Transactional + @CacheEvict(value = "recordsByPage", allEntries = true) public void updateRecordUrl(String applicantId, String url) { recordLoadPort .findByApplicantId(applicantId) @@ -156,6 +161,7 @@ record -> { @Override @Transactional + @CacheEvict(value = "recordsByPage", allEntries = true) public void updateRecordContents(String applicantId, String contents) { recordLoadPort .findByApplicantId(applicantId) @@ -167,6 +173,7 @@ record -> { @Override @Transactional + @CacheEvict(value = "recordsByPage", allEntries = true) public void updateRecord(String applicantId, UpdateRecordDto updateRecordDto) { recordLoadPort .findByApplicantId(applicantId) From 1e94f81ceb0d1584b770100272228d5b8832bb26 Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Thu, 29 Aug 2024 19:44:42 +0900 Subject: [PATCH 08/20] =?UTF-8?q?[fix]:=20LocalDateTime=20=EC=A7=81?= =?UTF-8?q?=EB=A0=AC=ED=99=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit InvalidDefinitionException: Java 8 date/time type `java.time.LocalDateTime` not supported by default 위와 같은 오류가 발생했고, `LocalDateTimeSerializer`, `LocalDateTimeDeserializer`를 적용해 오류 해결 --- .../recruitdomain/domains/BaseTimeEntity.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/domains/BaseTimeEntity.java b/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/domains/BaseTimeEntity.java index 24294388..8cd56420 100644 --- a/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/domains/BaseTimeEntity.java +++ b/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/domains/BaseTimeEntity.java @@ -1,5 +1,9 @@ package com.econovation.recruitdomain.domains; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import java.time.LocalDateTime; import javax.persistence.EntityListeners; import javax.persistence.MappedSuperclass; @@ -12,8 +16,16 @@ @MappedSuperclass @EntityListeners(AuditingEntityListener.class) public class BaseTimeEntity { - @CreatedDate private LocalDateTime createdAt; - @LastModifiedDate private LocalDateTime updatedAt; + + @JsonSerialize(using = LocalDateTimeSerializer.class) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + @CreatedDate + private LocalDateTime createdAt; + + @JsonSerialize(using = LocalDateTimeSerializer.class) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + @LastModifiedDate + private LocalDateTime updatedAt; public BaseTimeEntity() { this.createdAt = LocalDateTime.now(); From 7254ac2386baeb78254cfa573391b13b20f8432c Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Thu, 29 Aug 2024 19:48:37 +0900 Subject: [PATCH 09/20] =?UTF-8?q?[fix]:=20RedisCacheManager=EC=97=90?= =?UTF-8?q?=EC=84=9C=20BoardCardResponseDto=20=EC=A7=81=EB=A0=AC=ED=99=94?= =?UTF-8?q?=20=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기본 생성자가 없어 Jackson 라이브러리에서 `InvalidDefinitionException` 예외를 발생시킴 - 기본생성자를 `@@NoArgsConstructor`로 넣어주고 `@Builder` 어노테이션을 사용하기 위해 `@AllArgsConstructor`를 함께 추가 --- .../recruitdomain/domains/card/dto/BoardCardResponseDto.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/domains/card/dto/BoardCardResponseDto.java b/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/domains/card/dto/BoardCardResponseDto.java index 1ab2876b..d68cf903 100644 --- a/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/domains/card/dto/BoardCardResponseDto.java +++ b/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/domains/card/dto/BoardCardResponseDto.java @@ -3,13 +3,17 @@ import com.econovation.recruitdomain.domains.board.domain.Board; import com.econovation.recruitdomain.domains.board.domain.CardType; import com.econovation.recruitdomain.domains.card.domain.Card; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.Getter; +import lombok.NoArgsConstructor; @Getter @Data +@NoArgsConstructor @Builder +@AllArgsConstructor public class BoardCardResponseDto { private Long id; private Integer boardId; From 8f1cad3a9460dcd0b90d0bb019899d26ee46c8dc Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Thu, 29 Aug 2024 19:52:18 +0900 Subject: [PATCH 10/20] =?UTF-8?q?Revert=20"[config]:=20=EC=BA=90=EC=8B=B1?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=9C=20CacheManager=20=EB=B9=88=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 8f015439bf97055250de7b171d13a45bf2f43bce. --- .../recruit/api/config/CachingConfig.java | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100644 server/Recruit-Api/src/main/java/com/econovation/recruit/api/config/CachingConfig.java diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/config/CachingConfig.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/config/CachingConfig.java deleted file mode 100644 index c7d8eb65..00000000 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/config/CachingConfig.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.econovation.recruit.api.config; - -import java.util.List; -import org.springframework.cache.CacheManager; -import org.springframework.cache.annotation.EnableCaching; -import org.springframework.cache.concurrent.ConcurrentMapCacheManager; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@EnableCaching -@Configuration -public class CachingConfig { - - @Bean - public CacheManager cacheManager() { - ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager(); - cacheManager.setCacheNames(List.of( - "boardsByColumnsIds", // BoardService::getBoardByColumnsIds - "columnsByNavigationId", // ColumnService::getByNavigationId - "boardCardsByNavigationId", // CardService::getByNavigationId - "recordsByPage" // RecordService::execute - )); - return cacheManager; - } - -} From ec45fd2919c819f9c291ab08feb8ad9094311d5b Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Sun, 1 Sep 2024 01:57:15 +0900 Subject: [PATCH 11/20] =?UTF-8?q?[feat]:=20boardsByColumnIds=EA=B0=80=20co?= =?UTF-8?q?lumnId=EB=A7=88=EB=8B=A4=20=EA=B0=9C=EB=B3=84=EC=A0=81=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=BA=90=EC=8B=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - self invocation을 방지하기 위해 `BoardCacheService` 클래스를 구현 - columnIds를 순회하며 columnId 각각을 key로 가지는 캐싱 적용 이를 통해 `@CacheEvict` 시 key 값으로 columnId를 넘겨 필요한 부분만 무효화를 적용시킬 수 있음 --- .../api/card/service/BoardCacheService.java | 21 +++++++++++++++++++ .../api/card/service/BoardService.java | 6 ++++-- .../domains/board/adaptor/BoardAdaptor.java | 5 +++++ .../domains/board/domain/BoardRepository.java | 2 ++ .../recruitdomain/out/BoardLoadPort.java | 2 ++ 5 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardCacheService.java diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardCacheService.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardCacheService.java new file mode 100644 index 00000000..e90550ed --- /dev/null +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardCacheService.java @@ -0,0 +1,21 @@ +package com.econovation.recruit.api.card.service; + +import com.econovation.recruitdomain.domains.board.domain.Board; +import com.econovation.recruitdomain.out.BoardLoadPort; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class BoardCacheService { + + private final BoardLoadPort boardLoadPort; + + @Cacheable(value = "boardsByColumnsIds", key = "#columnsId") + public List getBoardByColumnsId(Integer columnsId) { + return boardLoadPort.getBoardByColumnsId(columnsId); + } + +} diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java index 7cb7b5fc..340023a6 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java @@ -41,6 +41,7 @@ public class BoardService implements BoardLoadUseCase, BoardRegisterUseCase { private final BoardLoadPort boardLoadPort; private final ColumnLoadPort columnLoadPort; private final ColumnRecordPort columnRecordPort; + private final BoardCacheService boardCacheService; /* @Override public Board save(Map newestLocation, String hopeField, Integer navLoc) { @@ -259,9 +260,10 @@ public Navigation getNavigationByNavLoc(Integer navLoc) { } @Override - @Cacheable(value = "boardsByColumnsIds") public List getBoardByColumnsIds(List columnsIds) { - return boardLoadPort.getBoardByColumnsIds(columnsIds); + return columnsIds.stream() + .flatMap(columnId -> boardCacheService.getBoardByColumnsId(columnId).stream()) + .toList(); } @Override diff --git a/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/domains/board/adaptor/BoardAdaptor.java b/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/domains/board/adaptor/BoardAdaptor.java index 91d4df55..14f99079 100644 --- a/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/domains/board/adaptor/BoardAdaptor.java +++ b/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/domains/board/adaptor/BoardAdaptor.java @@ -63,6 +63,11 @@ public List getBoardByColumnsIds(List columnsIds) { return boardRepository.findByColumnIdIn(columnsIds); } + @Override + public List getBoardByColumnsId(Integer columnsId) { + return boardRepository.findByColumnId(columnsId); + } + @Override public Board getBoardByCardId(Long cardId) { Optional board = boardRepository.findByCardId(cardId); diff --git a/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/domains/board/domain/BoardRepository.java b/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/domains/board/domain/BoardRepository.java index 95264bc7..147651b2 100644 --- a/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/domains/board/domain/BoardRepository.java +++ b/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/domains/board/domain/BoardRepository.java @@ -16,5 +16,7 @@ public interface BoardRepository extends JpaRepository { List findByColumnIdIn(List columnsIds); + List findByColumnId(Integer columnId); + Optional findByCardId(Long cardId); } diff --git a/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/out/BoardLoadPort.java b/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/out/BoardLoadPort.java index f21adee3..6e86baef 100644 --- a/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/out/BoardLoadPort.java +++ b/server/Recruit-Domain/src/main/java/com/econovation/recruitdomain/out/BoardLoadPort.java @@ -19,5 +19,7 @@ public interface BoardLoadPort { List getBoardByColumnsIds(List columnsIds); + List getBoardByColumnsId(Integer columnsId); + Board getBoardByCardId(Long cardId); } From 69c8383e49fc7029ca10e33010d2e85f8498446f Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Sun, 1 Sep 2024 15:57:05 +0900 Subject: [PATCH 12/20] =?UTF-8?q?[feat]:=20=EC=BB=A4=EC=8A=A4=ED=85=80=20?= =?UTF-8?q?=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=EC=97=90=EC=84=9C?= =?UTF-8?q?=20SpEL=20=EC=82=AC=EC=9A=A9=EC=9D=84=20=EC=9C=84=ED=95=B4=20?= =?UTF-8?q?=ED=8C=8C=EC=84=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../econovation/recruit/utils/SpELParser.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 server/Recruit-Api/src/main/java/com/econovation/recruit/utils/SpELParser.java diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/SpELParser.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/SpELParser.java new file mode 100644 index 00000000..964a870a --- /dev/null +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/SpELParser.java @@ -0,0 +1,26 @@ +package com.econovation.recruit.utils; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +public class SpELParser { + public static Object getDynamicValue(JoinPoint joinPoint, String name) { + ExpressionParser parser = new SpelExpressionParser(); + EvaluationContext context = new StandardEvaluationContext(); + + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + String[] parameterNames = signature.getParameterNames(); + Object[] args = joinPoint.getArgs(); + + for (int i = 0; i < parameterNames.length; i++) { + context.setVariable(parameterNames[i], args[i]); + } + + return parser.parseExpression(name).getValue(context); + } + +} From d5a355abf4b58807fc9dcd1312deb17a3f48b06e Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Sun, 1 Sep 2024 15:58:05 +0900 Subject: [PATCH 13/20] =?UTF-8?q?[feat]:=20=EC=BA=90=EC=8B=9C=20=EB=AC=B4?= =?UTF-8?q?=ED=9A=A8=ED=99=94=20=EC=B2=98=EB=A6=AC=EB=A5=BC=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20Aspect=EC=99=80=20=EC=96=B4=EB=85=B8=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../recruit/utils/aop/CacheEvictAspect.java | 114 ++++++++++++++++++ .../annotation/InvalidateCache.java | 15 +++ .../InvalidateCacheByCardLocation.java | 12 ++ .../InvalidateCacheByColumnLocation.java | 12 ++ .../InvalidateCacheByHopeField.java | 12 ++ .../annotation/InvalidateCaches.java | 13 ++ 6 files changed, 178 insertions(+) create mode 100644 server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java create mode 100644 server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCache.java create mode 100644 server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCardLocation.java create mode 100644 server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByColumnLocation.java create mode 100644 server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByHopeField.java create mode 100644 server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCaches.java diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java new file mode 100644 index 00000000..b7c6a70e --- /dev/null +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java @@ -0,0 +1,114 @@ +package com.econovation.recruit.utils.aop; + +import static com.econovation.recruitcommon.consts.RecruitStatic.DESIGNER_COLUMNS_ID; +import static com.econovation.recruitcommon.consts.RecruitStatic.DEVELOPER_COLUMNS_ID; +import static com.econovation.recruitcommon.consts.RecruitStatic.PLANNER_COLUMNS_ID; + +import com.econovation.recruit.utils.SpELParser; +import com.econovation.recruitcommon.annotation.InvalidateCacheByCardLocation; +import com.econovation.recruitcommon.annotation.InvalidateCacheByColumnLocation; +import com.econovation.recruitcommon.annotation.InvalidateCacheByHopeField; +import com.econovation.recruitcommon.annotation.InvalidateCache; +import com.econovation.recruitcommon.annotation.InvalidateCaches; +import com.econovation.recruitdomain.domains.board.domain.Board; +import com.econovation.recruitdomain.domains.board.domain.Columns; +import com.econovation.recruitdomain.domains.dto.UpdateLocationBoardDto; +import com.econovation.recruitdomain.domains.dto.UpdateLocationColumnDto; +import com.econovation.recruitdomain.out.BoardLoadPort; +import com.econovation.recruitdomain.out.ColumnLoadPort; +import lombok.RequiredArgsConstructor; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.stereotype.Component; + +@Aspect +@Component +@RequiredArgsConstructor +public class CacheEvictAspect { + + private final String BOARDS_BY_COLUMNS_IDS = "boardsByColumnsIds"; + private final String COLUMNS_BY_NAVIGATION_ID = "columnsByNavigationId"; + private final String BOARD_CARDS_BY_NAVIGATION_ID = "boardCardsByNavigationId"; + + private final CacheManager cacheManager; + private final BoardLoadPort boardLoadPort; + private final ColumnLoadPort columnLoadPort; + + @Before("@annotation(invalidateCaches)") + public void invalidateCaches(JoinPoint joinPoint, InvalidateCaches invalidateCaches) { + InvalidateCache[] value = invalidateCaches.value(); + for (InvalidateCache invalidateCache : value) { + invalidateCache(joinPoint, invalidateCache); + } + } + + @Before("@annotation(invalidateCache)") + public void invalidateCache(JoinPoint joinPoint, InvalidateCache invalidateCache) { + String cacheName = invalidateCache.cacheName(); + String key = invalidateCache.key(); + + if (key.isEmpty()) { + evictCache(cacheName, null); + return; + } + Integer parsedKey = (Integer) SpELParser.getDynamicValue(joinPoint, invalidateCache.key()); + evictCache(cacheName, parsedKey); + } + + private void evictCache(String cacheName, Integer key) { + Cache cache = cacheManager.getCache(cacheName); + if (cache == null) { + return; + } + + if (key == null) { + cache.clear(); + } else { + cache.evictIfPresent(key); + } + } + + @Before("@annotation(invalidateCacheByHopeField) && args(*, hopeField, ..)") + public void invalidateCacheByHopeField(InvalidateCacheByHopeField invalidateCacheByHopeField, String hopeField) { + Integer columnsId = 0; + switch (hopeField) { + case "개발자" -> columnsId = DEVELOPER_COLUMNS_ID; + case "디자이너" -> columnsId = DESIGNER_COLUMNS_ID; + case "기획자" -> columnsId = PLANNER_COLUMNS_ID; + default -> { + } + } + + evictCache(BOARDS_BY_COLUMNS_IDS, columnsId); + evictCache(BOARD_CARDS_BY_NAVIGATION_ID, 1); + } + + @Before("@annotation(invalidateCacheByColumnLocation) && args(updateLocationDto)") + public void invalidateCachetByColumnLocation(InvalidateCacheByColumnLocation invalidateCacheByColumnLocation, UpdateLocationColumnDto updateLocationDto) { + // Column 이동은 동일한 navigation에서 이루어지므로 하나만 조회해서 navigationId를 가져오고 무효화 + Columns column = columnLoadPort.findById(updateLocationDto.getColumnId()); + Integer navigationId = column.getNavigationId(); + + evictCache(COLUMNS_BY_NAVIGATION_ID, navigationId); + evictCache(BOARD_CARDS_BY_NAVIGATION_ID, navigationId); + } + + @Before("@annotation(invalidateCacheByCardLocation) && args(updateLocationDto)") + public void invalidateCachetByCardLocation(InvalidateCacheByCardLocation invalidateCacheByCardLocation, UpdateLocationBoardDto updateLocationDto) { + // Board 이동은 동일한 navigation에서 이루어지므로 하나만 조회해서 navigationId를 가져오고 무효화 + // Column에 해당하는 Board가 달라지므로 current, target 둘 다 조회해서 columnId를 가져오고 무효화 + + Board currentBoard = boardLoadPort.getBoardById(updateLocationDto.getBoardId()); + Board targetBoard = boardLoadPort.getBoardById(updateLocationDto.getTargetBoardId()); + + Integer navigationId = currentBoard.getNavigationId(); + + evictCache(BOARDS_BY_COLUMNS_IDS, currentBoard.getColumnId()); + evictCache(BOARDS_BY_COLUMNS_IDS, targetBoard.getColumnId()); + evictCache(BOARD_CARDS_BY_NAVIGATION_ID, navigationId); + } + +} diff --git a/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCache.java b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCache.java new file mode 100644 index 00000000..d3b7b325 --- /dev/null +++ b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCache.java @@ -0,0 +1,15 @@ +package com.econovation.recruitcommon.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface InvalidateCache { + + String cacheName() default ""; + + String key() default ""; +} diff --git a/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCardLocation.java b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCardLocation.java new file mode 100644 index 00000000..f000c512 --- /dev/null +++ b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCardLocation.java @@ -0,0 +1,12 @@ +package com.econovation.recruitcommon.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface InvalidateCacheByCardLocation { + +} diff --git a/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByColumnLocation.java b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByColumnLocation.java new file mode 100644 index 00000000..ab211c70 --- /dev/null +++ b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByColumnLocation.java @@ -0,0 +1,12 @@ +package com.econovation.recruitcommon.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface InvalidateCacheByColumnLocation { + +} diff --git a/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByHopeField.java b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByHopeField.java new file mode 100644 index 00000000..0e2309e5 --- /dev/null +++ b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByHopeField.java @@ -0,0 +1,12 @@ +package com.econovation.recruitcommon.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface InvalidateCacheByHopeField { + +} diff --git a/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCaches.java b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCaches.java new file mode 100644 index 00000000..b7b51ef8 --- /dev/null +++ b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCaches.java @@ -0,0 +1,13 @@ +package com.econovation.recruitcommon.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface InvalidateCaches { + + InvalidateCache[] value() default {}; +} From 50a27e2c024b7d1099810f5eb891cd06757f0f25 Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Sun, 1 Sep 2024 16:00:05 +0900 Subject: [PATCH 14/20] =?UTF-8?q?[feat]:=20BoardService=20=EC=BA=90?= =?UTF-8?q?=EC=8B=9C=20=EB=AC=B4=ED=9A=A8=ED=99=94=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/card/service/BoardService.java | 41 ++++++++----------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java index 340023a6..b9ba07c9 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java @@ -4,6 +4,11 @@ import com.econovation.recruit.api.card.usecase.BoardLoadUseCase; import com.econovation.recruit.api.card.usecase.BoardRegisterUseCase; +import com.econovation.recruitcommon.annotation.InvalidateCacheByCardLocation; +import com.econovation.recruitcommon.annotation.InvalidateCacheByColumnLocation; +import com.econovation.recruitcommon.annotation.InvalidateCacheByHopeField; +import com.econovation.recruitcommon.annotation.InvalidateCache; +import com.econovation.recruitcommon.annotation.InvalidateCaches; import com.econovation.recruitcommon.utils.Result; import com.econovation.recruitdomain.common.aop.redissonLock.RedissonLock; import com.econovation.recruitdomain.domains.board.domain.Board; @@ -25,9 +30,6 @@ import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.cache.annotation.Caching; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -108,16 +110,16 @@ public Board findById(Integer id) { } @Override - @Caching(evict = { - @CacheEvict(value = "boardsByColumnsIds", allEntries = true), - @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) + @InvalidateCaches({ + @InvalidateCache(cacheName = "boardsByColumnsIds", key = "#board.columnId"), + @InvalidateCache(cacheName = "boardCardsByNavigationId", key = "#board.navigationId") }) public void execute(Board board) { boardRecordPort.save(board); } @Override - @CacheEvict(value = "boardsByColumnsIds", allEntries = true) + @InvalidateCache(cacheName = "boardsByColumnsIds", key = "#columnId") public Board createWorkBoard(Integer columnId, Long cardId) { Columns column = columnLoadPort.findById(columnId); List boardByNavigationIdAndColumnId = @@ -169,13 +171,8 @@ public Columns createColumn(String title, Integer navigationId) { }*/ @Override - @Caching(evict = { - @CacheEvict(value = "boardsByColumnsIds", allEntries = true), - @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) - }) + @InvalidateCacheByHopeField public void createApplicantBoard(String applicantId, String hopeField, Long cardId) { - // \"hopeField\" -> hopeField 로 변경 - hopeField = hopeField; Integer columnsId = 0; if (hopeField.equals("개발자")) { columnsId = DEVELOPER_COLUMNS_ID; @@ -210,9 +207,9 @@ public void createApplicantBoard(String applicantId, String hopeField, Long card @Override @Transactional - @Caching(evict = { - @CacheEvict(value = "columnsByNavigationId", allEntries = true), - @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) + @InvalidateCaches({ + @InvalidateCache(cacheName = "columnsByNavigationId", key = "#navigationId"), + @InvalidateCache(cacheName = "boardCardsByNavigationId", key = "#navigationId") }) public Columns createColumn(String title, Integer navigationId) { Columns column = Columns.builder().title(title).navigationId(navigationId).build(); @@ -294,10 +291,7 @@ public Result getBoardByNextBoardId(Integer boardId) { paramClassType = UpdateLocationBoardDto.class, leaseTime = 500, waitTime = 500) - @Caching(evict = { - @CacheEvict(value = "boardsByColumnsIds", allEntries = true), - @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) - }) + @InvalidateCacheByCardLocation public void relocateCard(UpdateLocationBoardDto updateLocationBoardDto) { List invisibleBoard = List.of(1, 2, 3); // 기준 보드는 이동이 불가하다. @@ -318,10 +312,7 @@ public void relocateCard(UpdateLocationBoardDto updateLocationBoardDto) { @Override @Transactional - @Caching(evict = { - @CacheEvict(value = "columnsByNavigationId", allEntries = true), - @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) - }) + @InvalidateCacheByColumnLocation public void updateColumnLocation(UpdateLocationColumnDto updateLocationDto) { // 첫번째로 옮기는 경우 (nextColumnId == 0) if (updateLocationDto.getTargetColumnId().equals(0)) { @@ -363,7 +354,7 @@ public void updateColumnLocation(UpdateLocationColumnDto updateLocationDto) { } @Override - @CacheEvict(value = "boardsByColumnsIds", allEntries = true) + @InvalidateCache(cacheName = "boardsByColumnsIds", key = "#board.columnId") public void delete(Board board) { boardRecordPort.delete(board); } From b1a9523a536217652666536c110aebd005f4ddfd Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Sun, 1 Sep 2024 16:03:43 +0900 Subject: [PATCH 15/20] =?UTF-8?q?[feat]:=20ColumnService::getByNavigationI?= =?UTF-8?q?d=20=EC=BA=90=EC=8B=B1=20key=20=EB=AA=85=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/econovation/recruit/api/card/service/ColumnService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/ColumnService.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/ColumnService.java index ac2ff8be..821be404 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/ColumnService.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/ColumnService.java @@ -15,7 +15,7 @@ public class ColumnService implements ColumnsUseCase { private final ColumnRecordPort columnRecordPort; private final ColumnLoadPort columnLoadPort; - @Cacheable(value = "columnsByNavigationId") + @Cacheable(value = "columnsByNavigationId", key = "#navigationId") public List getByNavigationId(Integer navigationId) { return columnLoadPort.getColumnByNavigationId(navigationId); } From 8b11bf2db119fa455852176781e7fccae9986428 Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Mon, 2 Sep 2024 09:51:19 +0900 Subject: [PATCH 16/20] =?UTF-8?q?[feat]:=20CardService=20=EC=BA=90?= =?UTF-8?q?=EC=8B=9C=20=EB=AC=B4=ED=9A=A8=ED=99=94=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../recruit/api/card/service/CardService.java | 8 +++- .../recruit/utils/aop/CacheEvictAspect.java | 46 ++++++++++++++++--- .../annotation/InvalidateCacheByCardId.java | 12 +++++ .../InvalidateCacheByCreateWorkCard.java | 12 +++++ .../InvalidateCacheByUpdateWorkCard.java | 12 +++++ 5 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCardId.java create mode 100644 server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCreateWorkCard.java create mode 100644 server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByUpdateWorkCard.java diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/CardService.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/CardService.java index 91d21496..86366eb4 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/CardService.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/CardService.java @@ -7,6 +7,9 @@ import com.econovation.recruit.api.card.usecase.CardRegisterUseCase; import com.econovation.recruit.api.card.usecase.ColumnsUseCase; import com.econovation.recruit.api.config.security.SecurityUtils; +import com.econovation.recruitcommon.annotation.InvalidateCacheByCardId; +import com.econovation.recruitcommon.annotation.InvalidateCacheByCreateWorkCard; +import com.econovation.recruitcommon.annotation.InvalidateCacheByUpdateWorkCard; import com.econovation.recruitcommon.utils.Result; import com.econovation.recruitdomain.common.aop.domainEvent.Events; import com.econovation.recruitdomain.common.events.WorkCardDeletedEvent; @@ -156,7 +159,7 @@ public CardResponseDto findCardById(Long cardId) { @Override @Transactional - @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) + @InvalidateCacheByCardId public void deleteById(Long cardId) { Board board = boardLoadUseCase.getBoardByCardId(cardId); Result prevBoard = boardLoadUseCase.getBoardByNextBoardId(board.getId()); @@ -177,6 +180,7 @@ public void deleteById(Long cardId) { @Override @Transactional + @InvalidateCacheByCreateWorkCard public void saveWorkCard(CreateWorkCardDto createWorkCardDto) { Card card = Card.builder() @@ -190,7 +194,7 @@ public void saveWorkCard(CreateWorkCardDto createWorkCardDto) { @Override @Transactional - @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) + @InvalidateCacheByUpdateWorkCard public void update(Long cardId, UpdateWorkCardDto updateWorkCardDto) { Card card = cardLoadPort.findById(cardId); // 단 title 이 null일 수도 있고, content가 null일 수도 있다. diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java index b7c6a70e..bbc66b6b 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java @@ -5,16 +5,22 @@ import static com.econovation.recruitcommon.consts.RecruitStatic.PLANNER_COLUMNS_ID; import com.econovation.recruit.utils.SpELParser; +import com.econovation.recruitcommon.annotation.InvalidateCache; +import com.econovation.recruitcommon.annotation.InvalidateCacheByCardId; import com.econovation.recruitcommon.annotation.InvalidateCacheByCardLocation; import com.econovation.recruitcommon.annotation.InvalidateCacheByColumnLocation; +import com.econovation.recruitcommon.annotation.InvalidateCacheByCreateWorkCard; import com.econovation.recruitcommon.annotation.InvalidateCacheByHopeField; -import com.econovation.recruitcommon.annotation.InvalidateCache; +import com.econovation.recruitcommon.annotation.InvalidateCacheByUpdateWorkCard; import com.econovation.recruitcommon.annotation.InvalidateCaches; import com.econovation.recruitdomain.domains.board.domain.Board; import com.econovation.recruitdomain.domains.board.domain.Columns; +import com.econovation.recruitdomain.domains.card.domain.Card; +import com.econovation.recruitdomain.domains.dto.CreateWorkCardDto; import com.econovation.recruitdomain.domains.dto.UpdateLocationBoardDto; import com.econovation.recruitdomain.domains.dto.UpdateLocationColumnDto; import com.econovation.recruitdomain.out.BoardLoadPort; +import com.econovation.recruitdomain.out.CardLoadPort; import com.econovation.recruitdomain.out.ColumnLoadPort; import lombok.RequiredArgsConstructor; import org.aspectj.lang.JoinPoint; @@ -34,6 +40,7 @@ public class CacheEvictAspect { private final String BOARD_CARDS_BY_NAVIGATION_ID = "boardCardsByNavigationId"; private final CacheManager cacheManager; + private final CardLoadPort cardLoadPort; private final BoardLoadPort boardLoadPort; private final ColumnLoadPort columnLoadPort; @@ -54,11 +61,11 @@ public void invalidateCache(JoinPoint joinPoint, InvalidateCache invalidateCache evictCache(cacheName, null); return; } - Integer parsedKey = (Integer) SpELParser.getDynamicValue(joinPoint, invalidateCache.key()); + String parsedKey = (String) SpELParser.getDynamicValue(joinPoint, invalidateCache.key()); evictCache(cacheName, parsedKey); } - private void evictCache(String cacheName, Integer key) { + private void evictCache(String cacheName, String key) { Cache cache = cacheManager.getCache(cacheName); if (cache == null) { return; @@ -82,8 +89,8 @@ public void invalidateCacheByHopeField(InvalidateCacheByHopeField invalidateCach } } - evictCache(BOARDS_BY_COLUMNS_IDS, columnsId); - evictCache(BOARD_CARDS_BY_NAVIGATION_ID, 1); + evictCache(BOARDS_BY_COLUMNS_IDS, columnsId.toString()); + evictCache(BOARD_CARDS_BY_NAVIGATION_ID, "1"); } @Before("@annotation(invalidateCacheByColumnLocation) && args(updateLocationDto)") @@ -92,8 +99,8 @@ public void invalidateCachetByColumnLocation(InvalidateCacheByColumnLocation inv Columns column = columnLoadPort.findById(updateLocationDto.getColumnId()); Integer navigationId = column.getNavigationId(); - evictCache(COLUMNS_BY_NAVIGATION_ID, navigationId); - evictCache(BOARD_CARDS_BY_NAVIGATION_ID, navigationId); + evictCache(COLUMNS_BY_NAVIGATION_ID, navigationId.toString()); + evictCache(BOARD_CARDS_BY_NAVIGATION_ID, navigationId.toString()); } @Before("@annotation(invalidateCacheByCardLocation) && args(updateLocationDto)") @@ -109,6 +116,31 @@ public void invalidateCachetByCardLocation(InvalidateCacheByCardLocation invalid evictCache(BOARDS_BY_COLUMNS_IDS, currentBoard.getColumnId()); evictCache(BOARDS_BY_COLUMNS_IDS, targetBoard.getColumnId()); evictCache(BOARD_CARDS_BY_NAVIGATION_ID, navigationId); + evictCache(BOARDS_BY_COLUMNS_IDS, currentBoard.getColumnId().toString()); + evictCache(BOARDS_BY_COLUMNS_IDS, targetBoard.getColumnId().toString()); + evictCache(BOARD_CARDS_BY_NAVIGATION_ID, navigationId.toString()); + } + + @Before("@annotation(invalidateCacheByCardId)") + public void invalidateCacheByCardId(JoinPoint joinPoint, InvalidateCacheByCardId invalidateCacheByCardId) { + Long cardId = (Long) joinPoint.getArgs()[0]; + Board board = boardLoadPort.getBoardByCardId(cardId); + + evictCache(BOARD_CARDS_BY_NAVIGATION_ID, board.getNavigationId().toString()); + } + + @Before("@annotation(invalidateCacheByCreateWorkCard) && args(createWorkCardDto)") + public void invalidateCacheByCreateWorkCard(InvalidateCacheByCreateWorkCard invalidateCacheByCreateWorkCard, CreateWorkCardDto createWorkCardDto) { + Columns column = columnLoadPort.findById(createWorkCardDto.getColumnId()); + + evictCache(BOARD_CARDS_BY_NAVIGATION_ID, column.getNavigationId().toString()); + } + + @Before("@annotation(invalidateCacheByUpdateWorkCard) && args(cardId, ..)") + public void invalidateCacheByUpdateWorkCard(InvalidateCacheByUpdateWorkCard invalidateCacheByUpdateWorkCard, Long cardId) { + Board board = boardLoadPort.getBoardByCardId(cardId); + + evictCache(BOARD_CARDS_BY_NAVIGATION_ID, board.getNavigationId().toString()); } } diff --git a/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCardId.java b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCardId.java new file mode 100644 index 00000000..5e83dd0b --- /dev/null +++ b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCardId.java @@ -0,0 +1,12 @@ +package com.econovation.recruitcommon.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface InvalidateCacheByCardId { + +} diff --git a/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCreateWorkCard.java b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCreateWorkCard.java new file mode 100644 index 00000000..f2330a0c --- /dev/null +++ b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCreateWorkCard.java @@ -0,0 +1,12 @@ +package com.econovation.recruitcommon.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface InvalidateCacheByCreateWorkCard { + +} diff --git a/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByUpdateWorkCard.java b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByUpdateWorkCard.java new file mode 100644 index 00000000..c6296c8f --- /dev/null +++ b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByUpdateWorkCard.java @@ -0,0 +1,12 @@ +package com.econovation.recruitcommon.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface InvalidateCacheByUpdateWorkCard { + +} From 4bec5ca1f178dfdd88ef1cb1f30409a356937747 Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Mon, 2 Sep 2024 09:51:55 +0900 Subject: [PATCH 17/20] =?UTF-8?q?[feat]:=20CommentService=20=EC=BA=90?= =?UTF-8?q?=EC=8B=9C=20=EB=AC=B4=ED=9A=A8=ED=99=94=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/comment/service/CommentService.java | 14 ++++++-- .../recruit/utils/aop/CacheEvictAspect.java | 36 +++++++++++++++++-- .../InvalidateCacheByCommentId.java | 12 +++++++ .../InvalidateCacheByCreateComment.java | 12 +++++++ .../InvalidateCacheByDeleteComment.java | 12 +++++++ 5 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCommentId.java create mode 100644 server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCreateComment.java create mode 100644 server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByDeleteComment.java diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/comment/service/CommentService.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/comment/service/CommentService.java index 23bd6dbb..13d57b1d 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/comment/service/CommentService.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/comment/service/CommentService.java @@ -2,6 +2,9 @@ import com.econovation.recruit.api.comment.usecase.CommentUseCase; import com.econovation.recruit.api.config.security.SecurityUtils; +import com.econovation.recruitcommon.annotation.InvalidateCacheByCreateComment; +import com.econovation.recruitcommon.annotation.InvalidateCacheByCommentId; +import com.econovation.recruitcommon.annotation.InvalidateCacheByDeleteComment; import com.econovation.recruitcommon.utils.Result; import com.econovation.recruitdomain.common.aop.redissonLock.RedissonLock; import com.econovation.recruitdomain.domains.card.domain.Card; @@ -24,7 +27,7 @@ import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; -import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -40,7 +43,7 @@ public class CommentService implements CommentUseCase { @Override @Transactional - @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) + @InvalidateCacheByCreateComment public Comment saveComment(CommentRegisterDto commentDto) { Long userId = SecurityUtils.getCurrentUserId(); // applicantId null 이면 "" 으로 바꿔준다. cardId 가 null 이면 0 으로 바꿔준다. @@ -83,7 +86,7 @@ private Comment convertComment(CommentRegisterDto commentDto, Long userId) { @Override @Transactional - @CacheEvict(value = "boardCardsByNavigationId", allEntries = true) + @InvalidateCacheByCommentId public void deleteComment(Long commentId) { Long idpId = SecurityUtils.getCurrentUserId(); Comment comment = commentLoadPort.findById(commentId); @@ -120,6 +123,7 @@ public Comment findById(Long commentId) { @Override @RedissonLock(LockName = "댓글좋아요", identifier = "commentId") @Transactional + @InvalidateCacheByCommentId public void createCommentLike(Long commentId) { // 기존에 눌렀으면 취소 처리 Long idpId = SecurityUtils.getCurrentUserId(); @@ -148,6 +152,7 @@ private void createCommentLike(Comment comment, Long idpId) { @Override @RedissonLock(LockName = "댓글좋아요", identifier = "commentId") @Transactional + @InvalidateCacheByCommentId public void deleteCommentLike(Long commentId) { // 현재 내가 눌렀던 댓글만 삭제할 수 있다. Long idpId = SecurityUtils.getCurrentUserId(); @@ -220,6 +225,7 @@ public Boolean isCheckedLike(Long commentId) { @Override @Transactional + @InvalidateCacheByCommentId public void updateCommentContent(Long commentId, Map contents) { String content = contents.get("content"); // 내가 작성한 comment 만 수정할 수 있다. @@ -233,6 +239,7 @@ public void updateCommentContent(Long commentId, Map contents) { // @Override @Transactional(readOnly = true) + @Cacheable(value = "commentsByApplicantId", key = "#applicantId") public List findByApplicantId(String applicantId) { Long idpId = SecurityUtils.getCurrentUserId(); List comments = commentLoadPort.findByApplicantId(applicantId); @@ -241,6 +248,7 @@ public List findByApplicantId(String applicantId) { @Override @Transactional + @InvalidateCacheByDeleteComment public void deleteCommentByCardId(Long cardId) { List comments = commentLoadPort.findByCardId(cardId); if (comments.isEmpty()) { diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java index bbc66b6b..c9eccd5a 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java @@ -9,19 +9,25 @@ import com.econovation.recruitcommon.annotation.InvalidateCacheByCardId; import com.econovation.recruitcommon.annotation.InvalidateCacheByCardLocation; import com.econovation.recruitcommon.annotation.InvalidateCacheByColumnLocation; +import com.econovation.recruitcommon.annotation.InvalidateCacheByCreateComment; import com.econovation.recruitcommon.annotation.InvalidateCacheByCreateWorkCard; +import com.econovation.recruitcommon.annotation.InvalidateCacheByCommentId; +import com.econovation.recruitcommon.annotation.InvalidateCacheByDeleteComment; import com.econovation.recruitcommon.annotation.InvalidateCacheByHopeField; import com.econovation.recruitcommon.annotation.InvalidateCacheByUpdateWorkCard; import com.econovation.recruitcommon.annotation.InvalidateCaches; import com.econovation.recruitdomain.domains.board.domain.Board; import com.econovation.recruitdomain.domains.board.domain.Columns; import com.econovation.recruitdomain.domains.card.domain.Card; +import com.econovation.recruitdomain.domains.comment.domain.Comment; +import com.econovation.recruitdomain.domains.dto.CommentRegisterDto; import com.econovation.recruitdomain.domains.dto.CreateWorkCardDto; import com.econovation.recruitdomain.domains.dto.UpdateLocationBoardDto; import com.econovation.recruitdomain.domains.dto.UpdateLocationColumnDto; import com.econovation.recruitdomain.out.BoardLoadPort; import com.econovation.recruitdomain.out.CardLoadPort; import com.econovation.recruitdomain.out.ColumnLoadPort; +import com.econovation.recruitdomain.out.CommentLoadPort; import lombok.RequiredArgsConstructor; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; @@ -38,11 +44,13 @@ public class CacheEvictAspect { private final String BOARDS_BY_COLUMNS_IDS = "boardsByColumnsIds"; private final String COLUMNS_BY_NAVIGATION_ID = "columnsByNavigationId"; private final String BOARD_CARDS_BY_NAVIGATION_ID = "boardCardsByNavigationId"; + private final String COMMENTS_BY_APPLICANT_ID = "commentsByApplicantId"; private final CacheManager cacheManager; private final CardLoadPort cardLoadPort; private final BoardLoadPort boardLoadPort; private final ColumnLoadPort columnLoadPort; + private final CommentLoadPort commentLoadPort; @Before("@annotation(invalidateCaches)") public void invalidateCaches(JoinPoint joinPoint, InvalidateCaches invalidateCaches) { @@ -113,9 +121,6 @@ public void invalidateCachetByCardLocation(InvalidateCacheByCardLocation invalid Integer navigationId = currentBoard.getNavigationId(); - evictCache(BOARDS_BY_COLUMNS_IDS, currentBoard.getColumnId()); - evictCache(BOARDS_BY_COLUMNS_IDS, targetBoard.getColumnId()); - evictCache(BOARD_CARDS_BY_NAVIGATION_ID, navigationId); evictCache(BOARDS_BY_COLUMNS_IDS, currentBoard.getColumnId().toString()); evictCache(BOARDS_BY_COLUMNS_IDS, targetBoard.getColumnId().toString()); evictCache(BOARD_CARDS_BY_NAVIGATION_ID, navigationId.toString()); @@ -143,4 +148,29 @@ public void invalidateCacheByUpdateWorkCard(InvalidateCacheByUpdateWorkCard inva evictCache(BOARD_CARDS_BY_NAVIGATION_ID, board.getNavigationId().toString()); } + @Before("@annotation(invalidateCacheByCreateComment) && args(commentDto)") + public void invalidateCacheByCreateComment(InvalidateCacheByCreateComment invalidateCacheByCreateComment, CommentRegisterDto commentDto) { + Board board = boardLoadPort.getBoardByCardId(commentDto.getCardId()); + + // Card의 comment count를 변경하므로 무효화 + evictCache(BOARD_CARDS_BY_NAVIGATION_ID, board.getNavigationId().toString()); + evictCache(COMMENTS_BY_APPLICANT_ID, commentDto.getApplicantId()); + } + + @Before("@annotation(invalidateCacheByDeleteComment) && args(cardId)") + public void invalidateCacheByDeleteComment(InvalidateCacheByDeleteComment invalidateCacheByDeleteComment, Long cardId) { + Board board = boardLoadPort.getBoardByCardId(cardId); + Card card = cardLoadPort.findById(cardId); + + evictCache(BOARD_CARDS_BY_NAVIGATION_ID, board.getNavigationId().toString()); + evictCache(COMMENTS_BY_APPLICANT_ID, card.getApplicantId()); + } + + @Before("@annotation(invalidateCacheByCommentId) && args(commentId, ..)") + public void invalidateCacheByCommentId(InvalidateCacheByCommentId invalidateCacheByCommentId, Long commentId) { + Comment comment = commentLoadPort.findById(commentId); + + evictCache(COMMENTS_BY_APPLICANT_ID, comment.getApplicantId()); + } + } diff --git a/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCommentId.java b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCommentId.java new file mode 100644 index 00000000..f6ce799c --- /dev/null +++ b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCommentId.java @@ -0,0 +1,12 @@ +package com.econovation.recruitcommon.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface InvalidateCacheByCommentId { + +} diff --git a/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCreateComment.java b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCreateComment.java new file mode 100644 index 00000000..d747b1e2 --- /dev/null +++ b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByCreateComment.java @@ -0,0 +1,12 @@ +package com.econovation.recruitcommon.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface InvalidateCacheByCreateComment { + +} diff --git a/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByDeleteComment.java b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByDeleteComment.java new file mode 100644 index 00000000..08ad5181 --- /dev/null +++ b/server/Recruit-Common/src/main/java/com/econovation/recruitcommon/annotation/InvalidateCacheByDeleteComment.java @@ -0,0 +1,12 @@ +package com.econovation.recruitcommon.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface InvalidateCacheByDeleteComment { + +} From 329c39034dc42d9e487811032277e61a01a75b63 Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Tue, 3 Sep 2024 15:19:15 +0900 Subject: [PATCH 18/20] =?UTF-8?q?[fix]:=20=EC=A7=80=EC=9B=90=EC=84=9C=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=EC=99=80=20=EC=97=85=EB=AC=B4=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EC=BA=90=EC=8B=9C=20?= =?UTF-8?q?=EB=AC=B4=ED=9A=A8=ED=99=94=20=EC=A0=84=EB=9E=B5=EC=9D=84=20?= =?UTF-8?q?=EA=B5=AC=EB=B6=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../recruit/utils/aop/CacheEvictAspect.java | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java index c9eccd5a..10b8ad94 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java @@ -150,10 +150,20 @@ public void invalidateCacheByUpdateWorkCard(InvalidateCacheByUpdateWorkCard inva @Before("@annotation(invalidateCacheByCreateComment) && args(commentDto)") public void invalidateCacheByCreateComment(InvalidateCacheByCreateComment invalidateCacheByCreateComment, CommentRegisterDto commentDto) { - Board board = boardLoadPort.getBoardByCardId(commentDto.getCardId()); + // 업무카드 댓글 생성 요청 + if (commentDto.getApplicantId() == null) { + Board board = boardLoadPort.getBoardByCardId(commentDto.getCardId()); + evictCache(BOARD_CARDS_BY_NAVIGATION_ID, board.getNavigationId().toString()); + return; + } + + // 지원서카드 댓글 생성 요청 + Card card = cardLoadPort.findByApplicantId(commentDto.getApplicantId()); + Board board = boardLoadPort.getBoardByCardId(card.getId()); // Card의 comment count를 변경하므로 무효화 evictCache(BOARD_CARDS_BY_NAVIGATION_ID, board.getNavigationId().toString()); + // 지원자의 댓글 목록 조회 캐시 무효화 evictCache(COMMENTS_BY_APPLICANT_ID, commentDto.getApplicantId()); } @@ -162,15 +172,23 @@ public void invalidateCacheByDeleteComment(InvalidateCacheByDeleteComment invali Board board = boardLoadPort.getBoardByCardId(cardId); Card card = cardLoadPort.findById(cardId); + // 댓글 삭제 시 카드의 댓글 수 변경으로 인한 무효화 evictCache(BOARD_CARDS_BY_NAVIGATION_ID, board.getNavigationId().toString()); - evictCache(COMMENTS_BY_APPLICANT_ID, card.getApplicantId()); + + // 지원서 카드의 댓글 삭제 시 지원자의 댓글 목록 조회 캐시 무효화 + if (card.getApplicantId() != null) { + evictCache(COMMENTS_BY_APPLICANT_ID, card.getApplicantId()); + } } @Before("@annotation(invalidateCacheByCommentId) && args(commentId, ..)") public void invalidateCacheByCommentId(InvalidateCacheByCommentId invalidateCacheByCommentId, Long commentId) { Comment comment = commentLoadPort.findById(commentId); - evictCache(COMMENTS_BY_APPLICANT_ID, comment.getApplicantId()); + // 지원서 카드의 댓글인 경우 캐시 무효화 + if (comment.getApplicantId() != null) { + evictCache(COMMENTS_BY_APPLICANT_ID, comment.getApplicantId()); + } } } From 8d8faebfd7262367a89de9ba1fa65d0ad43600c0 Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Wed, 4 Sep 2024 08:58:43 +0900 Subject: [PATCH 19/20] =?UTF-8?q?[refactor]:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EB=A1=9C=EC=A7=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 업무카드를 삭제할 때만 호출되는 메서드이므로 지원서 카드 댓글에 대한 캐시 무효화 로직은 불필요해 제거 --- .../econovation/recruit/utils/aop/CacheEvictAspect.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java index 10b8ad94..d5b3135c 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java @@ -172,13 +172,8 @@ public void invalidateCacheByDeleteComment(InvalidateCacheByDeleteComment invali Board board = boardLoadPort.getBoardByCardId(cardId); Card card = cardLoadPort.findById(cardId); - // 댓글 삭제 시 카드의 댓글 수 변경으로 인한 무효화 + // 댓글 삭제 시 업무카드의 댓글 수 변경으로 인한 무효화 evictCache(BOARD_CARDS_BY_NAVIGATION_ID, board.getNavigationId().toString()); - - // 지원서 카드의 댓글 삭제 시 지원자의 댓글 목록 조회 캐시 무효화 - if (card.getApplicantId() != null) { - evictCache(COMMENTS_BY_APPLICANT_ID, card.getApplicantId()); - } } @Before("@annotation(invalidateCacheByCommentId) && args(commentId, ..)") From ad888837ef49d6a4addcc3aafb9f81de9f6a9e37 Mon Sep 17 00:00:00 2001 From: Profile-exe Date: Wed, 4 Sep 2024 09:06:37 +0900 Subject: [PATCH 20/20] =?UTF-8?q?[refactor]:=20=EC=BA=90=EC=8B=9C=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=EC=86=8C=20=EC=9D=B4=EB=A6=84=EC=9D=84=20=5F?= =?UTF-8?q?Ids=EC=97=90=EC=84=9C=20=5FId=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존에는 columnId 들을 리스트로 받아 key로 적용했기에 Ids를 사용 현재는 columnId마다 key로 구분하므로 Id로 변경 --- .../recruit/api/card/service/BoardCacheService.java | 2 +- .../recruit/api/card/service/BoardService.java | 6 +++--- .../econovation/recruit/utils/aop/CacheEvictAspect.java | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardCacheService.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardCacheService.java index e90550ed..7ce64d2f 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardCacheService.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardCacheService.java @@ -13,7 +13,7 @@ public class BoardCacheService { private final BoardLoadPort boardLoadPort; - @Cacheable(value = "boardsByColumnsIds", key = "#columnsId") + @Cacheable(value = "boardsByColumnsId", key = "#columnsId") public List getBoardByColumnsId(Integer columnsId) { return boardLoadPort.getBoardByColumnsId(columnsId); } diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java index b9ba07c9..277b7a14 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/api/card/service/BoardService.java @@ -111,7 +111,7 @@ public Board findById(Integer id) { @Override @InvalidateCaches({ - @InvalidateCache(cacheName = "boardsByColumnsIds", key = "#board.columnId"), + @InvalidateCache(cacheName = "boardsByColumnsId", key = "#board.columnId"), @InvalidateCache(cacheName = "boardCardsByNavigationId", key = "#board.navigationId") }) public void execute(Board board) { @@ -119,7 +119,7 @@ public void execute(Board board) { } @Override - @InvalidateCache(cacheName = "boardsByColumnsIds", key = "#columnId") + @InvalidateCache(cacheName = "boardsByColumnsId", key = "#columnId") public Board createWorkBoard(Integer columnId, Long cardId) { Columns column = columnLoadPort.findById(columnId); List boardByNavigationIdAndColumnId = @@ -354,7 +354,7 @@ public void updateColumnLocation(UpdateLocationColumnDto updateLocationDto) { } @Override - @InvalidateCache(cacheName = "boardsByColumnsIds", key = "#board.columnId") + @InvalidateCache(cacheName = "boardsByColumnsId", key = "#board.columnId") public void delete(Board board) { boardRecordPort.delete(board); } diff --git a/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java b/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java index d5b3135c..66289efa 100644 --- a/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java +++ b/server/Recruit-Api/src/main/java/com/econovation/recruit/utils/aop/CacheEvictAspect.java @@ -41,7 +41,7 @@ @RequiredArgsConstructor public class CacheEvictAspect { - private final String BOARDS_BY_COLUMNS_IDS = "boardsByColumnsIds"; + private final String BOARDS_BY_COLUMNS_ID = "boardsByColumnsId"; private final String COLUMNS_BY_NAVIGATION_ID = "columnsByNavigationId"; private final String BOARD_CARDS_BY_NAVIGATION_ID = "boardCardsByNavigationId"; private final String COMMENTS_BY_APPLICANT_ID = "commentsByApplicantId"; @@ -97,7 +97,7 @@ public void invalidateCacheByHopeField(InvalidateCacheByHopeField invalidateCach } } - evictCache(BOARDS_BY_COLUMNS_IDS, columnsId.toString()); + evictCache(BOARDS_BY_COLUMNS_ID, columnsId.toString()); evictCache(BOARD_CARDS_BY_NAVIGATION_ID, "1"); } @@ -121,8 +121,8 @@ public void invalidateCachetByCardLocation(InvalidateCacheByCardLocation invalid Integer navigationId = currentBoard.getNavigationId(); - evictCache(BOARDS_BY_COLUMNS_IDS, currentBoard.getColumnId().toString()); - evictCache(BOARDS_BY_COLUMNS_IDS, targetBoard.getColumnId().toString()); + evictCache(BOARDS_BY_COLUMNS_ID, currentBoard.getColumnId().toString()); + evictCache(BOARDS_BY_COLUMNS_ID, targetBoard.getColumnId().toString()); evictCache(BOARD_CARDS_BY_NAVIGATION_ID, navigationId.toString()); }