[Code] 좌석 메인 화면

김호정's avatar
Oct 09, 2024
[Code] 좌석 메인 화면
 
 

SeatController

@GetMapping("/api/seat") public String seat(HttpServletRequest request) { long showtimeId = (long) session.getAttribute("showtimeId"); SeatResponse.DTO model = seatService.좌석메인화면(showtimeId); request.setAttribute("model", model); return "seat/view"; }
 
좌석메인화면에 필요한 데이터를 조회하기 위해 showtimeId 가 필요한데
 
session으로 전달받아서 사용하였다.
 

SeatService

public SeatResponse.DTO 좌석메인화면(long id) { Showtime showtimePS = showtimeRepository.mFindById(id) .orElseThrow(() -> new Exception404("상영시간정보가 없습니다.")); Long screenId = showtimePS.getScreen().getId(); Screen screenPS = screenRepository.mFindAllById(screenId) .orElseThrow(() -> new Exception404("상영관정보가 없습니다.")); Integer totalSeat = seatRepository.mFindCountOfTotalSeat(id); if(totalSeat == null || totalSeat == 0){ throw new Exception404("좌석 정보가 없습니다."); } Integer reservedSeat = ticketRepository.mFindCountOfReservedSeats(id); if(reservedSeat == null){ reservedSeat = 0; } //System.out.println("예약된 좌석 수 " + reservedSeat); return new SeatResponse.DTO(showtimePS, screenPS, totalSeat, reservedSeat); }
 
null이나 0이 return 되는 경우 GlobalExceptionHandler 로 throw 해서 자바스크립트 alert 창이 뜨도록 처리하였다.
 

SeatRepository

@Query("select st from Showtime st left join fetch st.movie mt where st.id=:id") Optional<Showtime> mFindById(@Param("id") Long id);
 
컨벤션을 지키기 위해 m 을 매서드 이름 앞에 붙였다.
 

SeatResponse

@Data public static class DTO { // showtime private String startedAt; // 시작 시간 private String endedAt; // 끝나는 시간 private String wholeShowTime; // 일자 + 시간 private Integer price; // 영화 가격 ( 1좌석당, 1티켓당 ) // movie private Integer runtime; // 영화 러닝타임 private String movieNm; // 영화 pk private String ratingGrade; // 등급 //poster private String posterUrl; // 포스터 // screen private String screenNm; // 상영관 pk // cinema private String cinemaNm; // 영화관 pk private String cinemaImg; // 영화관 이미지 // seat count private Integer totalSeats; private Integer remainingSeats; public DTO(Showtime showtimePS, Screen screenPS, Integer totalSeat, Integer reservedSeat) { String formatGrande = "yyyy.MM.dd(E)"; String formatPequeno = "HH:mm"; String formatTotal = "yyyy.MM.dd(E) HH:mm"; //showtimePS.getStartedAt(); // 2024-09-12 14:00:00.0 // 시작 시간 형식 변환 this.startedAt = convertTimeStampToString(showtimePS.getStartedAt(), formatGrande); // 종료 시간 계산 ( 시작 시간 + runtime ) this.endedAt = calculateEndTime(showtimePS.getStartedAt(), showtimePS.getMovie().getRuntime()); // 종료 시간 계산 // 전체 시간 형식 변환 this.wholeShowTime = convertTimeStampToString(showtimePS.getStartedAt(), formatTotal); this.price = showtimePS.getPrice(); this.runtime = showtimePS.getMovie().getRuntime(); this.movieNm = showtimePS.getMovie().getMovieNm(); this.posterUrl = showtimePS.getMovie().getPosterUrls().get(0).getUrl(); String grade = showtimePS.getMovie().getRatingGrade(); if(grade == "전체"){ this.ratingGrade = "전체 관람가"; }else{ this.ratingGrade = grade + " 관람가"; } this.screenNm = screenPS.getName(); this.cinemaNm = screenPS.getCinema().getName(); this.cinemaImg = screenPS.getCinema().getImgName(); // 좌석 수 this.totalSeats = totalSeat; this.remainingSeats = totalSeats - reservedSeat; System.out.println(remainingSeats); } // Timestamp를 지정한 format으로 변환하는 매서드 public static String convertTimeStampToString(Timestamp timestamp, String format) { if(timestamp == null) return ""; try { Date date = new Date(); date.setTime(timestamp.getTime()); //return new SimpleDateFormat(format).format(date); // Locale 설정으로 요일을 한국어로 출력 SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.KOREAN); return sdf.format(date); } catch (Exception e) { throw new Exception404("날짜 정보가 뭔가 잘못되었습니다."); } } // 시작 시간에 runtime을 더해 종료 시간을 계산하는 매서드 public static String calculateEndTime(Timestamp startedAt, int runtimeMinutes){ LocalDateTime startDateTime = startedAt.toLocalDateTime(); // TimeStamp를 LocalDateTime으로 변환 LocalDateTime endDateTime = startDateTime.plus(runtimeMinutes, ChronoUnit.MINUTES); // runtime을 분 단위로 더함 // HH :mm 형식으로 변환 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm"); return endDateTime.format(formatter); } }
 
좌석 페이지에 필요한 정보들을 담았다
 
좌석은 제외.
 
→ 좌석 코드까지 들어가니 코드가 너무 길어져서 좌석을 제외한 정보만 담았다.
→ 좌석은 AJAX 로 요청해서 SeatDTO 에 담아서 return 하도록 코드를 분리하였다.
 

seatView.mustache

<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>title</title> <!-- 좌석 선택 --> <!-- 부트스트랩 CSS 링크 --> <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet"> <link rel="stylesheet" href="/css/seat.css"> <link rel="stylesheet" href="/css/header.css"> </head> <body> {{>layout/header}} <main> <div id="hidden-data" data-price="{{model.price}}" data-showtimeid="{{showtimeId}}"></div> <div class="container mt-5"> <!-- 상단 인원 / 좌석 --> <div class="text-center mb-4"> <div class="bg-dark text-white py-2 mb-3">인원 / 좌석</div> </div> <section> <div class="count__seat__section"> <!-- 인원 선택 --> <div class="count__section"> <div class="mb-4"> <div class="text-center"> <label>일반</label> <div class="btn-group btn-group-toggle" data-toggle="buttons"> <button class="btn btn-outline-primary" id="count0" value="0" onclick="resetCount()">0</button><!-- 0 클릭 시 초기화 --> <button class="btn btn-outline-primary" id="count1" value="1" onclick="getCount(this.value)">1</button> <button class="btn btn-outline-primary" id="count2" value="2" onclick="getCount(this.value)">2</button> <button class="btn btn-outline-primary" id="count3" value="3" onclick="getCount(this.value)">3</button> <button class="btn btn-outline-primary" id="count4" value="4" onclick="getCount(this.value)">4</button> </div> </div> </div> </div> <div class="vertical__line"></div> <div class="movie__info__section"> <!-- 상영 정보 --> <div class="text-center mb-4"> <img class="screen__img" src="/img/cinema01.jpg"><!-- model.cinema 이미지로 수정 --> <p class="font-weight-bold">{{model.cinemaNm}} | {{model.screenNm}} | 남은좌석 {{model.remainingSeats}}/{{model.totalSeats}}</p> <p>{{model.wholeShowTime}} ~ {{model.endedAt}}</p><!-- 2024.09.04 (수) 20:15 --> </div> </div> </div> </section> <!-- 좌석 배치 --> <div class="seat-selection text-center mb-4"> <div class="bg-dark text-white py-2 mb-3">SCREEN</div> <div id="seat-container"></div> <!-- 좌석 반복 추가 --> </div> </div> <!-- 하단 검은창 --> <div class="row bg-dark text-white py-2 mb-3"> <div class="col text-left"> <button class="btn btn-secondary">영화선택</button> </div> <div class="blackbox__middle__container"> <div class="blackbox__img__div"> <img class="movie__img" src="{{model.posterUrl}}"> </div> <div class="blackbox__movie__div"> <div>{{model.movieNm}}</div> <div>{{model.ratingGrade}}</div> </div> <div> <table> <tr> <td class="left__td">극장</td> <td class="right__td">{{model.cinemaNm}}</td> </tr> <tr> <td>일시</td> <td>{{model.wholeShowTime}}</td><!-- 2024.9.14(토) 12:00 --> </tr> <tr> <td>상영관</td> <td>{{model.screenNm}}</td> </tr> <tr> <td>인원</td> <td id="peopleNum"></td><!-- js로 --> </tr> </table> </div> <div class="seat__num__box" id="seatNumBox"> <!-- JS 로 동적으로 넣기 --> </div> <div class="seat__payment__box" id="paymentBox"> <!-- JS 로 동적으로 넣기 --> </div> </div> <div class="col text-right"> <form action="/api/seat/reservation" method="post"> <!--<input type="hidden" name="showtimeId" value="">--> <input type="hidden" name="showtimeId" value="{{showtimeId}}"> <input type="hidden" name="selectedSeatsIds" id="selectedSeatsIds"> <input type="hidden" name="totalPrice" id="totalPrice"> <button onclick="return didYouSelectAll()" class="btn btn-secondary" type="submit">결제선택</button> </form> </div> </div> <!-- 부트스트랩 JS 및 jQuery --> <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.3/dist/umd/popper.min.js"></script> <script src="/js/seat2.js"></script> </main> {{>layout/footer}} </body> </html>
 
 
notion image
 
좌석을 제외한 부분의 정보가 잘 들어왔다.
Share article

keepgoing