스프링/4. 스프링 MVC-2 87

77. 컨버전 서비스

우리가 정의한 컨버터를 직접 호출해서 썼다. 하지만 일일히 이렇게 호출해서 쓰면 굳이 스프링의 컨버터를 상속받아 사용한 의미가 없다. 이런 컨버터들을 모아서 관리해주는 것이 바로 컨버전 서비스이다. 이것도 어댑터 패턴이다. public interface ConversionService { boolean canConvert(@Nullable Class sourceType, Class targetType); boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType); @Nullable T convert(@Nullable Object source, Class targetType); @Nullable Object conve..

76. 스프링 타입컨버터

스프링은 컨버터 인터페이스를 제공해 준다. 되게 간단하다. public class StringToIntegerConverter implements Converter { @Override public Integer convert(String source) { return Integer.valueOf(source); } } Converter 이렇게 해서, convert라는 메소드를 @override 하면 된다. 그 안에 작업해서 return 해 버리면 된다. 예를들어, String 타입으로 들어온 것을 우리가 만든 IpPort 객체로 Convert 한다고 하면, @Getter @EqualsAndHashCode public class IpPort { private String ip; private int po..

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..