From a7ff38203ab56c9cd16e968b979c13bc04590182 Mon Sep 17 00:00:00 2001 From: ingpyo <109223081+ingpyo@users.noreply.github.com> Date: Thu, 3 Aug 2023 11:51:41 +0900 Subject: [PATCH] =?UTF-8?q?[BE]=20fix:=20=ED=81=B4=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EC=96=B8=ED=8A=B8=20=EC=9A=94=EC=B2=AD=20=EC=98=A4=EB=A5=98?= =?UTF-8?q?=EC=97=90=20=EB=8C=80=ED=95=9C=20=EC=98=88=EC=99=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20(#176)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 클라이언트 요청 오류에 대한 예외 처리 기능 추가 Co-authored-by: ingpyo * refactor: PathVariable에 Valid검증하는 로직 제거 Co-authored-by: ingpyo --------- Co-authored-by: echo724 --- .../service/request/CategoryAddRequest.java | 7 +- .../service/request/PublishRequest.java | 8 +- .../service/request/WritingModifyRequest.java | 6 +- .../backend/ui/CategoryController.java | 3 +- .../donggle/backend/ui/WritingController.java | 5 +- .../ui/common/GlobalExceptionHandler.java | 74 +++++++++++++++++++ 6 files changed, 97 insertions(+), 6 deletions(-) diff --git a/backend/src/main/java/org/donggle/backend/application/service/request/CategoryAddRequest.java b/backend/src/main/java/org/donggle/backend/application/service/request/CategoryAddRequest.java index 7e8f80500..5b71ce2f3 100644 --- a/backend/src/main/java/org/donggle/backend/application/service/request/CategoryAddRequest.java +++ b/backend/src/main/java/org/donggle/backend/application/service/request/CategoryAddRequest.java @@ -1,4 +1,9 @@ package org.donggle.backend.application.service.request; -public record CategoryAddRequest(String categoryName) { +import jakarta.validation.constraints.NotNull; + +public record CategoryAddRequest( + @NotNull(message = "카테고리 이름을 입력해주세요.") + String categoryName +) { } diff --git a/backend/src/main/java/org/donggle/backend/application/service/request/PublishRequest.java b/backend/src/main/java/org/donggle/backend/application/service/request/PublishRequest.java index 90036e790..a4bdacefb 100644 --- a/backend/src/main/java/org/donggle/backend/application/service/request/PublishRequest.java +++ b/backend/src/main/java/org/donggle/backend/application/service/request/PublishRequest.java @@ -1,6 +1,12 @@ package org.donggle.backend.application.service.request; +import jakarta.validation.constraints.NotNull; + import java.util.List; -public record PublishRequest(String publishTo, List tags) { +public record PublishRequest( + @NotNull(message = "블로그를 선택해주세요.") + String publishTo, + List tags +) { } diff --git a/backend/src/main/java/org/donggle/backend/application/service/request/WritingModifyRequest.java b/backend/src/main/java/org/donggle/backend/application/service/request/WritingModifyRequest.java index 6f0b6126c..2fefa2fb8 100644 --- a/backend/src/main/java/org/donggle/backend/application/service/request/WritingModifyRequest.java +++ b/backend/src/main/java/org/donggle/backend/application/service/request/WritingModifyRequest.java @@ -1,4 +1,8 @@ package org.donggle.backend.application.service.request; -public record WritingModifyRequest(String title, Long targetCategoryId, Long nextWritingId) { +public record WritingModifyRequest( + String title, + Long targetCategoryId, + Long nextWritingId +) { } diff --git a/backend/src/main/java/org/donggle/backend/ui/CategoryController.java b/backend/src/main/java/org/donggle/backend/ui/CategoryController.java index 3ca39d49f..435846a9f 100644 --- a/backend/src/main/java/org/donggle/backend/ui/CategoryController.java +++ b/backend/src/main/java/org/donggle/backend/ui/CategoryController.java @@ -1,5 +1,6 @@ package org.donggle.backend.ui; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.donggle.backend.application.service.CategoryService; import org.donggle.backend.application.service.request.CategoryAddRequest; @@ -25,7 +26,7 @@ public class CategoryController { private final CategoryService categoryService; @PostMapping - public ResponseEntity categoryAdd(@RequestBody final CategoryAddRequest request) { + public ResponseEntity categoryAdd(@Valid @RequestBody final CategoryAddRequest request) { final Long categoryId = categoryService.addCategory(1L, request); return ResponseEntity.created(URI.create("/categories/" + categoryId)).build(); } diff --git a/backend/src/main/java/org/donggle/backend/ui/WritingController.java b/backend/src/main/java/org/donggle/backend/ui/WritingController.java index 010aa1818..f4883c551 100644 --- a/backend/src/main/java/org/donggle/backend/ui/WritingController.java +++ b/backend/src/main/java/org/donggle/backend/ui/WritingController.java @@ -1,5 +1,6 @@ package org.donggle.backend.ui; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.donggle.backend.application.service.PublishService; import org.donggle.backend.application.service.WritingService; @@ -38,7 +39,7 @@ public ResponseEntity writingAdd(final MarkdownUploadRequest request) thro } @PostMapping("/notion") - public ResponseEntity writingAdd(@RequestBody final NotionUploadRequest request) { + public ResponseEntity writingAdd(@Valid @RequestBody final NotionUploadRequest request) { final Long writingId = writingService.uploadNotionPage(1L, request); return ResponseEntity.created(URI.create("/writings/" + writingId)).build(); } @@ -76,7 +77,7 @@ public ResponseEntity writingListWithCategory(@ @PostMapping("/{writingId}/publish") public ResponseEntity writingPublish(@PathVariable final Long writingId, - @RequestBody final PublishRequest request) { + @Valid @RequestBody final PublishRequest request) { publishService.publishWriting(1L, writingId, request); return ResponseEntity.ok().build(); } diff --git a/backend/src/main/java/org/donggle/backend/ui/common/GlobalExceptionHandler.java b/backend/src/main/java/org/donggle/backend/ui/common/GlobalExceptionHandler.java index d76b8ccb0..3bfc6f720 100644 --- a/backend/src/main/java/org/donggle/backend/ui/common/GlobalExceptionHandler.java +++ b/backend/src/main/java/org/donggle/backend/ui/common/GlobalExceptionHandler.java @@ -6,10 +6,19 @@ import org.donggle.backend.exception.notfound.NotFoundException; 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.MissingPathVariableException; +import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; @Slf4j @RestControllerAdvice @@ -42,6 +51,71 @@ public ResponseEntity handleIOException(final IOException e) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse); } + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity> handleMethodArgumentNotValidException(final MethodArgumentNotValidException e) { + log.warn("Exception from handleMethodArgumentNotValidException = ", e); + final Map errors = new HashMap<>(); + e.getBindingResult().getAllErrors().forEach((error) -> { + final String fieldName = ((FieldError) error).getField(); + final String errorMessage = error.getDefaultMessage(); + errors.put(fieldName, errorMessage); + }); + return ResponseEntity + .status(HttpStatus.BAD_REQUEST) + .body(errors); + } + + @ExceptionHandler(MissingServletRequestParameterException.class) + public ResponseEntity handleMissingServletRequestParameterException(final MissingServletRequestParameterException e) { + log.warn("Exception from handleMissingServletRequestParameterException = ", e); + final ErrorResponse errorResponse = new ErrorResponse( + "잘못된 요청입니다. 누락된 쿼리 파라미터 타입: " + e.getParameterName() + + "예상되는 쿼리 파라미터 타입: " + e.getParameterType() + ); + return ResponseEntity + .status(HttpStatus.BAD_REQUEST) + .body(errorResponse); + } + + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + public ResponseEntity handleHttpRequestMethodNotSupportedException(final HttpRequestMethodNotSupportedException e) { + log.warn("Exception from handleHttpRequestMethodNotSupportedException = ", e); + final ErrorResponse errorResponse = new ErrorResponse("잘못된 요청입니다. HTTP 메서드를 다시 확인해주세요. 입력한 HTTP 메서드: " + e.getMethod()); + return ResponseEntity + .status(HttpStatus.METHOD_NOT_ALLOWED) + .body(errorResponse); + } + + @ExceptionHandler(MissingPathVariableException.class) + public ResponseEntity handleMissingPathVariableException(final MissingPathVariableException e) { + log.warn("Exception from handleMissingPathVariableException = ", e); + final ErrorResponse errorResponse = new ErrorResponse("잘못된 요청입니다. 누락된 경로 변수: " + e.getVariableName()); + return ResponseEntity + .status(HttpStatus.BAD_REQUEST) + .body(errorResponse); + } + + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + public ResponseEntity handleMethodArgumentTypeMismatchException(final MethodArgumentTypeMismatchException e) { + log.warn("Exception from handleMethodArgumentTypeMismatchException = ", e); + final ErrorResponse errorResponse = new ErrorResponse( + "잘못된 요청입니다. 잘못된 변수: " + e.getName() + + "예상되는 변수 타입: " + e.getRequiredType() + ); + return ResponseEntity + .status(HttpStatus.BAD_REQUEST) + .body(errorResponse); + } + + @ExceptionHandler(HttpMessageNotReadableException.class) + public ResponseEntity handleHttpMessageNotReadableException(final HttpMessageNotReadableException e) { + log.warn("Exception from handleHttpMessageNotReadableException = ", e); + final ErrorResponse errorResponse = new ErrorResponse("잘못된 요청입니다. 요청 바디를 다시 확인해주세요."); + return ResponseEntity + .status(HttpStatus.BAD_REQUEST) + .body(errorResponse); + } + @ExceptionHandler(Exception.class) public ResponseEntity handleUnExpectedException(final Exception e) { log.error("Exception from handleUnExpectedException = ", e);