Spring 심화 1주차(6)

신성훈·2024년 6월 20일

TIL

목록 보기
42/162
post-thumbnail

오늘의 학습 키워드

  • Spring의 Global 예외처리
  • Error 메시지 관리하기

Spring의 Global 예외처리

  • Global 예외처리 방법

  • @ControllerAdvice 사용
    -@ControllerAdvice

    • @ControllerAdvice는 Spring에서 예외처리를 위한 클래스 레벨 애너테이션
    • 이 애너테이션은 모든 Controller에서 발생한 예외를 처리하기 위해 사용
    • @ControllerAdvice 가 붙은 클래스에서는 @ExceptionHandler메서드를 정의하여 예외를 처리하는 로직을 담을 수 있다.

    -@ControllerAdvice 사용하는 이유

    • 예외처리를 중앙 집중화하기 좋다.
    • 각각의 Controller에서 예외처리 로직을 반복하지 않아도 됨으로 코드의 중복을 방지하고 유지보수성을 높일 수 있다.
    • @ControllerAdvice 를 사용하면 예외 처리 로직을 모듈화하여 관리하기 쉽기 때문에, 팀 내에서 공통된 예외 처리 로직을 공유하거나 다른 팀에서 예외 처리를 참고할 수 있고 이를 통해 개발 생산성을 향상시키는 것도 가능 하다.
  • @RestControllerAdvice
    -@ControllerAdvice + @ResponseBody

    • @RestControllerAdvice 적용
@RestControllerAdvice
public class GlobalExceptionHandler {
	@ExceptionHandler({IllegalArgumentException.class})
	public ResponseEntity<RestApiException> handleException(IllegalArgumentException ex) {
		RestApiException restApiException = new RestApiException(ex.getMessage(), HttpStatus.BAD_REQUEST.value());
		return new ResponseEntity<>(
				// HTTP body
				restApiException,
				// HTTP status code
				HttpStatus.BAD_REQUEST
		);
	}
}
  • FolderController 의 예외처리 메서드 제거


Error 메시지 관리하기

  • Spring의 properties 파일을 이용한 에러 메시지 관리
    -Spring에서는 properties 파일을 이용하여 에러 메시지를 관리할 수 있다.
    -에러 메시지는 properties 파일에서 key-value 형태로 작성되며, 작성된 값은 messageSource 를 Bean으로 등록하여 사용할 수 있다.
    -> resources > messages.properties

    below.min.my.price=최저 희망가는 최소 {0}원 이상으로 설정해 주세요.
    not.found.product=해당 상품이 존재하지 않습니다.
  • Spring Boot에서는 messageSource 가 자동으로 Bean으로 등록된다.

private final MessageSource messageSource;
...
@Transactional
public ProductResponseDto updateProduct(Long id, ProductMypriceRequestDto requestDto) {
    int myprice = requestDto.getMyprice();
    if (myprice < MIN_MY_PRICE) {
        throw new IllegalArgumentException(messageSource.getMessage(
                "below.min.my.price",
                new Integer[]{MIN_MY_PRICE},
                "Wrong Price",
                Locale.getDefault()
        ));
    }
    Product product = productRepository.findById(id).orElseThrow(() ->
            new ProductNotFoundException(messageSource.getMessage(
                    "not.found.product",
                    null,
                    "Not Found Product",
                    Locale.getDefault()
            ))
    );
    product.update(requestDto);
    return new ProductResponseDto(product);
}

-Exception 클래스를 직접 구현하여 사용할 수도 있다.
-> ProductNotFoundException

package com.sparta.myselectshop.exception;

public class ProductNotFoundException extends RuntimeException{
	public ProductNotFoundException(String message) {
		super(message);
	}
}
  • essageSource.getMessage() 매서드
    -첫번째 파라미터는 messages.properties 파일에서 가져올 메시지의 키 값을 전달
    -두번째 파라미터는 메시지 내에서 매개변수를 사용할 경우 전달하는 값
    -세번째 파라미터는 언어 설정을 전달
  • Locale.getDefault() 매서드는 기본 언어 설정을 가져오는 매서드
    -> GlobalExceptionHandler
    package com.sparta.myselectshop.exception;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    @RestControllerAdvice
    public class GlobalExceptionHandler {
       @ExceptionHandler({IllegalArgumentException.class})
       public ResponseEntity<RestApiException> illegalArgumentExceptionHandler(IllegalArgumentException ex) {
           RestApiException restApiException = new RestApiException(ex.getMessage(), HttpStatus.BAD_REQUEST.value());
           return new ResponseEntity<>(
    				// HTTP body
                   restApiException,
    				// HTTP status code
                   HttpStatus.BAD_REQUEST
           );
       }
       @ExceptionHandler({NullPointerException.class})
       public ResponseEntity<RestApiException> nullPointerExceptionHandler(NullPointerException ex) {
           RestApiException restApiException = new RestApiException(ex.getMessage(), HttpStatus.NOT_FOUND.value());
           return new ResponseEntity<>(
    				// HTTP body
                   restApiException,
    				// HTTP status code
                   HttpStatus.NOT_FOUND
           );
       }
       @ExceptionHandler({ProductNotFoundException.class})
       public ResponseEntity<RestApiException> notFoundProductExceptionHandler(ProductNotFoundException ex) {
           RestApiException restApiException = new RestApiException(ex.getMessage(), HttpStatus.NOT_FOUND.value());
           return new ResponseEntity<>(
    // HTTP body
                   restApiException,
    // HTTP status code
                   HttpStatus.NOT_FOUND
           );
       }
    }
profile
조급해하지 말고, 흐름을 만들고, 기록하면서 쌓아가자.

0개의 댓글