[Spring boot] Bank App - Exception Handler

2025. 2. 13. 15:38·Spring
728x90

🚀 Exception Handler 처리 (HTTP 상태 코드)

📌 목표

  1. @ControllerAdvice, @RestControllerAdvice 개념 이해
  2. @ControllerAdvice vs @RestControllerAdvice 차이점
  3. 사용자 정의 예외 클래스 만들기
  4. @ControllerAdvice를 활용한 전역 예외 처리 구현
  5. 에러 페이지(errorPage.jsp) 코드 수정
  6. 직접 예외 발생하여 테스트
  7. HTTP 상태 코드 정리 (4xx & 5xx)
  8. @ControllerAdvice란?

 

 


1️⃣ @ControllerAdvice, @RestControllerAdvice란?

Spring에서 전역적으로 예외를 처리하는 어노테이션.
애플리케이션 전역에서 발생하는 예외를 중앙에서 관리 가능.

 

사용 이유?

  • 컨트롤러마다 try-catch로 예외를 처리하는 대신, 전역에서 한 번만 처리하도록 한다.
  • 예외 발생 시 일관된 응답을 제공할 수 있다.


2️⃣ @ControllerAdvice vs @RestControllerAdvice 차이점

어노테이션 설명
@ControllerAdvice @Controller에서 발생한 예외를 처리하며, HTML 뷰를 반환하는 웹 애플리케이션에서 주로 사용
@RestControllerAdvice @RestController에서 발생한 예외를 처리하며, JSON과 같은 데이터 응답을 반환하는 API 에서 주로 사용

 

👉 @RestControllerAdvice는 사실 @ControllerAdvice에 @ResponseBody가 추가된 것과 동일한 효과!


✅ 예제 코드 비교

@ControllerAdvice 예제 (HTML 페이지 반환)

@ControllerAdvice
public class GlobalExceptionHandler {

    // 특정 예외 처리 (리소스를 찾을 수 없는 경우)
    @ExceptionHandler(ResourceNotFoundException.class)
    public ModelAndView handleResourceNotFound(ResourceNotFoundException ex) {
        // errorPage.jsp로 이동하면서 에러 코드와 메시지 전달
        ModelAndView modelAndView = new ModelAndView("errorPage");
        modelAndView.addObject("statusCode", HttpStatus.NOT_FOUND.value());
        modelAndView.addObject("message", ex.getMessage());
        return modelAndView;
    }
}

 

@RestControllerAdvice 예제 (JSON 응답)

@RestControllerAdvice
public class GlobalExceptionHandler {

    // 특정 예외 처리 (리소스를 찾을 수 없는 경우)
    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<Object> handleResourceNotFound(ResourceNotFoundException ex) {
        // JSON 형식으로 응답 반환
        return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
    }
}

3️⃣ 사용자 정의 예외 클래스 만들기

Spring에서 기본 제공하는 예외 클래스 외에도 사용자 정의 예외를 만들어서 관리할 수 있음.

 

위 그림처럼 패키지와 자바 파일을 만들어 주세요 (handler/GlobalControllerAdivce.java 파일 생성)

  • handler/GlobalControllerAdivce.java 파일 생성
  • handler/exception 패키지 생성
  • handler/exception/UnAuthorizedException 자바 파일 생성

: UnAuthorizedException 클래스는 인증이 안된 사용자가 인증이 필요하 서비스에 접근 요청을 할 때 예외를 발생 시킬 사용자 정의 예외 클래스를 설계 합니다.


✅ 예외 클래스 예제

📌 예제 - 인증 예외 (UnAuthorizedException)

@Getter
public class UnAuthorizedException extends RuntimeException {

    private HttpStatus status;

    // 생성자에서 예외 메시지와 상태 코드 설정
    public UnAuthorizedException(String message, HttpStatus status) {
        super(message);
        this.status = status;
    }
}
 

📌 예제 - 에러 페이지 이동 예외 (RedirectException)

@Getter
public class RedirectException extends RuntimeException {
    private HttpStatus status;

    public RedirectException(String message, HttpStatus status) {
        super(message);
        this.status = status;
    }
}

 

📌 예제 - 데이터 전달 예외 (DataDeliveryException)

 

@Getter
public class DataDeliveryException extends RuntimeException {
    private HttpStatus status;

    public DataDeliveryException(String message, HttpStatus status) {
        super(message);
        this.status = status;
    }
}

🔹 4. @ControllerAdvice 구현해보기 (전역 예외 처리)

위에서 만든 사용자 정의 예외를 전역 예외 처리(Global Exception Handler) 에서 처리해봅니다.

@ControllerAdvice // 전역 예외 처리
public class GlobalControllerAdvice {

    /**
     * 🔹 모든 예외 로깅
     * - 예외가 발생하면 해당 내용을 콘솔에 출력 (로그로 남길 수도 있음)
     */
    @ExceptionHandler(Exception.class)
    public void logException(Exception e) {
        System.out.println("----------------");
        System.out.println("예외 발생: " + e.getClass().getName());
        System.out.println("예외 메시지: " + e.getMessage());
        System.out.println("----------------");
    }

    /**
     * 🔹 인증 예외 (`UnAuthorizedException`) 처리
     * - alert 메시지로 클라이언트에게 알림
     */
    @ResponseBody
    @ExceptionHandler(UnAuthorizedException.class)
    public String handleUnAuthorizedException(UnAuthorizedException e) {
        return "<script>alert('" + e.getMessage() + "'); window.history.back();</script>";
    }

    /**
     * 🔹 데이터 전달 예외 (`DataDeliveryException`) 처리
     * - alert 메시지로 클라이언트에게 알림
     */
    @ResponseBody
    @ExceptionHandler(DataDeliveryException.class)
    public String handleDataDeliveryException(DataDeliveryException e) {
        return "<script>alert('" + e.getMessage() + "'); window.history.back();</script>";
    }

    /**
     * 🔹 에러 페이지 이동 예외 (`RedirectException`) 처리
     * - 에러 페이지로 이동하면서 상태 코드와 메시지를 전달
     */
    @ExceptionHandler(RedirectException.class)
    public ModelAndView handleRedirectException(RedirectException e) {
        ModelAndView modelAndView = new ModelAndView("errorPage");
        modelAndView.addObject("statusCode", e.getStatus().value());
        modelAndView.addObject("message", e.getMessage());
        return modelAndView;
    }
}

 


🔹 5. 에러 페이지 (errorPage.jsp) 코드 

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>${statusCode} Error - Page Not Found</title>
  <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
  <style>
    body { display: flex; justify-content: center; align-items: center; height: 100vh; }
    .error-message { text-align: center; margin-bottom: 20px; }
  </style>
</head>
<body>
  <div class="container text-center">
    <h1 class="display-1">${statusCode}</h1>
    <p class="error-message">Page Not Found</p>
    <p>${message}</p>
    <a href="/" class="btn btn-primary">홈으로 가기</a>
  </div>
</body>
</html>

 

404에러 샘플이미지


🔹 6. 직접 예외 발생시켜 보기

테스트를 위해 컨트롤러에서 강제로 예외를 발생시켜 봅니다.

@Controller
public class MainController {

    /**
     * 🔹 테스트 1: 잘못된 요청 → `RedirectException`
     */
    @GetMapping("/error-test1/{isError}")
    public String errorTest1(@PathVariable boolean isError) {
        if (isError) throw new RedirectException("잘못된 요청입니다.", HttpStatus.BAD_REQUEST);
        return "mainPage";
    }

    /**
     * 🔹 테스트 2: 중복된 이메일 → `DataDeliveryException`
     */
    @GetMapping("/error-test2/{isError}")
    public String errorTest2(@PathVariable boolean isError) {
        if (isError) throw new DataDeliveryException("중복된 이메일을 사용할 수 없습니다.", HttpStatus.INTERNAL_SERVER_ERROR);
        return "mainPage";
    }

    /**
     * 🔹 테스트 3: 로그인 필요 → `UnAuthorizedException`
     */
    @GetMapping("/error-test3/{isError}")
    public String errorTest3(@PathVariable boolean isError) {
        if (isError) throw new UnAuthorizedException("로그인 먼저 해주세요", HttpStatus.UNAUTHORIZED);
        return "mainPage";
    }
}


7️⃣ HTTP 상태 코드 정리 (4xx & 5xx)

📌 HTTP 상태 코드란?

**HTTP(Hypertext Transfer Protocol)**는 클라이언트(브라우저)와 서버 간에 데이터를 주고받는 프로토콜이다.
서버는 클라이언트의 요청을 처리한 후 **HTTP 상태 코드(응답 코드)**를 반환한다.

 

✅ 1xx (정보 응답) → 요청이 수신되었으며 계속 진행 중
✅ 2xx (성공 응답) → 요청이 정상적으로 처리됨
✅ 3xx (리다이렉션 응답) → 추가 작업이 필요함
✅ 4xx (클라이언트 에러) → 클라이언트 요청 오류
✅ 5xx (서버 에러) → 서버에서 요청을 정상적으로 처리하지 못함

 

📌 4xx 상태 코드 (클라이언트 에러)

클라이언트의 요청이 잘못되었거나 유효하지 않은 경우 발생
사용자의 요청을 수정해야 해결 가능

 

상태
코드
상태
텍스트
뜻 서버 측면에서의 의미
400 Bad Request 잘못된 요청 요청 구문, 유효하지 않은 요청 메시지 또는 디코딩할 수 없는
내용으로 인해 서버가 요청을 이해할 수 없음.
401 Unauthorized 권한 없음 요청이 인증을 필요로 하며, 클라이언트가 해당 인증을 제공하지 않았음.
WWW-Authenticate 헤더를 통해 인증 방식을 지정.
403 Forbidden 금지됨 서버가 요청을 이해했으나, 권한 부족 또는 기타 사유로 인해 요청을 거부함.
404 Not Found 찾을 수 없음 서버가 요청한 리소스를 찾을 수 없음. 주소 오타,
리소스 이동/삭제 등이 원인
일 수 있음.

📌 5xx 상태 코드 (서버 에러)

클라이언트의 요청은 유효하지만, 서버 측 문제로 요청이 처리되지 않은 경우 발생
클라이언트가 아닌 서버에서 원인을 분석하고 수정해야 함

 

코드 상태 텍스트 한국어 뜻 서버 측면에서의 의미
500 Internal Server Error 내부 서버 오류 서버 내부에서 오류가 발생하여 요청을 처리할 수 없음.
예상치 못한 예외 발생 시 반환됨.
501 Not Implemented 구현되지 않음 서버가 요청된 메소드를 지원하지 않거나 구현하지 않음.
예: 서버가 PUT 요청을 지원하지 않는 경우
502 Bad Gateway 불량 게이트웨이 게이트웨이/프록시 서버가 뒤쪽 서버에서 잘못된 응답을 받았을 때 발생.
503 Service Unavailable 서비스 제공 불가 서버가 일시적으로 과부하 상태이거나 유지 보수 중이라
요청을 처리할 수 없음.

🚀 Spring Global Exception Handler (GlobalControllerAdvice) 정리

📌 개요

Spring에서는 컨트롤러별로 개별적으로 예외를 처리하는 것이 아니라,
전역적으로 예외를 처리할 수 있는 @ControllerAdvice를 제공합니다.

이 코드는 GlobalControllerAdvice 클래스를 통해 예외를 중앙에서 관리하도록 설계되어 있습니다.
즉, 컨트롤러에서 발생하는 특정 예외를 일괄적으로 처리하여 일관된 응답을 제공할 수 있습니다.


8️⃣ @ControllerAdvice란?

Spring에서 모든 컨트롤러에서 발생하는 예외를 한 곳에서 처리할 수 있도록 도와주는 어노테이션.

  • @ExceptionHandler와 함께 사용하여 특정 예외를 처리할 수 있음.
  • HTML 뷰를 반환할 경우 @ControllerAdvice 사용.
  • JSON 데이터를 반환할 경우 @RestControllerAdvice 사용.

✅ @ControllerAdvice는 **View 반환(웹 애플리케이션)**에 사용
✅ @RestControllerAdvice는 **REST API(데이터 반환)**에 사용


GlobalControllerAdvice 

package com.tenco.bank.handler;

import com.tenco.bank.handler.exception.DataDeliveryException;
import com.tenco.bank.handler.exception.RedirectException;
import com.tenco.bank.handler.exception.UnAuthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

/**
 * 📌 글로벌 예외 처리 핸들러
 * - @ControllerAdvice : HTML 뷰(View)를 반환하는 예외 처리에 사용
 * - @RestControllerAdvice : JSON 데이터를 반환하는 예외 처리에 사용
 */
@ControllerAdvice
public class GlobalControllerAdvice {

    /**
     * 🛠️ 모든 예외를 처리 (기본 로그 출력)
     * - 로깅을 통해 어떤 예외가 발생했는지 확인 가능
     */
    @ExceptionHandler(Exception.class)
    public void exception(Exception e) {
        System.out.println("----------------");
        System.out.println("예외 클래스: " + e.getClass().getName());
        System.out.println("예외 메시지: " + e.getMessage());
        System.out.println("----------------");
    }

    /**
     * 🔹 DataDeliveryException 처리
     * - 데이터를 alert 창으로 클라이언트에게 전달
     * - @ResponseBody 를 사용하여 HTML 코드 반환 (뷰 리졸버 탐색 X)
     */
    @ResponseBody
    @ExceptionHandler(DataDeliveryException.class)
    public String dataDeliveryException(DataDeliveryException e) {
        StringBuffer sb = new StringBuffer();
        sb.append("<script>");
        sb.append(" alert('" + e.getMessage() + "');");
        sb.append(" window.history.back();");
        sb.append("</script>");
        return sb.toString();
    }

    /**
     * 🔹 UnAuthorizedException 처리
     * - 인증되지 않은 요청을 alert 창으로 클라이언트에게 알림
     */
    @ResponseBody
    @ExceptionHandler(UnAuthorizedException.class)
    public String unAuthorizedException(UnAuthorizedException e) {
        StringBuffer sb = new StringBuffer();
        sb.append("<script>");
        sb.append(" alert('" + e.getMessage() + "');");
        sb.append(" window.history.back();");
        sb.append("</script>");
        return sb.toString();
    }

    /**
     * 🔹 RedirectException 처리
     * - 에러 발생 시 특정 JSP 페이지로 이동
     * - ModelAndView를 사용하여 상태 코드 및 메시지 전달
     */
    @ExceptionHandler(RedirectException.class)
    public ModelAndView redirectException(RedirectException e) {
        ModelAndView modelAndView = new ModelAndView("/errorPage");
        modelAndView.addObject("statusCode", e.getStatus().value());
        modelAndView.addObject("message", e.getMessage());
        return modelAndView;
    }
}

 

 

🔝 맨 위로 이동

'Spring' 카테고리의 다른 글

[Spring boot] Bank App - 회원가입  (0) 2025.02.15
[Spring boot] Bank App - MyBatis 설정 (DB 접근 기술)  (0) 2025.02.14
[Spring boot] Bank App - MainController, mainPage.jsp 구현  (2) 2025.01.15
[Spring boot] Bank App - 화면 구현(레이아웃 분리)  (0) 2025.01.15
[Spring boot] Bank App - 화면 구현(템플릿 가져오기)  (0) 2025.01.15
'Spring' 카테고리의 다른 글
  • [Spring boot] Bank App - 회원가입
  • [Spring boot] Bank App - MyBatis 설정 (DB 접근 기술)
  • [Spring boot] Bank App - MainController, mainPage.jsp 구현
  • [Spring boot] Bank App - 화면 구현(레이아웃 분리)
공돌이 출신 개발자
공돌이 출신 개발자
공돌이 출신 개발자입니다
  • 공돌이 출신 개발자
    공돌이 출신 개발자
    공돌이 출신 개발자
  • 전체
    오늘
    어제
    • 분류 전체보기 (124)
      • Database (0)
        • SQL (0)
        • 1일 1쿼리 (9)
      • Flutter (40)
        • Dart 언어 (18)
        • App (22)
      • Git (0)
      • Http 기초 지식 (14)
      • HTML5 & CSS3 (0)
      • Java (33)
      • JSP (0)
      • JavaScript (0)
      • Linux (0)
      • MSA (0)
      • Project (0)
      • React (0)
      • Spring (19)
      • 설치 메뉴얼 (1)
      • [Flutter] 프로젝트 (눈길) (8)
        • 작업일지 (8)
  • 블로그 메뉴

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

    • GitHub
  • 공지사항

  • 인기 글

  • 태그

    android studio
    코딩
    데이터
    SQL
    객체지향
    spring boot
    프로젝트
    Android
    개발
    클래스
    안드로이드 앱 개발
    SQLD
    블로그 만들기
    로그인
    앱개발
    1일1쿼리
    회원가입
    JAVA 기초
    객체
    dart
    안드로이드
    프로그래밍
    메서드
    플러터
    jsp
    flutter
    HTTP
    Java
    공부
    앱 개발
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
공돌이 출신 개발자
[Spring boot] Bank App - Exception Handler
상단으로

티스토리툴바