Eclipse에서 Spring Boot 프로젝트 생성
🔹 사전 준비
- JDK 17 이상
- Eclipse IDE (최신)
- Maven 설치 (또는 Eclipse 내장 Maven 사용)
- MySQL 실행 중
🔹 Step 1: Spring 프로젝트 생성
- Eclipse 실행 → File → New → Spring Starter Project
- 프로젝트 정보 입력:
- Name: reservation
- Type: Maven
- Packaging: Jar
- Java Version: 17
- Language: Java
- Group: com.example
- Artifact: j reservation
- Dependencies 추가:
- Spring Web
- Spring Data JPA
- Spring Boot DevTools (선택)
- Spring Security
- MySQL Driver
- Lombok
- Validation
- Finish 클릭하면 프로젝트가 생성됩니다.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>reservation</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>reservation</name>
<description>Demo project for Spring Boot</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.38</version> <!-- 최신 버전으로 변경 가능 -->
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/reservation?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
format_sql: true
application:
name: reservation
jwt:
secret: my-very-secret-key-for-jwt-token-signing
expiration: 3600000 # 1 hour
ReservationApplication.java
package com.example.reservation;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
@SpringBootApplication
@EnableMethodSecurity // 메서드 보안 활성화
public class ReservationApplication {
public static void main(String[] args) {
SpringApplication.run(ReservationApplication.class, args);
}
}
JwtUtil.java
package com.example.reservation.util;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.security.Key;
import java.util.Date;
import java.util.List;
@Component
public class JwtUtil {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private long expiration;
// 토큰 생성 시 역할 포함
public String generateToken(String email, String role) {
Date now = new Date();
Date expiry = new Date(now.getTime() + expiration);
Key key = Keys.hmacShaKeyFor(secret.getBytes());
return Jwts.builder()
.setSubject(email)
.claim("role", role) // 역할 추가
.setIssuedAt(now)
.setExpiration(expiry)
.signWith(key)
.compact();
}
// 토큰에서 사용자 이메일 추출
public String extractUsername(String token) {
Key key = Keys.hmacShaKeyFor(secret.getBytes());
return Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody()
.getSubject();
}
// 토큰에서 역할 목록 추출
@SuppressWarnings("unchecked")
public List<String> extractRoles(String token) {
Key key = Keys.hmacShaKeyFor(secret.getBytes());
Claims claims = Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();
Object roles = claims.get("role");
if (roles instanceof List<?>) {
return (List<String>) roles;
}
return List.of();
}
// 토큰 유효성 검사
public boolean isTokenValid(String token) {
try {
Key key = Keys.hmacShaKeyFor(secret.getBytes());
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
return true;
} catch (JwtException e) {
return false;
}
}
}
JwtFilter.java
package com.example.reservation.config;
import com.example.reservation.service.CustomUserDetailsService;
import com.example.reservation.util.JwtUtil;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.*;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@Component
@RequiredArgsConstructor
public class JwtFilter extends OncePerRequestFilter {
private static final Logger logger = LoggerFactory.getLogger(JwtFilter.class);
private final JwtUtil jwtUtil;
private final CustomUserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
final String header = request.getHeader("Authorization");
if (header == null || !header.startsWith("Bearer ")) {
chain.doFilter(request, response);
return;
}
try {
final String token = header.substring(7);
final String username = jwtUtil.extractUsername(token);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
var userDetails = userDetailsService.loadUserByUsername(username);
if (jwtUtil.isTokenValid(token)) {
var auth = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities()
);
auth.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
chain.doFilter(request, response);
}
catch (Exception e) {
{
logger.warn("JWT 인증 중 오류 발생: {}", e.getMessage());
}
}
}
}
SecurityConfig.java
package com.example.reservation.config;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.*;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.*;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.*;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import java.util.List;
@Configuration
@RequiredArgsConstructor
public class SecurityConfig {
private static final Logger logger = LoggerFactory.getLogger(JwtFilter.class);
private final JwtFilter jwtFilter;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.disable())
.cors(cors -> cors.configurationSource(request -> {
CorsConfiguration corsConfig = new CorsConfiguration();
corsConfig.setAllowedOrigins(List.of("http://localhost:5173"));
corsConfig.setAllowedMethods(List.of("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
corsConfig.setAllowedHeaders(List.of("Authorization", "Content-Type"));
corsConfig.setAllowCredentials(true);
return corsConfig;
}))
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() // OPTIONS 요청 허용
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.requestMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
);
http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration config
) throws Exception {
return config.getAuthenticationManager();
}
}
ApiResponse.java
package com.example.reservation.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class ApiResponse {
private boolean success;
private String message;
}
AuthRequest.java
package com.example.reservation.dto;
import lombok.Data;
@Data
public class AuthRequest {
private String email;
private String password;
}
AuthResponse.java
package com.example.reservation.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class AuthResponse {
private String token;
private String name;
private String role;
}
RegisterRequest.java
package com.example.reservation.dto;
import lombok.Data;
@Data
public class RegisterRequest {
private String email;
private String password;
private String name;
}
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<>();
}
ReservationStatus.java
package com.example.reservation.model;
public enum ReservationStatus {
PENDING, APPROVED, REJECTED, CANCELLED
}
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;
}
}
User.java
package com.example.reservation.model;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
@Entity
@Table(name = "users")
@Getter
@Setter
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false)
private String password;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String role;
}
ReservationRepository.java
package com.example.reservation.repository;
import com.example.reservation.model.Reservation;
import com.example.reservation.model.User;
import java.time.LocalDate;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ReservationRepository extends JpaRepository<Reservation, Long> {
// JpaRepository를 상속받으면 save() 등 기본 CRUD 메서드 사용 가능
// 특정 사용자에 대한 예약 목록 조회
List<Reservation> findByUser(User user);
// 날짜 기준 예약 목록 조회
List<Reservation> findByDate(LocalDate date);
}
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> {}
UserRepository.java
package com.example.reservation.repository;
import com.example.reservation.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
}
CustomUserDetailsService.java
package com.example.reservation.service;
import com.example.reservation.config.JwtFilter;
import com.example.reservation.model.User;
import com.example.reservation.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.userdetails.*;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {
private static final Logger logger = LoggerFactory.getLogger(JwtFilter.class);
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmail(email)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
logger.info("Loaded user roles: " + user.getRole()); // 여기서 roles 확인
return org.springframework.security.core.userdetails.User
.withUsername(user.getEmail())
.password(user.getPassword())
.roles(user.getRole())
.build();
}
}
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()
);
}
/**
* 관리자: 예약 상태 변경 (APPROVED, REJECTED, CANCELLED 등)
*/
@Transactional
public Reservation updateReservationStatus(Long reservationId, ReservationStatus status) {
Reservation reservation = reservationRepository.findById(reservationId)
.orElseThrow(() -> new RuntimeException("Reservation not found"));
reservation.setStatus(status);
return reservationRepository.save(reservation);
}
/**
* 관리자: 전체 예약 목록 조회
*/
public List<Reservation> getAllReservations() {
return reservationRepository.findAll();
}
public List<Reservation> getReservationsByDate(String date) {
// date 형식에 맞게 파싱 후 DB 쿼리 (예: '2025-05-27')
LocalDate localDate = LocalDate.parse(date); // 문자열 → LocalDate 변환
return reservationRepository.findByDate(localDate);
}
/**
* 사용자: 내 예약 목록 조회
*/
public List<Reservation> getReservationsByUser(String email) {
User user = userRepository.findByEmail(email).orElseThrow();
return reservationRepository.findByUser(user);
}
public void cancelReservation(Long reservationId, String email) {
Reservation reservation = reservationRepository.findById(reservationId)
.orElseThrow(() -> new RuntimeException("예약을 찾을 수 없습니다."));
// 클라이언트에서 로그인 후 예약을 취소하므로 본인의 예약만 취소를 한다.
// 승인 또는 거부가 된 예약도 취소할 수 있다.
// if (!reservation.getEmail().equals(email)) {
// throw new SecurityException("본인의 예약만 취소할 수 있습니다.");
// }
// if (reservation.getStatus() != ReservationStatus.PENDING) {
// throw new IllegalStateException("대기 중인 예약만 취소할 수 있습니다.");
// }
reservation.setStatus(ReservationStatus.CANCELLED);
reservationRepository.save(reservation);
}
}
AuthController.java
package com.example.reservation.controller;
import com.example.reservation.dto.*;
import com.example.reservation.model.User;
import com.example.reservation.repository.UserRepository;
import com.example.reservation.util.JwtUtil;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
@CrossOrigin(origins = "http://localhost:5173")
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final JwtUtil jwtUtil;
@PostMapping("/register")
public ResponseEntity<ApiResponse> register(@RequestBody @Valid RegisterRequest request) {
if (userRepository.findByEmail(request.getEmail()).isPresent()) {
return ResponseEntity.status(HttpStatus.CONFLICT)
.body(new ApiResponse(false, "Email already registered"));
}
User user = new User();
user.setEmail(request.getEmail());
user.setPassword(passwordEncoder.encode(request.getPassword()));
user.setName(request.getName());
user.setRole("USER");
userRepository.save(user);
return ResponseEntity.ok(new ApiResponse(true, "User registered successfully"));
}
@PostMapping("/login")
public ResponseEntity<AuthResponse> login(@RequestBody AuthRequest request) {
User user = userRepository.findByEmail(request.getEmail())
.orElseThrow(() -> new UsernameNotFoundException("Invalid email or password"));
if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
throw new BadCredentialsException("Invalid email or password");
}
// role 포함해서 토큰 생성
String token = jwtUtil.generateToken(user.getEmail(), user.getRole());
AuthResponse response = new AuthResponse(token, user.getName(), user.getRole());
return ResponseEntity.ok(response);
}
}
ReservationController.java
package com.example.reservation.controller;
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.service.ReservationService;
import com.example.reservation.util.JwtUtil;
import lombok.RequiredArgsConstructor;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/")
@CrossOrigin(origins = "http://localhost:5173")
@RequiredArgsConstructor
public class ReservationController {
private static final Logger logger = LoggerFactory.getLogger(ReservationController.class);
private final ReservationService reservationService;
private final JwtUtil jwtUtil;
@PostMapping("auth/reservation")
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);
}
/**
* ✅ 사용자: 자신의 예약 목록 조회
*/
@GetMapping("auth/reservations/my")
@PreAuthorize("hasRole('USER')")
public List<Reservation> getMyReservations(
@RequestHeader("Authorization") String authHeader
) {
String token = authHeader.replace("Bearer ", "");
String email = jwtUtil.extractUsername(token);
return reservationService.getReservationsByUser(email);
}
/**
* ✅ 사용자: 자신의 예약 취소
*/
@PatchMapping("auth/reservations/{id}/cancel")
@PreAuthorize("hasRole('USER')")
public ResponseEntity<?> cancelReservation(
@PathVariable Long id,
@RequestHeader("Authorization") String authHeader
) {
String token = authHeader.replace("Bearer ", "");
String email = jwtUtil.extractUsername(token);
reservationService.cancelReservation(id, email);
return ResponseEntity.ok("예약이 취소되었습니다.");
}
/**
* ✅ 관리자: 전체 예약 목록 조회
*/
@GetMapping("admin/reservations")
@PreAuthorize("hasRole('ADMIN')")
public List<Reservation> getAllReservations(
@RequestParam(required = false) String date
) {
if (date != null && !date.isEmpty()) {
return reservationService.getReservationsByDate(date);
}
return reservationService.getAllReservations();
}
@PreAuthorize("hasRole('ADMIN')")
@PostMapping("admin/reservation/{id}/approve")
public ResponseEntity<?> approveReservation(@PathVariable Long id) {
logger.info("==== approveReservation : " + id);
reservationService.updateReservationStatus(id, ReservationStatus.APPROVED);
return ResponseEntity.ok("Reservation approved");
}
@PreAuthorize("hasRole('ADMIN')")
@PostMapping("admin/reservation/{id}/reject")
public ResponseEntity<?> rejectReservation(@PathVariable Long id) {
logger.info("==== rejectReservation : " + id);
reservationService.updateReservationStatus(id, ReservationStatus.REJECTED);
return ResponseEntity.ok("Reservation rejected");
}
}
'예약 관리 시스템 - Spring + Vue' 카테고리의 다른 글
예약 관리 시스템 완성 - 프론트엔드(Vue 3 + Vuetify) (0) | 2025.05.29 |
---|---|
예약 관리 시스템 완성 - Spring Boot 3 + Vue 3 (0) | 2025.05.29 |
예약 관리 시스템 (Spring Boot 3 + Vue 3) - 예약 조회(사용자) (0) | 2025.05.29 |
예약 관리 시스템 (Spring Boot 3 + Vue 3) - 예약 관리(관리자) (1) | 2025.05.27 |
예약 관리 시스템 (Spring Boot 3 + Vue 3) - 예약 하기 (백엔드) (0) | 2025.05.26 |