예약 관리 시스템 - Spring + Vue

예약 관리 시스템 (Spring Boot 3 + Vue 3) - 예약 하기 (백엔드)

그랜파 개발자 2025. 5. 26. 19:20

예약 기능 전체 흐름에 필요한 ReservationController, ReservationService, DTO, 모델, 리포지토리 구조를 포함한 전체 코드 입니다.
프론트엔드에서 JWT 토큰을 헤더로 넘기면 사용자의 이메일을 추출하여 예약을 등록합니다.


✅ ReservationController.java

package com.example.reservation.controller;

import com.example.reservation.dto.ReservationRequest;
import com.example.reservation.dto.ReservationResponse;
import com.example.reservation.service.ReservationService;
import com.example.reservation.util.JwtUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/auth")
@CrossOrigin(origins = "http://localhost:5173")
@RequiredArgsConstructor
public class ReservationController {

    private final ReservationService reservationService;
    private final JwtUtil jwtUtil;

    @PostMapping("/reservations")
    public ReservationResponse create(
            @RequestBody ReservationRequest request,
            @RequestHeader("Authorization") String authHeader
    ) {
        String token = authHeader.replace("Bearer ", "");
        String email = jwtUtil.extractUsername(token);
        return reservationService.createReservation(email, request);
    }
}

✅ ReservationService.java

package com.example.reservation.service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;

import com.example.reservation.dto.ReservationRequest;
import com.example.reservation.dto.ReservationResponse;
import com.example.reservation.model.Reservation;
import com.example.reservation.model.ReservationStatus;
import com.example.reservation.model.ReservationTimeSlot;
import com.example.reservation.model.User;
import com.example.reservation.repository.ReservationRepository;
import com.example.reservation.repository.UserRepository;

import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class ReservationService {

    private final ReservationRepository reservationRepository;
    private final UserRepository userRepository;

    @Transactional
    public ReservationResponse createReservation(String email, ReservationRequest request) {
        User user = userRepository.findByEmail(email).orElseThrow();

        Reservation reservation = new Reservation();
        reservation.setDate(LocalDate.parse(request.getDate()));
        reservation.setUser(user);
        reservation.setMemo(request.getMemo());
        reservation.setStatus(ReservationStatus.PENDING);
        reservation.setCreatedAt(LocalDateTime.now());

        List<ReservationTimeSlot> slotEntities = request.getTimeSlots().stream()
            .map(ts -> {
                ReservationTimeSlot slot = new ReservationTimeSlot();
                slot.setTimeSlot(ts);
                slot.setReservation(reservation);  // 필수
                return slot;
            }).collect(Collectors.toList());

        reservation.setTimeSlots(slotEntities);

        Reservation saved = reservationRepository.save(reservation);

        return new ReservationResponse(
                saved.getId(),
                saved.getDate().toString(),
                saved.getTimeSlots().stream().map(ReservationTimeSlot::getTimeSlot).toList(),
                saved.getMemo(),
                saved.getStatus().name(),
                saved.getCreatedAt().toString()
        );
    }
}

✅ ReservationRequest.java

package com.example.reservation.dto;

import lombok.Data;
import java.util.List;

@Data
public class ReservationRequest {
    private String date; // "yyyy-MM-dd"
    private List<String> timeSlots; // e.g., ["10:00~11:00", "11:00~12:00"]
    private String memo;
}

✅ ReservationResponse.java

package com.example.reservation.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;

@Data
@AllArgsConstructor
public class ReservationResponse {
    private Long id;
    private String date;
    private List<String> timeSlots;
    private String memo;
    private String status;
    private String createdAt;
}

✅ Reservation.java

 
package com.example.reservation.model;

import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Reservation {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private LocalDate date;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;

    private String memo;

    @Enumerated(EnumType.STRING)
    private ReservationStatus status;

    private LocalDateTime createdAt;

    @OneToMany(mappedBy = "reservation", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<ReservationTimeSlot> timeSlots = new ArrayList<>();
}

✅ ReservationTimeSlot.java

package com.example.reservation.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.*;
import lombok.*;

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ReservationTimeSlot {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String timeSlot;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "reservation_id")
    @JsonIgnore
    private Reservation reservation;

    public ReservationTimeSlot(Reservation reservation, String timeSlot) {
        this.reservation = reservation;
        this.timeSlot = timeSlot;
    }
}

✅ ReservationStatus.java

package com.example.reservation.model;

public enum ReservationStatus {
    PENDING, APPROVED, REJECTED, CANCELLED
}

✅ Repository 인터페이스

ReservationRepository.java

package com.example.reservation.repository;

import com.example.reservation.model.Reservation;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ReservationRepository extends JpaRepository<Reservation, Long> {
    // JpaRepository를 상속받으면 save() 등 기본 CRUD 메서드 사용 가능
}

 

ReservationTimeSlotRepository.java
package com.example.reservation.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import com.example.reservation.model.ReservationTimeSlot;

public interface ReservationTimeSlotRepository extends JpaRepository<ReservationTimeSlot, Long> {}