티스토리 뷰

1. @ControllerAdvice와 @RestControllerAdvice

HTTP 통신을 통해 예외 상황을 클라이언트에게 알려주는 방법은 여러 가지가 있으며, 이들을 적절히 사용하는 것이 중요합니다.

 

@ControllerAdvice와 @RestControllerAdvice는 Spring Framework에서 제공하는 어노테이션들로, 애플리케이션 전역에 걸쳐 발생하는 예외를 효과적으로 관리하고 처리하는 데 사용됩니다. 이들은 일종의 "예외 처리의 중앙 집중화"를 가능하게 해주며, 애플리케이션 내 여러 컨트롤러나 서비스에서 공통적으로 발생할 수 있는 예외를 한 곳에서 관리할 수 있게 해줍니다.

 

 

 

2. @ControllerAdivce 와 @RestControllerAdivce 의 차이점

 

  • @ControllerAdvice

주로 @Controller 또는 @RequestMapping 어노테이션이 적용된 클래스(즉, MVC 컨트롤러)에서 발생하는 예외를 처리하기 위해 사용됩니다. HTML 뷰를 반환하는 전통적인 웹 애플리케이션에서 주로 사용됩니다.

 

  • @RestControllerAdvice

@ControllerAdvice와 유사한 기능을 제공하지만, @RestController에서 발생하는 예외를 처리하는 데 특화되어 있습니다. 즉, RESTful 웹 서비스에서 JSON이나 XML 같은 응답을 반환할 때 사용됩니다.

사실상, @RestControllerAdvice는 @ControllerAdvice에 @ResponseBody를 추가한 것과 동일한 효과를 제공하여, 응답 본문에 직접 데이터를 매핑할 수 있습니다.

 

 

ControllerAdvice 에서 데이터를 반환하는 예시 코드

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = ResourceNotFoundException.class)
    @ResponseBody
    public ResponseEntity<Object> handleResourceNotFoundException(ResourceNotFoundException ex) {
        // 에러 메시지와 함께 404 상태 코드를 반환
        return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
    }
}

 

 

RestControllerAdvice 에서 반환

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = ResourceNotFoundException.class)
		// @ResponseBody 사용 안해도 됨(데이터를 반환 처리 함) 
    public ResponseEntity<Object> handleResourceNotFoundException(ResourceNotFoundException ex) {
        // 에러 메시지와 함께 404 상태 코드를 반환
        return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
    }
}

 

 

3. 사용자 정의 예외 클래스를 만들기

RuntimeException은 프로그램의 실행 도중 발생하는 예외를 나타냅니다.

컴파일 시 예외가 아닌 실행 시 예외로 분류되며, 따로 try-catch 블록으로 처리하지 않아도 컴파일러가 오류로 인식하지 않습니다.

 

예시로는 NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException 등이 있습니다. 여기서는 RuntimeException 확장해서 사용자 정의 예외 클래스를 만들어 봅니다.

 

 

 

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

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

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

 

 

package com.tenco.bank.handler.exception;

import org.springframework.http.HttpStatus;

import lombok.Getter;

@Getter
public class UnAuthorizedException extends RuntimeException  {
	
	private HttpStatus status; 
	
	// throw new UnAuthorizedException(   ,  ) 
	public UnAuthorizedException(String message, HttpStatus status) {
		super(message);
		this.status = status;
	}
}

 

 

package com.tenco.bank.handler.exception;

import org.springframework.http.HttpStatus;

import lombok.Getter;

// 에러 발생시에 여러 페이지로 이동 시킬 때 사용 예정 

@Getter
public class RedirectException extends RuntimeException {
	
	private HttpStatus status;
	
	// throw new RedirectException(???, ???);
	public RedirectException(String message, HttpStatus status) {
		super(message);
		this.status = status;
	}
}

 

package com.tenco.bank.handler.exception;

import org.springframework.http.HttpStatus;

import lombok.Getter;

@Getter
public class DataDeliveryException extends RuntimeException {
	
	private HttpStatus status;
	
	public DataDeliveryException(String message, HttpStatus status) {
		super(message);
		this.status = status;
	}
}

 

 

4.@ControllerAdvice 구현해 보기

package com.tenco.bank.handler;

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;

import com.tenco.bank.handler.exception.DataDeliveryException;
import com.tenco.bank.handler.exception.RedirectException;
import com.tenco.bank.handler.exception.UnAuthorizedException;

@ControllerAdvice  // IoC 대상 (싱글톤 패턴) --> HTML 렌더링 예외에 많이 사용
public class GlobalControllerAdvice {
	
	/**
	 * (개발시에 많이 활용) 
	 * 모든 예외 클래스를 알 수 없기 때문에 로깅으로 확인할 수 있도록 설정  
	 * 로깅처리 - 동기적 방식(System.out.println), @slf4j (비동기 처리 됨) 
	 */
	@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("----------------------");
	}
	
	/**
	 * Data로 예외를 내려주는 방법 
	 * @ResponseBody 활용 
	 * 브라우저에서 자바스크립트 코드로 동작 하게 됨
	 */
	
	// 예외를 내릴 때 데이터를 내리고 싶다면 1. @RestControllerAdvice 를 사용하면 된다.
	// 단. @ControllerAdvice 사용하고 있다면 @ResponseBody 를 붙여서 사용하면 된다. 
	@ResponseBody
	@ExceptionHandler(DataDeliveryException.class)
	public String dataDeleveryExcption(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(); 
	}
	
	@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(); 
	}
	
	/*
	 *  에러 페이지로 이동 처리 
	 *  JSP로 이동시 데이터를 담아서 보내는 방법 
	 *  ModelAndView, Model 사용 가능 
	 *  throw new RedirectException('페이지 없는데???', 404);
	 */
	@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; // 페이지 반환 + 데이터 내려줌 
	}
}

 

 

5. 에러 페이지 생성 (errorPage.jsp) 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${statusCode} Error - Page Not Found</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
<style type="text/css">
	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">
		<div class="text-center">
			<h1>${statusCode}</h1>
			<p class="error--message"> Page Not Found </p>
			<p>${message}</p>
			<a href="/index" class="btn btn-primary">Go to Home Page</a>
		</div>
	</div>
</body>
</html>

 

 

6. 예외 발생

package com.tenco.bank.controller;

import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.tenco.bank.handler.exception.DataDeliveryException;
import com.tenco.bank.handler.exception.RedirectException;
import com.tenco.bank.handler.exception.UnAuthorizedException;

import jakarta.annotation.PostConstruct;

@Controller  // IoC 대상(싱글톤 패턴 관리가 된다.) --> 제어의 역전  
public class MainController {
	
	// REST API  기반으로 주소설계 가능 
		
	// 	// http:localhost:8080/main/main-page
	// 주소설계 
	// http:localhost:8080/main-page
	@GetMapping({"/main-page", "/index"})
	// @ResponseBody
	public String mainPage() {
		System.out.println("mainPage() 호출 확인");
		// [JSP 파일 찾기 (yml 설정) ] - 뷰 리졸버 
		// prefix: /WEB-INF/view
		//         /main  
		// suffix: .js 
		return "main";
	}
	
	// todo - 삭제 예정 
	// 주소 설계 
	// http://localhost:8080/error-test1/true
	// http://localhost:8080/error-test1/false
	
	@GetMapping("/error-test1")
	public String errorPage() {
		if(true) {
			throw new RedirectException("잘못된 요청입니다.", HttpStatus.NOT_FOUND);
		}
		return "main";
	} 
	
	
	// http://localhost:8080/error-test2
	@GetMapping("/error-test2")
	public String errorData2() {
		if(true) {
			throw new DataDeliveryException("잘못된 데이터 입니다", HttpStatus.BAD_REQUEST);
		}
		return "main";
	} 
	
	@GetMapping("/error-test3")
	public String errorData3() {
		if(true) {
			throw new UnAuthorizedException("인증 안된 사용자 입니다.", HttpStatus.UNAUTHORIZED);
		}
		return "main";
	}
}

 

 

HTTP 상태 코드란?

HTTP(Hypertext Transfer Protocol)는 웹 서버와 웹 클라이언트 사이에서 데이터를 주고받기 위해 사용하는 통신 방식으로 TCP/IP 프로토콜 위에서 동작합니다. 즉, 우리가 웹을 이용하려면 웹 서버와 웹 클라이언트는 각각 TCP/IP 동작에 필수적인 IP 주소를 가져야 한다는 의미입니다.

HTTP란 이름대로라면 하이퍼텍스트(Hypertext)만 전송할 수 있어 보이지만, 실제로는 HTML이나 XML과 같은 하이퍼텍스트뿐 아니라 이미지, 음성, 동영상, Javascript, PDF와 각종 문서 파일 등 컴퓨터에서 다룰 수 있는 데이터라면 무엇이든 전송할 수 있습니다.

우리가 웹 브라우저의 주소창에 https://www.naver.com을 입력하고 Enter 를 누르면 웹 클라이언트와 웹 서버 사이에 HTTP 연결이 맺어지고 웹 클라이언트는 웹 서버에 HTTP 요청 메시지를 보냅니다. 웹 서버는 요청에 따른 처리를 진행한 후에 그 결과를 웹 클라이언트에 HTTP 응답 메시지로 보냅니다.

 

 

 

 

100~500번 대까지 상태 코드 정의

  • 1XX: Informational(정보 제공)
    • 임시 응답으로 현재 클라이언트의 요청까지는 처리되었으니 계속 진행하라는 의미입니다. HTTP 1.1 버전부터 추가되었습니다.
  • 2XX: Success(성공)
    • 클라이언트의 요청이 서버에서 성공적으로 처리되었다는 의미입니다.
  • 3XX: Redirection(리다이렉션)
    • 완전한 처리를 위해서 추가 동작이 필요한 경우입니다. 주로 서버의 주소 또는 요청한 URI의 웹 문서가 이동되었으니 그 주소로 다시 시도하라는 의미입니다.
  • 4XX: Client Error(클라이언트 에러)
    • 없는 페이지를 요청하는 등 클라이언트의 요청 메시지 내용이 잘못된 경우를 의미합니다.
  • 5XX: Server Error(서버 에러)
    • 서버 사정으로 메시지 처리에 문제가 발생한 경우입니다. 서버의 부하, DB 처리 과정 오류, 서버에서 익셉션이 발생하는 경우를 의미합니다.
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/06   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함