[SpringBoot] 게시판 구현하기 11 (스프링의 다양한 기능 살펴보기 - 예외처리)
FRAMEWORK/Spring

[SpringBoot] 게시판 구현하기 11 (스프링의 다양한 기능 살펴보기 - 예외처리)

반응형

들어가기 전에

하기 포스팅은 "스프링부트 시작하기(김인우 저)" 책을 공부하며 적은 포스팅입니다. 이번 포스팅에서는 예외처리에 대해 살펴보도록 하겠습니다.

예외처리

스프링의 예외처리 방식은 크게 3가지로 나눌 수 있습니다.

  1. try/catch를 이용한 예외처리
  2. 각각의 컨트롤러단에서 @ExceptionHandler를 이용한 예외처리
  3. @ControllerAdvice를 이용한 전역 예외처리

try/catch를 사용한 예외처리의 경우 스프링이 아닌 자바의 예외처리 방법이므로 여기서는 다루지 않습니다. 그리고 @ExceptionHandler 어노테이션을 이용한 예외처리의 경우 컨트롤러별로 동일 예외처리를 추가해야 해서 코드 중복이 많아져 이번 포스팅에서는 3번 @ControllerAdvice를 이용한 전역 예외처리에 대해 알아보겠습니다.

@ControllerAdvice 추가하기

@ControllerAdvice 어노테이션을 이용하면 추가 설정 없이 쉽게 예외처리를 할 수 있습니다.

  • XML 기반에서 @ControllerAdvice를 설정하기 위해서는 스프링 프레임워크의 Root Application Context와 Servlet Context에 대한 지식이 필요했습니다. 또한, XML 설정도 필요해서 사용하기가 쉽지 않았습니다. 하지만, 스프링부트에서는 단순히 어노테이션만 추가하면 쉽게 사용이 가능합니다.

src/main/java/board 밑에 common 패키지를 생성하고 ExceptionHandler 클래스를 만들어 하기 내용을 적어줍니다.

package board.common;

import javax.servlet.http.HttpServletRequest;

import lombok.extern.slf4j.Slf4j;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.ModelAndView;

@ControllerAdvice
@Slf4j
public class ExceptionHandler {

    @org.springframework.web.bind.annotation.ExceptionHandler(Exception.class)
    public ModelAndView defaultExceptionHandler(HttpServletRequest request, Exception exception) {
        ModelAndView mv = new ModelAndView("/error/error_default");
        mv.addObject("exception", exception);

        log.error("exception", exception);

        return mv;
    }
}
  • @ControllerAdvice: @ControllerAdvice 어노테이션을 사용하여 해당 클래스가 예외처리 클래스임을 알립니다.
  • @org.springframework.web.bind.annotation.ExceptionHandler(Exception.class): 해당 메소드에서 처리할 예외를 지정합니다. 여기서는 Exception.class로 설정하여 모든 예외를 처리했습니다.
    • 실제 프로젝트를 진행할 때에는 다양한 예외처리를 위해 각각의 예외처리가 필요합니다. 즉, NullPointerException, NumberFormatException 등 자바의 기본 예외 및 프로젝트에 필요한 커스텀 예외를 포함해 각각의 예외에 맞는 적절한 예외처리를 해야합니다.
    • 절대로 실제 프로젝트에서는 Exception.class를 사용해 한번에 모든 예외 처리하지 않도록 합니다.
    • 여러 예외처리 메소드를 추가할 때에는 자바의 모든 예외는 Exception 클래스를 상속받음을 생각해야 합니다. 따라서, 코드상에서 Exception.class를 처리하는 메소드보다 위쪽에 각 예외처리 메소드를 두어야 정상적으로 처리됩니다.
      • 즉, Exception.class 처리하는 메소드는 가장 마지막에 있어야 함
  • ModelAndView mv = new ModelAndView("/error/eror_default"): 예외 발생 시, 보여줄 화면을 지정합니다. 어플리케이션 실행 중 에러가 발생하면 해당 에러에 따라 적절한 예외처리 화면이 필요합니다.
  • log.error("exception", exception): 에러 로그를 출력합니다.

예외처리 화면 추가하기

template 폴더 밑에 error 폴더를 생성하고 error_default.html 파일을 생성하여 에러 발생 시 사용자에게 보여줄 화면을 만들어보겠습니다.

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>공통 에러 페이지</title>
    <link rel="stylesheet" th:href="@{/css/style.css}"/>
</head>
<body>
    <p>공통 에러 페이지</p>
    <p th:text="${exception}"></p>
    <ul th:each="list : ${exception.getStackTrace()}" th:text="${list.toString()}"></ul>
</body>
</html>
  • ${exception}: 에러 종류를 출력합니다.
  • ${exception.getStackTrace()}: 에러의 상세 내용을 출력합니다.

예외처리 확인하기

트랜잭션 포스팅에서 에러를 발생시킬 때 사용한 int i = 10 / 0;을 게시판 목록 조회(/board/openBoardList.do) 컨트롤러 메소드에 추가하고 스프링부트 어플리케이션을 시작합니다. 그 후, 게시판 목록 조회를 하면 하기와 같이 공통 에러 페이지가 나오는 것을 확인할 수 있습니다. 또한, 이클립스의 콘솔에서 해당 에러가 동일하게 출력됨을 확인할 수 있습니다.

공통 에러 페이지

여기서는 예외처리 방법에 대한 실습으로 사용자에게 에러 상세 내용을 표시하도록 했습니다. 하지만 실제 프로젝트에서는 이렇게 에러 로그를 화면에 직접 보여주면 안 됩니다. 이러한 로그를 통해 프로그램 취약점이 드러나 공격을 받을 수 있기 때문입니다. 따라서, 프로젝트 진행 시 예외별 예외 처리 메소드를 Exception.class 처리하는 메소드 위에 추가하여 각 예외별로 적절한 예외처리를 해야 합니다.

반응형