본문 바로가기

Java

(spring) Exception 이녀석........

예외... 그냥 throws Exception에 try-catch(Excetption e) 박았는데.............

 

try-catch를 매 클래스마다 박는건 비효율적이래요.

 

? 생각해보면 당연한데.. 난 생각을 안했지.......

 

예외부터 제대로 알아봐야겠는데... 왜 봐도봐도 모르겠냐

 

예외를 지정하는 방법은 여러가지가 있는데 처리되는 순서대로 알아봅시다.

 

1. @ExceptionHandler 

 

특정 컨트롤러에서 예외를 처리하기 위해 사용됩니다. 

@Controller
public class MyController {

    @GetMapping("/example")
    public String example() {
        throw new RuntimeException("Exception 발생!");
    }

    @ExceptionHandler(RuntimeException.class)
    public ModelAndView handleRuntimeException(RuntimeException ex) {
        ModelAndView mav = new ModelAndView("error");
        mav.addObject("message", ex.getMessage());
        return mav;
    }
}

 

이런식으로 예외 메서드를 컨트롤러 클래스에서 지정해주면 이 컨트롤러에서 발생하는 예외는 @ExceptionHandler 메서드를 통해 처리됩니다.

 

하나하나 알아봅시다.

 

일단 @ExceptionHandler(RuntimeException.class) 해당 컨트롤러에서 RuntimeException이 발생하면 이 메서드가 호출된다. 이 뜻입니다.

 

ModelAndView 객체는 데이터와 뷰 이름을 함께 담아 전송하는데 사용됩니다. new ModelAndView("error")는 뷰 이름이 error인 객체를 생성합니다. 

 

mav.addObject - ex.getMessgae()라는 예외 메세지를 message라는 이름으로 뷰에 전달할 모델 데이터를 추가합니다.

 

뷰와 데이터를 담은 객체를 반환하면 DispatcherServlet이 클라이언트에게 응답을 보낼 수 있도록 합니다.  

 

2. @ControllerAdvice

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(RuntimeException.class)
    public ModelAndView handleRuntimeException(RuntimeException ex) {
        ModelAndView mav = new ModelAndView("error");
        mav.addObject("message", ex.getMessage());
        return mav;
    }
}

 

클래스에 어노테이션이 붙어있으면 전역적으로 예외를 처리하기 위한 예외처리 메서드를 정의할 수 있습니다. 

 

* @ExceptionHandler 가 우선순위가 높습니다.

 

3. HandlerExceptionResolver

 

Spring MVC에서 제공하는 인터페이스로, 예외를 전역적으로 처리하는데 사용합니다. 인터페이스 구현 시 try-catch 블록 없이 예외를 처리할 수 있습니다.

public interface HandlerExceptionResolver {
    ModelAndView resolveException(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler,
            Exception ex);
}
  • HttpServletRequest request - 현재 요청에 대한 정보를 담고 있는 객체로 예외가 발생한 요청의 URL, 파라미터, 헤더 등의 정보를 가져올 수 있다.
  • HttpServletResponse response - 현재 응답에 대한 정보를 담고 있는 객체로 응답 상태 코드, 헤더 등을 설정할 수 있다. 
  • Object handler - 예외가 발생한 이벤트 핸들러(컨트롤러) 객체로 예외가 발생한 메서드와 관련된 정보를 얻을 수 있다.
  • Exception ex - 발생한 예외 객체이다.

* 4가지 인자는 자동으로 전달받아야 된다고 합니다.

public class CustomExceptionResolver implements HandlerExceptionResolver {

    private static final Logger logger = LoggerFactory.getLogger(CustomExceptionResolver.class);

    @Override
    public ModelAndView resolveException(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler,
            Exception ex) {

        logger.error("Exception occurred", ex);

        // 응답 코드 설정
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);  // 500 상태 코드 설정

        ModelAndView mav = new ModelAndView("error");
        mav.addObject("message", ex.getMessage());
        mav.addObject("url", request.getRequestURL());

        return mav;
    }
}

 

 

상속받아서 구현한 커스텀 예외이다. 

 

하 근데 얘기하다 보면 RuntimeException이 거슬린다. 이걸 알아보면 또 Checked Exception과 UnChecked Exception을 알아봐야 하고 알아보면 트랜잭션의 commit과 rollback 구간도 알아야 한다...............................

 

4. Checked Exception

  • 컴파일 타임에 예외 처리를 강제한다.
  • 예외가 발생할 수 있는 메서드는 throws 키워드를 사용하여 예외를 던진다고 선언해야 하며 이를 호출하는 메서드는 try-catch로 처리하거나 다시 던져야 한다.
  • 주로 RuntimeException의 하위 클래스가 아닌 예외들이다.

4-1. UnChecked Exception

  • 컴파일 타임에 처리가 강제되지 않는다.
  • try-catch 블록으로 처리하지 않아도 오류가 발생하지 않는다.
  • 런타임에 예기치 못한 상황에 발생할 수 있으며 적절히 처리되지 않으면 프로그램이 종료될 수 있다.
  • RuntimeException와 그 하위 클래스를 상속받는 예외들이다.

예를 들어 10 / 0 을 하는 메서드가 있다고 치자. 그럼 프로그램이 실행은 되는데 메서드를 호출하면 IllegalArgumentException이 발생하며 프로그램이 종료된다.

 

예외가 발생하면 UnChecked Exception은 기본적으로 롤백된다라고 하긴 하는데 사용자 지정 가능합니다. 무조건 아니에요.

@Transactional(noRollbackFor = IllegalArgumentException.class)
@Transactional(rollbackFor = IOException.class)

 

이렇게 롤백 하고 안하고 특정 예외에서만 하고 안하고 지정할 수 있습니다. 

 

아 트랜잭션 따로 정리해야겠다.

'Java' 카테고리의 다른 글

Logger 딱 대  (2) 2024.06.17
Set / Map / Iterator  (0) 2024.06.14
익명 클래스 / 람다식 / 메소드 참조  (1) 2024.06.08
형 변환 / valueOf() / stream  (0) 2024.06.07
String / StringBuilder / StringBuffer  (1) 2024.06.07