로그인 페이지
아이뒤 비밀번호 입력시 db에 있다면 로그인
- 세션 로그인

1.Controller
@PostMapping("/login")
public String login(@Valid UserRequest.LoginDTO loginDTO, Errors errors) {
User sessionUser = userSerivce.로그인(loginDTO);
session.setAttribute("sessionUser", sessionUser);
//TODO 주헌
//session.setAttribute();
return "redirect:/";
}
2.User
package shop.mtcoding.filmtalk.user;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import java.sql.Timestamp;
@Getter
@Setter
@Table(name = "user_tb")
@NoArgsConstructor
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String username;//아이디
@Column(nullable = false)
private String password;
@Column(nullable = false)
private String email;
@Column
private String phone;
@CreationTimestamp
private Timestamp createdAt;
@Builder
public User(Long id, String username, String password, String email,String phone, Timestamp createdAt) {
this.id = id;
this.username = username;
this.password = password;
this.email = email;
this.phone = phone;
this.createdAt = createdAt;
}
}
service
public User 로그인(UserRequest.LoginDTO loginDTO) {
User user = userQueryRepository.findByUsernameAndPassword(loginDTO.getUsername(), loginDTO.getPassword());
return user;
}
repository
public User findByUsernameAndPassword(String username, String password) {
Query query = em.createQuery("select u from User u where u.username=:username and u.password =:password", User.class);
query.setParameter("username", username);
query.setParameter("password", password);
try {
User user = (User) query.getSingleResult();
return user;
} catch (Exception e) {
throw new Exception401("인증되지 않았습니다.");
}
}
인증되지 않으면 예외처리 진행
관리자 로그인 페이지
관리자페이지로그인

Admin
package shop.mtcoding.filmtalk.admin;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import shop.mtcoding.filmtalk.cinema.Cinema;
import java.sql.Timestamp;
@Getter
@Setter
@Table(name = "admin_tb")
@NoArgsConstructor
@Entity
public class Admin {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false)
private String password;
@Column(nullable = false, unique = true)
private String email;
private String phone;
@Column(nullable = false)
private String name; // 실제 이름 추가
private String role; // ROLE_ADMIN, ROLE_SUPERADMIN 등
@Column(nullable = false)
private Boolean approved = false; // 승인 여부 추가
private String profileUrl; // 프로필 사진 URL 추가
@CreationTimestamp
private Timestamp createdAt;
@ManyToOne(fetch = FetchType.LAZY)
private Cinema cinema;
@Builder
public Admin(Long id, String username, String password, String email, String phone, String name, String role, Boolean approved, String profileUrl, Timestamp createdAt, Cinema cinema) {
this.id = id;
this.username = username;
this.password = password;
this.email = email;
this.phone = phone;
this.name = name;
this.role = role;
this.approved = approved;
this.profileUrl = profileUrl;
this.createdAt = createdAt;
this.cinema = cinema;
}
}
controller
@PostMapping("/admin/login")
public String adminLogin(AdminShotimeRequest.LoginDTO loginDTO){
Admin sessionAdmin = adminService.로그인(loginDTO);
session.setAttribute("sessionAdmin", sessionAdmin);
return "admin/dashboard";
}
세션이 등록
service
public Admin 로그인(AdminShotimeRequest.LoginDTO loginDTO) {
Admin admin = adminRepository.mFindByOneUsernameAndPassword(loginDTO.getUsername(),loginDTO.getPassword())
.orElseThrow(() -> new Exception401("인증되지 않았습니다"));
return admin;
}
아이디와 패스워드가 틀리다면 예외처리
상영관 등록하기
상영관등록하기


상영관 등록을 위한 로직
- 프론트에서 상영관id, 영화id. 상영날짜를 보내준다
- 관리자 권한이 등록이 가능한 사람인지를 체크한다.
- 영화와 상영관의 상영시간을 가져온다.
- 상영시간을 등록한다.
1. controller
@PostMapping("/admin/showtime")
public String saveShowtime(@ModelAttribute AdminShotimeRequest.ShowtimeSaveRequest req) {
// 상영관 등록 처리
int day = adminService.상영관등록하기(req);
// 리다이렉트로 /admin/showtime 페이지로 이동
return "redirect:/admin/showtime/"+ day;
}
2.service
//어드민 유저확인해야함 원래 -- 추가필요
@Transactional
public int 상영관등록하기(AdminShotimeRequest.ShowtimeSaveRequest req) {
// 영화와 상영관을 가져옴
Movie movie = movieRepository.findById(req.getMovieId())
.orElseThrow(() -> new ExceptionApi401("Movie not found"));
Screen screen = screenRepository.findById(req.getScreenId())
.orElseThrow(() -> new ExceptionApi404("Screen not found"));
// 상영 시간 엔티티 생성
Showtime showtime = new Showtime();
showtime.setMovie(movie);
showtime.setScreen(screen);
showtime.setPrice(req.getPrice());
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime localDateTime = LocalDateTime.parse(req.getTime(), formatter);
// LocalDateTime을 Timestamp로 변환
Timestamp timestamp = Timestamp.valueOf(localDateTime);
showtime.setStartedAt(timestamp); // 상영 시작 시간 설정
int dayOfMonth = localDateTime.getDayOfMonth();
// 상영 시간 저장
showtimeRepository.save(showtime);
return dayOfMonth;
}
3.dto
public class AdminShotimeRequest {
@Data
public static class LoginDTO {
@NotEmpty
private String username;
@NotEmpty
private String password;
}
@Data
public static class ShowtimeSaveRequest {
private Long movieId;
private String time; // 상영 시작 시간
private Long screenId; // 상영관 ID
private Integer price =10;
public ShowtimeSaveRequest(){}
public ShowtimeSaveRequest(Long movieId, String time, Long screenId) {
this.movieId = movieId;
this.time = time;
this.screenId = screenId;
}
}
}
추가로직
등록하려는 상영시간에 중복되는 시간이 없는지 검증을 하는 로직이 필요해 보인다.
날짜별 상영시간 계산하기
상영시간을 계산해야되는 이유

프론트를 보면 날짜별 상영관을 보여준다.
우리는 프론트에게 날짜별 상영리스트와 상영관 등록시 상영시작가능 시간을 알려줘야한다.(아니면 상영시간이 겹치는 상황 발생)
다음상영시간을 구하는 로직
- 그날짜에 상영시간이 있을 경우
- 그날짜에 상영시간이 없을 경우
크게 이렇게 2가지 경우로 나누었다.
1.1 상영시간이 있을 경우
f (!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);
}
}
그전 상영시간에 영화 런타임을 더하고 +30분을 한 시간이 다음 상영가능 시간이 된다.
1.2 상영시간이 있을 경우(자정을 넘었는지 체크)
// selectedDate의 다음날 자정 기준으로 비교
LocalDateTime midnight = selectedDate.plusDays(1).atTime(0, 0); // 다음날 자정
// 자정 기준 검증
if (showtimeEnd.isBefore(midnight)) {
screenDTO.setCanAddShowtime("true");
screenDTO.setNextAvailableTime(showtimeEnd);
} else {
screenDTO.setCanAddShowtime(null);
}
근데 만약 상영시간이 자정을 넘겼다면 다른 처리를 해줘야한다.
왜냐하면 12일 11시 59분에 등록을 했다고 가정을 한다면 당연히 영화 런타임을 더하면 다음날이 되기 때문에 다음날의 데이터는 프론트에게 넘기면 안된다.
2.1 상영시간이 없을경우
if (previousDayShowtimes.isEmpty()) {
// 전날에도 상영 시간이 없는 경우
screenDTO.setNextAvailableTime(selectedDate.atStartOfDay()); // 0시로 설정
screenDTO.setCanAddShowtime("true");
}
전날에 상영시간이 조회가 안되는거는 휴무였을 가능성이 높다 이럴경우에는 첫시작시간은 마음대로 설정해도 겹치는 시간이 발생하지 않는다 설정하지 않는다면 기초시간을 0시로 설정했다.
2.2
// 전날 상영 시간이 있는 경우
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");
}
전날에 상영시간이 있는 경우 상영시간 중 가장 마지막에 상영된 상영스케줄을 찾아 자정을 넘었는지를 체크하고 넘었다면 넘은 시간 뒤가 오늘 상영가능한 시간으로 설정

상영시간이 넘어간 상영관을 상영스케줄 등록을 막았고

다음날 상영가능 시간을 추가한거를 확인할 수 있다.
상영관 및 상영시간 테스트
testController
@GetMapping("/admin/test/showtime")
public ResponseEntity<?> showtimetest() {
Admin sessionAdmin = (Admin) session.getAttribute("sessionAdmin");
int cinemaId = 1;
LocalDate startDate = LocalDate.of(2024, 9, 25);
// DTO 생성
AdminShowtimeResponse.CinemaScheduleWithMoviesDTO cinemaSchedule = adminService.상영관별상영스케줄(sessionAdmin, startDate);
// 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());
}
// JSON 형식으로 DTO 반환
return ResponseEntity.ok(cinemaSchedule);
}
결과 json
{
"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"
}
],
"nextAvailableTime": "2024-09-25T22:42:00",
"canAddShowtime": "true",
"formattedNextAvailableTime": "2024-09-25 22:42"
},
{
"screenId": 2,
"screenName": "서면2상영관",
"showtimes": [ ],
"nextAvailableTime": "2024-09-25T00:00:00",
"canAddShowtime": "true",
"formattedNextAvailableTime": "2024-09-25 00:00"
},
{
"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
}
]
}
Service
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);
}
리포지토리 테스트
@Test
public void findScreensWithShowtimesByIdsAndDate_test(){
Long cinemaId = 1L;
Cinema cinemas = cinemaRepository.mFindByIdWithScreen(cinemaId);
List<Long> screenIds = new ArrayList<>();;
for (Screen screen : cinemas.getScreens()) {
screenIds.add(screen.getId());
System.out.println(screen.getId());
}
;
LocalDate date12 = LocalDate.of(2024, 9, 12); // 2024년 9월 12일
LocalDate date13 = LocalDate.of(2024, 9, 13); // 2024년 9월 13일
List<Screen> screens1 =screenRepository.findScreensWithShowtimesByIdsAndDate(screenIds,date12);
System.out.println("--------------------");
System.out.println("12일");
for (Screen screen : screens1) {
System.out.println(screen.getName());
for (Showtime showtime : screen.getShowtimes()){
System.out.println(showtime.getStartedAt());
}
}
System.out.println("33333333333333333333");
System.out.println("13일");
List<Screen> screens2 =screenRepository.findScreensWithShowtimesByIdsAndDate(screenIds,date13);
for (Screen screen : screens2) {
System.out.println(screen.getName());
for (Showtime showtime : screen.getShowtimes()){
System.out.println(showtime.getStartedAt());
}
}
}
@Test
public void admin_mFindAllwithScreenByIds(){
Long cinemaId = 1L;
Cinema cinemas = cinemaRepository.mFindByIdWithScreen(cinemaId);
List<Long> screenIds = new ArrayList<>();;
for (Screen screen : cinemas.getScreens()) {
screenIds.add(screen.getId());
}
for (Long screenId : screenIds) {
System.out.println("상영관id = " + screenId);
}
// 저장된 상영관 ID들을 통해 상영관과 그에 속한 showtime을 조회
List<Screen> screensWithShowtimes = screenRepository.findScreensWithShowtimesByIds(screenIds);
// 결과 출력 (테스트용)
for (Screen screen : screensWithShowtimes) {
System.out.println("상영관 id = " + screen.getId());
for (Showtime showtime : screen.getShowtimes()) {
System.out.println("상영시간 = " + showtime.getMovie().getRuntime());
}
}
}
Share article