본문 바로가기

Spring

@ControllerAdvice를 이용한 예외 처리

@ControllerAdvice를 이용한 예외 처리

Custom 한 Exception class를 만들어서 @ControllerAdvice과 함께 예외 처리를 해보자.

CustomValidationException

Validation 예외 처리를 해줄 클래스를 다음과 같이 만든다.

public class CustomValidationException extends RuntimeException{
    public CustomValidationException() {
        super();
    }

    public CustomValidationException(String message) {
        super(message);
    }

    public CustomValidationException(String message, Throwable cause) {
        super(message, cause);
    }

RuntimeException을 상속하며 다음과 같이 상황에 맞게 사용할 수 있도록 세 개의 생성자를 오버 로딩 한다.

ExceptionAdvice

예외가 발생했을 때 이를 처리해 줄 수 있는 ExceptionAdvice 클래스를 만들어준다.


import com.soc.BackEnd.api.CommonResponse;
import com.soc.BackEnd.api.ResponseService;
import com.soc.BackEnd.config.advice.exception.CustomValidationException;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;

@RequiredArgsConstructor
@RestControllerAdvice
public class ExceptionAdvice {

    private final ResponseService responseService;

    @ExceptionHandler(CustomValidationException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    protected CommonResponse validationException(HttpServletRequest req, CustomValidationException e) {
        if (e.getMessage() != null) {
            if (e.getMessage().equals("studentId")) return responseService.getFailResponse("중복되는 학번입니다.");
            else if (e.getMessage().equals("email")) return responseService.getFailResponse("중복되는 이메일입니다.");
            else if (e.getMessage().equals("nickname")) return responseService.getFailResponse("중복되는 이메일입니다.");
        }
        return responseService.getFailResponse("잘 못 된 입력 값입니다.");
    }
}

@RequiredArgsConstructor

return 때 필요한 응답 전송을 위해 responseService을 의존성 주입하기 위해 사용했다.

responseService.getFailResponse에 String 값을 인자로 넣어 return 하면 JSON 형식의 "message" 키값에 값을 담아 리턴해주게 만들어놨다.

@RestControllerAdvice

전역 컨트롤러를 사용하는 어노테이션으로써, 서버 전역의 예외 처리를 가능하게 해준다.

@ExceptionHandler(CustomValidationException.class)

어떤 예외가 발생할 때 핸들링 해줄 것인지를 명시해 주는 어노테이션

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)

예외 발생 시 Response로 보내줄 서버 상태를 설정할 수 있다.

if (e.getMessage().equals("studentId")) return responseService.getFailResponse("중복되는 학번입니다.");

오버 로딩 한 생성자 중, String message가 인자일 때의 생성자를 다음과 같이 사용할 수 있다.

예외 처리에서 사용

다음과 같이 서비스단에서의 예외 처리 시에 사용할 수 있다.

public CommonResponse signUp(SignupDto dto, Errors errors) {

        if(errors.hasErrors()) throw new CustomValidationException();
        if(accountRepository.findByEmail(dto.getEmail()).isPresent()){
            throw new CustomValidationException("email");
        }
        if(accountRepository.findByStudentId(dto.getStudentId()).isPresent()){
            throw new CustomValidationException("studentId");
        }
        if(accountRepository.findByNickname(dto.getStudentId()).isPresent()){
            throw new CustomValidationException("nickname");
        }

        //...
    }

메시지를 보낼 수 있는 에러가 아닐 시엔 throw new CustomValidationException()를 통해 에러 처리를 한다.

다른 중복의 경우엔 중복의 이유를 메시지로 보내주었다.

Swagger로 예외 처리 확인

Swagger를 통해 예외 처리가 적용되는 것을 확인해보자.

계정을 하나 만들고 똑같은 닉네임으로 다시 회원가입 api를 부르면 다음과 같은 결과가 나타난다.

ExceptionAdvice에 의해 앞서 언급했던 responseService.getFailResponse에 메시지가 잘 전달되어 JSON으로 리턴된 것을 확인할 수 있다.