From 973fe1ad900d9c386132b57d9de3ac704a3b4796 Mon Sep 17 00:00:00 2001 From: Creamcheesepie Date: Tue, 16 Dec 2025 20:37:05 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=EC=98=A4=EB=A5=98=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=20=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/concert/ConcertLikeResponse.java | 1 - .../concert/ConcertTicketTimeSetRequest.java | 3 +++ .../dto/concert/ConcertUpdateRequest.java | 10 ++++++++ .../repository/TicketOfficeRepository.java | 2 ++ .../concerts/service/ConcertService.java | 25 +++++++++++-------- .../concerts/service/KopisApiService.java | 5 ++++ .../global/error/code/ConcertErrorCode.java | 7 ++++-- 7 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertLikeResponse.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertLikeResponse.java index 7e7b0e96..b535d9eb 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertLikeResponse.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertLikeResponse.java @@ -1,7 +1,6 @@ package com.back.web7_9_codecrete_be.domain.concerts.dto.concert; import com.back.web7_9_codecrete_be.domain.concerts.entity.Concert; -import com.back.web7_9_codecrete_be.domain.concerts.entity.ConcertLike; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertTicketTimeSetRequest.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertTicketTimeSetRequest.java index 73d2e7fd..6b671696 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertTicketTimeSetRequest.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertTicketTimeSetRequest.java @@ -1,6 +1,7 @@ package com.back.web7_9_codecrete_be.domain.concerts.dto.concert; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; import lombok.Getter; import java.time.LocalDateTime; @@ -8,8 +9,10 @@ @Getter public class ConcertTicketTimeSetRequest { @Schema(description = "공연 ID 입니다.") + @NotEmpty private Long concertId; @Schema(description = "티켓팅 시간입니다.") + @NotEmpty private LocalDateTime ticketTime; } diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertUpdateRequest.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertUpdateRequest.java index 3f016745..503d112b 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertUpdateRequest.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertUpdateRequest.java @@ -1,6 +1,7 @@ package com.back.web7_9_codecrete_be.domain.concerts.dto.concert; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; import lombok.Getter; import java.time.LocalDate; @@ -8,29 +9,38 @@ @Getter public class ConcertUpdateRequest { @Schema(description = "수정할 대상이 될 공연 ID 입니다.") + @NotEmpty private Long concertId; @Schema(description = "공연 이름입니다.") + @NotEmpty private String name; @Schema(description = "공연 설명입니다.") + @NotEmpty private String description; @Schema(description = "공연장 ID 입니다.") + @NotEmpty private Long placeId; @Schema(description = "공연 시작 날짜입니다.") + @NotEmpty private LocalDate StartDate; @Schema(description = "공연 종료 날짜입니다.") + @NotEmpty private LocalDate EndDate; @Schema(description = "공연 포스터 URL 입니다.") + @NotEmpty private String posterUrl; @Schema(description = "공연 티켓 최고가입니다.") + @NotEmpty private int maxPrice; @Schema(description = "공연 티켓 최저가입니다.") + @NotEmpty private int minPrice; } diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/repository/TicketOfficeRepository.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/repository/TicketOfficeRepository.java index 198e58d0..378c465b 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/repository/TicketOfficeRepository.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/repository/TicketOfficeRepository.java @@ -27,4 +27,6 @@ public interface TicketOfficeRepository extends JpaRepository getTicketOfficesByConcert_ConcertId(Long concertConcertId); } diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/service/ConcertService.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/service/ConcertService.java index 45c0d197..9e677b50 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/service/ConcertService.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/service/ConcertService.java @@ -48,9 +48,8 @@ public List getNoTicketTimeConcertsList(Pageable pageable) { public List getConcertListByKeyword(String keyword, Pageable pageable) { if(keyword == null || keyword.isEmpty()){ - + throw new BusinessException(ConcertErrorCode.KEYWORD_IS_NULL); } - return concertRepository.getConcertItemsByKeyword(keyword, pageable); } @@ -81,8 +80,7 @@ public List getConcertsList2(Pageable pageable) { */ public List getTicketOfficesList(long concertId) { - Concert concert = new Concert(concertId); - List ticketOffices = ticketOfficeRepository.getTicketOfficesByConcert(concert); + List ticketOffices = ticketOfficeRepository.getTicketOfficesByConcert_ConcertId(concertId); List ticketOfficeList = new ArrayList<>(); for (TicketOffice ticketOffice : ticketOffices) { ticketOfficeList.add(new TicketOfficeElement(ticketOffice)); @@ -92,7 +90,7 @@ public List getTicketOfficesList(long concertId) { } public ConcertLikeResponse isLikeConcert(Long concertId, User user) { - Concert concert = concertRepository.getConcertByConcertId(concertId); + Concert concert = findConcertByConcertId(concertId); ConcertLikeResponse concertLikeResponse; if(concertLikeRepository.existsConcertLikeByConcertAndUser(concert,user)){ concertLikeResponse = new ConcertLikeResponse(concert,true); @@ -105,7 +103,8 @@ public ConcertLikeResponse isLikeConcert(Long concertId, User user) { @Transactional public void likeConcert(long concertId, User user) { - Concert concert = concertRepository.findById(concertId).orElseThrow(); + Concert concert = findConcertByConcertId(concertId); + if(concertLikeRepository.existsConcertLikeByConcertAndUser(concert,user)){ throw new BusinessException(ConcertErrorCode.LIKE_CONFLICT); } @@ -116,7 +115,8 @@ public void likeConcert(long concertId, User user) { @Transactional public void dislikeConcert(long concertId, User user) { - Concert concert = concertRepository.findById(concertId).orElseThrow(); + Concert concert = findConcertByConcertId(concertId); + ConcertLike concertLike = concertLikeRepository.findConcertLikeByConcertAndUser(concert, user); if(concertLike == null){ throw new BusinessException(ConcertErrorCode.NOT_FOUND_CONCERTLIKE); @@ -126,7 +126,7 @@ public void dislikeConcert(long concertId, User user) { } public ConcertItem updateConcert(long concertId, ConcertUpdateRequest concertUpdateRequest) { - Concert concert = concertRepository.findById(concertId).orElseThrow(); + Concert concert = findConcertByConcertId(concertId); ConcertPlace concertPlace = concertPlaceRepository.findById(concertUpdateRequest.getPlaceId()).orElseThrow(); concert.update(concertUpdateRequest, concertPlace); Concert updatedConcert = concertRepository.save(concert); @@ -134,15 +134,20 @@ public ConcertItem updateConcert(long concertId, ConcertUpdateRequest concertUpd } public ConcertDetailResponse setConcertTime(ConcertTicketTimeSetRequest concertTicketTimeSetRequest) { - Concert concert = concertRepository.findById(concertTicketTimeSetRequest.getConcertId()).orElseThrow(); + Concert concert = findConcertByConcertId(concertTicketTimeSetRequest.getConcertId()); concert.ticketTimeSet(concertTicketTimeSetRequest.getTicketTime()); Concert savedConcert = concertRepository.save(concert); return concertRepository.getConcertDetailById(savedConcert.getConcertId()); } public void deleteConcert(long concertId) { - Concert concert = concertRepository.findById(concertId).orElseThrow(); concertRepository.deleteById(concertId); } + private Concert findConcertByConcertId(long concertId) { + return concertRepository.findById(concertId).orElseThrow( + () -> new BusinessException(ConcertErrorCode.CONCERT_NOT_FOUND) + ); + } + } diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/service/KopisApiService.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/service/KopisApiService.java index 8cffc768..eda55046 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/service/KopisApiService.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/service/KopisApiService.java @@ -20,6 +20,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashMap; @@ -64,6 +65,7 @@ public KopisApiService(ConcertRepository concertRepository, ConcertPlaceReposito public SetResultResponse setConcertsList() throws InterruptedException { // 최초 시작 시간 저장 LocalDateTime now = LocalDateTime.now(); + Long startNs = System.currentTimeMillis(); // 콘서트 목록 받아올 Response 객체 선언 ConcertListResponse plr; @@ -145,6 +147,9 @@ public SetResultResponse setConcertsList() throws InterruptedException { ConcertUpdateTime concertUpdateTime = new ConcertUpdateTime(now); concertUpdateTimeRepository.save(concertUpdateTime); log.info(now + "시 기준 " + totalConcertsList.size() + "개의 공연 데이터 저장 완료!"); + long endNs = System.currentTimeMillis(); + long durationSec = ((endNs - startNs) / 1000); + log.info(durationSec/60 + "분, " + durationSec % 60 + "초 소요되었습니다." ); return new SetResultResponse(addedConcerts,0,addedConcertPlaces,0,addedConcertImages,0,addedTicketOffices,0); } diff --git a/src/main/java/com/back/web7_9_codecrete_be/global/error/code/ConcertErrorCode.java b/src/main/java/com/back/web7_9_codecrete_be/global/error/code/ConcertErrorCode.java index 01b7bd8c..fb467962 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/global/error/code/ConcertErrorCode.java +++ b/src/main/java/com/back/web7_9_codecrete_be/global/error/code/ConcertErrorCode.java @@ -8,8 +8,11 @@ @RequiredArgsConstructor public enum ConcertErrorCode implements ErrorCode { - LIKE_CONFLICT(HttpStatus.CONFLICT,"C131","이미 좋아요를 누른 공연입니다."), - NOT_FOUND_CONCERTLIKE(HttpStatus.NOT_FOUND,"C130","좋아요를 누르지 않은 공연입니다.") + // C-10* 공연 탐색 관련 + CONCERT_NOT_FOUND(HttpStatus.NOT_FOUND,"C-101","공연을 찾을 수 없습니다."), + KEYWORD_IS_NULL(HttpStatus.BAD_REQUEST,"C-102","검색 키워드를 입력해주세요."), + LIKE_CONFLICT(HttpStatus.CONFLICT,"C-131","이미 좋아요를 누른 공연입니다."), + NOT_FOUND_CONCERTLIKE(HttpStatus.NOT_FOUND,"C-130","좋아요를 누르지 않은 공연입니다.") ; private final HttpStatus status; From d74babf980627c0a93f8f4ee4a817292512140bf Mon Sep 17 00:00:00 2001 From: Creamcheesepie Date: Wed, 17 Dec 2025 11:30:18 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=EA=B3=B5=EC=97=B0=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EC=A4=80=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80,=20=EA=B3=B5=EC=97=B0=20=EB=AA=A9=EB=A1=9D?= =?UTF-8?q?=20=EC=A1=B0=ED=9A=8C=EB=A5=BC=20=ED=95=98=EB=82=98=EC=9D=98=20?= =?UTF-8?q?API=EC=97=90=EC=84=9C=20PathVariable=20=EB=B6=84=EA=B8=B0=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=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 --- .../controller/ConcertController.java | 60 +++++----- .../domain/concerts/dto/concert/ListSort.java | 9 ++ .../repository/ConcertRepository.java | 107 +++++++++++++++++- .../concerts/service/ConcertService.java | 26 ++++- 4 files changed, 160 insertions(+), 42 deletions(-) create mode 100644 src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ListSort.java diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/controller/ConcertController.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/controller/ConcertController.java index ef185836..4268d4ed 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/controller/ConcertController.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/controller/ConcertController.java @@ -5,6 +5,7 @@ import com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertDetailResponse; import com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertItem; import com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertLikeResponse; +import com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ListSort; import com.back.web7_9_codecrete_be.domain.concerts.dto.ticketOffice.TicketOfficeElement; import com.back.web7_9_codecrete_be.domain.concerts.entity.TicketOffice; import com.back.web7_9_codecrete_be.domain.concerts.service.ConcertService; @@ -37,42 +38,39 @@ public class ConcertController { private final ConcertService concertService; private final Rq rq; - @Operation(summary = "공연목록", description = "공연 전체 목록을 조회합니다. 시작일자를 기준으로 오름차순 조회합니다.") - @GetMapping("list") - public RsData> getList ( + @Operation(summary = "공연목록", + description = """ +

공연 전체 목록을 조회하는 통합 API입니다.

+
+ 다양한 조회 기준에 따라 공연 목록을 조회합니다.
+ """) + @GetMapping("list/{sort}") + public RsData> getList( + @Schema(description = """ +

리스트를 받아올 기준이 될 경로 변수입니다. 대문자로 예시에 있는 것만 사용해 주세요.

+
+ LIKE : 좋아요 순
+ VIEW : 조회수 순
+ TICKETING : 오늘을 기준으로 다가오는 티켓팅 날짜 순
+ UPCOMING : 오늘을 기준으로 다가오는 공연 시작 날짜 순
+ REGISTERED : 가장 최근에 API에 등록된 공연 순
+
+ """, examples = {"LIKE", "VIEW", "TICKETING", "UPCOMING", "REGISTERED"}) + @PathVariable ListSort sort, @Schema(description = "페이징 처리 또는 무한 스크롤 구현에 쓸 Pageable 객체입니다.") Pageable pageable ) { - return RsData.success(concertService.getConcertsList(pageable)); - } - - @Operation(summary = "다가오는 공연 목록", description = "오늘을 기준으로 다가오는 공연 목록을 조회합니다.") - @GetMapping("upComingList") - public RsData> getUpComingList ( - @Schema(description = "페이징 처리 또는 무한 스크롤 구현에 쓸 Pageable 객체입니다.") - Pageable pageable - ) { - return RsData.success(concertService.getUpcomingConcertsList(pageable)); - } - - // todo: 내용 구현 필요 - @Operation(summary = "공연 예매일 기준 조회(구현 전)", description = "현 시간을 기준으로 예매시간을 내림차순으로 출력하는 공연 목록을 조회합니다.") - @GetMapping("upComingTicketingList") - public RsData> getUpComingTicketingList ( - @Schema(description = "페이징 처리 또는 무한 스크롤 구현에 사용할 Pageable 객체입니다.") - Pageable pageable - ){ - return null; + return RsData.success(concertService.getConcertsList(pageable, sort)); } @Operation(summary = "좋아요 한 공연 조회", description = "좋아요를 누른 공연에 대한 목록을 조회합니다. 저장 날짜를 기준으로 내림차순 정렬로 표시합니다.(최신으로 추가된 목록순입니다.)") @GetMapping("likedConcertList") - public RsData> getLikedConcertList ( + public RsData> getLikedConcertList( @Schema(description = "페이징 처리 또는 무한 스크롤 구현에 쓸 Pageable 객체입니다.") Pageable pageable - ){ + ) { User user = rq.getUser(); - return RsData.success(concertService.getLikedConcertsList(pageable,user)); + return RsData.success(concertService.getLikedConcertsList(pageable, user)); } @Operation(summary = "공연 상세 조회", description = "공연에 대한 상세 목록을 조회합니다.") @@ -87,11 +85,11 @@ public ConcertDetailResponse getConcertDetail( @Operation(summary = "공연 예매처 조회", description = "공연에 대한 예매처들을 조회합니다.") @GetMapping("ticketOffices") - public RsData> getTicketOffices ( + public RsData> getTicketOffices( @RequestParam @Schema(description = "조회 기준이 되는 concertId입니다. ?concertId={concertId} 로 값을 넘기시면 됩니다.") long concertId - ){ + ) { return RsData.success(concertService.getTicketOfficesList(concertId)); } @@ -119,7 +117,7 @@ public RsData dislikeConcert( @GetMapping("isLike/{concertId}") public RsData isLikeConcert( @PathVariable long concertId - ){ + ) { User user = rq.getUser(); return RsData.success(concertService.isLikeConcert(concertId, user)); } @@ -133,8 +131,8 @@ public RsData> searchConcert( @Schema(description = "페이징 처리 또는 무한 스크롤 구현에 쓸 Pageable 객체입니다.") Pageable pageable - ){ - return RsData.success(concertService.getConcertListByKeyword(keyword,pageable)); + ) { + return RsData.success(concertService.getConcertListByKeyword(keyword, pageable)); } } diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ListSort.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ListSort.java new file mode 100644 index 00000000..ddaa7d5a --- /dev/null +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ListSort.java @@ -0,0 +1,9 @@ +package com.back.web7_9_codecrete_be.domain.concerts.dto.concert; + +public enum ListSort { + LIKE, + VIEW, + TICKETING, + UPCOMING, + REGISTERED; +} diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/repository/ConcertRepository.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/repository/ConcertRepository.java index 3d56dcc8..b5b815d6 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/repository/ConcertRepository.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/repository/ConcertRepository.java @@ -3,11 +3,6 @@ import com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertDetailResponse; import com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertItem; import com.back.web7_9_codecrete_be.domain.concerts.entity.Concert; -import com.back.web7_9_codecrete_be.domain.concerts.entity.ConcertPlace; -import com.back.web7_9_codecrete_be.domain.concerts.entity.ConcertTime; -import com.back.web7_9_codecrete_be.domain.users.entity.User; -import jakarta.persistence.ManyToOne; -import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; @@ -16,6 +11,7 @@ import org.springframework.stereotype.Repository; import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.List; @Repository @@ -42,6 +38,75 @@ public interface ConcertRepository extends JpaRepository { """) List getConcertItems(Pageable pageable); + @Query(""" + SELECT + new com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertItem( + c.concertId as id, + c.name as name, + c.concertPlace.placeName as placeName, + c.ticketTime as ticketTime, + c.startDate as startDate, + c.endDate as endDate, + c.posterUrl as posterUrl, + c.maxPrice as maxPrice, + c.minPrice as minPrice, + c.viewCount as viewCount, + c.likeCount as likeCount + ) + FROM + Concert c + ORDER BY + c.apiConcertId +""") + List getConcertItemsOrderByApiId(Pageable pageable); + + @Query(""" + SELECT + new com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertItem( + c.concertId as id, + c.name as name, + c.concertPlace.placeName as placeName, + c.ticketTime as ticketTime, + c.startDate as startDate, + c.endDate as endDate, + c.posterUrl as posterUrl, + c.maxPrice as maxPrice, + c.minPrice as minPrice, + c.viewCount as viewCount, + c.likeCount as likeCount + ) + FROM + Concert c + ORDER BY + c.viewCount + DESC +""") + List getConcertItemsOrderByViewCountDesc(Pageable pageable); + + @Query(""" + SELECT + new com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertItem( + c.concertId as id, + c.name as name, + c.concertPlace.placeName as placeName, + c.ticketTime as ticketTime, + c.startDate as startDate, + c.endDate as endDate, + c.posterUrl as posterUrl, + c.maxPrice as maxPrice, + c.minPrice as minPrice, + c.viewCount as viewCount, + c.likeCount as likeCount + ) + FROM + Concert c + ORDER BY + c.likeCount + desc +""") + List getConcertItemsOrderByLikeCountDesc(Pageable pageable); + + @Query(""" SELECT new com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertItem( @@ -65,11 +130,41 @@ public interface ConcertRepository extends JpaRepository { c.startDate asc """) - List getUpComingConcertItems( + List getUpComingConcertItemsFromDateASC( Pageable pageable, @Param("fromDate") LocalDate fromDate ); + @Query(""" + SELECT + new com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertItem( + c.concertId as id, + c.name as name, + c.concertPlace.placeName as placeName, + c.ticketTime as ticketTime, + c.startDate as startDate, + c.endDate as endDate, + c.posterUrl as posterUrl, + c.maxPrice as maxPrice, + c.minPrice as minPrice, + c.viewCount as viewCount, + c.likeCount as likeCount + ) + FROM + Concert c + WHERE + c.ticketTime >= :fromDate + AND + c.ticketTime IS NOT NULL + ORDER BY + c.ticketTime + asc +""") + List getUpComingTicketingConcertItemsFromDateASC( + Pageable pageable, + @Param("fromDate") LocalDateTime fromDate + ); + @Query(""" SELECT new com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertItem( diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/service/ConcertService.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/service/ConcertService.java index 9e677b50..84f754c2 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/service/ConcertService.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/service/ConcertService.java @@ -13,6 +13,8 @@ import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; import java.util.ArrayList; import java.util.List; @@ -30,12 +32,26 @@ public class ConcertService { private final ConcertImageRepository concertImageRepository; - public List getConcertsList(Pageable pageable) { - return concertRepository.getConcertItems(pageable); - } + public List getConcertsList(Pageable pageable, ListSort sort) { + switch (sort) { + case LIKE -> { + return concertRepository.getConcertItemsOrderByLikeCountDesc(pageable); + } + case VIEW -> { + return concertRepository.getConcertItemsOrderByViewCountDesc(pageable); + } + case TICKETING -> { + return concertRepository.getUpComingTicketingConcertItemsFromDateASC(pageable, LocalDateTime.of(LocalDate.now(), LocalTime.MIN)); + } + case UPCOMING -> { + return concertRepository.getUpComingConcertItemsFromDateASC(pageable,LocalDate.now()); + } + case REGISTERED -> { + return concertRepository.getConcertItemsOrderByApiId(pageable); + } + } - public List getUpcomingConcertsList(Pageable pageable) { - return concertRepository.getUpComingConcertItems(pageable, LocalDate.now()); + return concertRepository.getConcertItems(pageable); } public List getLikedConcertsList(Pageable pageable,User user) { From 89c0df0237e872776550dce92521d8393be71b3b Mon Sep 17 00:00:00 2001 From: Creamcheesepie Date: Wed, 17 Dec 2025 12:13:34 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat=20:=20=EC=8A=A4=EC=9B=A8=EA=B1=B0=20?= =?UTF-8?q?=EC=84=A4=EB=AA=85=20=EB=B3=B4=EA=B0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ConcertAdminController.java | 66 ++++++++++++++----- .../controller/ConcertController.java | 65 ++++++++++++++---- 2 files changed, 101 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/controller/ConcertAdminController.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/controller/ConcertAdminController.java index 8874a2c3..f20a1cab 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/controller/ConcertAdminController.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/controller/ConcertAdminController.java @@ -35,16 +35,27 @@ public RsData setConcert() throws InterruptedException { return RsData.success(kopisApiService.setConcertsList()); } - @Operation(summary = "공연 정보 갱신",description = "공연 정보를 직접 갱신합니다.") + @Operation(summary = "공연 정보 갱신", description = "공연 정보를 직접 갱신합니다.") @PatchMapping("updateConcert/{concertId}") public RsData updateConcert( - @Schema(description = "갱신 대상이 될 공연의 ID 값입니다.") - @PathVariable Long concertId, - @Schema(description = "갱신 내용입니다.") - @RequestBody ConcertUpdateRequest concertUpdateRequest - ){ + @PathVariable + @Schema(description = """ +

갱신 대상이 될 공연의 concertId입니다.

+
+ DB에 저장되어 있는 공연의 ID 값입니다.
+ /updateConcert/{concertId} 형태로 요청하면 됩니다. + """) + Long concertId, + @RequestBody + @Schema(description = """ +

공연 갱신 요청 정보입니다.

+
+ 공연의 제목, 설명 등 수정이 필요한 정보들을 전달합니다. + """) + ConcertUpdateRequest concertUpdateRequest + ) { ConcertItem concertItem = concertService.updateConcert(concertId, concertUpdateRequest); - return RsData.success("공연 정보 수정이 완료되었습니다.",concertItem); + return RsData.success("공연 정보 수정이 완료되었습니다.", concertItem); } @Operation(summary = "예매 시간이 없는 공연 목록 조회", description = "예매 시간이 없는 공연들을 공연시간 내림차순으로 출력합니다.") @@ -58,25 +69,46 @@ public List getNoTicketTimeConcertsList( @Operation(summary = "공연을 삭제합니다.", description = "해당 공연을 삭제합니다.") @DeleteMapping("deleteConcert/{concertId}") - public RsData deleteConcert(@PathVariable Long concertId){ + public RsData deleteConcert( + @PathVariable + @Schema(description = """ +

삭제 대상이 될 공연의 concertId입니다.

+
+ DB에 저장되어 있는 공연의 ID 값입니다.
+ /deleteConcert/{concertId} 형태로 요청하면 됩니다. + """) + Long concertId + ) { concertService.deleteConcert(concertId); - return RsData.success("공연 정보 삭제에 성공하였습니다.",null); + return RsData.success("공연 정보 삭제에 성공하였습니다.", null); } - @Operation(summary = "예매 시간 등록",description = "개별 공연에 대한 예매 시간을 설정합니다.") + @Operation(summary = "예매 시간 등록", description = "개별 공연에 대한 예매 시간을 설정합니다.") @PatchMapping("ticketTimeSet") - public RsData ticketTimeSet( - @RequestBody ConcertTicketTimeSetRequest concertTicketTimeSetRequest - ){ + public RsData ticketTimeSet( + @RequestBody + @Schema(description = """ +

공연 예매 시간 설정 정보입니다.

+
+ 공연 ID와 예매 시작 시간 정보를 전달합니다. + """) + ConcertTicketTimeSetRequest concertTicketTimeSetRequest + ) { return RsData.success(concertService.setConcertTime(concertTicketTimeSetRequest)); } - @Operation(summary = "개별 공연 API통한 갱신",description = "개별 공연에 대해서 공연 예술 통합망(Kopis)을 통해 데이터를 조회하고 해당 데이터를 갱신합니다.") + @Operation(summary = "개별 공연 API통한 갱신", description = "개별 공연에 대해서 공연 예술 통합망(Kopis)을 통해 데이터를 조회하고 해당 데이터를 갱신합니다.") @PatchMapping("updateConcertByKopisAPI/{concertId}") public RsData updateConcertByKopisAPI( - @Schema(description = "갱신 대상이 될 공연의 ID 값입니다.") - @PathVariable Long concertId - ){ + @PathVariable + @Schema(description = """ +

갱신 대상이 될 공연의 concertId입니다.

+
+ DB에 저장되어 있는 공연의 ID 값입니다.
+ /updateConcertByKopisAPI/{concertId} 형태로 요청하면 됩니다. + """) + Long concertId + ) { kopisApiService.concertUpdateByKopisApi(concertId); return RsData.success(concertService.getConcertDetail(concertId)); } diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/controller/ConcertController.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/controller/ConcertController.java index 4268d4ed..35488a22 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/controller/ConcertController.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/controller/ConcertController.java @@ -47,17 +47,20 @@ public class ConcertController { @GetMapping("list/{sort}") public RsData> getList( @Schema(description = """ -

리스트를 받아올 기준이 될 경로 변수입니다. 대문자로 예시에 있는 것만 사용해 주세요.

+

리스트를 받아올 기준이 될 경로 변수입니다. 대문자로 예시에 있는 것만 사용해 주세요.


- LIKE : 좋아요 순
- VIEW : 조회수 순
- TICKETING : 오늘을 기준으로 다가오는 티켓팅 날짜 순
- UPCOMING : 오늘을 기준으로 다가오는 공연 시작 날짜 순
- REGISTERED : 가장 최근에 API에 등록된 공연 순
+ LIKE : 좋아요 순
+ VIEW : 조회수 순
+ TICKETING : 오늘을 기준으로 다가오는 티켓팅 날짜 순
+ UPCOMING : 오늘을 기준으로 다가오는 공연 시작 날짜 순
+ REGISTERED : 가장 최근에 API에 등록된 공연 순

""", examples = {"LIKE", "VIEW", "TICKETING", "UPCOMING", "REGISTERED"}) @PathVariable ListSort sort, - @Schema(description = "페이징 처리 또는 무한 스크롤 구현에 쓸 Pageable 객체입니다.") + @Schema(description = """ + 페이징 처리 또는 무한 스크롤 구현에 쓸 Pageable 객체입니다.
+ sort 부분은 사용하지 않으니 지워주시고 "page", "size" 만 넘겨주시면 됩니다. *sort 부분이 남아있으면 오류가 발생합니다. + """) Pageable pageable ) { return RsData.success(concertService.getConcertsList(pageable, sort)); @@ -77,7 +80,12 @@ public RsData> getLikedConcertList( @GetMapping("concertDetail") public ConcertDetailResponse getConcertDetail( @RequestParam - @Schema(description = "조회 기준이 되는 concertId입니다. ?concertId={concertId} 로 값을 넘기시면 됩니다.") + @Schema(description = """ +

조회 기준이 되는 concertId입니다.

+
+ DB에 저장되어 있는 공연의 ID 값을 기준으로 조회합니다.
+ ?concertId={concertId} 로 값을 넘기시면 됩니다. + """) long concertId ) { return concertService.getConcertDetail(concertId); @@ -87,7 +95,12 @@ public ConcertDetailResponse getConcertDetail( @GetMapping("ticketOffices") public RsData> getTicketOffices( @RequestParam - @Schema(description = "조회 기준이 되는 concertId입니다. ?concertId={concertId} 로 값을 넘기시면 됩니다.") + @Schema(description = """ +

조회 기준이 되는 concertId입니다.

+
+ DB에 저장되어 있는 공연의 ID 값을 기준으로 조회합니다.
+ ?concertId={concertId} 로 값을 넘기시면 됩니다. + """) long concertId ) { return RsData.success(concertService.getTicketOfficesList(concertId)); @@ -96,7 +109,14 @@ public RsData> getTicketOffices( @Operation(summary = "공연 좋아요 기능", description = "사용자가 마음에 드는 공연에 대해 좋아요를 통해 저장할 수 있습니다.") @PostMapping("like/{concertId}") public RsData likeConcert( - @PathVariable long concertId + @PathVariable + @Schema(description = """ +

좋아요를 누를 공연의 concertId입니다.

+
+ DB에 저장되어 있는 공연의 ID 값입니다.
+ /like/{concertId} 형태로 요청하면 해당 공연에 좋아요가 등록됩니다. + """) + long concertId ) { User user = rq.getUser(); concertService.likeConcert(concertId, user); @@ -106,7 +126,14 @@ public RsData likeConcert( @Operation(summary = "공연 좋아요 해제 기능", description = "좋아요를 해제할 수 있습니다.") @DeleteMapping("dislike/{concertId}") public RsData dislikeConcert( - @PathVariable long concertId + @PathVariable + @Schema(description = """ +

좋아요를 해제할 공연의 concertId입니다.

+
+ DB에 저장되어 있는 공연의 ID 값입니다.
+ /dislike/{concertId} 형태로 요청하면 좋아요가 해제됩니다. + """) + long concertId ) { User user = rq.getUser(); concertService.dislikeConcert(concertId, user); @@ -116,7 +143,14 @@ public RsData dislikeConcert( @Operation(summary = "공연 좋아요 여부 확인", description = "좋아요 여부를 확인합니다.") @GetMapping("isLike/{concertId}") public RsData isLikeConcert( - @PathVariable long concertId + @PathVariable + @Schema(description = """ +

좋아요 여부를 확인할 공연의 concertId입니다.

+
+ DB에 저장되어 있는 공연의 ID 값입니다.
+ /isLike/{concertId} 형태로 요청하면 좋아요 여부를 확인할 수 있습니다. + """) + long concertId ) { User user = rq.getUser(); return RsData.success(concertService.isLikeConcert(concertId, user)); @@ -126,7 +160,12 @@ public RsData isLikeConcert( @Operation(summary = "공연 검색", description = "제목에 키워드를 포함하고 있는 공연 정보를 검색합니다.") @GetMapping("search") public RsData> searchConcert( - @Schema(description = "공연 정보 검색 키워드입니다.") + @Schema(description = """ +

검색어가 되는 Keyword입니다.

+
+ ?keyword={keyword} 로 값을 넘기시면 됩니다.
+ DB에서 해당 문자열을 가지고 있는 모든 결과값을 반환합니다. + """) @RequestParam String keyword, @Schema(description = "페이징 처리 또는 무한 스크롤 구현에 쓸 Pageable 객체입니다.") Pageable pageable