본문 바로가기

Spring Boot

API 예외처리 공통화 2

이번 글에서는 API 예외처리를 공통화해볼 것이다.


1. Global Exception 처리를 위한 class 생성

GlobalExceptionHandler

package hello.hellospring.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ErrorResponseException.class)
    protected ResponseEntity<ErrorMessage> handleErrorResponseException(ErrorResponseException e) {
        ErrorMessage message = e.getErrorMessage();
//        log.error("handleErrorResopnseException : {msg: " + message.msg + "" +
//                "title: " + message.title + "}");
        log.error("handleErrorResponseException : {msg: " + message.msg + "" + "title: " + message.title + "}");
        return new ResponseEntity<>(message, HttpStatus.BAD_REQUEST);
    }
}

 

Global Exception을 처리하기 위해 @ControllerAdvice를 사용했다.
또한 handleErrorResponseException method는 @ExceptionHandler를 통해
ErrorResponseException에 관한 예외만 처리하도록 설정했다.
method 내부에서는 BAD_REQUEST 상태값과 함께 ErrorMessage 객체를
ResponseEntity로 감싸서 전달하는 일만 한다.
이렇게 ErrorResponseException을 처리하기 위한 로직을 작성했으니 이제 try-catch문을 제거하기만 하면 공통화가 끝난다.

2. MemberController try-catch 제거

MemberService

package hello.hellospring.service;

import hello.hellospring.exception.ErrorMessage;
import hello.hellospring.exception.ErrorResponseException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

@Service
@Transactional(readOnly = true)
public class MemberService {

    public void join(String id, String pw, String name) {
        if (!StringUtils.hasLength(id) || !StringUtils.hasLength(pw) || !StringUtils.hasLength(name)) {
            throw new ErrorResponseException(new ErrorMessage("", "빈칸없이 입력해주세요."));
        }

        // 그 외 유효성 검사, 중복검사, 회원가입 처리로직 등등
    }
}

 

MemberService는 변화가 없다.

 

MemberController

package hello.hellospring.controller;

import hello.hellospring.exception.ErrorResponseException;
import hello.hellospring.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
@RequiredArgsConstructor
public class MemberController {

    private final MemberService memberService;

    @GetMapping("join")
    public ResponseEntity join(String id, String pw, String name) {
        memberService.join(id, pw, name);
        return new ResponseEntity(HttpStatus.OK);
    }
}

 

MemberController에서 try-catch를 제거했다.
이제 memberService.join에서 ErrorResponseException을 던질 경우
GlobalExceptionHandler.handleErrorResponseException에 의해 처리되게 된다.
즉, error log를 찍고, API를 호출한 곳에 응답으로 ErrorMessage 객체를 반환하는 것이다.
따라서 앞으로는 API 호출의 응답으로 ErrorMessage 객체를 반환하고싶을 때는
ErrorResponseException을 던지기만 하면 끝난다.

3. 동작확인

postman을 통한 API 호출 결과
log 결과

API 호출결과와 log를 통해 잘 동작하는 것을 확인할 수 있다.