πŸƒSpring/Exception

# Spring Boot μ „μ—­ μ˜ˆμ™Έ 처리 + μ—λŸ¬ νŽ˜μ΄μ§€ ν›„ λ¦¬λ‹€μ΄λ ‰νŠΈ κ΅¬ν˜„ 정리

λ­‰μ§€λ§˜ 2025. 5. 29. 11:08

1. λͺ©ν‘œ

  • μ»¨νŠΈλ‘€λŸ¬μ—μ„œ μ˜ˆμ™Έ λ°œμƒ μ‹œ, μ‚¬μš©μžκ°€ μ—λŸ¬ λ©”μ‹œμ§€λ₯Ό ν™•μΈν•œ ν›„ 일정 μ‹œκ°„ λ’€ μžλ™μœΌλ‘œ / 메인 νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•˜λ„λ‘ ꡬ성
  • μ»€μŠ€ν…€ μ˜ˆμ™Έ CustomExceptionκ³Ό 일반 μ˜ˆμ™Έ λͺ¨λ‘ 처리

뷰단 ν…œν”Œλ¦Ώμ€ νƒ€μž„λ¦¬ν”„ μ‚¬μš©ν•¨.

 

2. 디렉토리 ꡬ쑰

src/
 └── main/
     └── java/
         └── com.example.demo/
             β”œβ”€β”€ controller/
             β”‚    └── TestController.java
             └── global/
                  └── exception/
                      β”œβ”€β”€ CustomException.java
                      └── GlobalExceptionHandler.java
     └── resources/
         β”œβ”€β”€ templates/
         β”‚    β”œβ”€β”€ custom-error.html
         β”‚    └── index.html
         └── application.properties

 

3.μ½”λ“œ ꡬ성

CustomException.java

package com.example.demo.global.exception;

public class CustomException extends RuntimeException{
    public CustomException(String message) {
        super(message);
    }
}

 

TestController.java

package com.example.demo.controller;

import com.example.demo.global.exception.CustomException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class TestController {

    @GetMapping("/")
    public String index() {
        return "index";
    }

    @GetMapping("/test/error")
    public String throwCustomError() {
        throw new CustomException("ν…ŒμŠ€νŠΈμš© μ‚¬μš©μž μ •μ˜ μ˜ˆμ™Έμž…λ‹ˆλ‹€.");
    }

    @GetMapping("/test/null")
    public String throwNullPointer() {
        String x = null;
        x.length(); // NullPointerException
        return "index";
    }
    
    // 404 κ°•μ œ μœ λ„ (μ—†λŠ” νŽ˜μ΄μ§€λ‘œ λ¦¬λ‹€μ΄λ ‰νŠΈ)
    @GetMapping("/test/404")
    public String force404() {
        return "redirect:/μ—†λŠ”νŽ˜μ΄μ§€";
    }

    // 500 κ°•μ œ μœ λ„ (Exception λ°œμƒ)
    @GetMapping("/test/500")
    public String force500() {
        throw new RuntimeException("κ°•μ œλ‘œ λ°œμƒμ‹œν‚¨ 500 μ„œλ²„ μ—λŸ¬μž…λ‹ˆλ‹€.");
    }
}

 

GlobalExceptionHandler.java

package com.example.demo.global.exception;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;

@ControllerAdvice
public class GlobalExceptionHandler {
    /*@ExceptionHandler(CustomException.class)
    public ResponseEntity<String> handleCustomException(CustomException ex){
        return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleException(Exception ex){
        return new ResponseEntity<>("μ„œλ²„ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€:" + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }*/

    @ExceptionHandler(CustomException.class)
    public ModelAndView handleCustomException(CustomException ex) {
        ModelAndView mav = new ModelAndView("custom-error"); // templates/custom-error.html
        mav.addObject("message", ex.getMessage());
        mav.addObject("redirectUrl", "/");
        mav.addObject("delay", 3); // 3초 λ’€ 이동
        return mav;
    }

    @ExceptionHandler(Exception.class)
    public ModelAndView handleGeneralException(Exception ex) {
        ModelAndView mav = new ModelAndView("custom-error");
        mav.addObject("message", "예기치 λͺ»ν•œ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: " + ex.getMessage());
        mav.addObject("redirectUrl", "/");
        mav.addObject("delay", 5);
        return mav;
    }

    @ExceptionHandler(NoHandlerFoundException.class)
    public ModelAndView handle404(NoHandlerFoundException ex) {
        ModelAndView mav = new ModelAndView("custom-error");
        mav.addObject("message", "μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” νŽ˜μ΄μ§€μž…λ‹ˆλ‹€. μž…λ ₯ν•œ μ£Όμ†Œλ₯Ό λ‹€μ‹œ ν™•μΈν•΄μ£Όμ„Έμš”.");
        mav.addObject("redirectUrl", "/");
        mav.addObject("delay", 5);
        return mav;
    }

}

 

custom-error.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>였λ₯˜ λ°œμƒ</title>
    <meta http-equiv="refresh"
          th:content="${delay} + ';url=' + ${redirectUrl}" />
</head>
<body>
    <h2>μ£„μ†‘ν•©λ‹ˆλ‹€. λ¬Έμ œκ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.</h2>
    <p>κ΄€λ¦¬μžμ—κ²Œ λ¬Έμ˜ν•΄μ£Όμ„Έμš”.</p>
    <p th:text="'μ—λŸ¬ λ‚΄μš©: ' + ${message}"></p>
    <p th:text="'μž μ‹œ ν›„ ' + ${delay} + '초 뒀에 메인 νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•©λ‹ˆλ‹€.'"></p>
    <p><a th:href="${redirectUrl}">μ§€κΈˆ λ°”λ‘œ μ΄λ™ν•˜κΈ°</a></p>
</body>
</html>

 

index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>메인 νŽ˜μ΄μ§€</title>
</head>
<body>
    <h1>ν™ˆ(index) νŽ˜μ΄μ§€μž…λ‹ˆλ‹€</h1>
    <p>이 νŽ˜μ΄μ§€λŠ” μ—λŸ¬ λ°œμƒ ν›„ λ¦¬λ‹€μ΄λ ‰νŠΈλ˜λŠ” κ³³μž…λ‹ˆλ‹€.</p>
</body>
</html>

 

application.properties

spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.cache=false

 

4.ν…ŒμŠ€νŠΈ 방법

  • /test/error: μ‚¬μš©μž μ •μ˜ μ˜ˆμ™Έ λ°œμƒ
  • /test/null: 일반 μ˜ˆμ™Έ (NullPointerException) λ°œμƒ
  • λ‘˜ λ‹€ μ—λŸ¬ λ©”μ‹œμ§€λ₯Ό 좜λ ₯ν•˜κ³ , 3초 ν›„ 메인 νŽ˜μ΄μ§€(/)둜 이동

5. κ²°λ‘ 

이 방식은 Spring Boot MVC ν™˜κ²½μ—μ„œ μ‚¬μš©μžμ—κ²Œ μΉœμ ˆν•˜κ²Œ μ˜ˆμ™Έλ₯Ό μ•Œλ¦¬κ³ , μžλ™μœΌλ‘œ μ•ˆμ „ν•œ 경둜둜 μœ λ„ν•  수 μžˆλŠ” μ˜ˆμ™Έ 처리 방법이닀.
λ©”μ‹œμ§€, 이동 경둜, μ§€μ—° μ‹œκ°„ 등을 상황에 맞게 ν™•μž₯ κ°€λŠ₯ν•˜λ©°, ν–₯ν›„ 곡톡 μ—λŸ¬ 응닡 포맷으둜 λ°œμ „μ‹œν‚¬ 수 μžˆλ‹€.