Skip to content

Latest commit

 

History

History
332 lines (189 loc) · 10.2 KB

TIL220331.md

File metadata and controls

332 lines (189 loc) · 10.2 KB

Daily to do list

Java


Spring


CS


알고리즘


오늘의 회고

220331 Spring MVC

——————————————————

예외처리, 오류 페이지

서블릿

 이렇게 하면 톰캣 자체 오류페이지 제공 Exception은 무조건 500에러로 나가게 됨

  • response.sendError(Http상태 코드, 오류 메시지)

오류가 발생했을 때 HttpServletResponse가 제공하는 sendError라는 메서드를 사용 서블릿 컨테이너에게 오류가 발생했다는 점을 전달. 상태코드와 오류 메시지 추가 가능 

———————————————————— 서블릿 예외 처리 - 오류 화면 제공

 이렇게 에러의 종류를 지정해서 페이지를 지정할 수 있다.

 고객의 요청이 한번 일어났는데 컨트롤러는 2번 요청됨. 오직 서버 내부에서 오류 페이지를 찾기 위해 추가적인 호출을 한다.

이때, 오류 페이지 경로로 필터, 서블릿, 인터셉터, 컨트롤러가 모두 다시 호출된다.

  • 오류 정보 추가 WAS는 오류 페이지를 단순히 다시 요청만 하는 것이 아니라, 오류

—————————————————— 서블릿 예외 처리 - 필터

오류가 발생하면 오류 페이지를 출력하기 위해 WAS내부에서 다시 한번 호출이 발생한다.
이떄 필터, 서블릿, 인터셉터도 다시 호출 된다.

근데 생각해보면 로그인이나 여러 체크가 한번 더 ? 매우 비효율

결국은 클라이언트로부터 발생한 요청인지 아니면 오류 페이지 출력을 위한 요청인지….

DispatcherType 으로 구분 가능

필터는 이런 경우를 위해서 DispatcherType이라는 옵션이 있다. 

 필터를 등록하는데 이번엔 DispatcherType으로 요청과 에러 둘 다 들어오게

——————————————————— 서블릿 예외 처리 - 인터셉터

필터와 마찬가지로 한번 더 불리게 된다.. 어떻게 이것을 막을?? 수 있는지

 인터셉터의 경우는 이렇게 강력한 경로 설정으로 오류 페이지의 경로를 넣어서 막는다. 따로 dispatcherType이런게 없어서 이렇게 그냥 경로 추가로 한다.

————————————————— 스프링 부트 - 오류 페이지 1

스프링 부트는 ErrorPage를 자동으로 등록한다. 이 떄 /error라는 경로로 기본 오류 페이지를 설정 new ErrorPage(“/error“) 상태코드와 예외를 설정하지 않으면 기본 오류 페이지로 사용된다. 

  • 개발자는 오류 페이지만 등록!

Path가 이미 잡혀있고.. 뭐 다 등록이 되어 있어서 오류 페이지 화면만 BasicErrorController의 룰과 우선순위에 따라서 등록하면 된다.

templates/error 에 넣으면 됨  이렇게 우선순위를 따른다.

 이렇게 다양한 정보를 담아서 전달 가능.

이런식으로 출력 가능.

오류 관련 내부 정보들을 고객에게 노출하지 않는 것이 좋다. 고객이 대항 오류를 알아도 혼란만 하고 보안 취약점을 노출하게 되는 것이다.

 이쁜 오류 메시지만 남겨야 한다.

————————————————— API 예외 처리

좀 전에 웹 페이지 와는 다르게 API는 각 오류 상황에 맞는 오류 응답 스펙을 정하고, JSON으로 데이터를 내려주어야 한다.

api는 예외 처리를 클라이언트와의 약속을 통해서? 반환한다.

 이런식으로 API미디어 타입을 받아서 json을 반환

———————————— 스프링부트 기본 오류 처리

스프링부트에서도 제공해준다. 미디어 타입에 따라서 제공을 해주도록 나옴  이렇게….

API 오류 처리는 다른 차원.. 회원과 관련된 API에서 예외가 발생할 때 응답과, 상품과 관련된 API에서 발생하는 예외에 따라 그 결과가 달라질 수 있다. 결과적으로 매우 세밀하고 복잡하다. 따라서 이 방법은 HTML 화면을 처리할 때 사용하고 API는 오류처리는 @ExceptionHandler를 사용…

————————————————— API 예외 처리 - HandlerExceptionResolver

예를 들어 IllegalArgumentException이 온다면.. 400으로 에러 상태를 반환하고 싶은데 throw로 반환하게 되면 500 코드로 반환이 되게 된다ㅣ..

  • HandlerExceptionResolver 스프링 MVC는 컨트롤러(핸들러)밖으로 예외가 던져진 경우 예외를 해결하고, 동작을 새로 정의할 수 있는 방밥. 컨트롤러 밖으로 던져진 예외를 해결하고, 동작 방식을 변경하고 싶으면 HandlerExceptionResolver를 사용하면 된다. 줄여서 ExceptionResolver

에러가 발생시 dispatcherServlet에서 ExceptionResolver로 넘어가서 에러를 처리할 수 있음 (정상처리로 가능)

 WebConfig에 등록하고

 이렇게 만들면 됨..

exceptionResolver가 ModelAndView를 반환하는 이유는 마치 try catch를 하듯이 Exception을 처리해서 정상 흐름 처럼 변경하는 것이 목적.

빈 ModelANdView를 반환하면 뷰를 렌더링하지 않고 정상 흐름으로 서블릿이 리턴.

지정을 하게 되면 view, model 등의 정보를 지정해서 반환하면 뷰를 렌더링.

nul을 반환하면 다음 ExceptionREsolver를 찾아서 실행. 만약 없다면 그냥 기존 그대로 500에러 전달.

  • ExceptionResolver 활용 예외 상태 코드 변환 뷰 템플릿 처리 API 응답 처리 

———————————————— HaldlerExceptionResolver 활용

  • 예외를 여기서 마무리하기 예외가 발생하면 WAS까지 예외가 던져지고 WAS에서 오류 페이지 정보를 찾아서 다시 /error를 호출하는 과정은 생각해보면 너무 복잡하다. ExceptionREsolver를 활용하면 예외가 발생했을 때 이런 복잡한 과정 없이 여기서 해결 가능.

 이런식으로 ModelAndView에 빈 객체를 반환하면서 에러만 담고 넘김.

 그런데 ExceptionResolver를 직접 구현하려니… 상당히 복잡하다.

————————————————— API 예외 처리 - 스프링이 제공하는 ExceptionResolver

  • ExceptionHandlerExceptionResolver @ExceptionHandler를 처리한다. API 예외 처리는 대부분 이 기능으로 해결

  • ResponseStatusEceptionResolver HTTP 상태 코드를 지정해준다

  • DefaultHandelrExceptionREsolver 스프링 내부 기본 예외를 처리한다.

  • ResponseStatusEceptionResolver @ResponseStatus가 달려있는 예외 ResponseStatusException 예외

 이런식으로 선택하는 에러..  ㅇㅣ런식으로 불러옴

 이런식으로 직접 삽입도 가능, error.bad는 messages.properties만들었음

————————————————————

  • DefaultHandelrExceptionREsolver

스프링 내부에서 발생하는 스프링 예외를 해결한다. 대표적으로 타입 에러!

이런 것은 보통 클라이언트 오류이므로 DefaultHandelrExceptionREsolver 는 이것을 400에러로 바꿔준다..ㅎ

 이런식으로 바꿔줌..

사실상 그냥 스프링 내부 예외 처리..

——————————————————— @ExceptionHandler

이걸 위해… 배워왔다..

API는 각 시스템 마다 응답도 다르고 스펙도 모양도 다르다.. 매우 세밀한 제어가 필요

  • @ExceptionHandler 스프링은 API 예외 처리 문제를 해결하기 위해 @ExceptionHandler를 사용 
컨트롤러에서 예외가 발생 시 exceptionResolver로 이동한다, 그리고 거기서 ExceptionHandlerExceptionResolver를 부르고 1순위가 @ExceptionHandler이다.

 이렇게 만들면 된다.. 정상흐름으로 <<< 반환한다. (예외 상태 코드 변경 가능) 안변경하면; 200;;;

 이렇게 예외 붙이면 된다.

 이렇게도 가능..

 여기보면 Exception은 최상위 부모이므로 상세히 적히지 않은 에러는 모두 여기로 온다.

************** 정리 중요 @ExceptionHandler 애노테이션을 선언하고, 해당 컨트롤러에서 처리하고 싶은 예외를 지정해주면 된다. 해당 컨트롤러에서 예외가 발생하면 이 메서드가 호출된다. (해당 컨트롤러만 가능, 다른 컨트롤러는 반영 안됨) 참고로 지정한 예외 또는 그 예외의 자식 클래스는 모두 잡을 수 있다. (Exception 하면 전부 다 잡음)

우선순위 : 스플링은 항상 더 자세한 것이 우선권을 가진다!(UserException >> exception)

  • 다양한 예외  이렇게 예외를 한번에 처리 가능

 애노테이션에 적어야 하는데 생략하고 적어도 됨.. 파라미터와 동일하면

  • 파라미터와 응답 @Exceptionhandler에는 마치 스프링의 컨트롤러의 파라미터 응답처럼 다양한 파라미터와 응답을 지정할 수 있다.!!

  • 실행 흐름
  1. 컨트롤러를 호출한 결과 IllegalArgumentException 예외가 컨트롤러 밖으로 던져진다.
  2. 예외가 발생했으므로 ExceptionResolver가 작동한다. 가장 우선순위가 높은 ExceptionHandlerExceptionResolver가 실행된다.
  3. ExceptionHandlerExceptionResolver는 해당 컨트롤러에 IllegaArugumentExceptopn을 처리할 수 있는 @ExceptionHandler가 있는지 확인
  4. 있다! illegaExHandle()를 실행, @RestController이므로 illegalExHandle()에도 @ResponseBody가 적용된다. 따라서 HTTP 컨버터가 사용되고, 응답이 다음과 같은 JSON으로 반환된다.
  5. @ResponseStatus(HttpStatus.BAD_REQUEST)를 지정했으므로 HTTP 상태 코드를 400으로 지정한다. (지정하지 않으면 200 성공이 반환됨.)

근데 혹시 다른 컨트롤러도 같이 사용하고 싶다면?! @ControllerAdvice

————————————————————— @ControllerAdvice

@RestControllerAdvice 도 가능!!

대상을 지정하지 않으면 모든 컨트롤러에 적용!(글로벌)

  • 대상 컨트롤러 지정 방법 

특정 애노테이션이 있는 컨트롤러 지정 특정 패키지 지정(하위도 포함) 특정 클래스를 지정

셋 다 가능