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 6b1eeebf..ba55b07a 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 @@ -2,16 +2,21 @@ import com.back.web7_9_codecrete_be.domain.concerts.dto.KopisApiDto.concert.ConcertListResponse; import com.back.web7_9_codecrete_be.domain.concerts.dto.KopisApiDto.concertPlace.ConcertPlaceListResponse; +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.ConcertTicketTimeSetRequest; import com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertUpdateRequest; import com.back.web7_9_codecrete_be.domain.concerts.service.ConcertService; import com.back.web7_9_codecrete_be.domain.concerts.service.KopisApiService; import com.back.web7_9_codecrete_be.global.rsData.RsData; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; +import java.util.List; + @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/admin/concerts/") @@ -20,16 +25,12 @@ public class ConcertAdminController { // todo : 인증 권한 추가하기 private final ConcertService concertService; private final KopisApiService kopisApiService; - @GetMapping("tests") - public ConcertListResponse tests() { - return kopisApiService.getConcertsList(); - } - @GetMapping("totalGetTest") public ConcertListResponse totalGetTest() throws InterruptedException { return kopisApiService.setConcertsList(); } + @GetMapping("setConcertPlace") public ConcertPlaceListResponse setConcertPlace() throws InterruptedException { return kopisApiService.setConcertPlace(); @@ -44,9 +45,23 @@ public RsData updateConcert( return RsData.success("공연 정보 수정이 완료되었습니다.",concertItem); } + @GetMapping("noTicketTimeList") + public List getNoTicketTimeConcertsList( + Pageable pageable + ) { + return concertService.getNoTicketTimeConcertsList(pageable); + } + @DeleteMapping("deleteConcert/{concertId}") public RsData deleteConcert(@PathVariable Long concertId){ concertService.deleteConcert(concertId); return RsData.success("공연 정보 삭제에 성공하였습니다.",null); } + + @PatchMapping("ticketTimeSet") + public RsData ticketTimeSet( + @RequestBody ConcertTicketTimeSetRequest concertTicketTimeSetRequest + ){ + return RsData.success(concertService.setConcertTime(concertTicketTimeSetRequest)); + } } 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 b28084d8..71934c63 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 @@ -28,7 +28,6 @@ @RestController @RequestMapping("api/v1/concerts/") -@Controller @RequiredArgsConstructor @Tag(name = "Concerts", description = "공연에 대한 정보를 제공하는 API 입니다.") public class ConcertController { diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertDetailResponse.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertDetailResponse.java index 12168aa7..1a94ad4e 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertDetailResponse.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertDetailResponse.java @@ -4,10 +4,14 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.RequiredArgsConstructor; +import lombok.Setter; import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; @Getter +@Setter public class ConcertDetailResponse { @Schema(description = "콘서트 Id입니다.") @@ -22,6 +26,9 @@ public class ConcertDetailResponse { @Schema(description = "콘서트 장소 이름입니다.") private String placeName; + @Schema(description = "콘서트 예매 시작 날짜입니다.") + private LocalDateTime ticketTime; + @Schema(description = "콘서트 시작 날짜입니다.",format = "yyyy-MM-dd") private LocalDate startDate; @@ -43,4 +50,6 @@ public class ConcertDetailResponse { @Schema(description = "콘서트 좋아요수입니다.") private int likeCount; + @Schema(description = "콘서트 이미지 목록입니다.") + private List concertImageUrls; } diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertItem.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertItem.java index 446ffab3..a93bd3ca 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertItem.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertItem.java @@ -6,6 +6,7 @@ import lombok.Setter; import java.time.LocalDate; +import java.time.LocalDateTime; @Getter @Setter @@ -20,6 +21,9 @@ public class ConcertItem { @Schema(description = "콘서트 장소 이름입니다.") private String placeName; + @Schema(description = "콘서트 예매 시작 날짜입니다.") + private LocalDateTime ticketTime; + @Schema(description = "콘서트 시작 날짜입니다.",format = "yyyy-MM-dd") private LocalDate startDate ; @@ -45,6 +49,7 @@ public ConcertItem(Concert concert) { this.id = concert.getConcertId(); this.name = concert.getName(); this.placeName = concert.getConcertPlace().getPlaceName(); + this.ticketTime = concert.getTicketTime(); this.startDate = concert.getStartDate(); this.endDate =concert.getEndDate(); this.posterUrl = concert.getPosterUrl(); @@ -54,10 +59,11 @@ public ConcertItem(Concert concert) { this.likeCount = concert.getLikeCount(); } - public ConcertItem(long id, String name, String placeName, LocalDate startDate, LocalDate endDate, String posterUrl, int maxPrice, int minPrice, int viewCount, int likeCount) { + public ConcertItem(long id, String name, String placeName,LocalDateTime ticketTime, LocalDate startDate, LocalDate endDate, String posterUrl, int maxPrice, int minPrice, int viewCount, int likeCount) { this.id = id; this.name = name; this.placeName = placeName; + this.ticketTime = ticketTime; this.startDate = startDate; this.endDate = endDate; this.posterUrl = posterUrl; 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 new file mode 100644 index 00000000..b37178ab --- /dev/null +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/dto/concert/ConcertTicketTimeSetRequest.java @@ -0,0 +1,11 @@ +package com.back.web7_9_codecrete_be.domain.concerts.dto.concert; + +import lombok.Getter; + +import java.time.LocalDateTime; + +@Getter +public class ConcertTicketTimeSetRequest { + private Long concertId; + private LocalDateTime ticketTime; +} diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/entity/Concert.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/entity/Concert.java index 36733a36..d8644020 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/entity/Concert.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/entity/Concert.java @@ -4,6 +4,8 @@ import jakarta.persistence.*; import lombok.Getter; import lombok.RequiredArgsConstructor; +import org.hibernate.annotations.CreationTimestamp; +import org.springframework.data.annotation.LastModifiedDate; import java.time.LocalDate; import java.time.LocalDateTime; @@ -33,8 +35,8 @@ public class Concert { @Column(name = "end_date",nullable = false) private LocalDate endDate; - @Column(name = "ticket_time", nullable = false) - private String ticketTime; + @Column(name = "ticket_time", nullable = true) + private LocalDateTime ticketTime; @Column(name = "created_date", nullable = false) private LocalDateTime createdDate; @@ -60,7 +62,7 @@ public class Concert { - public Concert(ConcertPlace concertPlace, String name, String content, LocalDate startDate, LocalDate endDate, String ticketTime, int maxPrice, int minPrice, String posterUrl,String apiConcertId) { + public Concert(ConcertPlace concertPlace, String name, String content, LocalDate startDate, LocalDate endDate, LocalDateTime ticketTime, int maxPrice, int minPrice, String posterUrl,String apiConcertId) { this.concertPlace = concertPlace; this.name = name; this.content = content; @@ -81,7 +83,7 @@ public Concert(Long concertId) { this.concertId = concertId; } - public Concert update(ConcertPlace concertPlace, String content, String ticketTime, int maxPrice, int minPrice){ + public Concert update(ConcertPlace concertPlace, String content, LocalDateTime ticketTime, int maxPrice, int minPrice){ this.concertPlace = concertPlace; this.content = content; this.ticketTime = ticketTime; @@ -105,4 +107,9 @@ public Concert update(ConcertUpdateRequest concertUpdateRequest,ConcertPlace con return this; } + public Concert ticketTimeSet(LocalDateTime ticketTime){ + this.ticketTime = ticketTime; + return this; + } + } diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/entity/ConcertImage.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/entity/ConcertImage.java new file mode 100644 index 00000000..df2257a8 --- /dev/null +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/entity/ConcertImage.java @@ -0,0 +1,25 @@ +package com.back.web7_9_codecrete_be.domain.concerts.entity; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Entity +@NoArgsConstructor +public class ConcertImage { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @ManyToOne(fetch = FetchType.LAZY) + private Concert concert; + + @Column(name = "image_url") + private String imageUrl; + + public ConcertImage(Concert concert, String imageUrl) { + this.concert = concert; + this.imageUrl = imageUrl; + } +} diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/entity/ConcertLike.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/entity/ConcertLike.java index 0d37d309..426c5106 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/entity/ConcertLike.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/entity/ConcertLike.java @@ -25,7 +25,7 @@ public class ConcertLike { private User user; @CreationTimestamp - private LocalDateTime createdAt; + private LocalDateTime createDate; public ConcertLike(Concert concert, User user) { this.concert = concert; diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/repository/ConcertImageRepository.java b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/repository/ConcertImageRepository.java new file mode 100644 index 00000000..e4790e3f --- /dev/null +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/concerts/repository/ConcertImageRepository.java @@ -0,0 +1,12 @@ +package com.back.web7_9_codecrete_be.domain.concerts.repository; + +import com.back.web7_9_codecrete_be.domain.concerts.entity.ConcertImage; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ConcertImageRepository extends JpaRepository { + List getConcertImagesByConcert_ConcertId(Long concertConcertId); +} 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 66c48830..94c07379 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 @@ -26,6 +26,7 @@ public interface ConcertRepository extends JpaRepository { 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, @@ -45,6 +46,7 @@ public interface ConcertRepository extends JpaRepository { 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, @@ -66,12 +68,40 @@ List getUpComingConcertItems( @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 IS NULL + ORDER BY + c.startDate + DESC +""") + List getNoTicketTimeConcertList( + 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, @@ -88,7 +118,7 @@ List getUpComingConcertItems( AND cl.user.id = :userId ORDER BY - cl.createdAt + cl.createDate DESC """ ) @@ -102,6 +132,7 @@ List getLikedConcertsList(Pageable pageable, c.name as name, c.content as description, c.concertPlace.placeName as placeName, + c.ticketTime as ticketTime, c.startDate as startDate, c.endDate as endDate, c.posterUrl as posterUrl, 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 b740f304..d3417480 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 @@ -1,18 +1,9 @@ package com.back.web7_9_codecrete_be.domain.concerts.service; -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.ConcertUpdateRequest; +import com.back.web7_9_codecrete_be.domain.concerts.dto.concert.*; import com.back.web7_9_codecrete_be.domain.concerts.dto.ticketOffice.TicketOfficeElement; -import com.back.web7_9_codecrete_be.domain.concerts.entity.Concert; -import com.back.web7_9_codecrete_be.domain.concerts.entity.ConcertLike; -import com.back.web7_9_codecrete_be.domain.concerts.entity.ConcertPlace; -import com.back.web7_9_codecrete_be.domain.concerts.entity.TicketOffice; -import com.back.web7_9_codecrete_be.domain.concerts.repository.ConcertLikeRepository; -import com.back.web7_9_codecrete_be.domain.concerts.repository.ConcertPlaceRepository; -import com.back.web7_9_codecrete_be.domain.concerts.repository.ConcertRepository; -import com.back.web7_9_codecrete_be.domain.concerts.repository.TicketOfficeRepository; +import com.back.web7_9_codecrete_be.domain.concerts.entity.*; +import com.back.web7_9_codecrete_be.domain.concerts.repository.*; import com.back.web7_9_codecrete_be.domain.users.entity.User; import com.back.web7_9_codecrete_be.domain.users.repository.UserRepository; import com.back.web7_9_codecrete_be.global.error.code.AuthErrorCode; @@ -39,7 +30,8 @@ public class ConcertService { private final TicketOfficeRepository ticketOfficeRepository; - private final JsoupApiService jsoupApiService; + private final ConcertImageRepository concertImageRepository; + public List getConcertsList(Pageable pageable) { return concertRepository.getConcertItems(pageable); @@ -53,8 +45,19 @@ public List getLikedConcertsList(Pageable pageable,User user) { return concertRepository.getLikedConcertsList(pageable, user.getId()); } + public List getNoTicketTimeConcertsList(Pageable pageable) { + return concertRepository.getNoTicketTimeConcertList(pageable); + } + public ConcertDetailResponse getConcertDetail(long concertId) { - return concertRepository.getConcertDetailById(concertId); + ConcertDetailResponse concertDetailResponse = concertRepository.getConcertDetailById(concertId); + List concertImages = concertImageRepository.getConcertImagesByConcert_ConcertId(concertId); + List concertImageUrls = new ArrayList<>(); + for(ConcertImage concertImage : concertImages){ + concertImageUrls.add(concertImage.getImageUrl()); + } + concertDetailResponse.setConcertImageUrls(concertImageUrls); + return concertDetailResponse; } // N+1 문제 발생해서 버림 @@ -118,6 +121,13 @@ public ConcertItem updateConcert(long concertId, ConcertUpdateRequest concertUpd return new ConcertItem(updatedConcert); } + public ConcertDetailResponse setConcertTime(ConcertTicketTimeSetRequest concertTicketTimeSetRequest) { + Concert concert = concertRepository.findById(concertTicketTimeSetRequest.getConcertId()).orElseThrow(); + 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); 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 9f1c6115..36bb037c 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 @@ -6,8 +6,10 @@ import com.back.web7_9_codecrete_be.domain.concerts.dto.KopisApiDto.concertPlace.ConcertPlaceListElement; import com.back.web7_9_codecrete_be.domain.concerts.dto.KopisApiDto.concertPlace.ConcertPlaceListResponse; import com.back.web7_9_codecrete_be.domain.concerts.entity.Concert; +import com.back.web7_9_codecrete_be.domain.concerts.entity.ConcertImage; import com.back.web7_9_codecrete_be.domain.concerts.entity.ConcertPlace; import com.back.web7_9_codecrete_be.domain.concerts.entity.TicketOffice; +import com.back.web7_9_codecrete_be.domain.concerts.repository.ConcertImageRepository; import com.back.web7_9_codecrete_be.domain.concerts.repository.ConcertPlaceRepository; import com.back.web7_9_codecrete_be.domain.concerts.repository.ConcertRepository; import com.back.web7_9_codecrete_be.domain.concerts.repository.TicketOfficeRepository; @@ -38,6 +40,8 @@ public class KopisApiService { private final TicketOfficeRepository ticketOfficeRepository; + private final ConcertImageRepository imageRepository; + @Value("${kopis.api-key}") private String serviceKey; private LocalDate sdate = LocalDate.of(2025, 12, 1); @@ -45,10 +49,11 @@ public class KopisApiService { private final RestClient restClient; - public KopisApiService(ConcertRepository concertRepository, ConcertPlaceRepository placeRepository, TicketOfficeRepository ticketOfficeRepository) { + public KopisApiService(ConcertRepository concertRepository, ConcertPlaceRepository placeRepository, TicketOfficeRepository ticketOfficeRepository,ConcertImageRepository imageRepository) { this.concertRepository = concertRepository; this.placeRepository = placeRepository; this.ticketOfficeRepository = ticketOfficeRepository; + this.imageRepository = imageRepository; this.restClient = RestClient.builder() .baseUrl("https://kopis.or.kr/openApi/restful") .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE) @@ -113,7 +118,7 @@ public ConcertListResponse setConcertsList() throws InterruptedException { concertDetail.getConcertDescription(), dateStringToDateTime(concertDetail.getStartDate()), dateStringToDateTime(concertDetail.getEndDate()), - "", + null, ticketPrice.maxPrice, ticketPrice.minPrice, concertDetail.getPosterUrl(), @@ -132,6 +137,15 @@ public ConcertListResponse setConcertsList() throws InterruptedException { ); ticketOfficeRepository.save(to); } + + List concertImages = new ArrayList<>(); + for(String imageUrl : concertDetail.getConcertImageUrls()){ + ConcertImage concertImage = new ConcertImage(savedConcert, imageUrl); + concertImages.add(concertImage); + } + + imageRepository.saveAll(concertImages); + log.info("Concert saved: " + savedConcert); Thread.sleep(300); } @@ -193,7 +207,7 @@ public void updateConcertData() throws InterruptedException { // 1주일 단위 concertDetail.getConcertDescription(), dateStringToDateTime(concertDetail.getStartDate()), dateStringToDateTime(concertDetail.getEndDate()), - "", + null, ticketPrice.maxPrice, ticketPrice.minPrice, concertDetail.getPosterUrl(), @@ -203,7 +217,7 @@ public void updateConcertData() throws InterruptedException { // 1주일 단위 concert = concert.update( concertPlace, concertDetail.getConcertDescription(), - "", + null, ticketPrice.maxPrice, ticketPrice.minPrice ); @@ -221,6 +235,14 @@ public void updateConcertData() throws InterruptedException { // 1주일 단위 ); ticketOfficeRepository.save(to); } + + List concertImages = new ArrayList<>(); + for(String imageUrl : concertDetail.getConcertImageUrls()){ + ConcertImage concertImage = new ConcertImage(savedConcert, imageUrl); + concertImages.add(concertImage); + } + imageRepository.saveAll(concertImages); + log.info("Concert saved: " + savedConcert); Thread.sleep(300);