๐ ์๋ก
์๋
ํ์ธ์! ์ค๋์ Spring Boot ์์ API ์๋ต๊ณผ ์์ธ ์ฒ๋ฆฌ ๋ชจ๋ธ์ ๊ตฌ์ถํด๋ดค๋ ๋ด์ฉ์ ๊ณต์ ํด ๋ณด๋ ค๊ณ ํฉ๋๋ค. ์ฝ๋๋ค๋ ํ๋ํ๋ ๋ถ์ํด ๋ณผ๊ป์. ์คํํธ~!
1. ResponseModel - ์๋ต ๋ชจ๋ธ
๋จผ์ , ๋ชจ๋ API ์๋ต์ ๊ณตํต์ ์ผ๋ก ์ฌ์ฉ๋ ResponseModel ์ ์ดํด๋ด
๋๋ค.
@Getter
@Setter
@ToString
@AllArgsConstructor(staticName = "of")
public class ResponseModel<T> {
private boolean success;
private T data;
private ErrorModel error;
public static <T> ResponseModel<T> of(boolean success, T data) {
return ResponseModel.of(success, data, null);
}
public static ResponseModel of(boolean success, ErrorCode code) {
return ResponseModel.of(success, null, ErrorModel.of(code.name(), code.getMessage(), null));
}
public static ResponseModel of(boolean success, ErrorCode code, Exception ex) {
return ResponseModel.of(success, null, code, ex);
}
public static <T> ResponseModel<T> of(boolean success, T data, ErrorCode code, Exception ex) {
final ErrorModel error = (code != null) ? ErrorModel.of(code, ex) : null;
return ResponseModel.of(success, data, error);
}
}
์ฃผ์ ๊ตฌ์ฑ ์์:
1. success: ์์ฒญ ์ฒ๋ฆฌ์ ์ฑ๊ณต ์ฌ๋ถ๋ฅผ ๋ํ๋
๋๋ค.
2. data: ์์ฒญ์ ๋ํ ๊ฒฐ๊ณผ ๋ฐ์ดํฐ๋ฅผ ํฌํจํฉ๋๋ค.
3. error: ๋ฐ์ํ ์ค๋ฅ์ ๋ํ ์ ๋ณด๋ฅผ ํฌํจํ๋ ErrorModel ๊ฐ์ฒด ์
๋๋ค.
ResponseModel ์๋ ์ฌ๋ฌ static ์์ฑ ๋ฉ์๋๊ฐ ํฌํจ๋์ด ์์ต๋๋ค. ์ด ๋ฉ์๋๋ค์ ํตํด ์ฑ๊ณต ๋๋ ์ค๋ฅ ์ํฉ์ ๋ฐ๋ผ ์ฝ๊ฒ ์๋ต ๊ฐ์ฒด๋ฅผ ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
2. ErrorModel - ์๋ฌ ๋ชจ๋ธ
ErrorModel ์ ์ค๋ฅ์ ๋ํ ์ ๋ณด๋ฅผ ํ์คํํ์ฌ ์ ๋ฌํ๊ธฐ ์ํ ๋ชจ๋ธ์
๋๋ค.
package com.board.backend.model;
import com.board.backend.common.ErrorCode;
import com.board.backend.common.utils.ObjectUtil;
import com.board.backend.common.utils.StringUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
@AllArgsConstructor(staticName = "of")
public class ErrorModel {
private String code;
private String message;
private ErrorData data;
@Getter
@Setter
@ToString
@AllArgsConstructor(staticName = "of")
public static class ErrorData {
private String exceptionMessage;
private String stackTrace;
}
public static ErrorModel of(ErrorCode code, Exception ex) {
final String exceptionMessage = ObjectUtil.nonEmpty(ex) ? ex.getMessage() : null;
final String stackTrace = ObjectUtil.nonEmpty(ex) ? getStackTraceAsString(ex) : null;
final ErrorData data = (StringUtil.nonEmpty(exceptionMessage) || StringUtil.nonEmpty(stackTrace)) ? ErrorData.of(exceptionMessage, stackTrace) : null;
return ErrorModel.of(code.name(), code.getMessage(), data);
}
private static String getStackTraceAsString(Exception ex) {
final StringBuilder sb = new StringBuilder();
for (StackTraceElement element : ex.getStackTrace()) {
sb.append(element.toString());
sb.append("\n");
}
return sb.toString();
}
}
์ฃผ์ ๊ตฌ์ฑ ์์:
1. code : ์ค๋ฅ ์ฝ๋๋ฅผ ๋ํ๋
๋๋ค.
2. message : ์ค๋ฅ ๋ฉ์์ง๋ฅผ ๋ํ๋
๋๋ค.
3. data : ์ค๋ฅ ๋ฐ์ ์์ ์ถ๊ฐ ์ ๋ณด๋ฅผ ๋ํ๋ด๋ ErrorData ๊ฐ์ฒด์
๋๋ค.
ErrorData ํด๋์ค๋ ๋ฐ์ํ ์์ธ์ ๋ฉ์์ง์ ์คํ ํธ๋ ์ด์ค ์ ๋ณด๋ฅผ ํฌํจํฉ๋๋ค. ์ด๋ฅผ ํตํด ์ค๋ฅ์ ์์ธ์ ๋์ฑ ์์ธํ ํ์
ํ ์ ์์ต๋๋ค.(์คํ ํธ๋ ์ด์ค๋ ? ํ๋ก๊ทธ๋จ์์ ์์ธ๊ฐ ๋ฐ์ํ์ ๋ ํด๋น ์์ธ์ ๋ฐ์ ๊ฒฝ๋ก๋ฅผ ์ถ์ ํ๋ ์ ๋ณด์
๋๋ค. ์ด๋ ๋ฉ์๋ ํธ์ถ ์์์ ๋ผ์ธ ๋ฒํธ๋ฅผ ํฌํจํ์ฌ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์์น์ ๊ทธ ์์ธ์ ํ์ธํ ์ ์๊ฒ ๋์์ค๋๋ค.)
3. ErrorCode - ์๋ฌ ์ฝ๋
@Getter
@AllArgsConstructor
public enum ErrorCode {
SERVER_ERROR("์๋ฒ ์๋ฌ"),
ARGUMENT_TYPE_MISMATCH("์๋ชป๋ ํ๋ผ๋ฏธํฐํ์
์ด ์ ๋ฌ๋์์ต๋๋ค."),
BOARD_NOT_FOUND("๊ธ์ด ์กด์ฌํ์ง ์์ต๋๋ค");
...
private String message;
}
๊ฐ ์ค๋ฅ ์ ํ์ ๋ํ ๋ฉ์์ง๋ฅผ ํจ๊ป ์ ๊ณตํ์ฌ ์ฌ์ฉ์์๊ฒ ์๋ฏธ ์๋ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ์ ๋ฌ ํฉ๋๋ค. enum ํ์
์ผ๋ก ์ฝ๋์ ๋ฉ์์ง๋ฅผ ํจ๊ป ๊ด๋ฆฌํ์์ต๋๋ค.
4. ExceptionAdvice - ์ ์ญ ์์ธ ์ฒ๋ฆฌ๊ธฐ
Spring Boot ์์ ์์ธ ์ฒ๋ฆฌ์ ์ค์์ฑ์ ๊ฐ์กฐํ๋ฉฐ, ์ด๋ฅผ ์ํด @ControllerAdvice ์ @ExceptionHandler ๋ฅผ ํตํด ํจ๊ณผ์ ์ธ ์ ์ญ ์์ธ ์ฒ๋ฆฌ ๋ฐฉ์์ ์ ๊ณตํฉ๋๋ค.
@ControllerAdvice
public class ExceptionAdvice {
@ExceptionHandler(value = {Exception.class})
public ResponseEntity handleException(Exception ex, WebRequest request) {
final ResponseModel responseModel = ResponseModel.of(false, ErrorCode.SERVER_ERROR, ex);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(responseModel);
}
@ExceptionHandler(value = {MethodArgumentTypeMismatchException.class})
public ResponseEntity handleTypeException(Exception ex) {
final ResponseModel<Object> responseModel = ResponseModel.of(false, ErrorCode.ARGUMENT_TYPE_MISMATCH, ex);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(responseModel);
}
...
}
1) @ControllerAdvice ์ ์ญํ
@ControllerAdvice ๋ Spring ์์ ๋ชจ๋ ์ปจํธ๋กค๋ฌ์์ ๋ฐ์ํ ์ ์๋ ์์ธ๋ค์ ํ๊ณณ์์ ๊ด๋ฆฌํ๊ณ ์ฒ๋ฆฌํ๊ธฐ ์ํด ๋์
๋ ์ด๋
ธํ
์ด์
์
๋๋ค. ์ด๋ฅผ ํตํด ์ฝ๋์ ์ค๋ณต์ ์ค์ด๊ณ , ์ผ๊ด๋ ์์ธ ์ฒ๋ฆฌ ๋ก์ง์ ๊ตฌ์ฑํ ์ ๋์์ค๋๋ค.
2) @ExceptionHandler
@ExceptionHandler ๋ ํน์ ์์ธ๋ฅผ ์ฒ๋ฆฌํ ๋ฉ์๋๋ฅผ ์ง์ ํ๊ธฐ ์ํ Spring MVC ์ ์ด๋
ธํ
์ด์
์
๋๋ค. ๊ทธ ์์ฒด๋ก๋ ์ ์ฉํ์ง๋ง, @ControllerAdvice์ ๊ฒฐํฉํ์ฌ ์ฌ์ฉํ ๊ฒฝ์ฐ, ์ ํ๋ฆฌ์ผ์ด์
์ ์ฒด์ ์์ธ๋ฅผ ์ค์์์ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์๊ฒ ๋ฉ๋๋ค.
์์:
// ๋จ์ผ ์ง์
@ExceptionHandler({CustomException.class})
// ๋ค์ค ์ง์
@ExceptionHandler({CustomException1.class, CustomException2.class, CustomException3.class})
์ด๋ ๊ฒ ์ค์ ํ๋ฉด, ์์์ ์ง์ ๋ ์์ธ๋ค์ด ๋ฐ์ํ์ ๋ ๋์ผํ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค.
3) ํ์ฅ์ฑ
@ControllerAdvice ์ ์ฅ์ ์ค ํ๋๋ ๊ทธ ํ์ฅ์ฑ์
๋๋ค. ์๋ก์ด ์์ธ๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ์์ธ ์ฒ๋ฆฌ ๋ฐฉ์์ ์์ ํด์ผ ํ ๋, @ExceptionHandler ๋ฅผ ์ ์ ํ ๋ฉ์๋์ ์ถ๊ฐํ๊ฑฐ๋ ์์ ํจ์ผ๋ก์จ ์ค์์์ ์์ธ ์ฒ๋ฆฌ ๋ก์ง์ ์ฝ๊ฒ ๊ด๋ฆฌํ๊ณ ํ์ฅํ ์ ์์ต๋๋ค.
๐ค ๊ฒฐ๋ก
Spring Boot ํ๊ฒฝ์์ ๋๋ฆ๋๋ก ์๊ฐํด์ ๊ตฌํํ๋ ์๋ต๊ณผ ์์ธ ์ฒ๋ฆฌ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด์์ต๋๋ค. ์ผ๊ด๋ ์๋ต๊ณผ ์ ํํ ์์ธ ์ฒ๋ฆฌ๋ API์ ์ ๋ขฐ์ฑ์ ๋์ด๋ ํต์ฌ ์์๋ก, ์ด๋ฅผ ํตํด ์ฌ์ฉ์์์ ์ ๋ขฐ ๊ด๊ณ๋ฅผ ๊ตฌ์ถํ๊ณ , ๊ฐ๋ฐํ ๊ฐ์ ํ์
ํจ์จ์ ๋์ผ ์ ์์ต๋๋ค. ๐