스프링 347

75. 스프링의 자동 타입 변환

타입 컨버터는 말 그대로 타입을 바꿔주는. 문자 -> 숫자 등 타입을 변환해 줘야 할 일은 상당히 많다. 요청메시지의 모든 파라미터의 값은 사실 문자이다. @GetMapping("/hello-v1") public String helloV1(HttpServletRequest request){ String data = request.getParameter("data"); Integer intValue = Integer.valueOf(data); System.out.println("intValue = " + intValue); return "ok"; } 그렇기에 이렇게 필요에 따라 숫자로 변환 해 줘야 한다. 근데 아무래도 스프링은 이런 것을 자동으로 해 준다. 예시로 @GetMapping("/hello-v2..

74. ControllerAdviece

전에 @ExceptionHandler(IllegalArgumentException.class) 해서 컨트롤러 안에 에러를 처리 할 로직을 넣는 것은 나름 좋은 방법이었지만, 에러와 컨트롤러가 분리가 안됀다. 완벽히는 힘들더라도 잘 분리가 되어야만 유지보수 하기가 편하다. @ControllerAdvice 또는 @RestControllerAdvice를 쓰면 컨트롤러와 예외처리 로직을 분리할 수 있다. @Slf4j @RestController public class ApiExceptionV2Controller { @GetMapping("/api2/members/{id}") public ApiExceptionController.MemberDto getMember(@PathVariable("id") String ..

73. @ExceptionHandler API 예외

Html 화면 오류 vs API 오류 html 사용하는 환경의 오류는 BasicErrorController를 사용하는게 편하다. 그냥 리소스의 템플릿에 /error 폴더 만들어서 코드명.html로 에러 페이지 만들어 놓으면 스프링이 자동으로 등록시키는 BasicErrorController에서 자동으로 인식한다. 근데 API는 시스템마다 응답의 모양도 다르고, 스펙도 다르다. 단순히 예외에 대한 정보를 보여주는 게 아니라, 특정 예외에 따라서 각각 다른 데이터를 보내줘야 할 때도 있다. 한마디로 세밀한 제어가 필요하다. 예를 들어 상품API와 주문 API 의 오류는 에러정보를 Json으로 내려줄 때 모양새가 완전히 다를 수 있다. 스프링은 이러 한 문제점을 해결하기 위해, @Exceptionhandler라..

72. 스프링 내부에서 발생하는 예외를 처리해주는 Resolver

자동등록 됨. DefaultHandlerExceptionResolver라고 보통 파라미터 바인딩 시점에서 타입이 맞지 않으면 내부에서 TypeMismatchException이 발생하는데, 이게 원래는 컨트롤러에서 발생한 에러이기 때문에 500에러로 올라간다. 근데 사실 저 TypeMismatchException 대부분은 클라이언트가 정보를 잘못 입력했기 때문에 발생하는거다. @GetMapping("/api/default-handler-ex") public String defaultException(@RequestParam Integer data){ return "ok"; } 컨트롤러에 이렇게 해 봤다. 그냥 숫자를 받고 응답으로 ok라고 보내주는 거다. 내가 요청헤더 acception을 applicati..

71. 스프링이 자동등록해주는 ExceptionResolver

기본적으로 등록되는게 3가지가 있는데, 우선순위 순으로 ExceptionHandlerExceptionResolver : @ExceptionHandler 라는 애노테이션이 붙은 걸 처리한다. API는 대부분 이걸로 해결이 된다. ResponseStatusExceptionResolver : @ResponseStatus(value = HttpStatus.NOT_FOUND) 등 응답 상태 코드를 지정해 준다. DefaultHandlerExceptionResolver : 스프링 내부에서 처리해주는 기본 예외 저렇게 다 거친 후에도 처리가 안되면 그제서야 WAS로 간다. ResponseStatusExceptionResolver 이건 예외에 따라 상태코드를 지정해 주는 역할을 한다. @ResponseStatus가 달..

70. HandlerExceptionResolver로 API 예외 처리

예외가 발생하면, 그 예외가 서블릿, WAS까지 올라갔다가 WAS는 그 예외에 대해 등록해놓은 ErrorPage를 호출하여 (아무것도 등록 안해도 BasicErrorController가 자동으로 등록되니, 그것을 호출한다.) 다시 그 ErrorPage에 있는 컨트롤러까지 갔다가 또 그게 쭉 WAS까지 갔다가 그제서야 응답이 간다. 근데 HandlerExceptionResolver는 명명 그대로 해결사이기 때문에 컨트롤러에서 에러를 뿜어도 정상동작이라고 ModelAndView를 만들어 저 Controller -> DispatcherServlet -> HandlerExceptionResolver(정상적인 ModelAndView를 만듦) -> DispatcherServlet -> WAS 이 흐름에서 정상동작이..

69. API를 위한 예외처리 기능

HandlerExceptionResolver. 컨트롤러에서 예외가 발생했다면, 그 예외를 어떻게 처리할 지 구현할 수 있는 인터페이스이다. public interface HandlerExceptionResolver { @Nullable ModelAndView resolveException( HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex); } 이것이 실제 HandlerExceptionResolver의 인터페이스이다. 이 추상체를 구현하면 되는거다. 위 인터페이스명과 함수명도 그렇고, 예외를 해결해 주는 것이다. 만약 Exception ex

68. 스프링 부트의 API 오류 처리

과거 우리가 BasicErrorController를 사용했을 때(별다른 설정 없어도 자동으로 등록 해주는), 우리가 템플릿에 /error 경로에 에러 페이지를 에러코드.html로 만들어 두면 아무것도 하지 않아도 에러 발생 시(에러를 뿜거나 아니면 response.sendError()를 하던가) 저 에러 페이지 템플릿을 호출하게끔 해 주었다. 그럼 text/html 같은 경우는 이랬고, API는 어떻게 할까? 아무것도 안해도 된다. 먼저, BasicErrorController를 들어가 보자. @Controller @RequestMapping("${server.error.path:${error.path:/error}}") public class BasicErrorController extends Abstr..

67. API 예외처리

html 같은 경우는 그냥 4xx, 5xx등의 오류 페이지만 있으면 거의 해결 가능하다. 근데 API는, 각 오류 상황에 맞는 오류 응답 스펙을 클라이언트 사이드와 서버 사이드에서 약속을 하고 데이터를 내려주어야 한다. 먼저, 그냥 가상으로 /api/members/ex 라는 uri로 호출되면 에러를 뿜게 해줬고, 그 외에는 그냥 오브젝트를 만들어서 return 해 줬다. @RestController라 Json객체로 변환되어 들어간다. @RestController @Slf4j public class ApiExceptionController { @GetMapping("/api/members/{id}") public MemberDto getMember(@PathVariable("id") String id){ ..

66. BasicErrorController가 제공하는 정보들

스프링 부트가 자동으로 등록해주는 BasicErrorController는 timestamp status error exception trace message errors path 등을 model에 담아주기에, 이걸 템플릿에서 활용할 수 있다. 하지만 저걸 그래서 템플릿에서 모델에 넣어준 걸 꺼내서 템플릿에 뿌려보면.. 해커의 맛있는 밥이다. 그래서 사실, 원래 저렇게 안나온다. 저거는 내가 application.properties에 server.error.include-exception=true server.error.include-message=always server.error.include-stacktrace=always server.error.include-binding-errors=always ..