ControllerAdvice, ExceptionHandler Annotation

ControllerAdvice && ExceptionHandler

@ExceptionHandler

예를 들어, 서비스에서 발생하는 예외를 처리하기 위해 UserServiceException 클래스를 정의하고, UserController 클래스에서 이 예외를 처리하고자 할 때 다음과 같이 코드를 작성할 수 있습니다.

public class UserServiceException extends RuntimeException {
    public UserServiceException(String message) {
        super(message);
    }
}
@RestController
@RequestMapping("/users")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/{userId}")
    public ResponseEntity<UserDto> getUserById(@PathVariable("userId") String userId) {
        UserDto userDto = userService.getUserById(userId);
        return ResponseEntity.ok(userDto);
    }

    @PostMapping
    public ResponseEntity<UserDto> createUser(@RequestBody UserDto userDto) {
        UserDto createdUserDto = userService.createUser(userDto);
        return ResponseEntity.created(URI.create("/users/" + createdUserDto.getId())).body(createdUserDto);
    }

    @ExceptionHandler(value = {UserServiceException.class})
    public ResponseEntity<String> handleUserServiceExceptions(UserServiceException ex) {
        return ResponseEntity.badRequest().body("An error occurred: " + ex.getMessage());
    }
}

위의 예제에서는 @ExceptionHandler 어노테이션을 이용하여 UserServiceException을 처리하는 handleUserServiceExceptions 메서드를 정의하였습니다. 이렇게 각 컨트롤러에서 예외 처리를 정의하면 코드의 중복이 발생할 수 있습니다.

@ContollerAdvice

Spring Framework에서는 @ControllerAdvice와 @ExceptionHandler 어노테이션을 이용하여 예외 처리를 분리하고 통합할 수 있습니다.

@ControllerAdvice 어노테이션은 전역적으로 예외 처리를 담당하는 클래스를 정의할 때 사용됩니다. 즉, 해당 클래스에서 예외 발생 시 처리할 수 있습니다.

이 어노테이션을 사용하면 여러 개의 컨트롤러에서 발생하는 예외를 하나의 클래스에서 처리할 수 있어서 코드의 중복을 줄일 수 있습니다.

이전 예제를 @ControllerAdvice를 이용하여 수정하면 다음과 같습니다.

@ControllerAdvice
public class ExceptionHandlerAdvice {
    @ExceptionHandler(value = {UserServiceException.class})
    public ResponseEntity<String> handleUserServiceExceptions(UserServiceException ex) {
        return ResponseEntity.badRequest().body("An error occurred: " + ex.getMessage());
    }
}

@RestController
@RequestMapping("/users")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/{userId}")
    public ResponseEntity<UserDto> getUserById(@PathVariable("userId") String userId) {
        UserDto userDto = userService.getUserById(userId);
        return ResponseEntity.ok(userDto);
    }

    @PostMapping
    public ResponseEntity<UserDto> createUser(@RequestBody UserDto userDto) {
        UserDto createdUserDto = userService.createUser(userDto);
        return ResponseEntity.created(URI.create("/users/" + createdUserDto.getId())).body(createdUserDto);
    }
}

@Service
public class UserService {

    private List<User> users = new ArrayList<>();

    public void addUser(User user) {
        users.add(user);
    }

    public User getUserById(int id) throws UserNotFoundException {
        for (User user : users) {
            if (user.getId() == id) {
                return user;
            }
        }
        throw new UserNotFoundException("User with id " + id + " not found");
    }

}

위의 예제에서는 @ControllerAdvice 어노테이션을 사용하여 ExceptionHandlerAdvice 클래스를 전역 예외 처리 클래스로 정의하였습니다.

이 클래스에서는 @ExceptionHandler 어노테이션을 이용하여 UserServiceException을 처리하도록 정의하였습니다. 이렇게 하면 UserController에서 UserServiceException을 처리하는 코드가 제거되어 코드의 중복을 줄일 수 있습니다.


© 2024. Chiptune93 All rights reserved.