💡 학습 목표
- @ControllerAdvice, @RestControllerAdvice 는 뭘까?
- @ControllerAdivce 와 @RestControllerAdivce 에 차이점을 이해 하자.
- 사용자 정의 예외 클래스를 만들기
- @ControllerAdvice 구현해 보기
- 에러 페이지 코드 수정 (errorPage.jsp)
- 직업 예외 발생해보기
1. @ControllerAdvice, @RestControllerAdvice 는 뭘까?
HTTP 통신을 통해 예외 상황을 클라이언트에게 알려주는 방법은 여러 가지가 있으며, 이들을 적절히 사용하는 것이 중요합니다.
**@ControllerAdvice**와 **@RestControllerAdvice**는 Spring Framework에서 제공하는 어노테이션들로, 애플리케이션 전역에 걸쳐 발생하는 예외를 효과적으로 관리하고 처리하는 데 사용됩니다. 이들은 일종의 "예외 처리의 중앙 집중화"를 가능하게 해주며, 애플리케이션 내 여러 컨트롤러나 서비스에서 공통적으로 발생할 수 있는 예외를 한 곳에서 관리할 수 있게 해줍니다.
2. @ControllerAdivce 와 @RestControllerAdivce 에 차이점을 이해 하자.
@ControllerAdvice와 @RestControllerAdvice 차이점
- @ControllerAdvice: 이 어노테이션은 주로 @Controller 또는 @RequestMapping 어노테이션이 적용된 클래스(즉, MVC 컨트롤러)에서 발생하는 예외를 처리하기 위해 사용됩니다. HTML 뷰를 반환하는 전통적인 웹 애플리케이션에서 주로 사용됩니다.
- @RestControllerAdvice: **@ControllerAdvice**와 유사한 기능을 제공하지만, **@RestController**에서 발생하는 예외를 처리하는 데 특화되어 있습니다. 즉, RESTful 웹 서비스에서 JSON이나 XML 같은 응답을 반환할 때 사용됩니다. 사실상, **@RestControllerAdvice**는 **@ControllerAdvice**에 **@ResponseBody**를 추가한 것과 동일한 효과를 제공하여, 응답 본문에 직접 데이터를 매핑할 수 있습니다.
@ControllerAdvice와 @RestControllerAdvice 차이점
- @ControllerAdvice: 이 어노테이션은 주로 @Controller 또는 @RequestMapping 어노테이션이 적용된 클래스(즉, MVC 컨트롤러)에서 발생하는 예외를 처리하기 위해 사용됩니다. HTML 뷰를 반환하는 전통적인 웹 애플리케이션에서 주로 사용됩니다.
- @RestControllerAdvice: **@ControllerAdvice**와 유사한 기능을 제공하지만, **@RestController**에서 발생하는 예외를 처리하는 데 특화되어 있습니다. 즉, RESTful 웹 서비스에서 JSON이나 XML 같은 응답을 반환할 때 사용됩니다. 사실상, **@RestControllerAdvice**는 **@ControllerAdvice**에 **@ResponseBody**를 추가한 것과 동일한 효과를 제공하여, 응답 본문에 직접 데이터를 매핑할 수 있습니다.
예시 코드 확인 - 1
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);
}
}
예시 코드 확인 - 2
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"%>
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 처리 과정 오류, 서버에서 익셉션이 발생하는 경우를 의미합니다.
주요 4xx 상태코드 확인 (클라이언트 에러) 클라이언트의 요청에 오류가 있다.
상태 코드 상태 텍스트 한국어 뜻 서버 측면에서의 의미
400 | Bad Request | 잘못된 요청 | 요청 구문, 유효하지 않은 요청 메시지 또는 디코딩할 수 없는 내용으로 인해 서버가 요청을 이해할 수 없음. |
401 | Unauthorized | 권한 없음 | 요청이 인증을 필요로 하며, 클라이언트가 해당 인증을 제공하지 않았음. WWW-Authenticate 헤더를 통해 인증 방식을 지정. |
403 | Forbidden | 금지됨 | 서버가 요청을 이해했으나, 권한 없음 또는 기타 사유로 인해 요청을 수행 거부. |
404 | Not Found | 찾을 수 없음 | 서버가 요청한 리소스를 찾을 수 없음. 주소 오타 또는 리소스 이동/삭제 등이 원인일 수 있음. |
주요 5xx 상태코드 확인 (서버 에러) - 클라이언트의 요청은 유효한데 서버가 처리에 실패하였다.
'Spring boot > Bank App 만들기' 카테고리의 다른 글
12. MyBatis 설정 (DB 접근 기술이란?) (0) | 2024.08.08 |
---|---|
11. 어노테이션 정리 (0) | 2024.08.08 |
9. MainController, mainPage.jsp 구현 (0) | 2024.08.07 |
8. 화면 구현 -2(레이아웃 분리) (0) | 2024.08.07 |
7. 화면 구현 - 1(템플릿 가져오기) (0) | 2024.08.07 |