๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Spring

Spring GlobalExceptionHandler ์ƒ์„ฑ

GlobalExceptionHandler ์ƒ์„ฑ

์„œ๋ฒ„์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์ด๋ฅผ ํ•„ํ„ฐ๋งํ•ด์ฃผ๊ณ  ์˜ค๋ฅ˜ ํŽ˜์ด์ง€๋กœ ์ฒ˜๋ฆฌํ•ด ์ฃผ๋Š” Global Exception Handler๋ฅผ ์ƒ์„ฑํ•˜์ž.

Exception

TaskService

    @Transactional(readOnly = true)
    public Task findTask(long id) {
        Task requestTask = taskRepository.findById(id).orElseThrow(()->{
            return new IllegalArgumentException("ํ•ด๋‹น task๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
        });
        return requestTask;
    }

๋‹ค์Œ๊ณผ ๊ฐ™์ด Task๋ผ๋Š” Entity๋ฅผ ์กฐํšŒํ•˜๋Š” Service ๊ฐ์ฒด๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•˜์ž.

id๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฐพ์œผ๋ฉด return ํ•ด์ฃผ์ง€๋งŒ, ํ•ด๋‹นํ•˜๋Š” id๊ฐ€ ์—†์„ ๋• IllegalArgumentException ์˜ˆ์™ธ๋ฅผ return ํ•œ๋‹ค.

์˜ˆ์™ธ ๋ฐœ์ƒ

Task ํ…Œ์ด๋ธ”์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” id๋ฅผ ์กฐํšŒํ•˜์—ฌ Exception์„ ํ˜ธ์ถœํ•ด๋ณด์ž.


Whitelabel Error Page ํŽ˜์ด์ง€๊ฐ€ ์ƒ์„ฑ๋˜๋ฉฐ, ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ๋กœ๊ทธ๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.

์ด๋Ÿฌํ•œ ๋กœ๊ทธ๋“ค์„ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ชจ๋‘ ๋ณด์—ฌ์ฃผ๋Š” ๊ฑด ์ข‹์ง€ ์•Š์€ ์›นํŽ˜์ด์ง€์ด๋ฏ€๋กœ, ์˜ค๋ฅ˜๋ฅผ ํ•„ํ„ฐ๋งํ•ด์ฃผ๋Š” ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋งŒ๋“ค๊ณ , ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋”ฐ๋กœ ๋ณด์—ฌ์ค˜์•ผ ํ•œ๋‹ค.

GlobalExceptionHandler

handler๋ผ๋Š” ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค๊ณ  GlobalExceptionHandler๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ด ์ฃผ๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•˜์ž.

package com.vividswan.studymate.handler;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;

@RestController
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(value = Exception.class)
    public String handleException(Exception e){
        return e.getMessage();
    }
}

์šฐ์„  error์˜ getMessage() ๋ฉ”์„œ๋“œ๊ฐ€ ์ž˜ ์ถœ๋ ฅ๋˜๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด RestController๋กœ ์ƒ์„ฑํ•ด ์ฃผ์ž.

@ControllerAdvice๋Š” Controller์—์„œ ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๊ณณ์—์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•ด ์ฃผ๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด๋‹ค.

@handleException๋ฅผ ๋ฉ”์„œ๋“œ์— ์„ ์–ธํ•ด ์ค€๋‹ค.

์ด๋•Œ value๋Š” Exception.class๋กœ ์„ ์–ธํ•˜์˜€๋‹ค.

์œ„์˜ ์˜ˆ์ œ์˜ IllegalArgumentException.class๋กœ ์„ ์–ธํ•œ๋‹ค๋ฉด, ์ธ์ž์— ๋Œ€ํ•œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ค„ ์ˆ˜ ์žˆ์ง€๋งŒ, Exception.class๋Š” ๋ชจ๋“  ์˜ˆ์™ธ ํด๋ž˜์Šค์˜ ๋ถ€๋ชจ์ด๋ฏ€๋กœ ๋‹ค๋ฅธ ์˜ˆ์™ธ๋“ค๋„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฉ”์„œ๋“œ์˜ ์ธ์ž๋ฅผ Exception e๋กœ ๋ฐ›๊ณ  e.getMessage()๋ฅผ return ํ•ด์ค€๋‹ค.

์œ„์˜ ์˜ค๋ฅ˜๋ฅผ ๋‹ค์‹œ ๋ฐœ์ƒ์‹œ์ผœ๋ณด์ž.


e.getMessage()๋งŒ ์ถœ๋ ฅ๋˜์—ˆ๋‹ค.

Exception View

Exception์— ๋Œ€ํ•œ view ํŽ˜์ด์ง€๋ฅผ Mustache๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“ค์–ด๋ณด์ž.

์šฐ์„  ์œ„์—์„œ ๋งŒ๋“  RestController๋ฅผ Controller๋กœ ๋ฐ”๊ฟ”์ฃผ์–ด ํŽ˜์ด์ง€๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์ž.

package com.vividswan.studymate.handler;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@Controller
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(value = Exception.class)
    public String handleException(Exception e,Model model){
        model.addAttribute("errorMessage",e.getMessage());
        return "errorView";
    }
}

์ด์ œ errorView ํŽ˜์ด์ง€๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ž‘์„ฑํ•˜์ž.

mustache์™€ ์ œ์ด์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ž‘์„ฑํ•œ๋‹ค.

errorView

<script>
    const backFunc = function (){
        history.back();
    }
</script>
<br>
<div class="container">
    <h1>Error Message Page</h1>
    <hr>
    <div class="d-flex justify-content-center">
    <h3>{{errorMessage}}</h3>
    </div>
    <hr>
    <div class="d-flex flex-row-reverse">
        <button onclick="backFunc()" class="btn btn-primary">๋’ค๋กœ ๊ฐ€๊ธฐ</button>
    </div>
</div>

html body ๋ถ€๋ถ„์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ„๋‹จํ•œ ํŽ˜์ด์ง€๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

onClick์„ ํ†ตํ•ด ๋’ค๋กœ ๊ฐ€๊ธฐ ๋ฒ„ํŠผ๋„ ์ƒ์„ฑํ•˜์—ฌ ๋Œ์•„๊ฐˆ ์ˆ˜ ์žˆ๊ฒŒ ์ž‘์„ฑํ–ˆ๋‹ค.

์ด๋กœ์จ GlobalExceptionHandler์„ ํ†ตํ•œ ์—๋Ÿฌ ํŽ˜์ด์ง€๋ฅผ ์™„์„ฑํ–ˆ๋‹ค.