8.상영관 상영가능시간 로직

강재영's avatar
Dec 16, 2024
8.상영관 상영가능시간 로직
 
notion image
 

상영관 등록을 위한 로직

  1. 선택한 날짜와 등록한 관리자 가져오기
  1. 영화관 과 상영관을 가져오기
  1. 상영관별 선택한 날짜의 상영시간을 조회하기
  1. 상영관별 상영가능시간을 계산하기
 

1.상영관 등록 + 버튼 클릭

notion image
클릭시 모달창이 나오고 이모달창에는 기본적으로 상영가능 시간이 들어가있다.
 
notion image
영화는 우리 영화관에 등록되어있는 영화들을 등록할 수 있으며 이 영화를 선택시 런타임 계산되어서 보여준다.
 

2.Controller

@GetMapping("/admin/showtime/{day}") public String showtime(@PathVariable("day") int day, HttpServletRequest request, Model model) { Admin sessionAdmin = (Admin) session.getAttribute("sessionAdmin"); // 12일부터 시작하는 날짜 리스트 생성 LocalDate startDate = LocalDate.of(2024, 9, 25); LocalDate selectedDate = LocalDate.of(2024, 9, day); // URL에서 선택된 날짜 사용 LocalDate today = startDate; // 12일을 "오늘"로 취급 List<Map<String, Object>> dateList = new ArrayList<>(); for (int i = 0; i < 7; i++) { LocalDate currentDate = startDate.plusDays(i); // 25일부터 7일간 생성 Map<String, Object> dateMap = new HashMap<>(); dateMap.put("formattedDate", currentDate.format(DateTimeFormatter.ofPattern("dd"))); // "dd" 형식 dateMap.put("formattedDay", currentDate.format(DateTimeFormatter.ofPattern("E", Locale.KOREAN))); // 요일 dateMap.put("isToday", currentDate.equals(selectedDate)); // URL에서 선택된 날짜를 기준으로 오늘 처리 dateMap.put("fullDate", currentDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); // yyyy-MM-dd 형식 dateList.add(dateMap); } AdminShowtimeResponse.CinemaScheduleWithMoviesDTO cinemaSchedule = adminService.상영관별상영스케줄(sessionAdmin, selectedDate); // DTO 상태를 확인 for (int i = 0; i < cinemaSchedule.getCinemaSchedule().getScreens().size(); i++) { System.out.println("Screen " + (i + 1) + " can add showtime: " + cinemaSchedule.getCinemaSchedule().getScreens().get(i).getCanAddShowtime()); } model.addAttribute("dates", dateList); // 생성된 날짜 리스트를 모델에 추가 request.setAttribute("model", cinemaSchedule); return "admin/showtime"; }
사실 중간에 날짜를 계산하는 부분은 테스트 단계에만 필요하다 날짜마다 더미 데이터를 넣을 순 없으니 나는 25일을 고정으로 7일간의 날짜를 가지고 왔다
 

3.Service

상영시간을 계산하는 로직인데 문제가 되는 부분은 다음 상영시간을 계산하는것에 어려움을 겪었다.
 
notion image
 
여기를 보면 20시42분에 시작해서 런타임 112분인 유어네임이 있다 이영화가 끝나고 청소시간을 30분으로 임의로 잡으면 다음 상영시간이 나온다.
문제는 다음 상영시간이 나올때는 높은 확률로 자정이 넘었을 가능성이 높다
9월 12일 23:59:59가 넘으면 여기 26일 상영시간표의 1상영관에서는 +버튼이 나오면 안된다
 
notion image
 
notion image
 
영화를 등록하면 이날짜에 등록이 안되게 막아야한다.
 
또한 다음날 27일의 상영가능시간은 0시부터가 아니라 그전날 상영시간에 +30분을 더해야한다.
notion image
 
public AdminShowtimeResponse.CinemaScheduleWithMoviesDTO 상영관별상영스케줄(Admin sessionAdmin, LocalDate selectedDate) { System.out.println(selectedDate); // 영화 목록을 가져옴 List<Movie> movies = movieRepository.findAll(); List<AdminShowtimeResponse.movieDTO> movieDTOList = new ArrayList<>(); for (Movie movie : movies) { movieDTOList.add(new AdminShowtimeResponse.movieDTO(movie)); } Long cinemaId = 1L; // 영화관 정보를 가져옴 Cinema cinema = cinemaRepository.findById(cinemaId) .orElseThrow(() -> new IllegalArgumentException("Cinema not found")); // CinemaWithScreensDTO에 영화관 정보를 저장 AdminShowtimeResponse.CinemaWithScreensDTO cinemaWithScreensDTO = new AdminShowtimeResponse.CinemaWithScreensDTO(cinema); // 상영관들의 ID 리스트를 추출 List<Long> screenIds = new ArrayList<>(); for (Screen screen : cinema.getScreens()) { screenIds.add(screen.getId()); } // 각 상영관에 대한 ScreenDTO 생성 for (Screen screen : cinema.getScreens()) { AdminShowtimeResponse.ScreenDTO screenDTO = new AdminShowtimeResponse.ScreenDTO(screen); cinemaWithScreensDTO.addScreen(screenDTO); // 각 상영관 정보를 추가 } // 상영시간을 조회 (주어진 날짜와 상영관 ID 리스트에 맞게) List<Showtime> showtimes = showtimeRepository.findByScreenIdsAndShowDate(screenIds, selectedDate); // 각 상영관에 대해 showtime 추가 및 검증 for (AdminShowtimeResponse.ScreenDTO screenDTO : cinemaWithScreensDTO.getScreens()) { // 상영관에 해당하는 상영시간 필터링 List<Showtime> screenShowtimes = new ArrayList<>(); for (Showtime showtime : showtimes) { if (showtime.getScreen().getId().equals(screenDTO.getScreenId())) { screenShowtimes.add(showtime); } } // 상영 시간이 있을 경우 if (!screenShowtimes.isEmpty()) { for (Showtime showtime : screenShowtimes) { AdminShowtimeResponse.ShowtimeDTO showtimeDTO = new AdminShowtimeResponse.ShowtimeDTO(showtime); screenDTO.addShowtime(showtimeDTO); // 마지막 상영 종료 시간을 계산 (상영 시작 시간 + 런타임 + 30분) LocalDateTime showtimeEnd = showtime.getStartedAt().toLocalDateTime() .plusMinutes(showtime.getMovie().getRuntime() + 30); // selectedDate의 다음날 자정 기준으로 비교 LocalDateTime midnight = selectedDate.plusDays(1).atTime(0, 0); // 다음날 자정 // 자정 기준 검증 if (showtimeEnd.isBefore(midnight)) { screenDTO.setCanAddShowtime("true"); screenDTO.setNextAvailableTime(showtimeEnd); } else { screenDTO.setCanAddShowtime(null); } } } else { // 상영 시간이 없을 경우 LocalDate previousDate = selectedDate.minusDays(1); System.out.println("상영시간이 없을경우"); List<Showtime> previousDayShowtimes = showtimeRepository.findByScreenIdsAndShowDate(Collections.singletonList(screenDTO.getScreenId()), previousDate); if (previousDayShowtimes.isEmpty()) { // 전날에도 상영 시간이 없는 경우 screenDTO.setNextAvailableTime(selectedDate.atStartOfDay()); // 0시로 설정 screenDTO.setCanAddShowtime("true"); } else { // 전날 상영 시간이 있는 경우 Showtime lastShowtime = previousDayShowtimes.get(previousDayShowtimes.size() - 1); LocalDateTime previousEndTime = lastShowtime.getStartedAt().toLocalDateTime() .plusMinutes(lastShowtime.getMovie().getRuntime() + 30); if (previousEndTime.isBefore(selectedDate.atStartOfDay())) { screenDTO.setNextAvailableTime(selectedDate.atStartOfDay()); // 0시로 설정 } else { screenDTO.setNextAvailableTime(previousEndTime); } screenDTO.setCanAddShowtime("true"); } } } // 최종적으로 CinemaScheduleWithMoviesDTO 반환 return new AdminShowtimeResponse.CinemaScheduleWithMoviesDTO(cinemaWithScreensDTO, movieDTOList); }
 

4. 프론트에게 넘겨줄 데이터

{ "cinemaSchedule": { "cinemaId": 1, "cinemaName": "서면롯데시네마", "screens": [ { "screenId": 1, "screenName": "서면1상영관", "showtimes": [ { "showtimeId": 7, "movieName": "Interstellar", "runtime": 169, "startedAt": "18:00" }, { "showtimeId": 12, "movieName": "Parasite", "runtime": 132, "startedAt": "20:00" }, { "showtimeId": 22, "movieName": "Your Name", "runtime": 112, "startedAt": "22:42" } ], "nextAvailableTime": "2024-09-25T22:42:00", "canAddShowtime": null, "formattedNextAvailableTime": "2024-09-25 22:42" }, { "screenId": 2, "screenName": "서면2상영관", "showtimes": [ { "showtimeId": 21, "movieName": "Parasite", "runtime": 132, "startedAt": "00:00" }, { "showtimeId": 23, "movieName": "Parasite", "runtime": 132, "startedAt": "02:42" }, { "showtimeId": 25, "movieName": "Spirited Away", "runtime": 125, "startedAt": "04:00" }, { "showtimeId": 26, "movieName": "Interstellar", "runtime": 169, "startedAt": "18:35" }, { "showtimeId": 27, "movieName": "Parasite", "runtime": 132, "startedAt": "21:54" } ], "nextAvailableTime": "2024-09-25T21:54:00", "canAddShowtime": null, "formattedNextAvailableTime": "2024-09-25 21:54" }, { "screenId": 3, "screenName": "서면3상영관", "showtimes": [ ], "nextAvailableTime": "2024-09-25T00:00:00", "canAddShowtime": "true", "formattedNextAvailableTime": "2024-09-25 00:00" }, { "screenId": 4, "screenName": "서면4상영관", "showtimes": [ ], "nextAvailableTime": "2024-09-25T00:00:00", "canAddShowtime": "true", "formattedNextAvailableTime": "2024-09-25 00:00" } ] }, "movieList": [ { "movieId": 1, "movieName": "Interstellar", "runtime": 169 }, { "movieId": 2, "movieName": "Parasite", "runtime": 132 }, { "movieId": 3, "movieName": "The Godfather", "runtime": 175 }, { "movieId": 4, "movieName": "Your Name", "runtime": 112 }, { "movieId": 5, "movieName": "Spirited Away", "runtime": 125 } ] }
 
Share article

강재영 블로그