[Spring Boot] REST-API 공통 에러(Exception) 처리 개발 과정

2023. 3. 17. 14:49·Spring Framework

https://kdyspring.tistory.com/44

 

[Spring Boot] REST-API 공통 응답(Response) 포맷 개발 과정

CRUD를 구현할때 R(Read)을 제외한 API들의 Response 값을 공통으로 클라이언트에 리턴해주는 기능을 개발했던 과정을 정리해 보겠습니다. 1. Response 값을 공통으로 리턴 시 얻게 되는 장점 - GET 요청 API

kdyspring.tistory.com

이전 글에 이어서 System Exception 또는 Custom Exception 에러 발생 시 공통 Response 값에 에러 데이터들(에러 코드, 에러 메시지)을 객체에 담아서 공통으로 에러 데이터를 리턴해주는 기능을 개발한 과정에 대해 정리해 보았습니다.

 

 

 

1. System Exception과 Custom Exception를 정의한 Enum 클래스를 생성.

package com.example.login.common.error;

import lombok.Getter;
import lombok.ToString;
import org.springframework.http.HttpStatus;

@Getter
@ToString
public enum ExceptionEnum {

    // System Exception
    RUNTIME_EXCEPTION(HttpStatus.BAD_REQUEST, "E0001"),
    ACCESS_DENIED_EXCEPTION(HttpStatus.UNAUTHORIZED, "E0002"),
    INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "E0003"),
    // Custom Exception
    SECURITY(HttpStatus.UNAUTHORIZED, "CE0001", "로그인이 필요합니다");

    private final HttpStatus status;
    private final String code;
    private String message;

    ExceptionEnum(HttpStatus status, String code) {
        this.status = status;
        this.code = code;
    }

    ExceptionEnum(HttpStatus status, String code, String message) {
        this.status = status;
        this.code = code;
        this.message = message;
    }
}

 

 

2. 사용자 정의 예외 클래스 생성 

1. 컴파일 시 발생하는 예외 처리를 구현할 경우에는 Exception을 상속받아 구현
2. 실행 시 발생하는 예외 처리를 구현할 경우에는 RuntimeException을 상속받아 구현

 

ApiException.java

package com.example.login.common.error;

import lombok.Getter;

@Getter
public class ApiException extends RuntimeException {
    private ExceptionEnum error;

    public ApiException(ExceptionEnum e) {
        super(e.getMessage());
        this.error = e;
    }
}

 

 

3. 전역 예외 처리 Class 생성

 

- 발생한 예외를 통합하여 관리 할 수 있는 @RestControllerAdvice 어노테이션과  System Exception 및 Custom Exception핸들링을 해주는 @ExceptionHandler를 사용 하여 전역으로 발생한 예외를 처리해줄 수 있는 Class를 생성.

 

 

ApiExceptionAdvice.java

package com.example.login.common.error;

import com.example.login.common.api.ApiResult;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.nio.file.AccessDeniedException;

@RestControllerAdvice
public class ApiExceptionAdvice {
    @ExceptionHandler({ApiException.class})
    public ResponseEntity<ApiResult> exceptionHandler(HttpServletRequest request, final ApiException e) {

        ApiExceptionEntity apiExceptionEntity = ApiExceptionEntity.builder()
                .errorCode(e.getError().getCode())
                .errorMessage(e.getError().getMessage())
                .build();

        //e.printStackTrace();

        return ResponseEntity
                .status(e.getError().getStatus())
                .body(ApiResult.builder()
                        .status("error")
                        .message("")
                        .exception(apiExceptionEntity)
                        .build());
    }

    @ExceptionHandler({RuntimeException.class})
    public ResponseEntity<ApiResult> exceptionHandler(HttpServletRequest request, final RuntimeException e) {

        ApiExceptionEntity apiExceptionEntity = ApiExceptionEntity.builder()
                .errorCode(ExceptionEnum.RUNTIME_EXCEPTION.getCode())
                .errorMessage(e.getMessage())
                .build();

        e.printStackTrace();

        return ResponseEntity
                .status(ExceptionEnum.RUNTIME_EXCEPTION.getStatus())
                .body(ApiResult.builder()
                        .status("error")
                        .message("")
                        .exception(apiExceptionEntity)
                        .build());
    }

    @ExceptionHandler({AccessDeniedException.class})
    public ResponseEntity<ApiResult> exceptionHandler(HttpServletRequest request, final AccessDeniedException e) {

        ApiExceptionEntity apiExceptionEntity = ApiExceptionEntity.builder()
                .errorCode(ExceptionEnum.ACCESS_DENIED_EXCEPTION.getCode())
                .errorMessage(e.getMessage())
                .build();

        e.printStackTrace();

        return ResponseEntity
                .status(ExceptionEnum.ACCESS_DENIED_EXCEPTION.getStatus())
                .body(ApiResult.builder()
                        .status("error")
                        .message("")
                        .exception(apiExceptionEntity)
                        .build());
    }

    @ExceptionHandler({Exception.class})
    public ResponseEntity<ApiResult> exceptionHandler(HttpServletRequest request, final Exception e) {

        ApiExceptionEntity apiExceptionEntity = ApiExceptionEntity.builder()
                .errorCode(ExceptionEnum.INTERNAL_SERVER_ERROR.getCode())
                .errorMessage(e.getMessage())
                .build();

        e.printStackTrace();

        return ResponseEntity
                .status(ExceptionEnum.INTERNAL_SERVER_ERROR.getStatus())
                .body(ApiResult.builder()
                        .status("error")
                        .message("")
                        .exception(apiExceptionEntity)
                        .build());
    }

}

 

 

4. 구현 및 테스트 결과

 

4-1. LoginCheckIntercepter.java

package com.example.login.common.intercepter;

import com.example.login.vo.UserVO;
import org.apache.catalina.User;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.util.WebUtils;

import javax.inject.Inject;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Arrays;

@Component
public class LoginCheckIntercepter implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        UserVO userVo = (UserVO) request.getSession().getAttribute("login");

        if (userVo != null) {
            return true;
        }

        request.setAttribute("exception", "AuthenticationException");
        request.getRequestDispatcher("/api/error").forward(request, response);

        return false;
    }

}

 

 

4-2. ErrorController.java

package com.example.login.common.error;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import javax.security.sasl.AuthenticationException;
import javax.servlet.http.HttpServletRequest;

@RestController
@RequestMapping("/api")
@ApiIgnore
public class ErrorController {

    @RequestMapping("/error")
    public void error(HttpServletRequest request) throws AuthenticationException{

        String exception = (String) request.getAttribute("exception");

        if ("AuthenticationException".equals(exception)) {
            throw new ApiException(ExceptionEnum.SECURITY);
        }
    }
}

 

 

4-3. 테스트 결과

저작자표시 (새창열림)

'Spring Framework' 카테고리의 다른 글

[Spring Boot] REST-API 공통 Response 값 포맷 개발 과정  (0) 2023.03.15
Spring Boot 프로젝트에서 Mybatis로 Mysql 데이터베이스(DB) 연동하는법  (2) 2021.10.05
(Spring,JSP) JSP에서 날짜 값을 fmt태그를 사용해 포맷하는법  (0) 2021.09.24
(Spring)Postman를 사용해서 Spring으로 구축한 REST API 서버가 정상작동하는지 테스트 하는 방법  (0) 2021.09.20
Spring Boot에서 JSP 연동(사용)하는 방법  (0) 2021.09.19
'Spring Framework' 카테고리의 다른 글
  • [Spring Boot] REST-API 공통 Response 값 포맷 개발 과정
  • Spring Boot 프로젝트에서 Mybatis로 Mysql 데이터베이스(DB) 연동하는법
  • (Spring,JSP) JSP에서 날짜 값을 fmt태그를 사용해 포맷하는법
  • (Spring)Postman를 사용해서 Spring으로 구축한 REST API 서버가 정상작동하는지 테스트 하는 방법
「김동윤」
「김동윤」
개발을 하면서 기록하고 공유하는 공간입니다
  • 「김동윤」
    평범한 개발 블로그
    「김동윤」
  • 전체
    오늘
    어제
    • 분류 전체보기 (21)
      • DB (3)
      • Git (1)
      • Spring Framework (6)
      • Spring Framework Error (9)
      • JS (2)
        • node.js (1)
        • react (1)
      • 머신 러닝 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 개인 github
  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
「김동윤」
[Spring Boot] REST-API 공통 에러(Exception) 처리 개발 과정
상단으로

티스토리툴바