스프링에서 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 |