Skip to content

Commit

Permalink
Merge pull request #7 from Leets-Official/feat/#4/예외-핸들러-구현
Browse files Browse the repository at this point in the history
  • Loading branch information
hyxklee authored Sep 28, 2024
2 parents 1876665 + 564232b commit fe1333c
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.leets.X.domain.user.controller;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum ResponseMessage {


SUCCESS_SAVE(201,"회원가입에 성공했습니다.");

private final int code;
private final String message;

}

Original file line number Diff line number Diff line change
@@ -1,9 +1,34 @@
package com.leets.X.domain.user.controller;

import com.leets.X.domain.user.exception.UserNotFoundException;
import com.leets.X.global.common.response.ResponseDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Controller
import static com.leets.X.domain.user.controller.ResponseMessage.SUCCESS_SAVE;

// 스웨거에서 controller 단위 설명 추가
@Tag(name = "USER")
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/users")
public class UserController {

@GetMapping("/")
@Operation(summary = "테스트용 API")// 스웨거에서 API 별로 설명을 넣기 위해 사용하는 어노테이션
public String index() {
throw new UserNotFoundException();
}

// API 응답 예시를 위한 테스트 API
@GetMapping("/test")
@Operation(summary = "테스트용 API2")
public ResponseDto<Void> test() {
return ResponseDto.response(SUCCESS_SAVE.getCode(), SUCCESS_SAVE.getMessage());
}

}
15 changes: 15 additions & 0 deletions src/main/java/com/leets/X/domain/user/exception/ErrorMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.leets.X.domain.user.exception;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum ErrorMessage {

USER_NOT_FOUND(404,"존재하지 않는 유저입니다.");

private final int code;
private final String message;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.leets.X.domain.user.exception;

import com.leets.X.global.exception.BaseException;

import static com.leets.X.domain.user.exception.ErrorMessage.*;

// 모든 사용자 정의 예외는 BaseException을 상속할 것
public class UserNotFoundException extends BaseException {
public UserNotFoundException() {
super(USER_NOT_FOUND.getCode(), USER_NOT_FOUND.getMessage());
}

}
31 changes: 31 additions & 0 deletions src/main/java/com/leets/X/global/common/response/ResponseDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.leets.X.global.common.response;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class ResponseDto<T> {

private int code;
private String message;
private T data;

// 실패시 호출(데이터가 비어있음)
public static <T> ResponseDto<T> errorResponse(int code, String message) {
return new ResponseDto<>(code, message, null);
}

// data가 없는 응답시 호출(성공)
public static <T> ResponseDto<T> response(int code, String message) {
return new ResponseDto<>(code, message, null);
}

// 성공시 호출(데이터 포함)
public static <T> ResponseDto<T> response(int code, String message, T data) {
return new ResponseDto<>(code, message, data);
}

}
15 changes: 15 additions & 0 deletions src/main/java/com/leets/X/global/exception/BaseException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.leets.X.global.exception;

import lombok.Getter;

@Getter
public abstract class BaseException extends RuntimeException {

private final int errorCode;

public BaseException(int errorCode, String message) {
super(message);
this.errorCode = errorCode;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.leets.X.global.exception;

import com.leets.X.global.common.response.ResponseDto;
import lombok.extern.slf4j.Slf4j;
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;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

private static final String LOG_FORMAT = "Class : {}, Code : {}, Message : {}";

// 사용자 정의 예외 발생 시
@ExceptionHandler(BaseException.class)
public ResponseEntity<ResponseDto<Void>> handle(BaseException e) {

// 개발 용이성을 위해 전체 에러로그를 재출력. 운영 환경에서는 제거할 것
log.warn(e.getMessage(), e);
// 간략한 예외 정보 출력
log.warn(LOG_FORMAT, e.getClass().getSimpleName(), e.getErrorCode(), e.getMessage());

ResponseDto<Void> response = ResponseDto.errorResponse(e.getErrorCode(), e.getMessage());

return ResponseEntity
.status(e.getErrorCode()) // 실제 HTTP 상태 코드 설정
.body(response); // 본문에 ResponseDto 전달
}

// 파라미터가 없을 시
@ExceptionHandler(MissingServletRequestParameterException.class)
public ResponseEntity<ResponseDto<Void>> handle(MissingServletRequestParameterException e) {
int statusCode = 400;

log.warn(e.getMessage(), e);
log.warn(LOG_FORMAT, e.getClass().getSimpleName(), statusCode, e.getMessage());

ResponseDto<Void> response = ResponseDto.errorResponse(statusCode, e.getMessage());

return ResponseEntity
.status(statusCode)
.body(response);
}

// @Valid에서 발생한 예외
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ResponseDto<Void>> handle(MethodArgumentNotValidException e) {
int statusCode = 400;

log.warn(e.getMessage(), e);
log.warn(LOG_FORMAT, e.getClass().getSimpleName(), statusCode, e.getMessage());

ResponseDto<Void> response = ResponseDto.errorResponse(statusCode, e.getMessage());

return ResponseEntity
.status(statusCode)
.body(response);
}

@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ResponseDto<Void>> handle(IllegalArgumentException e) {
int statusCode = 400;

log.warn(e.getMessage(), e);
log.warn(LOG_FORMAT, e.getClass().getSimpleName(), statusCode, e.getMessage());

ResponseDto<Void> response = ResponseDto.errorResponse(statusCode, e.getMessage());

return ResponseEntity
.status(statusCode) // 실제 HTTP 상태 코드 설정
.body(response);
}

// 잡지 못한 이외의 예외
@ExceptionHandler(Exception.class)
public ResponseEntity<ResponseDto<Void>> handle(Exception e) {
int statusCode = 500;

log.warn(e.getMessage(), e);
log.warn(LOG_FORMAT, e.getClass().getSimpleName(), statusCode, e.getMessage());

ResponseDto<Void> response = ResponseDto.errorResponse(statusCode, e.getMessage());

return ResponseEntity
.status(statusCode) // 실제 HTTP 상태 코드 설정
.body(response);
}

}

0 comments on commit fe1333c

Please sign in to comment.