728x90
반응형
SMALL
학습 내용
- CRUD 구조와 HTTP 메서드 이해
- 공통 응답 처리
- 공통 에러 처리
학습 정리
1. CRUD 구조와 HTTP 메서드 이해
CRUD 동작과 HTTP 메서드 매핑
작업 HTTP 메서드 엔드포인트 예시 조회 (Read) GET /api/products/{id}
생성 (Create) POST /api/products
수정 (Update) PUT /api/products/{id}
삭제 (Delete) DELETE /api/products/{id}
예제 코드
@RestController @RequiredArgsConstructor @RequestMapping("/api/products") public class ProductController { private final ProductService productService; @GetMapping public ResponseEntity<List<Product>> findProduct() { List<Product> products = productService.findAll(); return ResponseEntity.ok(products); } @GetMapping public ResponseEntity<Product> findProductById(@RequestParam("id") Long id) { Product product = productService.findById(id); return ResponseEntity.ok(product); } @PostMapping public ResponseEntity<Product> create(@RequestBody Product product) { Product newProduct = productService.create(product); return ResponseEntity.ok(newProduct); } @PutMapping("/{id}") public ResponseEntity<Product> update(@PathVariable Long id, @RequestBody Product product) { Product updateProduct = productService.update(id, product); return ResponseEntity.ok(updateProduct); } @DeleteMapping("/{id}") public ResponseEntity<String> delete(@PathVariable Long id) { productService.delete(id); return ResponseEntity.ok("삭제 완료"); } }
2.공통 응답 처리
ApiResponse 공통 응답 클래스
@Getter public class ApiResponse<T> { private final Boolean result; private final Error error; private final T message; public ApiResponse(Boolean result, String error, String errorMessage, T message) { this.result = result; this.error = Error.builder() .errorCode(error) .errorMessage(errorMessage) .build(); this.message = message; } public static <T> ApiResponse<T> success(T result) { return new ApiResponse<>(true, "", "", result); } # 반환 타입이 ResponseEntity 이유는 상태코드를 지정하기 위함 # 예외처리가 발생하면 전역예외처리가 대신 반환 하여 아래 메서드들을 호출하여 응답 public static <T> ResponseEntity<ApiResponse<T>> ResponseException(String code, String errorMessage) { return ResponseEntity.ok(new ApiResponse<>(false, code, errorMessage, null)); } public static <T> ResponseEntity<ApiResponse<T>> ValidException(String code, String errorMessage) { return ResponseEntity.status(400).body(new ApiResponse<>(false, code, errorMessage, null)); } public static <T> ResponseEntity<ApiResponse<T>> ServerException(String code, String errorMessage) { return ResponseEntity.status(500) .body(new ApiResponse<>(false, code, errorMessage, null)); } @Getter public static class Error { private final String errorCode; private final String errorMessage; @Builder public Error(String errorCode, String errorMessage) { this.errorCode = errorCode; this.errorMessage = errorMessage; } } }
공통 응답 사용방법
@GetMapping public ApiResponse<List<Product>> findProduct() { List<Product> products = productService.findAll(); return ApiResponse.Success(products); }
기존 RespnoseEntity 응답결과와 비교
#기존RespnseEntity 시 [ { 결과값 } ] #ApiResponse 공통응답 사용시 { "result": true, "error": { "errorCode":"string", "errorMessage":"string" }, "message":[ { 결과값 } ] }
3. 공통 에러 처리
커스텀 예외 클래스
@Getter public class ServiceException extends RuntimeException { private String code; private String message; public ServiceException() { } public ServiceException(ServiceExceptionCode response) { super(response.getMessage()); this.code = response.getCode(); this.message = super.getMessage(); } @Override public String getMessage() { return message; } }
에러코드 정의 Enum
@Getter public enum ServiceExceptionCode { NOT_FOUND_USERS("NOT_FOUND_USERS", "사용자를 찾을 수 없습니다"), NOT_FOUND_PRODUCT("NOT_FOUND_PRODUCT", "상품을 찾을 수 없습니다"), NOT_FOUND_CATEGORY("NOT_FOUND_CATEGORY", "카테고리를 찾을 수 없습니다"), NOT_FOUND_ORDER("NOT_FOUND_ORDER", "주문내역을 찾을 수 없습니다"), ORDER_NOT_MODIFIABLE("ORDER_NOT_MODIFIABLE", "주문상태변경 불가합니다."), NOT_FOUND_REFUND("NOT_FOUND_REFUND", "환불내역을 찾을 수 없습니다"), REFUND_NOT_MODIFIABLE("REFUND_NOT_MODIFIABLE", "환불상태변경 불가합니다."), OUT_OF_STOCK_PRODUCT("OUT_OF_STOCK_PRODUCT", "재고가 부족합니다."), CATEGORY_DELETE_CONFLICT("CATEGORY_DELETE_CONFLICT", "해당 카테고리는 제품이 등록되어 있어 삭제가 불가능합니다."), ; private final String code; private final String message; ServiceExceptionCode(String code, String message) { this.code = code; this.message = message; } @Override public String toString() { return "code : " + code + ", message :" + message; } }
서비스 내 커스텀 예외 사용방법
private Product findProductById(Long id) { return productRepository.findById(id) .orElseThrow(() -> new ServiceException(ServiceExceptionCode.NOT_FOUND_PRODUCT)); } #예외 발생시 결과값 { "reuslt": false, "errorCode": "NOT_FOUND_PRODUCT", "errorMessage": "Product를 찾을 수 없습니다.", "message": null }
Global Exception Handler
@Hidden @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(value = ServiceException.class) public ResponseEntity<?> handleResponseException(ServiceException ex) { return ApiResponse.ResponseException(ex.getCode(), ex.getMessage()); } @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<?> methodArgumentNotValidException(MethodArgumentNotValidException ex) { AtomicReference<String> errors = new AtomicReference<>(""); ex.getBindingResult().getAllErrors().forEach(c -> errors.set(c.getDefaultMessage())); return ApiResponse.ValidException("VALIDATE_ERROR", String.valueOf(errors)); } @ExceptionHandler(BindException.class) public ResponseEntity<?> bindException(BindException ex) { AtomicReference<String> errors = new AtomicReference<>(""); ex.getBindingResult().getAllErrors().forEach(c -> errors.set(c.getDefaultMessage())); return ApiResponse.ValidException("VALIDATE_ERROR", String.valueOf(errors)); } @ExceptionHandler(value = Exception.class) public ResponseEntity<?> handleException(Exception exception) { return ApiResponse.ServerException("SERVER_ERROR", exception.getMessage()); } }
- @RestControllerAdvice : @RestController에서 발생하는 예외를 전역적으로 처리
- @ExceptionHandler 특정 예외가 발생할 때 이를 처리하기 위한 메서드 정의
- 동작 흐름
- 클라이언트 REST API 요청
- 컨트롤러 호출
- 서비스에서 예외 발생
- Spring의 DispatcherServlet 예외 감지
- 예외 처리 핸들러 탐색
- 컨트롤러 내의 @ExceptionHandler 탐색
- 전역예외 처리 핸들러(@RestControllerAdvice) 탐색 해당 @ExceptionHandler 메서드 호출
- 위에가 다 없으면 기본 예외처리
- @ExceptionHandler 메서드 실행
- ApiResponse의 해당 결과 값으로 응답
728x90
반응형
LIST
'TIL' 카테고리의 다른 글
2_1.DB 설계 기본 개념 및 연관관계 매핑 (0) | 2025.01.09 |
---|---|
1_5. CRUD 구현과 MapStruct (0) | 2025.01.09 |
1_4.JPA Entity 설계와 DB 형상관리 (0) | 2025.01.09 |
1_3.RESTful API 설계와 데이터 검증, Lombok 심화 (0) | 2025.01.09 |
1_1.Spring Framework 환경 구성 (0) | 2025.01.09 |