IT 강좌(IT Lectures)/SpringBoot

8강. 예외 처리

소울입니다 2024. 7. 19. 08:07
728x90
반응형

 

챕터 8: 예외 처리

8.1 스프링부트 예외 처리 전략

8.1.1 예외 처리의 필요성

예외 처리는 소프트웨어 개발에서 필수적인 부분으로, 예상치 못한 오류가 발생했을 때 시스템의 안정성을 유지하고 사용자에게 적절한 피드백을 제공하기 위해 필요합니다. 예외 처리는 프로그램이 오류 상황에서도 중단되지 않고 정상적으로 동작할 수 있도록 도와줍니다.

8.1.2 글로벌 예외 처리 전략

스프링부트는 글로벌 예외 처리 메커니즘을 제공하여 애플리케이션 전반에 걸쳐 일관된 예외 처리를 구현할 수 있습니다. 이는 예외가 발생했을 때 이를 일관되게 처리하고, 적절한 응답을 제공하여 사용자 경험을 개선합니다.

8.2 @ExceptionHandler와 @ControllerAdvice

8.2.1 @ExceptionHandler 사용법

@ExceptionHandler 어노테이션은 특정 컨트롤러에서 발생하는 예외를 처리하는 데 사용됩니다. 이를 통해 예외가 발생했을 때 특정 메서드에서 이를 처리할 수 있습니다.


package com.example.demo;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

// 사용자 정의 예외 클래스
class CustomException extends RuntimeException {
    public CustomException(String message) {
        super(message);
    }
}

// @RestController 어노테이션을 사용하여 이 클래스를 RESTful 웹 컨트롤러로 정의
@RestController
public class ExceptionHandlerController {

    // @GetMapping을 사용하여 HTTP GET 요청을 매핑
    @GetMapping("/triggerException")
    public String triggerException() {
        // 사용자 정의 예외를 발생시킴
        throw new CustomException("Custom exception occurred!");
    }

    // @ExceptionHandler를 사용하여 CustomException을 처리
    @ExceptionHandler(CustomException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public String handleCustomException(CustomException ex) {
        // 예외 메시지를 응답으로 반환
        return ex.getMessage();
    }
}
    

위의 예제에서 @ExceptionHandler 어노테이션은 특정 예외를 처리하는 메서드를 정의합니다. triggerException 메서드는 사용자 정의 예외를 발생시키며, handleCustomException 메서드는 이를 처리하고 예외 메시지를 반환합니다.

8.2.2 @ControllerAdvice 사용법

@ControllerAdvice 어노테이션은 전역 예외 처리 메커니즘을 제공하여 모든 컨트롤러에 적용할 수 있는 예외 처리를 정의합니다. 이를 통해 애플리케이션 전반에 걸쳐 일관된 예외 처리를 구현할 수 있습니다.


package com.example.demo;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;

// @ControllerAdvice 어노테이션을 사용하여 전역 예외 처리 클래스를 정의
@ControllerAdvice
public class GlobalExceptionHandler {

    // @ExceptionHandler를 사용하여 CustomException을 처리
    @ExceptionHandler(CustomException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public String handleCustomException(CustomException ex) {
        // 예외 메시지를 응답으로 반환
        return ex.getMessage();
    }

    // @ExceptionHandler를 사용하여 다른 예외를 처리
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public String handleGeneralException(Exception ex) {
        // 예외 메시지를 응답으로 반환
        return "An error occurred: " + ex.getMessage();
    }
}
    

위의 예제에서 @ControllerAdvice 어노테이션은 전역 예외 처리 클래스를 정의합니다. GlobalExceptionHandler 클래스는 모든 컨트롤러에 적용될 예외 처리를 정의하며, handleCustomExceptionhandleGeneralException 메서드는 각각 특정 예외와 일반 예외를 처리합니다.

8.3 커스텀 예외 클래스 작성

8.3.1 사용자 정의 예외 클래스 작성

사용자 정의 예외 클래스는 특정 조건에서 발생하는 예외를 처리하기 위해 작성할 수 있습니다. 이를 통해 보다 명확하게 예외 상황을 정의하고 처리할 수 있습니다.


package com.example.demo;

// 사용자 정의 예외 클래스
public class ResourceNotFoundException extends RuntimeException {
    public ResourceNotFoundException(String message) {
        super(message);
    }
}
    

8.3.2 예외 메시지 설정

예외 메시지는 사용자 정의 예외 클래스의 생성자를 통해 설정할 수 있습니다. 이를 통해 예외가 발생했을 때 보다 구체적인 정보를 제공할 수 있습니다.


package com.example.demo;

// 사용자 정의 예외 클래스
public class ResourceNotFoundException extends RuntimeException {
    private String resourceName;
    private String fieldName;
    private Object fieldValue;

    public ResourceNotFoundException(String resourceName, String fieldName, Object fieldValue) {
        super(String.format("%s not found with %s : '%s'", resourceName, fieldName, fieldValue));
        this.resourceName = resourceName;
        this.fieldName = fieldName;
        this.fieldValue = fieldValue;
    }

    // Getter 메서드
    public String getResourceName() {
        return resourceName;
    }

    public String getFieldName() {
        return fieldName;
    }

    public Object getFieldValue() {
        return fieldValue;
    }
}
    

위의 예제에서 사용자 정의 예외 클래스는 특정 리소스를 찾지 못했을 때 발생합니다. 예외 메시지는 리소스 이름, 필드 이름 및 필드 값을 포함하여 예외 상황을 보다 명확하게 설명합니다.

8.4 예외 메시지 국제화

8.4.1 메시지 소스 설정

스프링부트에서 예외 메시지의 국제화를 위해 메시지 소스를 설정할 수 있습니다. 이를 통해 여러 언어로 예외 메시지를 제공할 수 있습니다.


# application.properties
spring.messages.basename=messages
    

package com.example.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;

// 메시지 소스 설정
@Configuration
public class MessageSourceConfig {

    @Bean
    public ResourceBundleMessageSource messageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setBasename("messages");
        messageSource.setDefaultEncoding("UTF-8");
        return messageSource;
    }
}
    

8.4.2 다국어 지원 예외 메시지 작성

다국어 지원을 위해 각 언어별 메시지 파일을 작성할 수 있습니다. 이는 여러 언어로 된 사용자에게 적절한 예외 메시지를 제공하는 데 유용합니다.


# messages.properties
resource.not.found=Resource not found

# messages_ko.properties
resource.not.found=리소스를 찾을 수 없습니다
    

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import java.util.Locale;

// @RestController 어노테이션을 사용하여 이 클래스를 RESTful 웹 컨트롤러로 정의
@RestController
public class LocalizationController {

    @Autowired
    private MessageSource messageSource;

    // @GetMapping을 사용하여 HTTP GET 요청을 매핑
    @GetMapping("/localizationTest")
    public String localizationTest(@RequestHeader(name = "Accept-Language", required = false) Locale locale) {
        // 요청된 언어에 맞는 예외 메시지를 반환
        return messageSource.getMessage("resource.not.found", null, locale);
    }

    // @ExceptionHandler를 사용하여 ResourceNotFoundException을 처리
    @ExceptionHandler(ResourceNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public String handleResourceNotFoundException(ResourceNotFoundException ex, Locale locale) {
        // 요청된 언어에 맞는 예외 메시지를 반환
        return messageSource.getMessage("resource.not.found", null, locale);
    }
}
    

위의 예제에서 MessageSource를 사용하여 국제화된 예외 메시지를 반환합니다. localizationTest 메서드는 요청 헤더에서 언어 정보를 받아서 해당 언어에 맞는 메시지를 반환합니다. handleResourceNotFoundException 메서드는 예외가 발생했을 때 적절한 언어로 메시지를 반환합니다.

 

반응형