diff --git a/backend/src/main/java/com/festago/common/handler/GlobalExceptionHandler.java b/backend/src/main/java/com/festago/common/handler/GlobalExceptionHandler.java index 0d314d4d3..b26be3752 100644 --- a/backend/src/main/java/com/festago/common/handler/GlobalExceptionHandler.java +++ b/backend/src/main/java/com/festago/common/handler/GlobalExceptionHandler.java @@ -15,6 +15,7 @@ import com.festago.common.exception.dto.ValidErrorResponse; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; +import org.apache.catalina.connector.ClientAbortException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; @@ -63,6 +64,11 @@ public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { private final AuthenticateContext authenticateContext; + @ExceptionHandler(ClientAbortException.class) + public ResponseEntity handle(ClientAbortException e) { + return ResponseEntity.badRequest().build(); + } + @ExceptionHandler(InvalidMediaTypeException.class) public ResponseEntity handle(InvalidMediaTypeException e) { return ResponseEntity.badRequest().build(); diff --git a/backend/src/main/java/com/festago/festival/application/PopularFestivalV1QueryService.java b/backend/src/main/java/com/festago/festival/application/PopularFestivalV1QueryService.java index ff850a433..7860c3523 100644 --- a/backend/src/main/java/com/festago/festival/application/PopularFestivalV1QueryService.java +++ b/backend/src/main/java/com/festago/festival/application/PopularFestivalV1QueryService.java @@ -3,6 +3,8 @@ import com.festago.festival.dto.FestivalV1Response; import com.festago.festival.dto.PopularFestivalsV1Response; import com.festago.festival.repository.PopularFestivalV1QueryDslRepository; +import java.time.Clock; +import java.time.LocalDate; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -14,9 +16,10 @@ public class PopularFestivalV1QueryService { private final PopularFestivalV1QueryDslRepository popularFestivalRepository; + private final Clock clock; public PopularFestivalsV1Response findPopularFestivals() { - List popularFestivals = popularFestivalRepository.findPopularFestivals(); + List popularFestivals = popularFestivalRepository.findPopularFestivals(LocalDate.now(clock)); return new PopularFestivalsV1Response( "요즘 뜨는 축제", popularFestivals diff --git a/backend/src/main/java/com/festago/festival/repository/PopularFestivalV1QueryDslRepository.java b/backend/src/main/java/com/festago/festival/repository/PopularFestivalV1QueryDslRepository.java index 7470d13c4..82e0f39f6 100644 --- a/backend/src/main/java/com/festago/festival/repository/PopularFestivalV1QueryDslRepository.java +++ b/backend/src/main/java/com/festago/festival/repository/PopularFestivalV1QueryDslRepository.java @@ -9,6 +9,7 @@ import com.festago.festival.dto.FestivalV1Response; import com.festago.festival.dto.QFestivalV1Response; import com.festago.festival.dto.QSchoolV1Response; +import java.time.LocalDate; import java.util.List; import org.springframework.stereotype.Repository; @@ -24,7 +25,7 @@ public PopularFestivalV1QueryDslRepository() { /** * 아직 명확한 추천 축제 기준이 없으므로 생성 시간(식별자) 내림차순으로 반환하도록 함 */ - public List findPopularFestivals() { + public List findPopularFestivals(LocalDate now) { return select(new QFestivalV1Response( festival.id, festival.name, @@ -38,6 +39,8 @@ public List findPopularFestivals() { festivalQueryInfo.artistInfo) ) .from(festival) + .where(festivalQueryInfo.artistInfo.ne("[]") + .and(festival.festivalDuration.endDate.goe(now))) .innerJoin(school).on(school.id.eq(festival.school.id)) .innerJoin(festivalQueryInfo).on(festivalQueryInfo.festivalId.eq(festival.id)) .orderBy(festival.id.desc()) diff --git a/backend/src/test/java/com/festago/festival/application/integration/query/PopularFestivalV1QueryServiceIntegrationTest.java b/backend/src/test/java/com/festago/festival/application/integration/query/PopularFestivalV1QueryServiceIntegrationTest.java index e19c11fe6..77f5526dc 100644 --- a/backend/src/test/java/com/festago/festival/application/integration/query/PopularFestivalV1QueryServiceIntegrationTest.java +++ b/backend/src/test/java/com/festago/festival/application/integration/query/PopularFestivalV1QueryServiceIntegrationTest.java @@ -13,6 +13,7 @@ import com.festago.support.fixture.FestivalFixture; import com.festago.support.fixture.FestivalQueryInfoFixture; import com.festago.support.fixture.SchoolFixture; +import java.time.LocalDate; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; @@ -27,13 +28,13 @@ class PopularFestivalV1QueryServiceIntegrationTest extends ApplicationIntegratio PopularFestivalV1QueryService popularQueryService; @Autowired - FestivalRepository festivalRepository; + SchoolRepository schoolRepository; @Autowired - FestivalInfoRepository festivalInfoRepository; + FestivalRepository festivalRepository; @Autowired - SchoolRepository schoolRepository; + FestivalInfoRepository festivalInfoRepository; School 대학교; @@ -45,29 +46,64 @@ class PopularFestivalV1QueryServiceIntegrationTest extends ApplicationIntegratio Festival 여섯번째로_저장된_축제; Festival 일곱번째로_저장된_축제; Festival 여덟번째로_저장된_축제; + Festival 아홉번째로_저장된_공연없는_축제; + Festival 열번째로_저장된_공연없는_축제; + Festival 열한번쨰로_저장된_기간이_지난_축제; @BeforeEach void setUp() { 대학교 = schoolRepository.save(SchoolFixture.builder().build()); - 첫번째로_저장된_축제 = createFestival(); - 두번째로_저장된_축제 = createFestival(); - 세번째로_저장된_축제 = createFestival(); - 네번째로_저장된_축제 = createFestival(); - 다섯번째로_저장된_축제 = createFestival(); - 여섯번째로_저장된_축제 = createFestival(); - 일곱번째로_저장된_축제 = createFestival(); - 여덟번째로_저장된_축제 = createFestival(); + LocalDate startDate = LocalDate.now();; + LocalDate endDate = startDate.plusDays(3); + + 첫번째로_저장된_축제 = createFestivalWithFilledFestivalInfo(startDate, endDate); + 두번째로_저장된_축제 = createFestivalWithFilledFestivalInfo(startDate, endDate); + 세번째로_저장된_축제 = createFestivalWithFilledFestivalInfo(startDate, endDate); + 네번째로_저장된_축제 = createFestivalWithFilledFestivalInfo(startDate, endDate); + 다섯번째로_저장된_축제 = createFestivalWithFilledFestivalInfo(startDate, endDate); + 여섯번째로_저장된_축제 = createFestivalWithFilledFestivalInfo(startDate, endDate); + 일곱번째로_저장된_축제 = createFestivalWithFilledFestivalInfo(startDate, endDate); + 여덟번째로_저장된_축제 = createFestivalWithFilledFestivalInfo(startDate, endDate); + 아홉번째로_저장된_공연없는_축제 = createFestivalWithEmptyFestivalInfo(startDate, endDate); + 열번째로_저장된_공연없는_축제 = createFestivalWithEmptyFestivalInfo(startDate, endDate); + 열한번쨰로_저장된_기간이_지난_축제 = createFestivalWithFilledFestivalInfo(startDate.minusDays(10L), endDate.minusDays(13L)); + } + + private Festival createFestivalWithFilledFestivalInfo(LocalDate startDate, LocalDate endDate) { + Festival festival = festivalRepository.save(makeBaseFestivalFixture(startDate, endDate)); + festivalInfoRepository.save(makeBaseFestivalInfoFixture(festival) + .artistInfo(""" + { + notEmpty + } + """) + .build()); + return festival; + } + + private Festival makeBaseFestivalFixture(LocalDate startDate, LocalDate endDate) { + return FestivalFixture.builder() + .school(대학교) + .startDate(startDate) + .endDate(endDate) + .build(); } - private Festival createFestival() { - Festival festival = festivalRepository.save(FestivalFixture.builder().school(대학교).build()); - festivalInfoRepository.save(FestivalQueryInfoFixture.builder().festivalId(festival.getId()).build()); + private FestivalQueryInfoFixture makeBaseFestivalInfoFixture(Festival festival) { + return FestivalQueryInfoFixture.builder() + .festivalId(festival.getId()); + } + + private Festival createFestivalWithEmptyFestivalInfo(LocalDate startDate, LocalDate endDate) { + Festival festival = festivalRepository.save(makeBaseFestivalFixture(startDate, endDate)); + festivalInfoRepository.save(makeBaseFestivalInfoFixture(festival) + .build()); return festival; } @Test - void 인기_축제는_7개까지_반환되고_식별자의_내림차순으로_정렬되어_조회된다() { + void 인기_축제는_공연이등록된_축제중_7개까지_반환되고_식별자의_내림차순으로_정렬되어_조회된다() { // when var expect = popularQueryService.findPopularFestivals().content(); @@ -84,4 +120,17 @@ private Festival createFestival() { 두번째로_저장된_축제.getId() ); } + + @Test + void 축제_기간이_끝난_축제는_반환되지_않는다() { + // when + var expect = popularQueryService.findPopularFestivals().content(); + + // then + assertThat(expect) + .map(FestivalV1Response::id) + .doesNotContain( + 열한번쨰로_저장된_기간이_지난_축제.getId() + ); + } } diff --git a/backend/src/test/java/com/festago/support/fixture/FestivalQueryInfoFixture.java b/backend/src/test/java/com/festago/support/fixture/FestivalQueryInfoFixture.java index b1b730cc0..526e908e4 100644 --- a/backend/src/test/java/com/festago/support/fixture/FestivalQueryInfoFixture.java +++ b/backend/src/test/java/com/festago/support/fixture/FestivalQueryInfoFixture.java @@ -6,7 +6,7 @@ public class FestivalQueryInfoFixture extends BaseFixture { private Long festivalId; - private String artistInfo = ""; + private String artistInfo = "[]"; private FestivalQueryInfoFixture() { }