- [Spring] Rest API ExceptionHandler2025년 01월 19일 23시 28분 28초에 업로드 된 글입니다.작성자: 이주여이
Rest API 서버 만들면서 예외 처리에 대한 부분이 필요했다.
설명은 없고 메모용이라 간략간략하게 확인만 하자.
필자는 STS4(Spring Tool Suite 4)에서 진행한다.
패키지 구조는 아래와 같다.
@Getter @AllArgsConstructor public enum ApiStatus { SUCCESS(200, "요청이 성공적으로 완료되었습니다."), CREATED(201, "리소스가 성공적으로 생성되었습니다."), BAD_REQUEST(400, "요청이 유효하지 않습니다."), UNAUTHORIZED(401, "권한이 확인되지 않았습니다."), FORBIDDEN(403, "접근이 거부되었습니다."), NOT_FOUND(404, "요청한 리소스를 찾을 수 없습니다."), REQUIRED_ERROR(422, "필수 값이 누락되었습니다."), INTERNAL_SERVER_ERROR(500, "서버에서 예기치 못한 오류가 발생했습니다."); private final int statusCode; private final String message; }
예외 던질 때 담을 HTTP 상태코드 및 메세지가 담겨있다.
@Data @Builder public class ApiResponse<T> { private int status; private String message; @Builder.Default // builder 패턴으로 객체 생성 시 기본 값 지정 private String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); private T data; @Builder.Default private List<String> errors = List.of(); public static <T> ApiResponse<T> success(T data) { return ApiResponse.<T>builder() .status(ApiStatus.SUCCESS.getStatusCode()) .message(ApiStatus.SUCCESS.getMessage()) .data(data) .build(); } public static <T> ApiResponse<T> error(int status, String message, List<String> errors) { return ApiResponse.<T>builder() .status(status) .message(message) .errors(errors) .build(); } }
ApiResponse는 ResponseEntity의 지네릭 타입에 명시할 클래스이다.
status는 ApiStatus의 HTTP 상태 코드를, message는 ApiStatus에 있는 메세지를, timestamp는 API 호출 시 호출한 시간을 찍어내기 위함이며 data는 return할 데이터이다.
성공 시에는 상태 코드랑 메세지가 동일하기에 미리 적어두었으며 data(VO)만 받아 객체를 생성한다. 반대로 실패 시에는 해당 객체 생성 시 인자 값으로 담은 상태 코드와 메세지, 에러를 받는다.
@Getter public class ApiException extends RuntimeException { private ApiStatus apiStatus; public ApiException(ApiStatus apiStatus) { this.apiStatus = apiStatus; } }
직접 만든 예외다.
해당 예외를 던질 때 해당 값은 ApiStatus(ENUM)에 있는 값들 중 하나를 고를 수 있다.
@RestControllerAdvice public class ApiExceptionAdvice { @ExceptionHandler(ApiException.class) public ResponseEntity<ApiResponse<Object>> customExceptionHandler(HttpServletRequest request, final ApiException e) { ApiResponse<Object> apiResponse = ApiResponse.<Object>builder() .status(e.getApiStatus().getStatusCode()) .message(e.getApiStatus().getMessage()) .errors(null) .build(); return ResponseEntity .ok(apiResponse); } @ExceptionHandler(DataIntegrityViolationException.class) public ResponseEntity<ApiResponse<Object>> dataIntegrityViolationExceptionHandler(HttpServletRequest request, final DataIntegrityViolationException e) { ApiResponse<Object> apiResponse = ApiResponse.<Object>builder() .status(ApiStatus.REQUIRED_ERROR.getStatusCode()) .message(ApiStatus.REQUIRED_ERROR.getMessage()) .errors(null) .build(); return ResponseEntity .ok(apiResponse); } }
위에 있는 customExceptionHandler는 내가 만들어놓은 ApiException을 던졌을 때 받기위한 메소드이며 dataIntegerityViolationExceptionHanlder는 fk 없이 INSERT 때릴 때 INSERT 때리기도 전에 해당 예외가 터지길래 추가해봤다. 물론 Vaildation 사용해서 작업을 해야하는 부분이지만 귀찮아서 안했으므로 땜빵용이다.
errors는 나중에 작업할꺼다.
이제 테스트해보자.
@PostMapping public ResponseEntity<ApiResponse<Object>> insBoard(BoardInsDto dto) { int insBoardRows = service.insBoard(dto); if (Util.isNull(insBoardRows)) { throw new ApiException(ApiStatus.REQUIRED_ERROR); } else { int result = dto.getIboard(); ApiResponse<Object> apiResponse = ApiResponse.success(result); return ResponseEntity.ok(apiResponse); } }
잘잡아준다.
'Study > Spring' 카테고리의 다른 글
[Spring] Swagger UI 초기 세팅 (0) 2025.01.26 [Spring] CustomExceptionHanlder (0) 2024.11.29 [Spring] 검색 결과 미리보기 (0) 2024.11.17 [Spring] 공개/비공개글 (2) 2024.11.03 [Spring] RSS(XML) Parsing (0) 2024.09.21 다음글이 없습니다.이전글이 없습니다.댓글