diff --git a/batch/src/main/java/org/cmc/curtaincall/batch/job/facility/FacilityItemProcessor.java b/batch/src/main/java/org/cmc/curtaincall/batch/job/show/FacilityItemProcessor.java similarity index 97% rename from batch/src/main/java/org/cmc/curtaincall/batch/job/facility/FacilityItemProcessor.java rename to batch/src/main/java/org/cmc/curtaincall/batch/job/show/FacilityItemProcessor.java index f4f3218b..711bfe5f 100644 --- a/batch/src/main/java/org/cmc/curtaincall/batch/job/facility/FacilityItemProcessor.java +++ b/batch/src/main/java/org/cmc/curtaincall/batch/job/show/FacilityItemProcessor.java @@ -1,4 +1,4 @@ -package org.cmc.curtaincall.batch.job.facility; +package org.cmc.curtaincall.batch.job.show; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/batch/src/main/java/org/cmc/curtaincall/batch/job/facility/FacilityJobConfig.java b/batch/src/main/java/org/cmc/curtaincall/batch/job/show/FacilityJobConfig.java similarity index 98% rename from batch/src/main/java/org/cmc/curtaincall/batch/job/facility/FacilityJobConfig.java rename to batch/src/main/java/org/cmc/curtaincall/batch/job/show/FacilityJobConfig.java index 88b3bc75..e0bc8709 100644 --- a/batch/src/main/java/org/cmc/curtaincall/batch/job/facility/FacilityJobConfig.java +++ b/batch/src/main/java/org/cmc/curtaincall/batch/job/show/FacilityJobConfig.java @@ -1,4 +1,4 @@ -package org.cmc.curtaincall.batch.job.facility; +package org.cmc.curtaincall.batch.job.show; import jakarta.persistence.EntityManagerFactory; import lombok.RequiredArgsConstructor; diff --git a/batch/src/main/java/org/cmc/curtaincall/batch/job/facility/FacilityPagingItemReader.java b/batch/src/main/java/org/cmc/curtaincall/batch/job/show/FacilityPagingItemReader.java similarity index 95% rename from batch/src/main/java/org/cmc/curtaincall/batch/job/facility/FacilityPagingItemReader.java rename to batch/src/main/java/org/cmc/curtaincall/batch/job/show/FacilityPagingItemReader.java index e8d5d950..a198e1ce 100644 --- a/batch/src/main/java/org/cmc/curtaincall/batch/job/facility/FacilityPagingItemReader.java +++ b/batch/src/main/java/org/cmc/curtaincall/batch/job/show/FacilityPagingItemReader.java @@ -1,4 +1,4 @@ -package org.cmc.curtaincall.batch.job.facility; +package org.cmc.curtaincall.batch.job.show; import lombok.RequiredArgsConstructor; import org.cmc.curtaincall.batch.service.kopis.KopisService; diff --git a/batch/src/main/java/org/cmc/curtaincall/batch/job/show/ShowCompleteUpdateJobConfig.java b/batch/src/main/java/org/cmc/curtaincall/batch/job/show/ShowCompleteUpdateJobConfig.java deleted file mode 100644 index b6b8437c..00000000 --- a/batch/src/main/java/org/cmc/curtaincall/batch/job/show/ShowCompleteUpdateJobConfig.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.cmc.curtaincall.batch.job.show; - -import jakarta.persistence.EntityManager; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.cmc.curtaincall.domain.show.ShowState; -import org.springframework.batch.core.Job; -import org.springframework.batch.core.Step; -import org.springframework.batch.core.configuration.annotation.JobScope; -import org.springframework.batch.core.job.builder.JobBuilder; -import org.springframework.batch.core.launch.support.RunIdIncrementer; -import org.springframework.batch.core.repository.JobRepository; -import org.springframework.batch.core.step.builder.StepBuilder; -import org.springframework.batch.repeat.RepeatStatus; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.transaction.PlatformTransactionManager; - -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.List; - -@Configuration -@Slf4j -@RequiredArgsConstructor -public class ShowCompleteUpdateJobConfig { - - private static final String JOB_NAME = "ShowCompleteUpdateJob"; - - private static final String STEP_NAME = "ShowCompleteUpdateStep"; - - private final JobRepository jobRepository; - - private final PlatformTransactionManager txManager; - - private final EntityManager em; - - @Bean - public Job showCompleteUpdateJob() { - JobBuilder jobBuilder = new JobBuilder(JOB_NAME, jobRepository); - return jobBuilder - .start(showCompleteUpdateStep(null)) - .incrementer(new RunIdIncrementer()) - .build(); - } - - @Bean - @JobScope - public Step showCompleteUpdateStep(@Value("#{jobParameters[date]}") String date) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); - StepBuilder stepBuilder = new StepBuilder(STEP_NAME, jobRepository); - return stepBuilder - .tasklet((contribution, chunkContext) -> { - em.createQuery(""" - update Show show - set show.state = :state, show.lastModifiedAt = :lastModifiedAt - where show.state in :prevStates and show.endDate < :date - """) - .setParameter("state", ShowState.COMPLETE) - .setParameter("prevStates", List.of(ShowState.PERFORMING, ShowState.TO_PERFORM)) - .setParameter("lastModifiedAt", LocalDateTime.now()) - .setParameter("date", LocalDate.parse(date, formatter)) - .executeUpdate(); - - em.createQuery(""" - update ShowReviewStats stats - set stats.state = :state, stats.lastModifiedAt = :lastModifiedAt - where stats.state in :prevStates and stats.endDate < :date - """) - .setParameter("state", ShowState.COMPLETE) - .setParameter("prevStates", List.of(ShowState.PERFORMING, ShowState.TO_PERFORM)) - .setParameter("lastModifiedAt", LocalDateTime.now()) - .setParameter("date", LocalDate.parse(date, formatter)) - .executeUpdate(); - - return RepeatStatus.FINISHED; - }, txManager) - .build(); - } -} diff --git a/batch/src/main/java/org/cmc/curtaincall/batch/job/show/ShowCreateJobConfig.java b/batch/src/main/java/org/cmc/curtaincall/batch/job/show/ShowCreateJobConfig.java index 87c39ef8..56312507 100644 --- a/batch/src/main/java/org/cmc/curtaincall/batch/job/show/ShowCreateJobConfig.java +++ b/batch/src/main/java/org/cmc/curtaincall/batch/job/show/ShowCreateJobConfig.java @@ -94,7 +94,7 @@ public ShowKopisPagingItemReader showKopisPagingItemReader( @Bean @StepScope public ShowKopisItemProcessor showKopisItemProcessor() { - return new ShowKopisItemProcessor(kopisService, showExistsDao); + return new ShowKopisItemProcessor(kopisService); } @Bean @@ -102,7 +102,6 @@ public ShowKopisItemProcessor showKopisItemProcessor() { public JpaItemWriter showItemWriter() { return new JpaItemWriterBuilder() .entityManagerFactory(emf) - .usePersist(true) .build(); } diff --git a/batch/src/main/java/org/cmc/curtaincall/batch/job/show/ShowDateTimeInitJobConfig.java b/batch/src/main/java/org/cmc/curtaincall/batch/job/show/ShowDateTimeInitJobConfig.java deleted file mode 100644 index 8a2fd975..00000000 --- a/batch/src/main/java/org/cmc/curtaincall/batch/job/show/ShowDateTimeInitJobConfig.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.cmc.curtaincall.batch.job.show; - -import jakarta.persistence.EntityManager; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.cmc.curtaincall.domain.show.Show; -import org.cmc.curtaincall.domain.show.ShowDateTime; -import org.cmc.curtaincall.domain.show.ShowDay; -import org.cmc.curtaincall.domain.show.ShowTime; -import org.springframework.batch.core.Job; -import org.springframework.batch.core.Step; -import org.springframework.batch.core.configuration.annotation.JobScope; -import org.springframework.batch.core.job.builder.JobBuilder; -import org.springframework.batch.core.repository.JobRepository; -import org.springframework.batch.core.step.builder.StepBuilder; -import org.springframework.batch.repeat.RepeatStatus; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.transaction.PlatformTransactionManager; - -import java.time.DayOfWeek; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.Period; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -@Configuration -@Slf4j -@RequiredArgsConstructor -public class ShowDateTimeInitJobConfig { - - private static final String JOB_NAME = "ShowDateTimeInitJob"; - - private static final String STEP_NAME = "ShowDateTimeInitStep"; - - private final JobRepository jobRepository; - - private final EntityManager em; - - private final PlatformTransactionManager txManager; - - private final Map showDayToDayOfWeek = Map.of( - ShowDay.MONDAY, DayOfWeek.MONDAY, - ShowDay.TUESDAY, DayOfWeek.TUESDAY, - ShowDay.WEDNESDAY, DayOfWeek.WEDNESDAY, - ShowDay.THURSDAY, DayOfWeek.THURSDAY, - ShowDay.FRIDAY, DayOfWeek.FRIDAY, - ShowDay.SATURDAY, DayOfWeek.SATURDAY, - ShowDay.SUNDAY, DayOfWeek.SUNDAY - ); - - @Bean - public Job showDateTimeInitJob() { - JobBuilder jobBuilder = new JobBuilder(JOB_NAME, jobRepository); - return jobBuilder - .start(showDateTimeInitStep()) - .build(); - } - - @Bean - @JobScope - public Step showDateTimeInitStep() { - StepBuilder stepBuilder = new StepBuilder(STEP_NAME, jobRepository); - return stepBuilder - .tasklet((contribution, chunkContext) -> { - final int size = 10; - int showCount = em.createQuery("select count(show) from Show show", Long.class) - .getSingleResult().intValue(); - for (int page = 0; page < showCount / size + 1; page++) { - List shows = em.createQuery(""" - select show - from Show show - """, Show.class) - .setFirstResult(page * size) - .setMaxResults(size) - .getResultList(); - List showDateTimes = new ArrayList<>(); - for (Show show : shows) { - showDateTimes.addAll(getShowDateTimes(show)); - } - - for (ShowDateTime showDateTime : showDateTimes) { - em.persist(showDateTime); - } - } - - return RepeatStatus.FINISHED; - }, txManager) - .build(); - } - - private List getShowDateTimes(Show show) { - Map> dayOfWeekToShowTimes = show.getShowTimes().stream() - .filter(showTime -> showDayToDayOfWeek.containsKey(showTime.getDayOfWeek())) - .collect(Collectors.groupingBy(showTime -> showDayToDayOfWeek.get(showTime.getDayOfWeek()))); - - LocalDate startDate = show.getStartDate(); - LocalDate endDate = show.getEndDate(); - List result = new ArrayList<>(); - for (int i = 0; i <= Period.between(startDate, endDate).getDays(); i++) { - LocalDate date = startDate.plusDays(i); - DayOfWeek dayOfWeek = date.getDayOfWeek(); - if (dayOfWeekToShowTimes.containsKey(dayOfWeek)) { - result.addAll(dayOfWeekToShowTimes.get(dayOfWeek).stream() - .map(showTime -> LocalDateTime.of(date, showTime.getTime())) - .map(showAt -> new ShowDateTime(show, showAt)) - .toList() - ); - } - } - return result; - } - -} diff --git a/batch/src/main/java/org/cmc/curtaincall/batch/job/show/ShowKopisItemProcessor.java b/batch/src/main/java/org/cmc/curtaincall/batch/job/show/ShowKopisItemProcessor.java index 85e24940..45db8a9b 100644 --- a/batch/src/main/java/org/cmc/curtaincall/batch/job/show/ShowKopisItemProcessor.java +++ b/batch/src/main/java/org/cmc/curtaincall/batch/job/show/ShowKopisItemProcessor.java @@ -8,20 +8,14 @@ import org.cmc.curtaincall.domain.show.Facility; import org.cmc.curtaincall.domain.show.FacilityId; import org.cmc.curtaincall.domain.show.Show; -import org.cmc.curtaincall.domain.show.ShowDay; import org.cmc.curtaincall.domain.show.ShowGenre; import org.cmc.curtaincall.domain.show.ShowId; import org.cmc.curtaincall.domain.show.ShowState; import org.cmc.curtaincall.domain.show.ShowTime; -import org.cmc.curtaincall.domain.show.dao.ShowExistsDao; import org.springframework.batch.item.ItemProcessor; -import java.time.DayOfWeek; import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.Period; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -35,8 +29,6 @@ public class ShowKopisItemProcessor implements ItemProcessor private final KopisService kopisService; - private final ShowExistsDao showExistsDao; - private final Set allowedGenreNames = Arrays.stream(ShowGenre.values()) .map(ShowGenre::getTitle) .collect(Collectors.toSet()); @@ -51,23 +43,9 @@ public class ShowKopisItemProcessor implements ItemProcessor private final Map stateMapper = Arrays.stream(ShowState.values()) .collect(Collectors.toMap(ShowState::getTitle, Function.identity())); - private final Map showDayToDayOfWeek = Map.of( - ShowDay.MONDAY, DayOfWeek.MONDAY, - ShowDay.TUESDAY, DayOfWeek.TUESDAY, - ShowDay.WEDNESDAY, DayOfWeek.WEDNESDAY, - ShowDay.THURSDAY, DayOfWeek.THURSDAY, - ShowDay.FRIDAY, DayOfWeek.FRIDAY, - ShowDay.SATURDAY, DayOfWeek.SATURDAY, - ShowDay.SUNDAY, DayOfWeek.SUNDAY - ); - @Override public Show process(ShowResponse item) throws Exception { final ShowId showId = new ShowId(item.id()); - if (showExistsDao.exists(showId)) { - log.debug("공연({})은 존재하는 데이터입니다.", showId); - return null; - } if (!allowedGenreNames.contains(item.genreName())) { log.debug("공연({})은 다루지 않는 장르({})입니다.", item.id(), item.genreName()); return null; @@ -78,10 +56,9 @@ public Show process(ShowResponse item) throws Exception { List showTimes = showTimeParser.parse(showDetail.showTimes()); LocalDate startDate = LocalDate.parse(showDetail.startDate(), showDateFormatter); LocalDate endDate = LocalDate.parse(showDetail.endDate(), showDateFormatter); - List showDateTimes = getShowDateTimes(startDate, endDate, showTimes); - Show show = Show.builder() - .id(new ShowId(showDetail.id())) + return Show.builder() + .id(showId) .facility(new Facility(new FacilityId(showDetail.facilityId()))) .name(showDetail.name()) .startDate(startDate) @@ -97,29 +74,9 @@ public Show process(ShowResponse item) throws Exception { .genre(showGenre) .state(stateMapper.get(showDetail.state())) .openRun(showDetail.openRun()) + .showTimes(showTimes) + .introductionImages(showDetail.introductionImages()) .build(); - show.getShowTimes().addAll(showTimes); - show.getIntroductionImages().addAll(showDetail.introductionImages()); - showDateTimes.forEach(show::addShowDateTime); - return show; } - private List getShowDateTimes(LocalDate startDate, LocalDate endDate, List showTimes) { - Map> dayOfWeekToShowTimes = showTimes.stream() - .filter(showTime -> showDayToDayOfWeek.containsKey(showTime.getDayOfWeek())) - .collect(Collectors.groupingBy(showTime -> showDayToDayOfWeek.get(showTime.getDayOfWeek()))); - - List result = new ArrayList<>(); - for (int i = 0; i < Period.between(startDate, endDate).getDays(); i++) { - LocalDate date = startDate.plusDays(i); - DayOfWeek dayOfWeek = date.getDayOfWeek(); - if (dayOfWeekToShowTimes.containsKey(dayOfWeek)) { - result.addAll(dayOfWeekToShowTimes.get(dayOfWeek).stream() - .map(showTime -> LocalDateTime.of(date, showTime.getTime())) - .toList() - ); - } - } - return result; - } } diff --git a/batch/src/main/java/org/cmc/curtaincall/batch/job/show/ShowPerformingUpdateJobConfig.java b/batch/src/main/java/org/cmc/curtaincall/batch/job/show/ShowPerformingUpdateJobConfig.java deleted file mode 100644 index 6146a8bc..00000000 --- a/batch/src/main/java/org/cmc/curtaincall/batch/job/show/ShowPerformingUpdateJobConfig.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.cmc.curtaincall.batch.job.show; - -import jakarta.persistence.EntityManager; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.cmc.curtaincall.domain.show.ShowState; -import org.springframework.batch.core.Job; -import org.springframework.batch.core.Step; -import org.springframework.batch.core.configuration.annotation.JobScope; -import org.springframework.batch.core.job.builder.JobBuilder; -import org.springframework.batch.core.launch.support.RunIdIncrementer; -import org.springframework.batch.core.repository.JobRepository; -import org.springframework.batch.core.step.builder.StepBuilder; -import org.springframework.batch.repeat.RepeatStatus; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.transaction.PlatformTransactionManager; - -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; - -@Configuration -@Slf4j -@RequiredArgsConstructor -public class ShowPerformingUpdateJobConfig { - - private static final String JOB_NAME = "ShowPerformingUpdateJob"; - - private static final String STEP_NAME = "ShowPerformingUpdateStep"; - - private final JobRepository jobRepository; - - private final PlatformTransactionManager txManager; - - private final EntityManager em; - - @Bean - public Job showPerformingUpdateJob() { - JobBuilder jobBuilder = new JobBuilder(JOB_NAME, jobRepository); - return jobBuilder - .start(showPerformingUpdateStep(null)) - .incrementer(new RunIdIncrementer()) - .build(); - } - - @Bean - @JobScope - public Step showPerformingUpdateStep(@Value("#{jobParameters[date]}") String date) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); - StepBuilder stepBuilder = new StepBuilder(STEP_NAME, jobRepository); - return stepBuilder - .tasklet((contribution, chunkContext) -> { - em.createQuery(""" - update Show show - set show.state = :state, show.lastModifiedAt = :lastModifiedAt - where show.state = :prevState and show.startDate <= :date - """) - .setParameter("state", ShowState.PERFORMING) - .setParameter("prevState", ShowState.TO_PERFORM) - .setParameter("lastModifiedAt", LocalDateTime.now()) - .setParameter("date", LocalDate.parse(date, formatter)) - .executeUpdate(); - - em.createQuery(""" - update ShowReviewStats stats - set stats.state = :state, stats.lastModifiedAt = :lastModifiedAt - where stats.state = :prevState and stats.startDate <= :date - """) - .setParameter("state", ShowState.PERFORMING) - .setParameter("prevState", ShowState.TO_PERFORM) - .setParameter("lastModifiedAt", LocalDateTime.now()) - .setParameter("date", LocalDate.parse(date, formatter)) - .executeUpdate(); - return RepeatStatus.FINISHED; - }, txManager) - .build(); - } -} diff --git a/domain/src/main/java/org/cmc/curtaincall/domain/review/ShowReviewStats.java b/domain/src/main/java/org/cmc/curtaincall/domain/review/ShowReviewStats.java index 2647a856..e465f514 100644 --- a/domain/src/main/java/org/cmc/curtaincall/domain/review/ShowReviewStats.java +++ b/domain/src/main/java/org/cmc/curtaincall/domain/review/ShowReviewStats.java @@ -101,4 +101,13 @@ public void cancelReviewGrade(final int grade) { private void calculateReviewGradeAvg() { reviewGradeAvg = ((double) reviewGradeSum) / reviewCount; } + + public void update( + final ShowGenre genre, final ShowState state, final LocalDate startDate, final LocalDate endDate + ) { + this.genre = genre; + this.state = state; + this.startDate = startDate; + this.endDate = endDate; + } } diff --git a/domain/src/main/java/org/cmc/curtaincall/domain/review/infra/ShowReviewEventHandler.java b/domain/src/main/java/org/cmc/curtaincall/domain/review/infra/ShowReviewEventHandler.java index 79a72272..9c2425bb 100644 --- a/domain/src/main/java/org/cmc/curtaincall/domain/review/infra/ShowReviewEventHandler.java +++ b/domain/src/main/java/org/cmc/curtaincall/domain/review/infra/ShowReviewEventHandler.java @@ -29,9 +29,13 @@ public class ShowReviewEventHandler { public void handleShowCreatedEvent(final ShowCreatedEvent event) { log.debug("handleShowCreatedEvent={}", event); final ShowCreatedEvent.Source source = event.getSource(); - showReviewStatsRepository.save(new ShowReviewStats( - source.id(), source.genre(), source.state(), source.startDate(), source.endDate() - )); + showReviewStatsRepository.findWithPessimisticLockById(source.id()).ifPresentOrElse( + showReviewStats -> showReviewStats.update( + source.genre(), source.state(), source.startDate(), source.endDate() + ), () -> showReviewStatsRepository.save(new ShowReviewStats( + source.id(), source.genre(), source.state(), source.startDate(), source.endDate() + )) + ); } @EventListener diff --git a/domain/src/main/java/org/cmc/curtaincall/domain/review/repository/ShowReviewStatsRepository.java b/domain/src/main/java/org/cmc/curtaincall/domain/review/repository/ShowReviewStatsRepository.java index 16849623..a3939ef5 100644 --- a/domain/src/main/java/org/cmc/curtaincall/domain/review/repository/ShowReviewStatsRepository.java +++ b/domain/src/main/java/org/cmc/curtaincall/domain/review/repository/ShowReviewStatsRepository.java @@ -12,4 +12,7 @@ public interface ShowReviewStatsRepository extends JpaRepository findWithLockById(ShowId id); + + @Lock(LockModeType.PESSIMISTIC_FORCE_INCREMENT) + Optional findWithPessimisticLockById(ShowId id); } diff --git a/domain/src/main/java/org/cmc/curtaincall/domain/show/FavoriteShow.java b/domain/src/main/java/org/cmc/curtaincall/domain/show/FavoriteShow.java index ad385681..6580b285 100644 --- a/domain/src/main/java/org/cmc/curtaincall/domain/show/FavoriteShow.java +++ b/domain/src/main/java/org/cmc/curtaincall/domain/show/FavoriteShow.java @@ -1,10 +1,23 @@ package org.cmc.curtaincall.domain.show; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.ConstraintMode; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.ForeignKey; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Index; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; -import org.cmc.curtaincall.domain.member.Member; +import org.cmc.curtaincall.domain.member.MemberId; @Entity @Table(name = "favorite_show", @@ -28,12 +41,11 @@ public class FavoriteShow { @JoinColumn(name = "show_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) private Show show; - @ManyToOne(fetch = FetchType.LAZY, optional = false) - @JoinColumn(name = "member_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) - private Member member; + @Embedded + private MemberId memberId; - public FavoriteShow(Show show, Member member) { + public FavoriteShow(final Show show, final MemberId memberId) { this.show = show; - this.member = member; + this.memberId = memberId; } } diff --git a/domain/src/main/java/org/cmc/curtaincall/domain/show/Show.java b/domain/src/main/java/org/cmc/curtaincall/domain/show/Show.java index 8f84c478..e197b740 100644 --- a/domain/src/main/java/org/cmc/curtaincall/domain/show/Show.java +++ b/domain/src/main/java/org/cmc/curtaincall/domain/show/Show.java @@ -1,6 +1,5 @@ package org.cmc.curtaincall.domain.show; -import jakarta.persistence.CascadeType; import jakarta.persistence.CollectionTable; import jakarta.persistence.Column; import jakarta.persistence.ConstraintMode; @@ -14,19 +13,16 @@ import jakarta.persistence.Index; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; -import jakarta.persistence.OneToMany; import jakarta.persistence.Table; -import jakarta.persistence.Version; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import org.cmc.curtaincall.domain.core.BaseTimeEntity; -import org.springframework.data.domain.Persistable; import java.time.LocalDate; -import java.time.LocalDateTime; import java.util.ArrayList; +import java.util.Collections; import java.util.List; @Entity @@ -43,15 +39,11 @@ ) @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class Show extends BaseTimeEntity implements Persistable { +public class Show extends BaseTimeEntity { @EmbeddedId private ShowId id; - @Version - @Column(nullable = false) - private Long version; - @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "facility_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) private Facility facility; @@ -105,7 +97,7 @@ public class Show extends BaseTimeEntity implements Persistable { name = "show_time", joinColumns = @JoinColumn(name = "show_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) ) - private List showTimes = new ArrayList<>(); + private List showTimes; @ElementCollection @CollectionTable( @@ -115,9 +107,6 @@ public class Show extends BaseTimeEntity implements Persistable { @Column(name = "image_url", length = 500, nullable = false) private List introductionImages = new ArrayList<>(); - @OneToMany(mappedBy = "show", cascade = CascadeType.ALL, orphanRemoval = true) - private List showDateTimes = new ArrayList<>(); - @Builder public Show( final ShowId id, @@ -135,7 +124,9 @@ public Show( final String story, final ShowGenre genre, final ShowState state, - final String openRun + final String openRun, + final List showTimes, + final List introductionImages ) { this.id = id; this.facility = facility; @@ -153,14 +144,15 @@ public Show( this.genre = genre; this.state = state; this.openRun = openRun; + this.showTimes = showTimes; + this.introductionImages = introductionImages; } - @Override - public boolean isNew() { - return getCreatedAt() == null; + public List getShowTimes() { + return Collections.unmodifiableList(showTimes); } - public void addShowDateTime(LocalDateTime showAt) { - showDateTimes.add(new ShowDateTime(this, showAt)); + public List getIntroductionImages() { + return Collections.unmodifiableList(introductionImages); } } diff --git a/domain/src/main/java/org/cmc/curtaincall/domain/show/ShowDateTime.java b/domain/src/main/java/org/cmc/curtaincall/domain/show/ShowDateTime.java deleted file mode 100644 index 7b381952..00000000 --- a/domain/src/main/java/org/cmc/curtaincall/domain/show/ShowDateTime.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.cmc.curtaincall.domain.show; - -import jakarta.persistence.*; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import java.time.LocalDateTime; -import java.util.Arrays; - -@Entity -@Table(name = "show_date_time", - indexes = { - @Index(name = "IX_show_date_time__show_show_at", columnList = "show_id, show_at"), - @Index(name = "IX_show_date_time__show_at", columnList = "show_at"), - @Index(name = "IX_show_date_time__show_end_at", columnList = "show_end_at"), - } -) -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class ShowDateTime { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "show_date_time_id") - private Long id; - - @ManyToOne(fetch = FetchType.LAZY, optional = false) - @JoinColumn(name = "show_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) - private Show show; - - @Column(name = "show_at", nullable = false) - private LocalDateTime showAt; - - @Column(name = "show_end_at", nullable = false) - private LocalDateTime showEndAt; - - public ShowDateTime(Show show, LocalDateTime showAt) { - this.show = show; - this.showAt = showAt; - this.showEndAt = showAt; - String runtime = show.getRuntime(); - Arrays.stream(runtime.split("\\s+")) - .forEach(rt -> { - if (rt.endsWith("시간")) { - long hour = Long.parseLong(rt.replace("시간", "")); - this.showEndAt = this.showEndAt.plusHours(hour); - } else if (rt.endsWith("분")) { - long minute = Long.parseLong(rt.replace("분", "")); - this.showEndAt = this.showEndAt.plusMinutes(minute); - } - }); - } -} diff --git a/domain/src/main/java/org/cmc/curtaincall/domain/show/infra/ShowFavoriteMemberValidatorImpl.java b/domain/src/main/java/org/cmc/curtaincall/domain/show/infra/ShowFavoriteMemberValidatorImpl.java new file mode 100644 index 00000000..21e97a0e --- /dev/null +++ b/domain/src/main/java/org/cmc/curtaincall/domain/show/infra/ShowFavoriteMemberValidatorImpl.java @@ -0,0 +1,22 @@ +package org.cmc.curtaincall.domain.show.infra; + +import lombok.RequiredArgsConstructor; +import org.cmc.curtaincall.domain.member.MemberId; +import org.cmc.curtaincall.domain.member.dao.MemberExistsDao; +import org.cmc.curtaincall.domain.member.exception.MemberNotFoundException; +import org.cmc.curtaincall.domain.show.validation.ShowFavoriteMemberValidator; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class ShowFavoriteMemberValidatorImpl implements ShowFavoriteMemberValidator { + + private final MemberExistsDao memberExistsDao; + + @Override + public void validate(final MemberId memberId) { + if (!memberExistsDao.exists(memberId)) { + throw new MemberNotFoundException(memberId); + } + } +} diff --git a/domain/src/main/java/org/cmc/curtaincall/domain/show/repository/FavoriteShowRepository.java b/domain/src/main/java/org/cmc/curtaincall/domain/show/repository/FavoriteShowRepository.java index af7b7caf..6eea8919 100644 --- a/domain/src/main/java/org/cmc/curtaincall/domain/show/repository/FavoriteShowRepository.java +++ b/domain/src/main/java/org/cmc/curtaincall/domain/show/repository/FavoriteShowRepository.java @@ -1,10 +1,9 @@ package org.cmc.curtaincall.domain.show.repository; -import org.cmc.curtaincall.domain.member.Member; +import org.cmc.curtaincall.domain.member.MemberId; import org.cmc.curtaincall.domain.show.FavoriteShow; import org.cmc.curtaincall.domain.show.Show; import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; @@ -14,12 +13,12 @@ public interface FavoriteShowRepository extends JpaRepository { - boolean existsByMemberAndShow(Member member, Show show); + boolean existsByMemberIdAndShow(MemberId member, Show show); - Optional findByMemberAndShow(Member member, Show show); + Optional findByMemberIdAndShow(MemberId member, Show show); - List findAllByMemberAndShowIn(Member member, Collection shows); + List findAllByMemberIdAndShowIn(MemberId member, Collection shows); @EntityGraph(attributePaths = {"show", "show.facility"}) - Slice findSliceWithShowByMember(Pageable pageable, Member member); + List findAllWithShowByMemberId(Pageable pageable, MemberId member); } diff --git a/domain/src/main/java/org/cmc/curtaincall/domain/show/repository/ShowDateTimeRepository.java b/domain/src/main/java/org/cmc/curtaincall/domain/show/repository/ShowDateTimeRepository.java deleted file mode 100644 index 563d37f2..00000000 --- a/domain/src/main/java/org/cmc/curtaincall/domain/show/repository/ShowDateTimeRepository.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.cmc.curtaincall.domain.show.repository; - -import org.cmc.curtaincall.domain.show.ShowDateTime; -import org.springframework.data.jpa.repository.EntityGraph; -import org.springframework.data.jpa.repository.JpaRepository; - -import java.time.LocalDateTime; -import java.util.List; - -public interface ShowDateTimeRepository extends JpaRepository { - - @EntityGraph(attributePaths = {"show", "show.facility"}) - List findAllByShowAtLessThanEqualAndShowAtGreaterThan( - LocalDateTime showAtLoe, LocalDateTime showAtGt); - - @EntityGraph(attributePaths = {"show", "show.facility"}) - List findAllByShowAtLessThanEqualAndShowEndAtGreaterThanEqual( - LocalDateTime showAt, LocalDateTime showEndAt); - - @EntityGraph(attributePaths = {"show", "show.facility"}) - List findAllByShowEndAtLessThanEqualAndShowEndAtGreaterThan( - LocalDateTime showEndAtLoe, LocalDateTime showEndAtGt); -} diff --git a/domain/src/main/java/org/cmc/curtaincall/domain/show/validation/ShowFavoriteMemberValidator.java b/domain/src/main/java/org/cmc/curtaincall/domain/show/validation/ShowFavoriteMemberValidator.java new file mode 100644 index 00000000..e55191a2 --- /dev/null +++ b/domain/src/main/java/org/cmc/curtaincall/domain/show/validation/ShowFavoriteMemberValidator.java @@ -0,0 +1,8 @@ +package org.cmc.curtaincall.domain.show.validation; + +import org.cmc.curtaincall.domain.member.MemberId; + +public interface ShowFavoriteMemberValidator { + + void validate(MemberId memberId); +} diff --git a/web/src/docs/asciidoc/show.adoc b/web/src/docs/asciidoc/show.adoc index 0838983d..4eeaa671 100644 --- a/web/src/docs/asciidoc/show.adoc +++ b/web/src/docs/asciidoc/show.adoc @@ -41,9 +41,3 @@ operation::show-get-show-detail[snippets='http-request,path-parameters,http-resp == 인기 순위 operation::box-office-get-list[snippets='http-request,query-parameters,http-response,response-fields-content'] - - -[[show-get-show-time-list]] -== 공연 시작 종료 일시로 조회 - -operation::show-get-show-time-list[snippets='http-request,request-headers,query-parameters,http-response,response-fields-content'] \ No newline at end of file diff --git a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/BoxOfficeService.java b/web/src/main/java/org/cmc/curtaincall/web/boxoffice/BoxOfficeService.java deleted file mode 100644 index 3921677e..00000000 --- a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/BoxOfficeService.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.cmc.curtaincall.web.boxoffice; - -import org.cmc.curtaincall.web.boxoffice.dto.BoxOfficeRequest; -import org.cmc.curtaincall.web.boxoffice.dto.BoxOfficeResponse; - -import java.util.List; - -public interface BoxOfficeService { - - List getList(BoxOfficeRequest request); -} diff --git a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/BoxOfficeController.java b/web/src/main/java/org/cmc/curtaincall/web/show/BoxOfficeController.java similarity index 88% rename from web/src/main/java/org/cmc/curtaincall/web/boxoffice/BoxOfficeController.java rename to web/src/main/java/org/cmc/curtaincall/web/show/BoxOfficeController.java index a3acfb5d..9d600b53 100644 --- a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/BoxOfficeController.java +++ b/web/src/main/java/org/cmc/curtaincall/web/show/BoxOfficeController.java @@ -1,12 +1,11 @@ -package org.cmc.curtaincall.web.boxoffice; +package org.cmc.curtaincall.web.show; import lombok.RequiredArgsConstructor; import org.cmc.curtaincall.domain.show.ShowId; -import org.cmc.curtaincall.web.boxoffice.dto.BoxOfficeRequest; -import org.cmc.curtaincall.web.boxoffice.dto.BoxOfficeResponse; +import org.cmc.curtaincall.web.show.request.BoxOfficeRequest; +import org.cmc.curtaincall.web.show.response.BoxOfficeResponse; import org.cmc.curtaincall.web.common.response.ListResult; import org.cmc.curtaincall.web.common.response.With; -import org.cmc.curtaincall.web.show.ShowReviewStatsQueryService; import org.cmc.curtaincall.web.show.response.ShowReviewStatsDto; import org.cmc.curtaincall.web.show.response.ShowReviewStatsResponse; import org.springframework.validation.annotation.Validated; diff --git a/web/src/main/java/org/cmc/curtaincall/web/show/BoxOfficeService.java b/web/src/main/java/org/cmc/curtaincall/web/show/BoxOfficeService.java new file mode 100644 index 00000000..8ed90235 --- /dev/null +++ b/web/src/main/java/org/cmc/curtaincall/web/show/BoxOfficeService.java @@ -0,0 +1,11 @@ +package org.cmc.curtaincall.web.show; + +import org.cmc.curtaincall.web.show.request.BoxOfficeRequest; +import org.cmc.curtaincall.web.show.response.BoxOfficeResponse; + +import java.util.List; + +public interface BoxOfficeService { + + List getList(BoxOfficeRequest request); +} diff --git a/web/src/main/java/org/cmc/curtaincall/web/show/FavoriteShowController.java b/web/src/main/java/org/cmc/curtaincall/web/show/FavoriteShowController.java index 9faa5066..db173c26 100644 --- a/web/src/main/java/org/cmc/curtaincall/web/show/FavoriteShowController.java +++ b/web/src/main/java/org/cmc/curtaincall/web/show/FavoriteShowController.java @@ -2,16 +2,20 @@ import jakarta.validation.constraints.Size; import lombok.RequiredArgsConstructor; +import org.cmc.curtaincall.domain.core.AllowedSort; import org.cmc.curtaincall.domain.member.MemberId; import org.cmc.curtaincall.domain.show.ShowId; +import org.cmc.curtaincall.web.common.response.ListResult; import org.cmc.curtaincall.web.security.config.LoginMemberId; import org.cmc.curtaincall.web.show.response.FavoriteShowResponse; import org.cmc.curtaincall.web.show.response.ShowFavoriteResponse; import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; -import org.springframework.data.domain.SliceImpl; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import java.util.List; @@ -23,24 +27,28 @@ public class FavoriteShowController { @PutMapping("/shows/{showId}/favorite") public void favoriteShow(@PathVariable ShowId showId, @LoginMemberId MemberId memberId) { - favoriteShowService.favorite(memberId.getId(), showId.getId()); + favoriteShowService.favorite(memberId, showId); } @DeleteMapping("/shows/{showId}/favorite") public void cancelFavorite(@PathVariable ShowId showId, @LoginMemberId MemberId memberId) { - favoriteShowService.cancelFavorite(memberId.getId(), showId.getId()); + favoriteShowService.cancelFavorite(memberId, showId); } @GetMapping("/member/favorite") - public Slice getFavorite( - @RequestParam @Validated @Size(max = 100) List showIds, @LoginMemberId MemberId memberId) { - List showFavoriteResponses = favoriteShowService.areFavorite(memberId.getId(), showIds); - return new SliceImpl<>(showFavoriteResponses); + public ListResult getFavorite( + @RequestParam @Size(max = 100) final List showIds, + @LoginMemberId final MemberId memberId + ) { + final List showFavoriteResponses = favoriteShowService.areFavorite(memberId, showIds); + return new ListResult<>(showFavoriteResponses); } @GetMapping("/members/{memberId}/favorite") - public Slice getFavoriteShowList( - @PathVariable MemberId memberId, Pageable pageable) { - return favoriteShowService.getFavoriteShowList(pageable, memberId.getId()); + public ListResult getFavoriteShowList( + @PathVariable final MemberId memberId, + @AllowedSort final Pageable pageable + ) { + return new ListResult<>(favoriteShowService.getFavoriteShowList(pageable, memberId)); } } diff --git a/web/src/main/java/org/cmc/curtaincall/web/show/FavoriteShowService.java b/web/src/main/java/org/cmc/curtaincall/web/show/FavoriteShowService.java index 11883225..4299c232 100644 --- a/web/src/main/java/org/cmc/curtaincall/web/show/FavoriteShowService.java +++ b/web/src/main/java/org/cmc/curtaincall/web/show/FavoriteShowService.java @@ -2,19 +2,17 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.cmc.curtaincall.domain.member.Member; -import org.cmc.curtaincall.domain.member.repository.MemberRepository; +import org.cmc.curtaincall.domain.member.MemberId; import org.cmc.curtaincall.domain.show.FavoriteShow; import org.cmc.curtaincall.domain.show.Show; +import org.cmc.curtaincall.domain.show.ShowHelper; import org.cmc.curtaincall.domain.show.ShowId; import org.cmc.curtaincall.domain.show.repository.FavoriteShowRepository; import org.cmc.curtaincall.domain.show.repository.ShowRepository; -import org.cmc.curtaincall.web.exception.EntityNotFoundException; +import org.cmc.curtaincall.domain.show.validation.ShowFavoriteMemberValidator; import org.cmc.curtaincall.web.show.response.FavoriteShowResponse; import org.cmc.curtaincall.web.show.response.ShowFavoriteResponse; import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; -import org.springframework.data.domain.SliceImpl; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -31,47 +29,43 @@ public class FavoriteShowService { private final FavoriteShowRepository favoriteShowRepository; - private final MemberRepository memberRepository; - private final ShowRepository showRepository; + private final ShowFavoriteMemberValidator showFavoriteMemberValidator; + @Transactional - public void favorite(Long memberId, String showId) { - Show show = getShowById(showId); - Member member = memberRepository.getReferenceById(memberId); - if (favoriteShowRepository.existsByMemberAndShow(member, show)) { + public void favorite(final MemberId memberId, final ShowId showId) { + showFavoriteMemberValidator.validate(memberId); + final Show show = ShowHelper.get(showId, showRepository); + if (favoriteShowRepository.existsByMemberIdAndShow(memberId, show)) { return; } - favoriteShowRepository.save(new FavoriteShow(show, member)); + favoriteShowRepository.save(new FavoriteShow(show, memberId)); } @Transactional - public void cancelFavorite(Long memberId, String showId) { - Show show = getShowById(showId); - Member member = memberRepository.getReferenceById(memberId); - favoriteShowRepository.findByMemberAndShow(member, show) + public void cancelFavorite(final MemberId memberId, final ShowId showId) { + final Show show = showRepository.getReferenceById(showId); + favoriteShowRepository.findByMemberIdAndShow(memberId, show) .ifPresent(favoriteShowRepository::delete); } - public List areFavorite(Long memberId, List showIds) { - Member member = memberRepository.getReferenceById(memberId); - List shows = showIds.stream() - .map(ShowId::new) + public List areFavorite(final MemberId memberId, final List showIds) { + final List shows = showIds.stream() .map(showRepository::getReferenceById) .toList(); - List favoriteShows = favoriteShowRepository.findAllByMemberAndShowIn(member, shows); - Set favoriteShowIds = favoriteShows.stream() - .map(favoriteShow -> favoriteShow.getShow().getId().getId()) + final List favoriteShows = favoriteShowRepository.findAllByMemberIdAndShowIn(memberId, shows); + final Set favoriteShowIds = favoriteShows.stream() + .map(favoriteShow -> favoriteShow.getShow().getId()) .collect(Collectors.toSet()); return showIds.stream() .map(showId -> new ShowFavoriteResponse(showId, favoriteShowIds.contains(showId))) .toList(); } - public Slice getFavoriteShowList(Pageable pageable, Long memberId) { - Member member = memberRepository.getReferenceById(memberId); - Slice favoriteShows = favoriteShowRepository.findSliceWithShowByMember(pageable, member); - List shows = favoriteShows.stream() + public List getFavoriteShowList(final Pageable pageable, final MemberId memberId) { + final List favoriteShows = favoriteShowRepository.findAllWithShowByMemberId(pageable, memberId); + return favoriteShows.stream() .map(FavoriteShow::getShow) .filter(Show::getUseYn) .map(show -> FavoriteShowResponse.builder() @@ -86,12 +80,5 @@ public Slice getFavoriteShowList(Pageable pageable, Long m .runtime(show.getRuntime()) .build() ).toList(); - return new SliceImpl<>(shows, pageable, favoriteShows.hasNext()); - } - - private Show getShowById(String id) { - return showRepository.findById(new ShowId(id)) - .filter(Show::getUseYn) - .orElseThrow(() -> new EntityNotFoundException("Show id=" + id)); } } diff --git a/web/src/main/java/org/cmc/curtaincall/web/show/ShowController.java b/web/src/main/java/org/cmc/curtaincall/web/show/ShowController.java index bb3f68b2..f2ca6735 100644 --- a/web/src/main/java/org/cmc/curtaincall/web/show/ShowController.java +++ b/web/src/main/java/org/cmc/curtaincall/web/show/ShowController.java @@ -9,14 +9,11 @@ import org.cmc.curtaincall.web.common.response.ListResult; import org.cmc.curtaincall.web.common.response.With; import org.cmc.curtaincall.web.show.request.ShowListRequest; -import org.cmc.curtaincall.web.show.response.ShowDateTimeResponse; import org.cmc.curtaincall.web.show.response.ShowDetailResponse; import org.cmc.curtaincall.web.show.response.ShowResponse; import org.cmc.curtaincall.web.show.response.ShowReviewStatsDto; import org.cmc.curtaincall.web.show.response.ShowReviewStatsResponse; import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; -import org.springframework.data.domain.SliceImpl; import org.springframework.data.web.SortDefault; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; @@ -26,7 +23,6 @@ import org.springframework.web.bind.annotation.RestController; import java.time.LocalDate; -import java.time.LocalDateTime; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -84,11 +80,6 @@ public ListResult> getShowListOfFaci return getShowWithReviewStatsListResult(showService.getListOfFacility(pageable, facilityId, genre)); } - @GetMapping("/livetalk-show-times") - public Slice getLiveTalkShowTimeList(@RequestParam LocalDateTime baseDateTime) { - return new SliceImpl<>(showService.getLiveTalkShowTimeList(baseDateTime)); - } - private ListResult> getShowWithReviewStatsListResult( final List showResponses ) { diff --git a/web/src/main/java/org/cmc/curtaincall/web/show/ShowService.java b/web/src/main/java/org/cmc/curtaincall/web/show/ShowService.java index 14c46a2b..3ee5ee08 100644 --- a/web/src/main/java/org/cmc/curtaincall/web/show/ShowService.java +++ b/web/src/main/java/org/cmc/curtaincall/web/show/ShowService.java @@ -12,10 +12,8 @@ import org.cmc.curtaincall.domain.show.exception.FacilityNotFoundException; import org.cmc.curtaincall.domain.show.exception.ShowNotFoundException; import org.cmc.curtaincall.domain.show.repository.FacilityRepository; -import org.cmc.curtaincall.domain.show.repository.ShowDateTimeRepository; import org.cmc.curtaincall.domain.show.repository.ShowRepository; import org.cmc.curtaincall.web.show.request.ShowListRequest; -import org.cmc.curtaincall.web.show.response.ShowDateTimeResponse; import org.cmc.curtaincall.web.show.response.ShowDetailResponse; import org.cmc.curtaincall.web.show.response.ShowResponse; import org.springframework.data.domain.Pageable; @@ -23,11 +21,9 @@ import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; -import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.stream.Stream; @Service @RequiredArgsConstructor @@ -38,8 +34,6 @@ public class ShowService { private final FacilityRepository facilityRepository; - private final ShowDateTimeRepository showDateTimeRepository; - private final ShowReviewStatsRepository showReviewStatsRepository; public List getList(final ShowListRequest request, final Pageable pageable) { @@ -103,22 +97,6 @@ public ShowDetailResponse getDetail(final ShowId id) { return ShowDetailResponse.of(show); } - public List getLiveTalkShowTimeList(LocalDateTime baseDateTime) { - return Stream.of( - showDateTimeRepository.findAllByShowAtLessThanEqualAndShowAtGreaterThan( - baseDateTime.plusHours(2L), baseDateTime), - showDateTimeRepository.findAllByShowAtLessThanEqualAndShowEndAtGreaterThanEqual( - baseDateTime, baseDateTime), - showDateTimeRepository.findAllByShowEndAtLessThanEqualAndShowEndAtGreaterThan( - baseDateTime, baseDateTime.minusHours(2) - ) - ) - .flatMap(List::stream) - .distinct() - .map(ShowDateTimeResponse::of) - .toList(); - } - private Show getShowById(final ShowId id) { return showRepository.findById(id) .filter(Show::getUseYn) diff --git a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/config/BoxOfficeConfig.java b/web/src/main/java/org/cmc/curtaincall/web/show/config/BoxOfficeConfig.java similarity index 83% rename from web/src/main/java/org/cmc/curtaincall/web/boxoffice/config/BoxOfficeConfig.java rename to web/src/main/java/org/cmc/curtaincall/web/show/config/BoxOfficeConfig.java index 313ac6e1..2dade2e1 100644 --- a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/config/BoxOfficeConfig.java +++ b/web/src/main/java/org/cmc/curtaincall/web/show/config/BoxOfficeConfig.java @@ -1,7 +1,7 @@ -package org.cmc.curtaincall.web.boxoffice.config; +package org.cmc.curtaincall.web.show.config; import org.cmc.curtaincall.domain.show.repository.ShowRepository; -import org.cmc.curtaincall.web.boxoffice.infra.KopisBoxOfficeService; +import org.cmc.curtaincall.web.show.infra.KopisBoxOfficeService; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/config/KopisProperties.java b/web/src/main/java/org/cmc/curtaincall/web/show/config/KopisProperties.java similarity index 86% rename from web/src/main/java/org/cmc/curtaincall/web/boxoffice/config/KopisProperties.java rename to web/src/main/java/org/cmc/curtaincall/web/show/config/KopisProperties.java index 6ecdc1fe..9e7e28c5 100644 --- a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/config/KopisProperties.java +++ b/web/src/main/java/org/cmc/curtaincall/web/show/config/KopisProperties.java @@ -1,4 +1,4 @@ -package org.cmc.curtaincall.web.boxoffice.config; +package org.cmc.curtaincall.web.show.config; import jakarta.validation.constraints.NotNull; import lombok.Data; diff --git a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/infra/KopisBoxOfficeResponse.java b/web/src/main/java/org/cmc/curtaincall/web/show/infra/KopisBoxOfficeResponse.java similarity index 95% rename from web/src/main/java/org/cmc/curtaincall/web/boxoffice/infra/KopisBoxOfficeResponse.java rename to web/src/main/java/org/cmc/curtaincall/web/show/infra/KopisBoxOfficeResponse.java index 5a5ca383..37ce6912 100644 --- a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/infra/KopisBoxOfficeResponse.java +++ b/web/src/main/java/org/cmc/curtaincall/web/show/infra/KopisBoxOfficeResponse.java @@ -1,4 +1,4 @@ -package org.cmc.curtaincall.web.boxoffice.infra; +package org.cmc.curtaincall.web.show.infra; import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; diff --git a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/infra/KopisBoxOfficeResponseList.java b/web/src/main/java/org/cmc/curtaincall/web/show/infra/KopisBoxOfficeResponseList.java similarity index 93% rename from web/src/main/java/org/cmc/curtaincall/web/boxoffice/infra/KopisBoxOfficeResponseList.java rename to web/src/main/java/org/cmc/curtaincall/web/show/infra/KopisBoxOfficeResponseList.java index b0c9ec84..404cab41 100644 --- a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/infra/KopisBoxOfficeResponseList.java +++ b/web/src/main/java/org/cmc/curtaincall/web/show/infra/KopisBoxOfficeResponseList.java @@ -1,4 +1,4 @@ -package org.cmc.curtaincall.web.boxoffice.infra; +package org.cmc.curtaincall.web.show.infra; import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.XmlRootElement; diff --git a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/infra/KopisBoxOfficeService.java b/web/src/main/java/org/cmc/curtaincall/web/show/infra/KopisBoxOfficeService.java similarity index 93% rename from web/src/main/java/org/cmc/curtaincall/web/boxoffice/infra/KopisBoxOfficeService.java rename to web/src/main/java/org/cmc/curtaincall/web/show/infra/KopisBoxOfficeService.java index 69fcb5a9..a42d337e 100644 --- a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/infra/KopisBoxOfficeService.java +++ b/web/src/main/java/org/cmc/curtaincall/web/show/infra/KopisBoxOfficeService.java @@ -1,13 +1,13 @@ -package org.cmc.curtaincall.web.boxoffice.infra; +package org.cmc.curtaincall.web.show.infra; import lombok.extern.slf4j.Slf4j; import org.cmc.curtaincall.domain.show.BoxOfficeGenre; import org.cmc.curtaincall.domain.show.Show; import org.cmc.curtaincall.domain.show.ShowId; import org.cmc.curtaincall.domain.show.repository.ShowRepository; -import org.cmc.curtaincall.web.boxoffice.BoxOfficeService; -import org.cmc.curtaincall.web.boxoffice.dto.BoxOfficeRequest; -import org.cmc.curtaincall.web.boxoffice.dto.BoxOfficeResponse; +import org.cmc.curtaincall.web.show.BoxOfficeService; +import org.cmc.curtaincall.web.show.request.BoxOfficeRequest; +import org.cmc.curtaincall.web.show.response.BoxOfficeResponse; import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; @@ -24,7 +24,6 @@ import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; @@ -104,7 +103,7 @@ private KopisBoxOfficeResponseList requestEntity(final BoxOfficeRequest request) } @CacheEvict(value = "boxOffices", allEntries = true) - @Scheduled(timeUnit = TimeUnit.HOURS, fixedRate = 1L) + @Scheduled(cron = "0 0 12 * * ?") public void emptyBoxOfficesCache() { log.info("emptying BoxOffices cache"); } diff --git a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/infra/ShowIdXmlAdapter.java b/web/src/main/java/org/cmc/curtaincall/web/show/infra/ShowIdXmlAdapter.java similarity index 88% rename from web/src/main/java/org/cmc/curtaincall/web/boxoffice/infra/ShowIdXmlAdapter.java rename to web/src/main/java/org/cmc/curtaincall/web/show/infra/ShowIdXmlAdapter.java index 5ed33501..b43a8df3 100644 --- a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/infra/ShowIdXmlAdapter.java +++ b/web/src/main/java/org/cmc/curtaincall/web/show/infra/ShowIdXmlAdapter.java @@ -1,4 +1,4 @@ -package org.cmc.curtaincall.web.boxoffice.infra; +package org.cmc.curtaincall.web.show.infra; import jakarta.xml.bind.annotation.adapters.XmlAdapter; import org.cmc.curtaincall.domain.show.ShowId; diff --git a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/dto/BoxOfficeRequest.java b/web/src/main/java/org/cmc/curtaincall/web/show/request/BoxOfficeRequest.java similarity index 89% rename from web/src/main/java/org/cmc/curtaincall/web/boxoffice/dto/BoxOfficeRequest.java rename to web/src/main/java/org/cmc/curtaincall/web/show/request/BoxOfficeRequest.java index 25704d88..ea0f8f87 100644 --- a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/dto/BoxOfficeRequest.java +++ b/web/src/main/java/org/cmc/curtaincall/web/show/request/BoxOfficeRequest.java @@ -1,4 +1,4 @@ -package org.cmc.curtaincall.web.boxoffice.dto; +package org.cmc.curtaincall.web.show.request; import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotNull; diff --git a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/dto/BoxOfficeResponse.java b/web/src/main/java/org/cmc/curtaincall/web/show/response/BoxOfficeResponse.java similarity index 92% rename from web/src/main/java/org/cmc/curtaincall/web/boxoffice/dto/BoxOfficeResponse.java rename to web/src/main/java/org/cmc/curtaincall/web/show/response/BoxOfficeResponse.java index 5c7b5d86..14fd09f3 100644 --- a/web/src/main/java/org/cmc/curtaincall/web/boxoffice/dto/BoxOfficeResponse.java +++ b/web/src/main/java/org/cmc/curtaincall/web/show/response/BoxOfficeResponse.java @@ -1,4 +1,4 @@ -package org.cmc.curtaincall.web.boxoffice.dto; +package org.cmc.curtaincall.web.show.response; import lombok.Builder; import org.cmc.curtaincall.domain.show.ShowGenre; diff --git a/web/src/main/java/org/cmc/curtaincall/web/show/response/ShowDateTimeResponse.java b/web/src/main/java/org/cmc/curtaincall/web/show/response/ShowDateTimeResponse.java deleted file mode 100644 index c0d7d3f2..00000000 --- a/web/src/main/java/org/cmc/curtaincall/web/show/response/ShowDateTimeResponse.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.cmc.curtaincall.web.show.response; - -import lombok.Builder; -import org.cmc.curtaincall.domain.show.Facility; -import org.cmc.curtaincall.domain.show.FacilityId; -import org.cmc.curtaincall.domain.show.Show; -import org.cmc.curtaincall.domain.show.ShowDateTime; -import org.cmc.curtaincall.domain.show.ShowGenre; - -import java.time.LocalDateTime; - -@Builder -public record ShowDateTimeResponse( - String id, - String name, - FacilityId facilityId, - String facilityName, - String poster, - ShowGenre genre, - LocalDateTime showAt, - LocalDateTime showEndAt -) { - - public static ShowDateTimeResponse of(ShowDateTime showDateTime) { - Show show = showDateTime.getShow(); - Facility facility = show.getFacility(); - return ShowDateTimeResponse.builder() - .id(show.getId().getId()) - .name(show.getName()) - .facilityId(facility.getId()) - .facilityName(facility.getName()) - .poster(show.getPoster()) - .genre(show.getGenre()) - .showAt(showDateTime.getShowAt()) - .showEndAt(showDateTime.getShowEndAt()) - .build(); - } -} diff --git a/web/src/main/java/org/cmc/curtaincall/web/show/response/ShowFavoriteResponse.java b/web/src/main/java/org/cmc/curtaincall/web/show/response/ShowFavoriteResponse.java index e624bdfb..5b762251 100644 --- a/web/src/main/java/org/cmc/curtaincall/web/show/response/ShowFavoriteResponse.java +++ b/web/src/main/java/org/cmc/curtaincall/web/show/response/ShowFavoriteResponse.java @@ -1,19 +1,9 @@ package org.cmc.curtaincall.web.show.response; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; +import org.cmc.curtaincall.domain.show.ShowId; -@Getter -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class ShowFavoriteResponse { - - private String showId; - - private boolean favorite; - - public ShowFavoriteResponse(String showId, boolean favorite) { - this.showId = showId; - this.favorite = favorite; - } +public record ShowFavoriteResponse( + ShowId showId, + boolean favorite +) { } diff --git a/web/src/main/java/org/cmc/curtaincall/web/show/response/ShowReviewStatsResponse.java b/web/src/main/java/org/cmc/curtaincall/web/show/response/ShowReviewStatsResponse.java index cec16dc3..d611cfd9 100644 --- a/web/src/main/java/org/cmc/curtaincall/web/show/response/ShowReviewStatsResponse.java +++ b/web/src/main/java/org/cmc/curtaincall/web/show/response/ShowReviewStatsResponse.java @@ -8,6 +8,8 @@ public record ShowReviewStatsResponse( Long reviewGradeSum, Double reviewGradeAvg ) { + public static ShowReviewStatsResponse EMPTY = new ShowReviewStatsResponse(0, 0L, 0D); + public static ShowReviewStatsResponse of(final ShowReviewStatsDto stats) { return ShowReviewStatsResponse.builder() .reviewCount(stats.reviewCount()) diff --git a/web/src/test/java/org/cmc/curtaincall/web/boxoffice/BoxOfficeControllerDocsTest.java b/web/src/test/java/org/cmc/curtaincall/web/show/BoxOfficeControllerDocsTest.java similarity index 94% rename from web/src/test/java/org/cmc/curtaincall/web/boxoffice/BoxOfficeControllerDocsTest.java rename to web/src/test/java/org/cmc/curtaincall/web/show/BoxOfficeControllerDocsTest.java index bc459445..b10d5b34 100644 --- a/web/src/test/java/org/cmc/curtaincall/web/boxoffice/BoxOfficeControllerDocsTest.java +++ b/web/src/test/java/org/cmc/curtaincall/web/show/BoxOfficeControllerDocsTest.java @@ -1,10 +1,12 @@ -package org.cmc.curtaincall.web.boxoffice; +package org.cmc.curtaincall.web.show; import org.cmc.curtaincall.domain.show.BoxOfficeType; import org.cmc.curtaincall.domain.show.ShowGenre; import org.cmc.curtaincall.domain.show.ShowId; -import org.cmc.curtaincall.web.boxoffice.dto.BoxOfficeRequest; -import org.cmc.curtaincall.web.boxoffice.dto.BoxOfficeResponse; +import org.cmc.curtaincall.web.show.BoxOfficeController; +import org.cmc.curtaincall.web.show.BoxOfficeService; +import org.cmc.curtaincall.web.show.request.BoxOfficeRequest; +import org.cmc.curtaincall.web.show.response.BoxOfficeResponse; import org.cmc.curtaincall.web.common.AbstractWebTest; import org.cmc.curtaincall.web.show.ShowReviewStatsQueryService; import org.cmc.curtaincall.web.show.response.ShowReviewStatsDto; diff --git a/web/src/test/java/org/cmc/curtaincall/web/show/FavoriteShowControllerDocsTest.java b/web/src/test/java/org/cmc/curtaincall/web/show/FavoriteShowControllerDocsTest.java index 79fa17ac..4df64c71 100644 --- a/web/src/test/java/org/cmc/curtaincall/web/show/FavoriteShowControllerDocsTest.java +++ b/web/src/test/java/org/cmc/curtaincall/web/show/FavoriteShowControllerDocsTest.java @@ -10,7 +10,6 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.data.domain.SliceImpl; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; @@ -80,8 +79,8 @@ void cancelFavorite_Docs() throws Exception { void getFavorite_Docs() throws Exception { given(favoriteShowService.areFavorite(any(), any())).willReturn( List.of( - new ShowFavoriteResponse("PF220846", true), - new ShowFavoriteResponse("PF189549", false) + new ShowFavoriteResponse(new ShowId("PF220846"), true), + new ShowFavoriteResponse(new ShowId("PF189549"), false) ) ); @@ -135,7 +134,7 @@ void getFavoriteShowList_Docs() throws Exception { .build() ); given(favoriteShowService.getFavoriteShowList(any(), any())).willReturn( - new SliceImpl<>(favoriteShowResponseList) + favoriteShowResponseList ); // expected diff --git a/web/src/test/java/org/cmc/curtaincall/web/show/ShowControllerDocsTest.java b/web/src/test/java/org/cmc/curtaincall/web/show/ShowControllerDocsTest.java index 6f638ed3..09b926a1 100644 --- a/web/src/test/java/org/cmc/curtaincall/web/show/ShowControllerDocsTest.java +++ b/web/src/test/java/org/cmc/curtaincall/web/show/ShowControllerDocsTest.java @@ -8,7 +8,6 @@ import org.cmc.curtaincall.domain.show.ShowTime; import org.cmc.curtaincall.web.common.AbstractWebTest; import org.cmc.curtaincall.web.common.RestDocsAttribute; -import org.cmc.curtaincall.web.show.response.ShowDateTimeResponse; import org.cmc.curtaincall.web.show.response.ShowDetailResponse; import org.cmc.curtaincall.web.show.response.ShowResponse; import org.cmc.curtaincall.web.show.response.ShowReviewStatsDto; @@ -19,7 +18,6 @@ import org.springframework.http.MediaType; import java.time.LocalDate; -import java.time.LocalDateTime; import java.time.LocalTime; import java.util.List; @@ -510,57 +508,4 @@ void getShowListOfFacility_Docs() throws Exception { )); } - @Test - void getLiveTalkShowTimeList_Docs() throws Exception { - // given - var response = List.of( - ShowDateTimeResponse.builder() - .id("PF220846") - .name("잘자요, 엄마 [청주]") - .facilityId(new FacilityId("FC000182")) - .facilityName("예술나눔 터") - .genre(ShowGenre.PLAY) - .poster("http://www.kopis.or.kr/upload/pfmPoster/PF_PF220846_230704_164730.jpg") - .showAt(LocalDateTime.of(2023, 4, 28, 19, 0)) - .showEndAt(LocalDateTime.of(2023, 4, 28, 20, 30)) - .build() - ); - - given(showService.getLiveTalkShowTimeList(any())).willReturn(response); - - // expected - mockMvc.perform(get("/livetalk-show-times") - .header(HttpHeaders.AUTHORIZATION, "Bearer ACCESS_TOKEN") - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON) - .param("page", "0") - .param("size", "20") - .param("baseDateTime", LocalDateTime.of(2023, 4, 13, 22, 0).toString()) - ) - .andExpect(status().isOk()) - .andDo(print()) - .andDo(document("show-get-show-time-list", - requestHeaders( - headerWithName(HttpHeaders.AUTHORIZATION).description("인증 필요") - ), - queryParameters( - parameterWithName("page").description("페이지"), - parameterWithName("size").description("페이지 사이즈").optional(), - parameterWithName("baseDateTime").description("기준 시간 (현재 시간)") - ), - responseFields( - beneathPath("content[]").withSubsectionId("content"), - fieldWithPath("id").description("공연 아이디"), - fieldWithPath("name").description("공연명"), - fieldWithPath("facilityId").description("공연 시설 ID"), - fieldWithPath("facilityName").description("공연 시설명"), - fieldWithPath("poster").description("공연 포스터 경로"), - fieldWithPath("genre").description("공연 장르명") - .type(ShowGenre.class.getSimpleName()), - fieldWithPath("showAt").description("공연 시작 일시"), - fieldWithPath("showEndAt").description("공연 종료 일시") - ) - )); - } - } \ No newline at end of file diff --git a/web/src/test/java/org/cmc/curtaincall/web/boxoffice/infra/KopisBoxOfficeServiceTest.java b/web/src/test/java/org/cmc/curtaincall/web/show/infra/KopisBoxOfficeServiceTest.java similarity index 96% rename from web/src/test/java/org/cmc/curtaincall/web/boxoffice/infra/KopisBoxOfficeServiceTest.java rename to web/src/test/java/org/cmc/curtaincall/web/show/infra/KopisBoxOfficeServiceTest.java index 1f58ff99..d45e21b6 100644 --- a/web/src/test/java/org/cmc/curtaincall/web/boxoffice/infra/KopisBoxOfficeServiceTest.java +++ b/web/src/test/java/org/cmc/curtaincall/web/show/infra/KopisBoxOfficeServiceTest.java @@ -1,4 +1,4 @@ -package org.cmc.curtaincall.web.boxoffice.infra; +package org.cmc.curtaincall.web.show.infra; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; @@ -8,8 +8,9 @@ import org.cmc.curtaincall.domain.show.ShowGenre; import org.cmc.curtaincall.domain.show.ShowId; import org.cmc.curtaincall.domain.show.repository.ShowRepository; -import org.cmc.curtaincall.web.boxoffice.dto.BoxOfficeRequest; -import org.cmc.curtaincall.web.boxoffice.dto.BoxOfficeResponse; +import org.cmc.curtaincall.web.show.infra.KopisBoxOfficeService; +import org.cmc.curtaincall.web.show.request.BoxOfficeRequest; +import org.cmc.curtaincall.web.show.response.BoxOfficeResponse; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach;