본문 바로가기

Spring Boot

API 예외처리 공통화 1

Spring Boot로 프로젝트를 만들다보면 API도 꽤 많이 작성하게 된다. (아님 말고,,,,,,)
이 API를 작성할 때 예외처리도 해야한다.
ex) 회원가입 시 아이디나 전화번호 중복되는 경우, 상품주문 시 재고가 부족한 경우 등등
우리는 굉장히 많은 예외처리를 해야한다.
이 예외는 Service단에서 던지게 되고, 처리는 Controller단에서 하게 된다.
또한, 이러한 예외처리를 매번 반복하게 된다.

먼저 공통화하지 않는 경우, 예외처리를 살펴보자!


1. Error 처리를 위한 class 생성

ErrorMessage.java

package hello.hellospring.exception;

import lombok.AllArgsConstructor;

@AllArgsConstructor
public class ErrorMessage {
    public String title;
    public String msg;
}

 

에러발생 시 client에게 반환할 DTO이다.(굉장히 간단...)
보여줄 메시지의 제목인 title과 내용인 msg field가 있다.

 

ErrorResponseException.java

package hello.hellospring.exception;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public class ErrorResponseException extends RuntimeException {
    private final ErrorMessage errorMessage;
}

 

RuntimeException을 상속받는 예외클래스를 직접 만들었다.(try-catch 필요 X)

(자세한 내용은 checked exception과 unchecked exception에 대해 공부하자.)

또한 errorMessage field는 처음에 생성자를 통해서 설정되며,
Getter를 통해 errorMessage를 받아올 수 있다.

 


2. Error 처리

MemberService.java

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("", "빈칸없이 입력해주세요."));
        }

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

 

id, pw, name을 입력받아서 회원가입을 처리하는데 값이 있는지 없는지 검사해야 한다고 가정하자.
(물론 실무에서는 이럴 일 절대 없지만 말이다. 이게 중요한 게 아니니까 대충 넘어가자...)
위와 같이 비어있는 문자열이 온 경우 ErrorResopnseException을 던지게 작성했다.

method에 throws 구문을 작성하지 않아도 된다.
자세한 부분은 checked exception과 unchecked exception을 공부하자.

 

MemberController.java

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 test(String id, String pw, String name) {
        try {
            memberService.join(id, pw, name);
        } catch (ErrorResponseException e) {
            return new ResponseEntity(e.getErrorMessage(), HttpStatus.BAD_REQUEST);
        }
        return new ResponseEntity(HttpStatus.OK);
    }
}

 

이제 MemberService를 이용해 회원가입을 처리하는 MemberController는에서는

catch 구문을 통해 Exception이 발생한 경우,
ResponseEntity에 error message와 상태값에 400(BAD_REQUEST)을 담아서 Client에게 반환한다.
또한 로직이 Exception 없이 정상실행된 경우에는, 상태값에 200(OK)을 담아서 반환한다.

 

postman을 통한 실행결과

 

예외처리를 공통화하면, 매번 이런 식의 작업을 반복하지 않아도 된다.
공통화를 통해 이 반복을 줄여보자!