Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Steady] 스테디 게시물 조회 첫 페이지 캐싱 처리 #198

Merged
merged 24 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8580669
:pushpin: 스프링 캐시 & 카페인 캐시 매니저 의존성 추가
weonest Jan 3, 2024
3ba4e4e
:wrench: application-dev DB 정보 변경
weonest Jan 3, 2024
efccf78
:sparkles: CacheConfig 추가
weonest Jan 3, 2024
725baf3
:sparkles: SteadyService 페이징 결과 캐싱 적용
weonest Jan 3, 2024
d1637ea
:art: SteadyQueryRepository 로 이름 변경
weonest Jan 3, 2024
e447a25
:white_check_mark: SteadyQueryRepository 로 이름 변경 & 기존 Search 내용 삭제
weonest Jan 3, 2024
84b51c8
:recycle: Steady getPromotedAt() 메서드 추가
weonest Jan 9, 2024
232e29b
:recycle: Cursor 생성자 팩토리 메서드 방식으로 변경
weonest Jan 9, 2024
53cfd68
:recycle: SteadyQueryRepository 조회 로직 변경
weonest Jan 9, 2024
1298f19
:sparkles: PrevCursor 추가
weonest Jan 9, 2024
8d8a2a4
:recycle: 커서를 사용하면서도 이전 페이지 커서를 반환할 수 있도록 수정
weonest Jan 9, 2024
41b9c4f
:recycle: FilterConditionDto 캐시 조건 수정
weonest Jan 9, 2024
d06c479
:art: 공백 수정
weonest Jan 9, 2024
6457ff3
:white_check_mark: 스테디 조회 캐싱 적용 사항 테스트
weonest Jan 9, 2024
bd9e53e
:art: filterCondition 메서드 filter로 이름 변경 (전반적인 필터링이기 때문)
weonest Jan 16, 2024
ee7a93d
:recycle: FilterConditionDto 캐시 조건 재수정
weonest Jan 16, 2024
c3223eb
:fire: PrevCursor 삭제
weonest Jan 16, 2024
220c654
:recycle: SteadySearchRequest page 필드 삭제
weonest Jan 16, 2024
1488d3e
:recycle: SteadyFilterResponse 필드 추가 및 가드 패턴 적용
weonest Jan 16, 2024
e7318b5
:recycle: SteadyFilterResponse 변경에 따른 SteadyQueryRepositoryImpl 수정
weonest Jan 16, 2024
1cacc19
:sparkles: CursorResponse 생성
weonest Jan 16, 2024
1d40c41
:recycle: SteadyService 필터링 조회 로직 분기 수정
weonest Jan 16, 2024
27ca664
:white_check_mark: SteadyService 변경사항 테스트 적용
weonest Jan 16, 2024
08e5bc9
:art: 네이밍 수정
weonest Jan 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

// Cache
implementation 'org.springframework.boot:spring-boot-starter-cache'
implementation 'com.github.ben-manes.caffeine:caffeine:3.1.2'

// QueryDSL
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta"
Expand Down
57 changes: 57 additions & 0 deletions src/main/java/dev/steady/global/config/CacheConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package dev.steady.global.config;

import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.Getter;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Configuration
@EnableCaching
public class CacheConfig {

private static final int DEFAULT_CACHE_TIME = 60 * 60 * 24;

@Getter
private enum CacheType {
STEADIES("steadies", DEFAULT_CACHE_TIME, 50),
;

private final String cacheName;
private final int expireAfterWriteTime;
private final int maxSize;

CacheType(String cacheName, int expireAfterWriteTime, int maxSize) {
this.cacheName = cacheName;
this.expireAfterWriteTime = expireAfterWriteTime;
this.maxSize = maxSize;
}
}

@Bean
public CacheManager cacheManager() {
List<CaffeineCache> caches = Arrays.stream(CacheType.values())
.map(cacheType ->
new CaffeineCache(
cacheType.getCacheName(),
Caffeine.newBuilder()
.recordStats()
.expireAfterWrite(cacheType.getExpireAfterWriteTime(), TimeUnit.SECONDS)
.maximumSize(cacheType.maxSize)
.build()
))
.toList();

SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(caches);
return cacheManager;
}

}
5 changes: 5 additions & 0 deletions src/main/java/dev/steady/steady/domain/Steady.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import lombok.NoArgsConstructor;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -209,6 +210,10 @@ public int getPromotionCount() {
return promotion.getPromotionCount();
}

public LocalDateTime getPromotedAt() {
return promotion.getPromotedAt();
}

public int getParticipantLimit() {
return participants.getParticipantLimit();
}
Expand Down
1 change: 0 additions & 1 deletion src/main/java/dev/steady/steady/domain/SteadyStatus.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,4 @@ public static SteadyStatus from(String status) {
return SteadyStatus.valueOf(status.toUpperCase());
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

import dev.steady.global.exception.NotFoundException;
import dev.steady.steady.domain.Steady;
import dev.steady.steady.infrastructure.SteadySearchRepository;
import dev.steady.steady.infrastructure.SteadyQueryRepository;
import org.springframework.data.jpa.repository.JpaRepository;

import static dev.steady.steady.exception.SteadyErrorCode.STEADY_NOT_FOUND;

public interface SteadyRepository extends JpaRepository<Steady, Long>, SteadySearchRepository {
public interface SteadyRepository extends JpaRepository<Steady, Long>, SteadyQueryRepository {

default Steady getSteady(Long steadyId) {
return findById(steadyId)
Expand Down
27 changes: 20 additions & 7 deletions src/main/java/dev/steady/steady/dto/FilterConditionDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import dev.steady.steady.domain.SteadyType;
import dev.steady.steady.dto.request.SteadySearchRequest;
import dev.steady.steady.uitl.Cursor;
import io.jsonwebtoken.lang.Strings;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
Expand All @@ -20,7 +21,8 @@ public record FilterConditionDto(
List<String> positions,
SteadyStatus status,
boolean like,
String keyword
String keyword,
boolean isFirstPage
) {

public static FilterConditionDto from(SteadySearchRequest request) {
Expand All @@ -31,6 +33,7 @@ public static FilterConditionDto from(SteadySearchRequest request) {
List<String> position = filterStackOrPositionCondition(request.position());
SteadyStatus status = filterSteadyStatusCondition(request.status());
boolean like = filterLikeCondition(request.like());
boolean isFirstPage = Objects.isNull(request.cursor());

return new FilterConditionDto(
cursor,
Expand All @@ -40,14 +43,16 @@ public static FilterConditionDto from(SteadySearchRequest request) {
position,
status,
like,
request.keyword());
request.keyword(),
isFirstPage);
}


private static Cursor filterCursor(String criteria, String cursor) {
if (Objects.isNull(criteria)) {
criteria = "promotion.promotedAt";
if (Objects.isNull(criteria) || criteria.equals("promotion.promotedAt")) {
return Cursor.promotedAtCursorFrom(cursor);
}
return Cursor.of(criteria, cursor);
return Cursor.deadlineCursorFrom(cursor);
}

private static SteadyType filterSteadyType(String steadyType) {
Expand Down Expand Up @@ -86,6 +91,14 @@ private static boolean filterLikeCondition(String like) {
return like.equals("true");
}

}

public boolean cacheable() {
if (Objects.isNull(steadyType) && Objects.isNull(steadyMode) && stacks.isEmpty()
&& positions.isEmpty() && !like && !Strings.hasText(keyword)
&& Objects.nonNull(status) && status.equals(SteadyStatus.RECRUITING)
&& isFirstPage) {
return true;
}
return false;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import org.springframework.data.domain.Sort;

public record SteadySearchRequest(
Integer page,
String direction,
String criteria,
String cursor,
Expand All @@ -24,7 +23,7 @@ public record SteadySearchRequest(

public Pageable toPageable() {
return PageRequest.of(
page == null ? DEFAULT_PAGE : page,
DEFAULT_PAGE,
DEFAULT_SIZE,
Sort.by(
direction == null ? Sort.Direction.DESC : Sort.Direction.fromString(direction),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package dev.steady.steady.dto.response;

public record CursorResponse<T>(
T prevCursor,
T nextCursor
) {
}
20 changes: 6 additions & 14 deletions src/main/java/dev/steady/steady/dto/response/PageResponse.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
package dev.steady.steady.dto.response;

import org.springframework.data.domain.Page;

import java.util.List;

public record PageResponse<T>(
List<T> content,
long numberOfElements,
int page,
int size,
int totalPages,
long totalElements
CursorResponse cursor
) {

public static <T> PageResponse<T> from(Page<T> page) {
return new PageResponse<>(
page.getContent(),
page.getNumberOfElements(),
page.getPageable().getPageNumber(),
page.getPageable().getPageSize(),
page.getTotalPages(),
page.getTotalElements());
public static <T> PageResponse<T> of(List<T> list, CursorResponse cursorResponse) {
return new PageResponse<>(list,
list.size(),
cursorResponse
);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package dev.steady.steady.dto.response;

import dev.steady.steady.domain.Steady;

import java.util.List;

public record SteadyFilterResponse(
List<Steady> result,
Steady prevCursorSteady,
Steady nextCursorSteady
) {

public SteadyFilterResponse(List<Steady> result, Steady prevCursorSteady, Steady nextCursorSteady) {
this.result = result;
this.prevCursorSteady = prevCursorSteady;
if (result.isEmpty()) {
this.nextCursorSteady = null;
}else {
this.nextCursorSteady = result.get(result.size() - 1);
}
}

public SteadyFilterResponse(List<Steady> result, Steady prevCursor) {
this(result, prevCursor, null);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public static SteadyQueryResponse from(Steady steady) {
steady.getStatus(),
steady.getDeadline(),
steady.getCreatedAt(),
steady.getPromotion().getPromotedAt(),
steady.getPromotedAt(),
steady.getParticipantLimit(),
steady.getNumberOfParticipants(),
steady.getViewCount(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
import dev.steady.steady.domain.SteadyStatus;
import dev.steady.steady.dto.FilterConditionDto;
import dev.steady.steady.dto.response.MySteadyQueryResponse;
import dev.steady.steady.dto.response.SteadyFilterResponse;
import dev.steady.user.domain.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;

import java.util.List;

public interface SteadySearchRepository {
public interface SteadyQueryRepository {

Page<Steady> findAllByFilterCondition(UserInfo userInfo, FilterConditionDto condition, Pageable pageable);
SteadyFilterResponse findAllByFilterCondition(UserInfo userInfo, FilterConditionDto condition, Pageable pageable);

Slice<MySteadyQueryResponse> findMySteadies(SteadyStatus status, User user, Pageable pageable);

Expand Down
Loading