Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat#11] 공연 좌석 정보 조회, 공연 좌석 예약 (동시성 해결 X) #15

Merged
merged 10 commits into from
Oct 2, 2021
Merged
2 changes: 2 additions & 0 deletions ticket/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
// validation
implementation 'org.springframework.boot:spring-boot-starter-validation'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'mysql:mysql-connector-java'
annotationProcessor 'org.projectlombok:lombok'
Expand Down
25 changes: 25 additions & 0 deletions ticket/src/main/java/comento/backend/ticket/config/ErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package comento.backend.ticket.config;

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public enum ErrorCode {
/**
* @see : 예외케이스 정의
*/

INVALID_VALUE(400, HttpStatus.BAD_REQUEST, "BAD REQUEST", "잘못된 요청입니다. 다시 요청해주세요."),
NO_USER(401, HttpStatus.UNAUTHORIZED,"UNAUTHORIZED", "등록되지 않은 사용자입니다"),
NO_DATA(404, HttpStatus.NOT_FOUND, "NOT FOUND ERROR", "요청할 수 없는 리소스입니다."),
INVALID_USER(409, HttpStatus.CONFLICT, "CONFLICT", "이미 존재하는 사용자입니다."),
INVALID_SEAT(409, HttpStatus.CONFLICT, "CONFLICT", "이미 예약된 좌석입니다."),
SERVER_ERROR(500, HttpStatus.INTERNAL_SERVER_ERROR, "INTERVAL_SERVER ERROR", "서버 에러입니다.");

private final Integer status;
private final HttpStatus httpStatus;
private final String message;
private final String reason;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package comento.backend.ticket.config;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

@Data
@AllArgsConstructor
@Builder
public class ErrorResponse<T>{
private Integer status;
private String message;
private String reason;

//공통된 Error Message를 전송할 때 사용
public static ErrorResponse res(final Integer status, final String message, final String reason){
return ErrorResponse.builder()
.status(status)
.message(message)
.reason(reason)
.build();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package comento.backend.ticket.config;

import com.fasterxml.jackson.core.JsonParseException;
import comento.backend.ticket.config.customException.DuplicatedException;
import comento.backend.ticket.config.customException.NoAuthException;
import comento.backend.ticket.config.customException.NotFoundDataException;
import javassist.NotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.validation.ConstraintViolationException;
import java.util.NoSuchElementException;

@RestControllerAdvice //@Conroller 전역에서 발생 가능한 예외를 잡아 처리
@Slf4j
public class GlobalExceptionHandler {
private static ErrorCode errorCode;

/**
* 특정 Exception을 지정하여 별도로 처리
*/

//ConstraintViolationException.class 는 유효성 검사 실패시 (@Validated)
@ExceptionHandler({JsonParseException.class,
MethodArgumentNotValidException.class,
ConstraintViolationException.class,
MethodArgumentTypeMismatchException.class,
MissingServletRequestParameterException.class})
public static ResponseEntity missMatchExceptionHandler(Throwable t){
errorCode = ErrorCode.INVALID_VALUE;
log.error(errorCode.getStatus() + " " + errorCode.getMessage(), t);
return new ResponseEntity<>(ErrorResponse.res(errorCode.getStatus(), errorCode.getMessage(), errorCode.getReason()),
errorCode.getHttpStatus());
}

@ExceptionHandler(NoAuthException.class)
public static ResponseEntity noAuthExceptionHandler(NoAuthException e){
errorCode = ErrorCode.NO_USER;
log.error(errorCode.getStatus() + errorCode.getMessage(), e);
return new ResponseEntity<>(ErrorResponse.res(errorCode.getStatus(), errorCode.getMessage(), errorCode.getReason()),
errorCode.getHttpStatus());
}

@ExceptionHandler({NoSuchElementException.class, NotFoundException.class, NotFoundDataException.class})
public static ResponseEntity notFoundExceptionHandler(Throwable t){
errorCode = ErrorCode.NO_DATA;
log.error(errorCode.getStatus() + " " + errorCode.getMessage(), t);
return new ResponseEntity<>(ErrorResponse.res(errorCode.getStatus(), errorCode.getMessage(), errorCode.getReason()),
errorCode.getHttpStatus());
}

@ExceptionHandler(DuplicatedException.class)
public static ResponseEntity duplicateExceptionHandler(DuplicatedException e){
if (e.getMessage() == "UserService") { //호출된 곳이 UserService
errorCode = ErrorCode.INVALID_USER;
log.error(errorCode.getStatus() + " " + errorCode.getMessage(), e);
}else{ //좌석 예약 시
errorCode = ErrorCode.INVALID_SEAT;
log.error(errorCode.getStatus() + " " + errorCode.getMessage(), e);
}
return new ResponseEntity<>(ErrorResponse.res(errorCode.getStatus(), errorCode.getMessage(), errorCode.getReason()),
errorCode.getHttpStatus());
}

@ExceptionHandler({IllegalStateException.class, RuntimeException.class})
public static ResponseEntity IllExceptionHandler(Throwable t){
errorCode = ErrorCode.SERVER_ERROR;
log.error(errorCode.getStatus() + " " + errorCode.getMessage(), t);
return new ResponseEntity<>(ErrorResponse.res(errorCode.getStatus(), errorCode.getMessage(), errorCode.getReason()),
errorCode.getHttpStatus());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package comento.backend.ticket.config;

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public enum SuccessCode {

OK(200, HttpStatus.OK, "OK"),
CREATED(201, HttpStatus.CREATED, "CREATED");

private final Integer status;
private final HttpStatus httpStatus;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package comento.backend.ticket.config;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

@Data
@AllArgsConstructor
@Builder
public class SuccessResponse<T> {
private Integer status;
private String message;
private Object data;

//공통된 Success Message를 전송할 때 사용
public static SuccessResponse res(final Integer status, final String message, final Object data){
return SuccessResponse.builder()
.status(status)
.message(message)
.data(data)
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package comento.backend.ticket.config.customException;

public class DuplicatedException extends RuntimeException{
public DuplicatedException() {
}

public DuplicatedException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package comento.backend.ticket.config.customException;

public class NoAuthException extends RuntimeException{
public NoAuthException() {
}

public NoAuthException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package comento.backend.ticket.config.customException;

public class NotFoundDataException extends RuntimeException{
public NotFoundDataException() {
}

public NotFoundDataException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package comento.backend.ticket.controller;

import comento.backend.ticket.config.SuccessCode;
import comento.backend.ticket.config.SuccessResponse;
import comento.backend.ticket.domain.Booking;
import comento.backend.ticket.dto.BookingDto;
import comento.backend.ticket.dto.BookingResponse;
import comento.backend.ticket.dto.BookingResponseCreated;
import comento.backend.ticket.service.BookingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.*;

@RestController
@RequestMapping("/api/performance/booking")
public class BookingController {
private final BookingService bookingService;
private SuccessCode successCode;

@Autowired
public BookingController(BookingService bookingService) {
this.bookingService = bookingService;
}

@PostMapping("")
public ResponseEntity addBooking(@Valid @RequestBody BookingDto reqBooking){
bookingService.saveBookging(reqBooking);
BookingResponseCreated result = new BookingResponseCreated(reqBooking.getSeatType(), reqBooking.getSeatNumber());
successCode = SuccessCode.CREATED;
return new ResponseEntity(SuccessResponse.res(successCode.getStatus(), successCode.getMessage(), result),
HttpStatus.CREATED);
}

@GetMapping("/email/{email}")
public ResponseEntity showMyBooking(@Valid @PathVariable String email){
List<BookingResponse> result = bookingService.getMyBooking(email);
successCode = SuccessCode.OK;
return new ResponseEntity(SuccessResponse.res(successCode.getStatus(), successCode.getMessage(), result),
HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package comento.backend.ticket.controller;

import comento.backend.ticket.config.SuccessCode;
import comento.backend.ticket.config.SuccessResponse;
import comento.backend.ticket.domain.Performance;
import comento.backend.ticket.dto.PerformanceDto;
import comento.backend.ticket.dto.PerformanceResponse;
import comento.backend.ticket.dto.SeatResponse;
import comento.backend.ticket.service.PerformanceService;
import comento.backend.ticket.service.SeatService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.*;
import java.util.Date;

@RestController
@RequestMapping("/api/performance")
public class PerformanceController {
private final PerformanceService performanceService;
private final SeatService seatService;
private SuccessCode successCode = SuccessCode.OK;

@Autowired
public PerformanceController(PerformanceService performanceService, SeatService seatService) {
this.performanceService = performanceService;
this.seatService = seatService;
}

@GetMapping("/info")
public ResponseEntity showPerformanceInfo(@Valid @RequestParam(value = "date", required = true)
@DateTimeFormat(pattern = "yyyy-MM-dd") Date date,
@Valid @RequestParam(value = "title", required = false) String title) {
PerformanceDto performanceDto = new PerformanceDto(title, date);
List<PerformanceResponse> result = performanceService.getListPerformance(performanceDto);

return new ResponseEntity(SuccessResponse.res(successCode.getStatus(), successCode.getMessage(), result),
HttpStatus.OK);
}

@GetMapping("/info/seat")
public ResponseEntity showPerformanceSeatInfo(@Valid @RequestParam(value = "date", required = true)
@DateTimeFormat(pattern = "yyyy-MM-dd") Date date,
@Valid @RequestParam(value = "title", required = true) String title) {
PerformanceDto performanceDto = new PerformanceDto(title, date);
List<PerformanceResponse> performanceData = performanceService.getListPerformance(performanceDto);

List<SeatResponse> seatResult = seatService.getListPerformanceSeat(performanceData.get(0));

return new ResponseEntity(SuccessResponse.res(successCode.getStatus(), successCode.getMessage(), seatResult),
HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package comento.backend.ticket.controller;

import comento.backend.ticket.config.SuccessCode;
import comento.backend.ticket.config.SuccessResponse;
import comento.backend.ticket.config.customException.NotFoundDataException;
import comento.backend.ticket.domain.User;
import comento.backend.ticket.dto.UserDto;
import comento.backend.ticket.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
public class UserController {
private SuccessCode successCode = SuccessCode.CREATED;
private final UserService userService;
private static final String CREATED_MSG = "등록 성공";

@Autowired
public UserController(UserService userService) {
this.userService = userService;
}

@PostMapping("/signup")
public ResponseEntity addEmail(@Validated @RequestBody UserDto userDto){
userService.saveUser(userDto);
return new ResponseEntity<>(SuccessResponse.res(successCode.getStatus(), successCode.getMessage(), CREATED_MSG),
successCode.getHttpStatus());
}
}
Loading