Skip to content

Commit b64ea43

Browse files
committed
✨ feat: 글로벌 예외 처리 핸들러 구현 및 validation 예외 처리 추가
1 parent 5501997 commit b64ea43

File tree

10 files changed

+222
-2
lines changed

10 files changed

+222
-2
lines changed
Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
package io.f1.backend.global.exception;
22

3+
import io.f1.backend.global.exception.errorcode.ErrorCode;
4+
35
public class CustomException extends RuntimeException {
46

5-
public CustomException(String message) {
6-
super(message);
7+
private final ErrorCode errorCode;
8+
9+
public CustomException(ErrorCode errorCode) {
10+
super(errorCode.getMessage());
11+
this.errorCode = errorCode;
12+
}
13+
14+
public ErrorCode getErrorCode() {
15+
return errorCode;
716
}
817
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package io.f1.backend.global.exception.errorcode;
2+
3+
import lombok.Getter;
4+
import lombok.RequiredArgsConstructor;
5+
import org.springframework.http.HttpStatus;
6+
7+
@Getter
8+
@RequiredArgsConstructor
9+
public enum AuthErrorCode implements ErrorCode {
10+
11+
UNAUTHORIZED("E401001", HttpStatus.UNAUTHORIZED, "로그인이 필요합니다."),
12+
AUTH_SESSION_NOT_FOUND("E401002", HttpStatus.UNAUTHORIZED, "세션이 존재하지 않습니다. 로그인 후 이용해주세요."),
13+
AUTH_SESSION_EXPIRED("E401003", HttpStatus.UNAUTHORIZED, "세션이 만료되었습니다. 다시 로그인해주세요."),
14+
AUTH_SESSION_LOST("E401004", HttpStatus.UNAUTHORIZED, "세션 정보가 유실되었습니다. 다시 로그인해주세요."),
15+
FORBIDDEN("E403001", HttpStatus.FORBIDDEN, "권한이 없습니다."),
16+
17+
LOGIN_FAILED("E401005", HttpStatus.UNAUTHORIZED, "아이디 또는 비밀번호가 일치하지 않습니다.");
18+
19+
private final String code;
20+
21+
private final HttpStatus httpStatus;
22+
23+
private final String message;
24+
25+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package io.f1.backend.global.exception.errorcode;
2+
3+
import lombok.Getter;
4+
import lombok.RequiredArgsConstructor;
5+
import org.springframework.http.HttpStatus;
6+
7+
@Getter
8+
@RequiredArgsConstructor
9+
public enum CommonErrorCode implements ErrorCode {
10+
11+
BAD_REQUEST_DATA("E400001", HttpStatus.BAD_REQUEST, "잘못된 요청 데이터입니다."),
12+
INVALID_PAGINATION("E400006", HttpStatus.BAD_REQUEST, "page와 size는 1 이상의 정수여야 합니다."),
13+
INTERNAL_SERVER_ERROR("E500001", HttpStatus.INTERNAL_SERVER_ERROR, "서버에러가 발생했습니다. 관리자에게 문의해주세요.");
14+
15+
private final String code;
16+
17+
private final HttpStatus httpStatus;
18+
19+
private final String message;
20+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.f1.backend.global.exception.errorcode;
2+
3+
import org.springframework.http.HttpStatus;
4+
5+
public interface ErrorCode {
6+
7+
String getCode();
8+
9+
HttpStatus getHttpStatus();
10+
11+
String getMessage();
12+
13+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.f1.backend.global.exception.errorcode;
2+
3+
import lombok.Getter;
4+
import lombok.RequiredArgsConstructor;
5+
import org.springframework.http.HttpStatus;
6+
7+
@Getter
8+
@RequiredArgsConstructor
9+
public enum QuestionErrorCode implements ErrorCode {
10+
11+
QUESTION_NOT_FOUND("E404003", HttpStatus.NOT_FOUND, "존재하지 않는 문제입니다.");
12+
13+
private final String code;
14+
15+
private final HttpStatus httpStatus;
16+
17+
private final String message;
18+
19+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package io.f1.backend.global.exception.errorcode;
2+
3+
import lombok.Getter;
4+
import lombok.RequiredArgsConstructor;
5+
import org.springframework.http.HttpStatus;
6+
7+
@Getter
8+
@RequiredArgsConstructor
9+
public enum QuizErrorCode implements ErrorCode {
10+
11+
FILE_SIZE_TOO_LARGE("E400005", HttpStatus.BAD_REQUEST, "파일 크기가 너무 큽니다."),
12+
UNSUPPORTED_MEDIA_TYPE("E415001", HttpStatus.UNSUPPORTED_MEDIA_TYPE, "지원하지 않는 파일 형식입니다."),
13+
INVALID_FILTER("E400007", HttpStatus.BAD_REQUEST, "title 또는 creator 중 하나만 입력 가능합니다."),
14+
QUIZ_NOT_FOUND("E404002", HttpStatus.NOT_FOUND, "존재하지 않는 퀴즈입니다.");
15+
16+
private final String code;
17+
18+
private final HttpStatus httpStatus;
19+
20+
private final String message;
21+
22+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.f1.backend.global.exception.errorcode;
2+
3+
import lombok.Getter;
4+
import lombok.RequiredArgsConstructor;
5+
import org.springframework.http.HttpStatus;
6+
7+
@Getter
8+
@RequiredArgsConstructor
9+
public enum RoomErrorCode implements ErrorCode {
10+
11+
ROOM_USER_LIMIT_REACHED("E403002", HttpStatus.FORBIDDEN, "정원이 모두 찼습니다."),
12+
ROOM_GAME_IN_PROGRESS("E403003", HttpStatus.FORBIDDEN, "게임이 진행 중 입니다."),
13+
ROOM_NOT_FOUND("E404005", HttpStatus.NOT_FOUND, "존재하지 않는 방입니다."),
14+
WRONG_PASSWORD("E401006", HttpStatus.UNAUTHORIZED, "비밀번호가 일치하지않습니다.");
15+
16+
private final String code;
17+
18+
private final HttpStatus httpStatus;
19+
20+
private final String message;
21+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package io.f1.backend.global.exception.errorcode;
2+
3+
import lombok.Getter;
4+
import lombok.RequiredArgsConstructor;
5+
import org.springframework.http.HttpStatus;
6+
7+
@Getter
8+
@RequiredArgsConstructor
9+
public enum UserErrorCode implements ErrorCode {
10+
11+
NICKNAME_EMPTY("E400002", HttpStatus.BAD_REQUEST, "닉네임은 필수 입력입니다."),
12+
NICKNAME_TOO_LONG("E400003", HttpStatus.BAD_REQUEST, "닉네임은 6글자 이하로 입력해야 합니다."),
13+
NICKNAME_NOT_ALLOWED("E400004", HttpStatus.BAD_REQUEST, "한글, 영문, 숫자만 입력해주세요."),
14+
NICKNAME_CONFLICT("E409001", HttpStatus.CONFLICT, "중복된 닉네임입니다."),
15+
USER_NOT_FOUND("E404001", HttpStatus.NOT_FOUND, "존재하지 않는 회원입니다.");
16+
17+
private final String code;
18+
19+
private final HttpStatus httpStatus;
20+
21+
private final String message;
22+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package io.f1.backend.global.exception.handler;
2+
3+
import io.f1.backend.global.exception.CustomException;
4+
import io.f1.backend.global.exception.errorcode.CommonErrorCode;
5+
import io.f1.backend.global.exception.errorcode.ErrorCode;
6+
import io.f1.backend.global.exception.response.ErrorResponse;
7+
import org.springframework.http.ResponseEntity;
8+
import org.springframework.validation.FieldError;
9+
import org.springframework.web.bind.MethodArgumentNotValidException;
10+
import org.springframework.web.bind.annotation.ExceptionHandler;
11+
import org.springframework.web.bind.annotation.RestControllerAdvice;
12+
13+
@RestControllerAdvice
14+
public class GlobalExceptionHandler {
15+
16+
@ExceptionHandler(CustomException.class)
17+
public ResponseEntity<ErrorResponse> handleCustomException(CustomException e) {
18+
ErrorCode errorCode = e.getErrorCode();
19+
20+
ErrorResponse response = new ErrorResponse(
21+
errorCode.getCode(),
22+
errorCode.getMessage()
23+
);
24+
return new ResponseEntity<>(response, errorCode.getHttpStatus());
25+
}
26+
27+
@ExceptionHandler(Exception.class)
28+
public ResponseEntity<ErrorResponse> handleException(Exception e) {
29+
CommonErrorCode errorCode = CommonErrorCode.INTERNAL_SERVER_ERROR;
30+
31+
ErrorResponse response = new ErrorResponse(
32+
errorCode.getCode(),
33+
errorCode.getMessage()
34+
);
35+
return new ResponseEntity<>(response, errorCode.getHttpStatus());
36+
}
37+
38+
@ExceptionHandler(MethodArgumentNotValidException.class)
39+
public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
40+
41+
CommonErrorCode code = CommonErrorCode.BAD_REQUEST_DATA;
42+
43+
String message = e.getBindingResult().getFieldErrors().stream()
44+
.map(FieldError::getDefaultMessage)
45+
.findFirst()
46+
.orElse(code.getMessage());
47+
48+
ErrorResponse response = new ErrorResponse(
49+
code.getCode(),
50+
message
51+
);
52+
53+
return new ResponseEntity<>(response, code.getHttpStatus());
54+
55+
}
56+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.f1.backend.global.exception.response;
2+
3+
import lombok.Getter;
4+
import lombok.RequiredArgsConstructor;
5+
6+
@Getter
7+
@RequiredArgsConstructor
8+
public class ErrorResponse {
9+
10+
private final String code;
11+
private final String message;
12+
13+
}

0 commit comments

Comments
 (0)