# API์—์„œ์˜ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
Study Repository

API์—์„œ์˜ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ

by rlaehddnd0422

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ HTML ํŽ˜์ด์ง€์˜ ๊ฒฝ์šฐ์—๋Š” 4xx, 400, 5xx .. ์™€ ๊ฐ™์€ ์˜ค๋ฅ˜ํŽ˜์ด์ง€ ์„ค์ •์„ ํ†ตํ•ด ์Šคํ”„๋ง ๋ถ€ํŠธ์˜ ํ™”์ดํŠธ๋ผ๋ฒจ ํŽ˜์ด์ง€๋‚˜ ํ†ฐ์บฃ์˜ ์˜ค๋ฅ˜ํ™”๋ฉด์„ ์ปค์Šคํ…€ํ•ด์„œ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

 

ํ•˜์ง€๋งŒ API์˜ ๊ฒฝ์šฐ์—๋Š” ๊ฐ ์˜ค๋ฅ˜ ์ƒํ™ฉ์— ๋งž๋Š” ์˜ค๋ฅ˜ ์‘๋‹ต ์ŠคํŽ™์„ ์ •ํ•˜๊ณ  , JSON์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋‚ด๋ ค์ฃผ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์˜ˆ์™ธ์ฒ˜๋ฆฌ์— ์ƒ๊ฐํ•  ๋ถ€๋ถ„์ด ๋งŽ์Šต๋‹ˆ๋‹ค.

 

์šฐ์„  API๋„ ์˜ค๋ฅ˜ ํŽ˜์ด์ง€์—์„œ ํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ์„œ๋ธ”๋ฆฟ ์˜ค๋ฅ˜ ํŽ˜์ด์ง€ ๋ฐฉ์‹์„ ๋จผ์ € ์‚ฌ์šฉํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

@Slf4j
@RestController
public class ApiExceptionController {

    @Data
    @AllArgsConstructor
    static class MemberDto
    {
        private String memberId;
        private String name;
    }

    @GetMapping("/api/members/{id}")
    public MemberDto getMember(@PathVariable("id") String id)
    {
        if(id.equals("ex"))
        {
            throw new RuntimeException("์ž˜๋ชป๋œ ์‚ฌ์šฉ์ž");
        }
        return new MemberDto(id,"hello "+id);
    }

์˜ˆ์™ธ๋ฐœ์ƒ ์‹œ ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋œ WebServerCustomizer์˜ RuntimeException๊ณผ ๋งคํ•‘๋œ ์—๋ŸฌํŽ˜์ด์ง€๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

API๋ฅผ ์š”์ฒญํ–ˆ์„ ๋•Œ

  • ์ •์ƒ์š”์ฒญ  : JSON ์ž˜ ๋ฐ˜ํ™˜๋จ
  • ์˜ค๋ฅ˜์š”์ฒญ : ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด๋‘” ์˜ค๋ฅ˜ ํŽ˜์ด์ง€ HTML์ด ๋ฐ˜ํ™˜

 

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ •์ƒ ์š”์ฒญ์ด๋˜, ์˜ค๋ฅ˜ ์š”์ฒญ์ด๋˜ JSON์ด ๋ฐ˜ํ™˜๋˜๊ธธ ๊ธฐ๋Œ€ํ•  ๋•Œ ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ์š”?

 

API ์‘๋‹ต์„ ์ถ”๊ฐ€ํ•ด์„œ ์˜ค๋ฅ˜ ์š”์ฒญ์ผ ๋•Œ ์˜ค๋ฅ˜ ์ •๋ณด JSON์œผ๋กœ ๋ฐ˜ํ™˜

@RequestMapping(value = "/error-page/500", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Map<String,Object>> errorPage500Api(HttpServletRequest request, HttpServletResponse response) {

    log.info("errorPage 500 API");

    Map<String, Object> result = new HashMap<>();
    Exception ex = (Exception) request.getAttribute(ERROR_EXCEPTION);

    result.put("status",request.getAttribute(ERROR_STATUS_CODE));
    result.put("message",ex.getMessage());

    Integer statusCode = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);

    return new ResponseEntity(result, HttpStatus.valueOf(statusCode));
}
  • ๋งคํ•‘ ์ •๋ณด์— produces ์˜ต์…˜์„ JSON์œผ๋กœ ์ง€์ •ํ•˜๋ฉด Request์˜ Acceptํ—ค๋”๊ฐ€ application/json์ผ ๊ฒฝ์šฐ์— ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
    • Jackson ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ResponseEntity๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์‘๋‹ตํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”์‹œ์ง€ ์ปจ๋ฒ„ํ„ฐ๊ฐ€ ๋™์ž‘ํ•˜๋ฉด์„œ ํด๋ผ์ด์–ธํŠธ JSON์ด ๋ฐ˜ํ™˜.
    • ResponseEntity์— ์˜ค๋ฅ˜ ์ƒํƒœ์ฝ”๋“œ, ๋ฉ”์‹œ์ง€๋ฅผ json ์œผ๋กœ ๋ฐ˜ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค. 

Postman ๊ฒฐ๊ณผ

 

์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ ์˜ค๋ฅ˜ ๋ฐฉ์‹ ์‚ฌ์šฉ - BasicErrorController

Customizing ํ•œ ์˜ค๋ฅ˜ ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๋•Œ๋Š”, ์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” BasicErrorController๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

BasicErrorController ์‚ฌ์šฉํ–ˆ์„ ๋•Œ

BasicErrorController๋ฅผ ์‚ฌ์šฉ ์‹œ

 

Acceptํ—ค๋”๊ฐ€ application/json ์ด๋ฉด json์— ์˜ค๋ฅ˜์ •๋ณด๋ฅผ ๋‹ด์•„ ๋ฆฌํ„ดํ•˜๊ณ ,

text/html์ด๋ฉด ๋””ํดํŠธ๋กœ ๋งคํ•‘๋œ /error ๊ฒฝ๋กœ์— ์žˆ๋Š” ๋ทฐ๋ฅผ ์ฐพ์•„ ์—๋Ÿฌ์ฝ”๋“œ์™€ ๋งค์นญ๋˜๋Š” ๋ทฐ๋ฅผ ์ฐพ์•„ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.

+ application.properties์— ์ถ”๊ฐ€์ ์œผ๋กœ ์˜ค๋ฅ˜ ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ
server.error.include-binding-errors=always
server.error.include-exception=true
server.error.include-message=always
server.error.include-stacktrace=always

๋ณด์•ˆ ์ƒ ์œ„ํ—˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์˜ค๋ฅ˜์— ๋Œ€ํ•ด์„œ๋Š” ๊ฐ„๊ฒฐํ•œ ๋ฉ”์‹œ์ง€๋งŒ ๋…ธ์ถœํ•˜๊ณ  ๋กœ๊ทธ๋ฅผ ํ†ตํ•ด์„œ ํ™•์ธํ•˜๋„๋ก ํ•ฉ์‹œ๋‹ค.

 

๋’ค์—์„œ ๋‹ค๋ฃฐ @ExceptionHandler๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์ด๊ธฐ ๋•Œ๋ฌธ์— ์ง€๊ธˆ์€ ์ด ์ •๋„๊นŒ์ง€๋งŒ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

HandlerExceptionResolver

๋™์ž‘ ์ˆœ์„œ

 

  • ์ปจํŠธ๋กค๋Ÿฌ์— ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ด์„œ WAS๊นŒ์ง€ ์˜ˆ์™ธ๊ฐ€ ์ „ํŒŒ๋˜์—ˆ์„ ๋•Œ HTTP ์ƒํƒœ์ฝ”๋“œ๋Š” 500 (์„œ๋ฒ„ ์˜ค๋ฅ˜)๋กœ ์ฒ˜๋ฆฌ๋˜๋Š”๋ฐ ์˜ˆ์™ธ์— ๋”ฐ๋ผ 400, 404 ๋“ฑ๋“ฑ ๋‹ค๋ฅธ ์ƒํƒœ์ฝ”๋“œ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์„ ๋•Œ
  • ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋‚˜ ํ˜•์‹์„ API๋งˆ๋‹ค ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์„ ๋•Œ

HandlerExceptionResolver๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

1. HandlerExceptionResolver๋ฅผ ์ƒ์†๋ฐ›์•„ ExceptionReseolver ์ƒ์„ฑ

@Slf4j
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
                                         Object handler, Exception ex) {
        try
        {
            if(ex instanceof IllegalStateException)
            {
                log.info("IllegalArgumentException resolver to 400");
                response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
                return new ModelAndView();
            }
        }catch(IOException e)
        {
            log.error("resolver ex" , e);
        }

        return null;
    }
}

 

2. WebConfig์— ๋“ฑ๋ก

@Override
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
    resolvers.add(new MyHandlerExceptionResolver());
}

์ด๋ ‡๊ฒŒ ExceptionResolver๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ์˜ˆ์™ธ์ •๋ณด๋ฅผ ๋ฐ”๊พธ์–ด ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋„˜๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋นˆ ModelAndView() ๋ฆฌํ„ด ์‹œ ๋ทฐ๋ฅผ ๋ Œ๋”๋ง ํ•˜์ง€์•Š๊ณ  ์ •์ƒ ํ๋ฆ„์œผ๋กœ ์„œ๋ธ”๋ฆฟ์œผ๋กœ ๋ฆฌํ„ด.
  • null ๋ฆฌํ„ด : ๋‹ค์Œ ExceptionResolver๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ•œ ์˜ˆ์™ธ๋ฅผ ๋„˜๊ฒจ์„œ ์‹คํ–‰. ๋‹ค์Œ ExceptionResolver๊ฐ€ ์—†์œผ๋ฉด  ์˜ˆ์™ธ๋ฅผ ์„œ๋ธ”๋ฆฟ ๋ฐ–์œผ๋กœ ๋˜์ง‘๋‹ˆ๋‹ค.

ExceptionResolver๋ฅผ ์ž˜ ํ™œ์šฉํ•˜๋ฉด ์ด๋Ÿฐ ์‚ฌ์•ˆ๋“ค์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

  1. ์˜ˆ์™ธ ์ƒํƒœ ์ฝ”๋“œ ๋ณ€ํ™˜ (response.sendError(...) )
  2. ๋ทฐ ํ…œํ”Œ๋ฆฟ ์ฒ˜๋ฆฌ ( ๋ชจ๋ธ๋ทฐ์— ๊ฐ’์„ ์ฑ„์›Œ์„œ ) : WAS
  3. API ์‘๋‹ต์ฒ˜๋ฆฌ (response.getWriter().println("hello"); ์ฒ˜๋Ÿผ HTTP ์‘๋‹ต ๋ฐ”๋””์— ์ง์ ‘ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์ฃผ๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅ. ์—ฌ๊ธฐ์„œ JSON์œผ๋กœ ์‘๋‹ตํ•˜๋ฉด API ์‘๋‹ต์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)  

์ถ”๊ฐ€๋กœ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ExceptionResolver๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์˜ˆ์™ธ๊ฐ€ WAS๊นŒ์ง€ ์ „ํŒŒ๋˜์ง€ ์•Š๊ณ  ์„œ๋ธ”๋ฆฟ ์„ ์—์„œ ํ•ด๊ฒฐ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๋‹นํžˆ ๊น”๋”ํ•ด์ง„๋‹ค๋Š” ๋ฉ”๋ฆฌํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

 

ํ•˜์ง€๋งŒ ์ด๋ ‡๊ฒŒ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋‚ด๋ ค๋ฐ›์•„ ๊ตฌํ˜„ํ•˜๊ณ  ๋กœ์ง์งœ๊ณ  ๋“ฑ๋กํ•˜๋Š” ๊ณผ์ • ์ž์ฒด๊ฐ€ ์ข€ ๊ท€์ฐฎ์€ ์ผ์ž…๋‹ˆ๋‹ค.

 

์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ExceptionResolver

1. DefaultHandlerExceptionResolver

  • ์Šคํ”„๋ง ๋‚ด๋ถ€์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์Šคํ”„๋ง ์˜ˆ์™ธ๋ฅผ ํ•ด๊ฒฐ
  • ๋Œ€ํ‘œ์ ์œผ๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ ์‹œ์ ์— ํƒ€์ž…์ด ๋งž์ง€ ์•Š์œผ๋ฉด ๋‚ด๋ถ€์—์„œ TypeMistmatchException์ด ๋ฐœ์ƒํ•˜๋Š”๋ฐ, ์ด ๊ฒฝ์šฐ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๊นŒ์ง€ ์˜ค๋ฅ˜๊ฐ€ ์˜ฌ๋ผ๊ฐ€๊ณ , ๊ฒฐ๊ณผ์ ์œผ๋กœ 500์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • ํ•˜์ง€๋งŒ ์‚ฌ์‹ค ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ž…๋ ฅ๊ฐ’์„ ํƒ€์ž…์— ๋งž์ง€ ์•Š๊ฒŒ ์ž…๋ ฅํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— 400 ์—๋Ÿฌ๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฆฌํ„ด ํ•ด์ฃผ์–ด์•ผํ•˜๋Š”๋ฐ ์ด๋Ÿฐ ์—ญํ• ์„ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ˆ˜ํ–‰ ํ•ด์ฃผ๋Š” Resolver๊ฐ€ DefaultHandlerExceptionResolver
@GetMapping("/api/default-handler-ex")
public String defaultException(@RequestParam Integer data)
{
    return "ok";
}

๋กœ๊ทธ๋ฅผ ๋ณด๋ฉด DefaultHandlerExceptionResolver๊ฐ€ ์‹คํ–‰๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

2. ResponseStatusExceptionHandler

  • ResponseStatusExceptionHandler๋Š” ์˜ˆ์™ธ์— ๋”ฐ๋ผ์„œ HTTP ์ƒํƒœ์ฝ”๋“œ๋ฅผ ์ง€์ •ํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
  • @ResponseStatus๊ฐ€ ๋‹ฌ๋ ค์žˆ๋Š” ์˜ˆ์™ธ์™€ ResponseStatusException ์˜ˆ์™ธ ๋‘ ๊ฐ€์ง€ ๊ฒฝ์šฐ๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์™ธ์— @ResponseStatus ์–ด๋…ธํ…Œ์ด์…˜์„ ์ ์šฉํ•˜๋ฉด HTTP ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@ResponseStatus(code= HttpStatus.BAD_REQUEST, reason = "์ž˜๋ชป๋œ ์š”์ฒญ ์˜ค๋ฅ˜")
public class BadRequestException extends RuntimeException{
}
  • BadRequestException์€ RuntimeException(500 ์„œ๋ฒ„ ์—๋Ÿฌ)๋ฅผ ์ƒ์†๋ฐ›์€ ์—๋Ÿฌ.
  • ์›๋ž˜ ๊ฐ™์œผ๋ฉด ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ƒ์†๋ฐ›์•˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒํƒœ์ฝ”๋“œ๊ฐ€ 500๋Œ€ ์—ฌ์•ผ ํ•˜์ง€๋งŒ @ResponseStatus์—์„œ ์ƒํƒœ์ฝ”๋“œ๋ฅผ ์›ํ•˜๋Š” ๋Œ€๋กœ ์ง€์ •ํ•˜๋ฉด ResponseStatusExceptionResolver๊ฐ€ ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์„ ํ™•์ธํ•˜๊ณ  ์˜ค๋ฅ˜์ฝ”๋“œ๋ฅผ ์ง€์ •ํ•œ ์ฝ”๋“œ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  reason์„ ํ†ตํ•ด ๋ฉ”์‹œ์ง€์„ ๋‹ด์Šต๋‹ˆ๋‹ค.

์˜ˆ์™ธ์— @ResponseStatus๋ฅผ ๋‹ฌ์•„ HTTP ์ƒํƒœ์ฝ”๋“œ ์ง€์ •ํ•˜๊ธฐ

@GetMapping("/api/response-status-ex1")
public String responseStatusEx1()
{
    throw new BadRequestException();
}

localhost:8080/api/response-status-ex1 ํ˜ธ์ถœ

reason์€ MessageSource์—์„œ ์ฐพ๋Š” ๊ธฐ๋Šฅ๋„ ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์— messages.properties๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

ResponseStatusException ์˜ˆ์™ธ ๋˜์ง€๊ธฐ

@GetMapping("/api/response-status-ex2")
public String responseStatusEx2()
{
    throw new ResponseStatusException(HttpStatus.NOT_FOUND,"์ž˜๋ชป๋œ ์š”์ฒญ ์˜ค๋ฅ˜", new IllegalArgumentException());
}

ResponseStatusException์— ์ง์ ‘ ์„ค์ •ํ•˜๊ณ ์ž ํ•˜๋Š” ์ƒํƒœ์ฝ”๋“œ์™€ ์ง€์ •ํ•œ ์˜ค๋ฅ˜๋ฅผ ๋งค์นญ์‹œ์ผœ ๋˜์ง€๋Š” ๋ฐฉ๋ฒ•

 

 

3. ExceptionHandlerExceptionResolver - @ExceptionHandler

์›น ๋ธŒ๋ผ์šฐ์ €์— HTML ํ™”๋ฉด์˜ค๋ฅ˜๋ฅผ ์ œ๊ณตํ•  ๋•Œ์—๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ BasicErrorController๋ฅผ ํ˜ธ์ถœํ•ด /error ๊ฒฝ๋กœ์— ๋งŒ๋“ค์–ด๋‘” ๋ทฐํ…œํ”Œ๋ฆฟ์„ ๋ Œ๋”๋ง ํ•œ๋‹ค๊ณ  ํ–ˆ์—ˆ์Šต๋‹ˆ๋‹ค. 

 

ํ•˜์ง€๋งŒ API ์˜ค๋ฅ˜์˜ ๊ฒฝ์šฐ์—๋Š” ์–˜๊ธฐ๊ฐ€ ์ข€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๊ฐ API๋Š” ์‹œ์Šคํ…œ๋งˆ๋‹ค ์‘๋‹ต์˜ ๋ชจ์–‘๋„, ์ŠคํŽ™๋„ ๋ชจ๋‘ ๋‹ค๋ฅด์ฃ . ๋”ฐ๋ผ์„œ ์˜ˆ์™ธ ์ƒํ™ฉ์— ๋‹จ์ˆœํžˆ ์›น๋ธŒ๋ผ์šฐ์ €์— ์˜ค๋ฅ˜ํ™”๋ฉด HTML ์„ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ์˜ˆ์™ธ์— ๋”ฐ๋ผ์„œ ๊ฐ๊ฐ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๋ฅผ ์ถœ๋ ฅํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ ๊ฐ™์€ ์˜ˆ์™ธ๋ผ๊ณ  ํ•ด๋„ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ ์ปจํŠธ๋กค๋Ÿฌ๋ณ„๋กœ ๋‹ค๋ฅธ ์‘๋‹ต์„ ๋‚ด๋ ค์ฃผ์–ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์–ด์š”.( ์˜ˆ๋ฅผ ๋“ค๋ฉด ์ƒํ’ˆ ๊ด€๋ฆฌ ์ปจํŠธ๋กค๋Ÿฌ์™€ ํšŒ์› ๊ด€๋ฆฌ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ์˜ RuntimeException ์˜ˆ์™ธ์— ๋Œ€ํ•ด ์„œ๋กœ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ).

 

์˜ˆ์™ธ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ์„ธ๋ฐ€ํ•œ ์ œ์–ด๊ฐ€ ํ•„์š”ํ•œ ์‹œ์ ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ•ด๊ฒฐ์ฑ…์ด ๋ฐ”๋กœ ExceptionHandlerExceptionResolver๊ฐ€ ์ œ๊ณตํ•˜๋Š” @ExceptionHandler ์ž…๋‹ˆ๋‹ค!

 

@ExceptionHandler ์žฅ์ 

  • ๋‹ค๋ฅธ ์˜ˆ์™ธ์ฒ˜๋ฆฌ ๋„๊ตฌ๋ณด๋‹ค ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์Šต๋‹ˆ๋‹ค.
  • ๊ตฌํ˜„์ด ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค!
  • ์Šคํ”„๋ง์˜ ์ปจํŠธ๋กค๋Ÿฌ์ฒ˜๋Ÿผ ๋‹ค์–‘ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ์‘๋‹ต ํƒ€์ž…์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@ExceptionHandler์—์„œ ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ์‘๋‹ตํƒ€์ž… 

https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-exceptionhandler-args

 

Web on Servlet Stack

Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, "Spring Web MVC," comes from the name of its source module (spring-webmvc), but it is more commonl

docs.spring.io

@ExceptionHandler // UserException.class ์ƒ๋žต ๊ฐ€๋Šฅ
public ResponseEntity<ErrorResult> userExHandler(UserException e)
{
    log.error("[exceptionHandler] ex", e);
    ErrorResult result = new ErrorResult("USER-EX",e.getMessage());
    return new ResponseEntity(result,HttpStatus.BAD_REQUEST);
}

@GetMapping("/api2/members/{id}")
public ApiExceptionController.MemberDto getMember(@PathVariable("id") String id)
{

    if(id.equals("user-ex"))
    {
        throw new UserException("์‚ฌ์šฉ์ž ์˜ค๋ฅ˜");
    }

์‚ฌ์šฉ๋ฒ•์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

  • @ExceptionHandler ์–ด๋…ธํ…Œ์ด์…˜์„ ์„ ์–ธํ•˜๊ณ  ํ•ด๋‹น ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์€ ์˜ˆ์™ธ๋ฅผ ์ง€์ •.
  • ์ด๋•Œ ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ž…๋ ฅํ•œ ์˜ˆ์™ธ์™€ @ExceptionHandler์— ์ง€์ •ํ•œ ์˜ˆ์™ธ๊ฐ€ ๊ฐ™์œผ๋ฉด @ExceptionHandler์— ์˜ˆ์™ธ ํด๋ž˜์Šค ์ด๋ฆ„ ์ง€์ • ์ƒ๋žต ๊ฐ€๋Šฅ.
    @ExceptionHandler({AException.class, BException.class}) ๋‹ค์–‘ํ•œ ์˜ˆ์™ธ๋ฅผ ํ•œ๋ฒˆ์— ์ฒ˜๋ฆฌ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ์ƒ์œ„ ์˜ˆ์™ธ ํด๋ž˜์Šค๋ฅผ @ExceptionHandler๋กœ ์ง€์ •ํ•˜๋ฉด ํ•˜์œ„ ์˜ˆ์™ธ ํด๋ž˜์Šค๋ฅผ ์•„์šฐ๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
@ExceptionHandler(์ƒ์œ„์˜ˆ์™ธ.class)
public ~ ๋ถ€๋ชจ์˜ˆ์™ธ์ฒ˜๋ฆฌ(์ƒ์œ„ ์˜ˆ์™ธ e) 
{}

@ExceptionHandler(ํ•˜์œ„์˜ˆ์™ธ.class)
public ~ ํ•˜์œ„์˜ˆ์™ธ์ฒ˜๋ฆฌ(ํ•˜์œ„ ์˜ˆ์™ธ e)
{}

- ์Šคํ”„๋ง์˜ ์šฐ์„ ์ˆœ์œ„๋Š” ํ•ญ์ƒ ์ž์„ธํ•œ ๊ฒƒ์ด ์šฐ์„ ๊ถŒ์„ ๊ฐ€์ง€๊ธฐ ๋•Œ๋ฌธ์— ํ•˜์œ„ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
- ์ด ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ž˜ ํ™œ์šฉํ•ด ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ•œ ๋ชจ๋“  ์˜ˆ์™ธ๋“ค์„ ๋ชจ๋“  ์˜ˆ์™ธ์˜ ๋ถ€๋ชจ ์˜ˆ์™ธ์ธ Exception์„ @ExceptionHandler๋กœ ์ฒ˜๋ฆฌํ•ด์„œ ๋‚จ์€ ์˜ˆ์™ธ๋“ค์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

+ @ControllerAdvice

@Slf4j
@RestControllerAdvice(annotations = RestController.class)
public class ExControllerAdvice {

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(IllegalArgumentException.class) // @ResponseBody ์ž๋™ ์ ์šฉ
    public ErrorResult illegalExHandler(IllegalArgumentException e)
    {
        log.error("[exceptionHandler] ex", e);
        return new ErrorResult("BAD",e.getMessage()); // json
    }

    @ExceptionHandler // UserException.class ์ƒ๋žต ๊ฐ€๋Šฅ
    public ResponseEntity<ErrorResult> userExHandler(UserException e)
    {
        log.error("[exceptionHandler] ex", e);
        ErrorResult result = new ErrorResult("USER-EX",e.getMessage());
        return new ResponseEntity(result,HttpStatus.BAD_REQUEST);
    }

    // ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ•˜๊ณ  ๋‚จ์€ ์˜ˆ์™ธ๋“ค ์ฒ˜๋ฆฌ
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler
    public ErrorResult exHandler(Exception e)
    {
        log.error("[exceptionHandler] ex", e);
        return new ErrorResult("EX","๋‚ด๋ถ€ ์˜ค๋ฅ˜");
    }
}

 

@ControllerAdvice

  • ๋Œ€์ƒ์œผ๋กœ ์ง€์ •ํ•œ ์—ฌ๋Ÿฌ ์ปจํŠธ๋กค๋Ÿฌ์— @ExceptionHandler๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋Œ€์ƒ์œผ๋กœ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ๋ชจ๋“  ์ปจํŠธ๋กค๋Ÿฌ์— ์ ์šฉ
  • @RestControllerAdvice = @ResponseBody + @ControllerAdvice

<์ฐธ๊ณ ์ž๋ฃŒ>

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2/dashboard

 

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

Study Repository

rlaehddnd0422

ํ™œ๋™ํ•˜๊ธฐ