본문 바로가기

Backend/Spring

Spring Boot 예외처리 @ControllerAdvice - (3)

Rest API를 개발할 때 제가 사용하는 아주 간단한 예외처리 방법을 소개해드릴게요.

클라이언트에게 상태코드로 예외의 성격을 알리고 body에 예외 상황에 대한 메시지를 알려줄거에요.

파일 두 개만 추가해주면 끝이에요.

실제로는 더 복잡할 수 있지만, 이해를 돕기 위해 아주 기본만 남겼으니 도움이 되었으면 좋겠네요.

 

RestException

상태코드와 메시지만 받도록 했어요.

우리는 이 클래스로 객체를 만들어서 throw하여 예외를 발생시킬 거에요.

HttpStatus는 스프링프레임워크에서 만들어 놓은 enum 클래스로 상태코드와 상태메시지를 미리 정의해놨어요.

 

public class RestException extends RuntimeException {

	private static final long serialVersionUID = 1L;
	
	private HttpStatus status;
	private String message;

	public RestException(HttpStatus status, String message) {
		this.status = status;
		this.message = message;
	}

	public HttpStatus getStatus() {
		return status;
	}

	public void setStatus(HttpStatus status) {
		this.status = status;
	}

	public String getMessage() {
		return message;
	}

}

 

ControllerAdvice

비즈니스 로직에서 RestException으로 예외를 발생시키면 아래 클래스의 @ExceptionHandler가 붙은 메서드에서 캐치하여 이후 로직을 공통적으로 처리할 수 있어요.

return 타입이 ResponseEntity<?>인데 여기서 파라미터로 HttpStatus를 넘겨줘야해요.

 

@RestControllerAdvice
public class ControllerAdvice {

    @ExceptionHandler(RestException.class)
	public ResponseEntity<Map<String, Object>> handler(RestException e) {
		Map<String, Object> resBody = new HashMap<>();
		resBody.put("message", e.getMessage());
		
		return new ResponseEntity<>(resBody, e.getStatus());
	}
	
}

 

UserService

Controller를 통해서 파라미터를 전달하고 Service에서 보통 비즈니스 로직을 구현하므로

Service에서 RestException 객체를 만들어서 예외를 발생시켜 볼게요.

 

@Service
public class UserService {
	
	@Autowired
	private UserRepository userRepository;
	
	public UserEntity getUser(String userId, String password) {
		UserEntity user = userRepository.findById(userId).orElseThrow(() -> 
        		new RestException(HttpStatus.NOT_FOUND, "Not found user"));
		if (!password.equals(user.getPassword())) {
			throw new RestException(HttpStatus.NOT_FOUND, "Password incorrect");
		}
		return user;
	}
	
	public UserEntity setUser(UserEntity user) {
		return userRepository.save(user);
	}

}

 

RestException 객체에 예외상황에 알맞는 상태코드와 메시지를 넣어서 throw하면 끝!

아주 간단하죠?

여기까지가 끝이에요. 위의 구조를 바탕으로 필요하다면 확장하면 되요.

 

테스트까지 한 번 해볼까요?

userId: "hong", password: "1234"로 이미 테이블에 데이터를 넣어놨어요.