-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from mju-likelion/feature/exception-#8
Feature/#8 전역 예외처리 적용
- Loading branch information
Showing
7 changed files
with
244 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
111 changes: 111 additions & 0 deletions
111
src/main/java/org/mjulikelion/baker/controller/ExceptionController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package org.mjulikelion.baker.controller; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
import org.mjulikelion.baker.dto.response.ResponseDto; | ||
import org.mjulikelion.baker.errorcode.ErrorCode; | ||
import org.mjulikelion.baker.errorcode.ValidationErrorCode; | ||
import org.mjulikelion.baker.exception.InvalidDataException; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.http.converter.HttpMessageNotReadableException; | ||
import org.springframework.validation.FieldError; | ||
import org.springframework.web.HttpRequestMethodNotSupportedException; | ||
import org.springframework.web.bind.MethodArgumentNotValidException; | ||
import org.springframework.web.bind.annotation.ExceptionHandler; | ||
import org.springframework.web.bind.annotation.ResponseStatus; | ||
import org.springframework.web.bind.annotation.RestControllerAdvice; | ||
import org.springframework.web.method.annotation.HandlerMethodValidationException; | ||
import org.springframework.web.servlet.resource.NoResourceFoundException; | ||
|
||
@Slf4j | ||
@RestControllerAdvice | ||
public class ExceptionController { | ||
//MethodArgumentNotValidException 예외를 처리하는 핸들러(Body(dto)의 Validation에 실패한 경우) | ||
@ResponseStatus(HttpStatus.BAD_REQUEST) | ||
@ExceptionHandler(MethodArgumentNotValidException.class) | ||
public ResponseEntity<ResponseDto<Void>> handleMethodArgumentNotValidException( | ||
MethodArgumentNotValidException methodArgumentNotValidException) { | ||
log.error("MethodArgumentNotValidException: {}", methodArgumentNotValidException.getMessage()); | ||
FieldError fieldError = methodArgumentNotValidException.getBindingResult().getFieldError(); | ||
if (fieldError == null) { | ||
return new ResponseEntity<>( | ||
ResponseDto.res(HttpStatus.BAD_REQUEST.toString(), methodArgumentNotValidException.getMessage()), | ||
HttpStatus.BAD_REQUEST); | ||
} | ||
ValidationErrorCode validationErrorCode = ValidationErrorCode.resolveAnnotation(fieldError.getCode()); | ||
String code = validationErrorCode.getCode(); | ||
String message = validationErrorCode.getMessage() + " : " + fieldError.getDefaultMessage(); | ||
return new ResponseEntity<>(ResponseDto.res(code, message), HttpStatus.BAD_REQUEST); | ||
} | ||
|
||
//HandlerMethodValidationException 예외를 처리하는 핸들러(HandlerMethod의 Validation에 실패한 경우(controller의 메소드의 파라미터에 대한 Validation)) | ||
@ResponseStatus(HttpStatus.BAD_REQUEST) | ||
@ExceptionHandler(HandlerMethodValidationException.class) | ||
public ResponseEntity<ResponseDto<Void>> handleHandlerMethodValidationException( | ||
HandlerMethodValidationException handlerMethodValidationException) { | ||
log.error("HandlerMethodValidationException: {}", handlerMethodValidationException.getMessage()); | ||
ValidationErrorCode errorCode = ValidationErrorCode.VALIDATION; | ||
String code = errorCode.getCode(); | ||
String message = errorCode.getMessage() + " : " | ||
+ handlerMethodValidationException.getDetailMessageArguments()[0].toString(); | ||
return new ResponseEntity<>(ResponseDto.res(code, message), HttpStatus.BAD_REQUEST); | ||
} | ||
|
||
//HttpMessageNotReadableException 예외를 처리하는 핸들러(Body가 잘못된 경우(json 형식이 잘못된 경우)) | ||
@ResponseStatus(HttpStatus.BAD_REQUEST) | ||
@ExceptionHandler(HttpMessageNotReadableException.class) | ||
public ResponseEntity<ResponseDto<Void>> handleHttpMessageNotReadableException( | ||
HttpMessageNotReadableException httpMessageNotReadableException) { | ||
log.error("HttpMessageNotReadableException: {}", httpMessageNotReadableException.getMessage()); | ||
ErrorCode errorCode = ErrorCode.INVALID_REQUEST_FORMAT_ERROR; | ||
String code = errorCode.getCode(); | ||
String message = errorCode.getMessage() + " : " + httpMessageNotReadableException.getMessage(); | ||
return new ResponseEntity<>(ResponseDto.res(code, message), HttpStatus.BAD_REQUEST); | ||
} | ||
|
||
//HttpRequestMethodNotSupportedException 예외를 처리하는 핸들러(요청의 메소드가 잘못된 경우) | ||
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) | ||
@ExceptionHandler(HttpRequestMethodNotSupportedException.class) | ||
public ResponseEntity<ResponseDto<Void>> handleHttpRequestMethodNotSupportedException( | ||
HttpRequestMethodNotSupportedException httpRequestMethodNotSupportedException) { | ||
log.error("HttpRequestMethodNotSupportedException: {}", httpRequestMethodNotSupportedException.getMessage()); | ||
ErrorCode errorCode = ErrorCode.METHOD_NOT_ALLOWED_ERROR; | ||
String code = errorCode.getCode(); | ||
String message = errorCode.getMessage(); | ||
return new ResponseEntity<>(ResponseDto.res(code, message), HttpStatus.METHOD_NOT_ALLOWED); | ||
} | ||
|
||
//NoResourceFoundException 예외를 처리하는 핸들러(리소스를 찾을 수 없는 경우(URI가 잘못된 경우)) | ||
@ResponseStatus(HttpStatus.NOT_FOUND) | ||
@ExceptionHandler(NoResourceFoundException.class) | ||
public ResponseEntity<ResponseDto<Void>> handleNoResourceFoundException( | ||
NoResourceFoundException noResourceFoundException) { | ||
log.error("NoResourceFoundException: {}", noResourceFoundException.getMessage()); | ||
ErrorCode errorCode = ErrorCode.NO_RESOURCE_ERROR; | ||
String code = errorCode.getCode(); | ||
String message = errorCode.getMessage(); | ||
return new ResponseEntity<>(ResponseDto.res(code, message), HttpStatus.NOT_FOUND); | ||
} | ||
|
||
//Exception 예외를 처리하는 핸들러(해당 클래스에 정의되지 않은 예외를 처리하는 핸들러) | ||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) | ||
@ExceptionHandler(Exception.class) | ||
public ResponseEntity<ResponseDto<Void>> handleException(Exception exception) { | ||
log.error("InternalServerException: {}", exception.getMessage()); | ||
ErrorCode errorCode = ErrorCode.INTERNAL_SERVER_ERROR; | ||
String code = errorCode.getCode(); | ||
String message = errorCode.getMessage() + " : " + exception.getClass(); | ||
return new ResponseEntity<>(ResponseDto.res(code, message), HttpStatus.INTERNAL_SERVER_ERROR); | ||
} | ||
|
||
// InvalidDataException 예외를 처리하는 핸들러(유효하지 않은 데이터가 요청된 경우) | ||
@ResponseStatus(HttpStatus.BAD_REQUEST) | ||
@ExceptionHandler(InvalidDataException.class) | ||
public ResponseEntity<ResponseDto<Void>> handleInvalidDataException(InvalidDataException invalidDataException) { | ||
log.error("InvalidDataException: {}", invalidDataException.getMessage()); | ||
ErrorCode errorCode = invalidDataException.getErrorCode(); | ||
String code = errorCode.getCode(); | ||
String message = errorCode.getMessage(); | ||
return new ResponseEntity<>(ResponseDto.res(code, message), HttpStatus.BAD_REQUEST); | ||
} | ||
} |
49 changes: 49 additions & 0 deletions
49
src/main/java/org/mjulikelion/baker/dto/response/ResponseDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package org.mjulikelion.baker.dto.response; | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Builder; | ||
import lombok.Data; | ||
import org.springframework.http.HttpStatusCode; | ||
|
||
@Data | ||
@Builder | ||
@AllArgsConstructor | ||
public class ResponseDto<T> { | ||
@JsonProperty | ||
private final String statusCode; | ||
@JsonProperty | ||
private final String message; | ||
@JsonProperty | ||
private final T data; | ||
|
||
public ResponseDto(final String statusCode, final String resultMsg) { | ||
this.statusCode = statusCode; | ||
this.message = resultMsg; | ||
this.data = null; | ||
} | ||
|
||
public static <T> ResponseDto<T> res(final String statusCode, final String resultMsg) { | ||
return res(statusCode, resultMsg, null); | ||
} | ||
|
||
public static <T> ResponseDto<T> res(final String statusCode, final String resultMsg, final T data) { | ||
return ResponseDto.<T>builder() | ||
.data(data) | ||
.statusCode(statusCode) | ||
.message(resultMsg) | ||
.build(); | ||
} | ||
|
||
public static <T> ResponseDto<T> res(final HttpStatusCode statusCode, final String resultMsg) { | ||
return res(statusCode, resultMsg, null); | ||
} | ||
|
||
public static <T> ResponseDto<T> res(final HttpStatusCode statusCode, final String resultMsg, final T data) { | ||
return ResponseDto.<T>builder() | ||
.data(data) | ||
.statusCode(String.valueOf(statusCode.value())) | ||
.message(resultMsg) | ||
.build(); | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/main/java/org/mjulikelion/baker/errorcode/ErrorCode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package org.mjulikelion.baker.errorcode; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
@AllArgsConstructor | ||
public enum ErrorCode { | ||
//잘못된 요청 오류들 | ||
PAGE_OUT_OF_RANGE("4000", "페이지가 범위를 벗어났습니다."), | ||
//서버 내부 오류들 | ||
INTERNAL_SERVER_ERROR("5000", "알 수 없는 서버 내부 오류."),//서버 내부 오류 | ||
//잘못된 경로, 메소드 오류들 | ||
METHOD_NOT_ALLOWED_ERROR("4050", "허용되지 않은 메소드 입니다."),//허용되지 않은 메소드 | ||
NO_RESOURCE_ERROR("4040", "해당 리소스를 찾을 수 없습니다."),//리소스를 찾을 수 없음(잘못된 URI) | ||
//잘못된 데이터 오류들 | ||
INVALID_REQUEST_FORMAT_ERROR("4000", "유효하지 않은 Body 형식입니다.");//요청 형식이 잘못됨 | ||
|
||
|
||
private final String code; | ||
private final String message; | ||
} |
32 changes: 32 additions & 0 deletions
32
src/main/java/org/mjulikelion/baker/errorcode/ValidationErrorCode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package org.mjulikelion.baker.errorcode; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
@AllArgsConstructor | ||
public enum ValidationErrorCode { | ||
VALIDATION("9000", "유효성 검사 실패."), | ||
NOT_NULL("9001", "필수값이 누락되었습니다."), | ||
NOT_BLANK("9002", "필수값이 빈 값이거나 공백으로 되어있습니다."), | ||
REGEX("9003", "형식에 맞지 않습니다."), | ||
ENUM_CONSTRAINT("9004", "유효하지 않은 Enum 값입니다."), | ||
GRADE_CONSTRAINT("9005", "학년이 형식에 맞지 않습니다."); | ||
|
||
|
||
private final String code; | ||
private final String message; | ||
|
||
//Dto의 어노테이션을 통해 발생한 에러코드를 반환 | ||
public static ValidationErrorCode resolveAnnotation(String code) { | ||
return switch (code) { | ||
case "NotNull" -> NOT_NULL; | ||
case "NotBlank" -> NOT_BLANK; | ||
case "Pattern" -> REGEX; | ||
case "EnumConstraint" -> ENUM_CONSTRAINT; | ||
case "GradeConstraint" -> GRADE_CONSTRAINT; | ||
default -> throw new IllegalArgumentException("Unexpected value: " + code); | ||
}; | ||
} | ||
} | ||
|
18 changes: 18 additions & 0 deletions
18
src/main/java/org/mjulikelion/baker/exception/CustomException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package org.mjulikelion.baker.exception; | ||
|
||
import lombok.Getter; | ||
import org.mjulikelion.baker.errorcode.ErrorCode; | ||
|
||
@Getter | ||
public class CustomException extends RuntimeException { | ||
protected ErrorCode errorCode; | ||
|
||
public CustomException(ErrorCode errorCode) { | ||
this.errorCode = errorCode; | ||
} | ||
|
||
public CustomException(ErrorCode errorCode, String message) { | ||
super(message); | ||
this.errorCode = errorCode; | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/main/java/org/mjulikelion/baker/exception/InvalidDataException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package org.mjulikelion.baker.exception; | ||
|
||
import lombok.Getter; | ||
import org.mjulikelion.baker.errorcode.ErrorCode; | ||
|
||
@Getter | ||
public class InvalidDataException extends CustomException { | ||
public InvalidDataException(ErrorCode errorCode) { | ||
super(errorCode); | ||
} | ||
} |