BackEnd/스프링 MVC

@ExceptionHandler

연향동큰손 2025. 1. 9. 15:18

스프링에서 API예외 처리 문제를 해결하기 위해 @ExceptionHandler를 제공한다. 매우 편리하여 사용하기 쉽다.

 

package com.example.exception.api;

import com.example.exception.Exception.UserException;
import com.example.exception.exhandler.ErrorResult;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
public class ApiExceptionV2Controller {

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(IllegalArgumentException.class)
    public ErrorResult illgalExHandler(IllegalArgumentException e){
        log.error("[exceptionHandler] ex",e);
        return new ErrorResult("BAD",e.getMessage());
    }

    @ExceptionHandler
    public ResponseEntity<ErrorResult> userExHandler(UserException e){
        log.error("[exceptionHandler] ex",e);
        ErrorResult errorResult = new ErrorResult("USER-EX",e.getMessage());
        return new ResponseEntity(errorResult,HttpStatus.BAD_REQUEST);
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler
    public ErrorResult exHandler(Exception e){
        log.error("[exceptionHandler] ex",e);
        return new ErrorResult("EX","내부 오류");
    }

    @GetMapping("/api2/members/{id}")
    public MemberDto getMember(@PathVariable("id") String id) {
        if (id.equals("ex")) {
            throw new RuntimeException("잘못된 사용자");
        }
        if (id.equals("bad")) {
            throw new IllegalArgumentException("잘못된 입력 값");
        }
        if (id.equals("user-ex")) {
            throw new UserException("사용자 오류");
        }
        return new MemberDto(id, "hello " + id);
    }

    @Data
    @AllArgsConstructor
    static class MemberDto{
        private String memberId;
        private String name;
    }
}

 

1. IllegalArgumentException 예외 처리

@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(IllegalArgumentException.class)
public ErrorResult illgalExHandler(IllegalArgumentException e){
    log.error("[exceptionHandler] ex",e);
    return new ErrorResult("BAD",e.getMessage());
}

 

IllegalArgumentException 또는 그 하위 자식 클래스를 모두 처리 가능하다.

 

 

 

2. ExceptionHandler 예외 생략

@ExceptionHandler
public ResponseEntity<ErrorResult> userExHandler(UserException e){
    log.error("[exceptionHandler] ex",e);
    ErrorResult errorResult = new ErrorResult("USER-EX",e.getMessage());
    return new ResponseEntity(errorResult,HttpStatus.BAD_REQUEST);
}

 

ExceptionHandler의 예외를 생략하게 되면 메서드 파라미터의 예외가 지정된다.

 

 

 

3. Exception 예외 처리

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler
public ErrorResult exHandler(Exception e){
    log.error("[exceptionHandler] ex",e);
    return new ErrorResult("EX","내부 오류");
}

 

가장 상위 예외 클래스 이므로 하위 예외 클래스에서 처리하지 못한 경우 위 코드에서 예외를 처리한다.

 

 

@RestControllerAdvice를 통해 예외 처리 코드 분리

 

@RestControllerAdvice를 사용하면 컨트롤러에서 예외처리 코드를 분리하여 사용 가능하다.

 

package com.example.exception.exhandler.advice;

import com.example.exception.Exception.UserException;
import com.example.exception.exhandler.ErrorResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@Slf4j
@RestControllerAdvice
public class ExControllerAdvice {
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(IllegalArgumentException.class)
    public ErrorResult illgalExHandler(IllegalArgumentException e){
        log.error("[exceptionHandler] ex",e);
        return new ErrorResult("BAD",e.getMessage());
    }

    @ExceptionHandler
    public ResponseEntity<ErrorResult> userExHandler(UserException e){
        log.error("[exceptionHandler] ex",e);
        ErrorResult errorResult = new ErrorResult("USER-EX",e.getMessage());
        return new ResponseEntity(errorResult,HttpStatus.BAD_REQUEST);
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler
    public ErrorResult exHandler(Exception e){
        log.error("[exceptionHandler] ex",e);
        return new ErrorResult("EX","내부 오류");
    }
}

 

 

위 코드처럼 @RestControllerAdvice를 사용하면 기존 컨트롤러에 예외 처리 코드를 포함시키지 않아도 된다.

 

package com.example.exception.api;

import com.example.exception.Exception.UserException;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
public class ApiExceptionV2Controller {

    @GetMapping("/api2/members/{id}")
    public MemberDto getMember(@PathVariable("id") String id) {
        if (id.equals("ex")) {
            throw new RuntimeException("잘못된 사용자");
        }
        if (id.equals("bad")) {
            throw new IllegalArgumentException("잘못된 입력 값");
        }
        if (id.equals("user-ex")) {
            throw new UserException("사용자 오류");
        }
        return new MemberDto(id, "hello " + id);
    }

    @Data
    @AllArgsConstructor
    static class MemberDto{
        private String memberId;
        private String name;
    }
}

 

 

@RestControllerAdvice 대상 컨트롤러 지정 방법 

// @RestController에만 적용 
 @ControllerAdvice(annotations = RestController.class)
 public class ExampleAdvice1 {}
 
 
 // 특정 패키지에만 적용
 @ControllerAdvice("org.example.controllers")
 public class ExampleAdvice2 {}
 
 
// 특정 클래스에만 적용
 @ControllerAdvice(assignableTypes = {ControllerInterface.class, 
AbstractController.class})
 public class ExampleAdvice3 {}

 

 

'BackEnd > 스프링 MVC' 카테고리의 다른 글

스프링 - 파일 업로드(1)  (0) 2025.01.10
포맷터 - Formatter , @NumberFormat, @DateTimeFormat  (0) 2025.01.10
스프링 부트 - ExceptionResolver  (0) 2025.01.09
HandlerExceptionResolver  (0) 2025.01.07
스프링 오류페이지  (0) 2025.01.07