๋ณธ๋ฌธ์œผ๋กœ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๋ฐ˜์‘ํ˜•

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 ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉ์ž์—๊ฒŒ ์นœ์ ˆํ•˜๊ฒŒ ์˜ˆ์™ธ๋ฅผ ์•Œ๋ฆฌ๊ณ , ์ž๋™์œผ๋กœ ์•ˆ์ „ํ•œ ๊ฒฝ๋กœ๋กœ ์œ ๋„ํ•  ์ˆ˜ ์žˆ๋Š” ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•์ด๋‹ค.
๋ฉ”์‹œ์ง€, ์ด๋™ ๊ฒฝ๋กœ, ์ง€์—ฐ ์‹œ๊ฐ„ ๋“ฑ์„ ์ƒํ™ฉ์— ๋งž๊ฒŒ ํ™•์žฅ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํ–ฅํ›„ ๊ณตํ†ต ์—๋Ÿฌ ์‘๋‹ต ํฌ๋งท์œผ๋กœ ๋ฐœ์ „์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

 

๋ฐ˜์‘ํ˜•