๐Ÿ‘จ‍๐Ÿ‘ฉ‍๐Ÿ‘ง‍๐Ÿ‘ฆ Project/๐Ÿ“บ KIOSEK

Custom Exception, ExceptionHandler ์„ค๊ณ„์—์„œ ๋‚˜์œ ์ฝ”๋“œ์— ๋Œ€ํ•œ ๊ณ ๋ฏผ๊ณผ ๋ฆฌํŒฉํ† ๋ง ๊ณผ์ •

DevPoong 2023. 5. 16. 15:10

1. ๋ฌธ์ œ ์ƒํ™ฉ


๊ธฐ์กด ์ฝ”๋“œ ํ๋ฆ„

@Getter
public enum ErrorCode {
    DUPLICATED_LONGIND("0101", ์ด๋ฏธ ์‚ฌ์šฉ์ค‘์ธ ์•„์ด๋””(ํ•™๋ฒˆ) ์ž…๋‹ˆ๋‹ค.)"),
    ...
public DuplicatedLoginIdException extends RuntimeException {
	public DuplicatedLoginIdException() {
    }
}
# SignupService
public void signup(LoginReq req) {
	...
    throw new DuplicatedLoginIdException();
}
@RestControllerAdvice
public class ControllerAdvice {

    @ResponseStatus(HttpsStatus.CONFLICT)
    @ExceptionHandler(DuplicatedLoginIdException.class)
    public ErrorResponse duplicatedLoginIdEXHandler(DuplicatedLoginIdException e){
        return new ErrorResponse(ErrorCode.DUPLICATED_ID);
    }
}

์œ„์™€ ๊ฐ™์ด ์˜ˆ์™ธ๋ฅผ ๊ฐ๊ฐ์˜ ์—๋Ÿฌ์ƒํ™ฉ์— ๊ฑฐ์˜ 1๋Œ€ 1๋กœ Custom Exception class๋ฅผ ๋งŒ๋“ค๊ณ  ์—๋Ÿฌ์— ๋Œ€ํ•œ ์‘๋‹ต HttpStatus๋‚˜ ErrorCode๋Š” Member์˜ ControllerAdvice์—์„œ ์˜ˆ์™ธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋˜ ์˜ˆ์™ธ๋งˆ๋‹ค ํ•˜๋‚˜์”ฉ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ–ˆ์—ˆ๋‹ค.

์ด๋Ÿฐ ๊ตฌ์กฐ๋กœ ํ•˜๋‹ค๋ณด๋‹ˆ ์ฝ”๋“œ๋ฅผ ๋‹ค ์ž‘์„ฑํ•˜๊ณ  ๋ณด๋‹ˆ ์•„๋ž˜์™€ ๊ฐ™์ด Member Aggregate์— ๊ด€๋ จํ•œ ์˜ˆ์™ธ๋งŒ 12๊ฐœ๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ๊ณ  ๋‹ค๋ฅธ ๋„๋ฉ”์ธ์—์„œ ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ๋ฅผ ํ•ฉ์น˜๋ฉด 40๊ฐœ๊ฐ€ ๋„˜๋Š” CustomException๊ณผ ์ด ์˜ˆ์™ธ๋ฅผ ๋‹ค๋ฃฐ ExceptionHandler ๋˜ํ•œ 40๊ฐœ๊ฐ€ ์ƒ์„ฑ๋˜๊ฒŒ ๋˜์—ˆ๋‹ค.

์ฝ”๋“œ๋ฅผ ์งœ๋ฉด์„œ ๊ณ„์† ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ด€๋ฆฌ๊ฐ€ ๋„ˆ๋ฌด ์–ด๋ ค์šธ ๊ฒƒ ๊ฐ™์€๋ฐ๋ผ๋Š” ์ƒ๊ฐ์€ ๊ณ„์†ํ–ˆ์ง€๋งŒ ๊ณ„์† ์—‰๋ง์ธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ๋ง์•˜๋‹ค. 

Effective Java ์ฑ…์ด๋‚˜ ๋‹ค๋ฅธ๊ณณ์—์„œ๋Š” ํ‘œ์ค€ ์˜ˆ์™ธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๋ฉ”์‹œ์ง€๋ฅผ ์ด์šฉํ•ด์„œ ์ƒํ™ฉ์„ ์ดํ•ดํ•˜๊ฒŒ๋” ํ•ด๋„ ๊ฐ€๋…์„ฑ๊ณผ ๊ด€๋ฆฌ๊ฐ€ ์šฉ์ดํ•˜๋‹ค๊ณ  ํ•˜์ง€๋งŒ Spring์ด๋‚˜ Jwt ๊ด€๋ จ ์˜ˆ์™ธ๋“ค๋งŒ ๋ด๋„ ์ด๋ฏธ Custom Exception์„ ์ƒ์„ฑํ•ด์„œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ณ 
๋‚ด ์ƒ๊ฐ์—๋Š” ์ปค์Šคํ…€ ์˜ˆ์™ธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฒƒ์ด ํ›จ์”ฌ ๊ฐ€๋…์„ฑ์ด ์ข‹๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๊ธฐ์— ์ปค์Šคํ…€ ์˜ˆ์™ธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์€ ์œ ์ง€ํ•˜๊ณ  ๋ฆฌํŒฉํ† ๋ง์„ ํ†ตํ•ด ๊ตฌ์กฐ๋ฅผ ๊ฐœ์„ ํ•˜๊ธฐ๋กœ ํ•˜์˜€๋‹ค.

์ด๋ฒˆ์— ์ด Custom Exception, Exception Handler, ErrorCode๋ฅผ ํ•จ๊ป˜ ๋ฆฌํŒฉํ† ๋ง ์‹œ๋„ํ•˜์˜€๊ณ  ๋งŒ์กฑํ• ๋งŒํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜จ ๊ฒƒ ๊ฐ™์•„ ์ •๋ฆฌํ•œ๋‹ค.

 

2. ๋ฌธ์ œ ํ•ด๊ฒฐ


์ ์ง„์ ์œผ๋กœ ๋ฆฌํŒฉํ† ๋งํ•˜์˜€์Šต๋‹ˆ๋‹ค.

โœ๏ธ 1์ฐจ ์‹œ๋„  - ๋ถ€๋ถ„ ์„ฑ๊ณต

1. ErrorCode์—์„œ HttpStatus๊นŒ์ง€ ๊ด€๋ฆฌํ•˜๋„๋ก ๋ณ€๊ฒฝ. 

@Getter
public enum ErrorCode {
    DUPLICATED_LOGINID(CONFLICT, "0101", "์ด๋ฏธ ์‚ฌ์šฉ์ค‘์ธ ์•„์ด๋””(ํ•™๋ฒˆ) ์ž…๋‹ˆ๋‹ค.)"),
    ....
    
    private final HttpStatus httpStatus;
    private final String code;
    private final String message;

    ErrorCode(final HttpStatus httpStatus, final String code, final String message) {
        this.httpStatus = httpStatus;
        this.code = code;
        this.message = message;
    }
}

 

 

2. ์ปค์Šคํ…€ ์˜ˆ์™ธ๋“ค์˜ ์ถ”์ƒ ์Šˆํผ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑ

@Getter
public abstract class AbstractErrorException extends RuntimeException{
    private final ErrorCode errorCode;

    public AbstractErrorException(ErrorCode errorCode) {
        super(errorCode.getMessage());
        this.errorCode = errorCode;
    }
}

public abstract class AbstractBusinessLogicException extends AbstractErrorException{
    public AbstractBusinessLogicException(ErrorCode errorCode) {
        super(errorCode);
    }
}
public class DuplicatedLoginIdException extends BusinessLogicException {
    public DuplicatedLoginIdException() {
        super(ErrorCode.DUPLICATED_LOGINID);
    }
}

 

 

3. ์ „์—ญ์ ์œผ๋กœ ์ถ”์ƒ ์ปค์Šคํ…€ ์˜ˆ์™ธ์— ๋Œ€ํ•œ ํ•˜๋‚˜์˜ Exception Handler ๋“ฑ๋ก

@RestControllerAdvice
public class GlobalExceptionHandler {
	....

    @ExceptionHandler(AbstractBusinessLogicException.class)
    public ResponseEntity<ErrorResponse> handleBusinessLogicException(AbstractBusinessLogicException e){
        ErrorCode errorCode = e.getErrorCode();
        ErrorResponse response = new ErrorResponse(errorCode.getCode(), e.getMessage());
        return new ResponseEntity<>(response, errorCode.getHttpStatus());
    }
    ...
}

์œ„์™€ ๊ฐ™์ด ErrorCode๋ฅผ ์ปค์Šคํ…€ ์˜ˆ์™ธ ๋‚ด๋ถ€์— ์ˆจ๊ฒจ์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ์ง์—์„œ๋Š” ์˜ˆ์™ธ์˜ ์ด๋ฆ„์„ ํ†ตํ•ด ๊ตฌ์ฒด์ ์ธ ์˜ˆ์™ธ ์ƒํ™ฉ์„ ๊ฐ€๋…์„ฑ ์ข‹๊ฒŒ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๊ณ  ์—๋Ÿฌ์ฝ”๋“œ์™€์˜ ์˜์กด์„ฑ์€ ๋Š์–ด์„œ ๊ดœ์ฐฎ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค.

๋˜ํ•œ ์ถ”์ƒ ์Šˆํผ ์˜ˆ์™ธ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“  ์ด์œ ๋Š” GlobalControllerAdvice๋ฅผ ํ†ตํ•ด ์ „์—ญ์ ์œผ๋กœ ํ•˜๋‚˜์˜ ControllerAdvice๋ฅผ ๊ฐ€์ง€๊ณ  ์ปค์Šคํ…€ ์˜ˆ์™ธ์˜ ๋ถ€๋ชจ ํด๋ž˜์Šค์— ๋Œ€ํ•ด์„œ ExceptionHandler๋ฅผ ๋“ฑ๋กํ•˜๋ฉด ํ•˜๋‚˜์˜ ์˜ˆ์™ธ ํ•ธ๋“ค๋Ÿฌ๋กœ ๋ชจ๋“  ์ปค์Šคํ…€ ์˜ˆ์™ธ์— ๋Œ€ํ•ด์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋ฏ€๋กœ ์ค‘๋ณต ์ฝ”๋“œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

ํ™•์‹คํžˆ ์˜ˆ์™ธ ํ•ธ๋“ค๋Ÿฌ๋„ ๊ณตํ†ต์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ณ  ์ข‹์€ ์‹œ๋„์˜€๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ๊ฒฐ๋ก ์ ์œผ๋กœ Custom Exception์˜ ๊ฐœ์ˆ˜๋Š” ์ค„์–ด๋“ค์ง€ ์•Š์•˜๋‹ค. ๊ณ„์† ๊ฐœ์„ ํ•ด ๋‚˜๊ฐ€ ๋ณด์ž!

 

โœ๏ธ 2์ฐจ ์‹œ๋„ - ์„ฑ๊ณต!

1์ฐจ ์‹œ๋„์—์„œ ํ–ˆ๋˜ ์ถ”์ƒ ์Šˆํผ ์˜ˆ์™ธ ํด๋ž˜์Šค ๋ฐฉ์‹๊ณผ Global Exception Handler ๋ฐฉ์‹๋„ ์œ ์ง€ํ•˜๊ณ 
Custom Exception์˜ ๊ฐœ์ˆ˜๋ฅผ ์ค„์—ฌ ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ƒ๊ฐํ•ด ๋ดค๋‹ค.

์˜ˆ์™ธ ์ด๋ฆ„๋“ค์„ ๋ณด๋‹ˆ DuplicatedXXException, NotFoundXXException ๋“ฑ ์ƒํ™ฉ์ด ๋น„์Šทํ•œ ๊ฒƒ๋“ค์ด ๊ฝค ๋งŽ์•˜๋‹ค.
๊ทธ๋ž˜์„œ ์ƒํ™ฉ์— ๋งž๋Š” ์˜ˆ์™ธ์˜ ๊ฐ€๋…์„ฑ์€ ์ง€์ผœ์ฃผ๋”๋ผ๋„ ๋น„์Šทํ•œ ๊ฒƒ๋“ค๋ผ๋ฆฌ ๋˜ ์Šˆํผ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ErrorCode๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ ์ชฝ์—์„œ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ๋•Œ ์˜ˆ์™ธ์— ๋„ฃ์–ด์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰ํ•ด ๋ณด์•˜๋‹ค. 

์ค‘๋ณต์— ๋Œ€ํ•œ ์˜ˆ์™ธ๊ฐ€ ์•„์ด๋”” ๊ฒ€์ฆ, ์ด๋ฉ”์ผ ๊ฒ€์ฆ, ์˜ˆ์•ฝ ์‹œ ๋“ฑ๋“ฑ ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ๋‹ค.
๋”ฐ๋ผ์„œ DuplicationException์œผ๋กœ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์˜€๋‹ค.

public class DuplicationException extends AbstractBusinessLogicException {
    public DuplicationException(ErrorCode errorCode) {
        super(errorCode);
    }
}
# SignupService
public void signup(LoginReq req) {
	...
    throw new DuplicationException(ErrorCode.DUPLICATED_LOGINID);
}

์œ„์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋‹ค๋ฅธ ์˜ˆ์™ธ๋„ ๊ณตํ†ตํ™”ํ•˜์˜€๋‹ค.

๋” ์ค„์ผ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์ตœ๋Œ€ํ•œ ์˜ˆ์™ธ๋ฅผ ์ฝ๋Š”๋ฐ ๊ฐ€๋…์„ฑ์„ ํ—ค์น˜์ง€ ์•Š์„ ์ •๋„๋กœ ์ถ”์ƒํ™”ํ•˜์˜€๊ณ  ์ด 12๊ฐœ์˜ ๊ตฌ์ฒด ์ปค์Šคํ…€ ์˜ˆ์™ธ๋กœ ์ค„์–ด๋“ค๊ฒŒ ๋˜์—ˆ๋‹ค.

40๊ฐœ -> 12๊ฐœ๋Š” ํฐ ๋ณ€ํ™”์˜€๊ณ  ์ข‹์€ ๋ฆฌํŒฉํ† ๋ง ๊ณผ์ •์„ ๊ฒฝํ—˜ํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.