250x250
jhs0129
프로그래밍
jhs0129
전체 방문자
오늘
어제
  • 분류 전체보기
    • 자격증
      • SQLD
      • 정보처리기사
    • 프로젝트
      • html csss js - todolist
      • JSP 방명록
      • 졸업작품
    • 공부기록
      • Java
      • Spring
      • Spring Security
      • Algorithm
      • JPA
      • DB
      • Servlet JSP
      • html
      • 기술공유
    • 잡다한 생각

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • codedeploy
  • spring
  • rest docs
  • spring data jpa
  • nhn cloud 강의
  • 프로젝트
  • github
  • EC2
  • spring boot
  • spring framework
  • NHN Cloud
  • AWS
  • Spring Security Login
  • 스프링
  • 스프링시큐리티
  • 스프링 프레임워크
  • cicd
  • oAuth2
  • Spring Security
  • JPA

최근 댓글

최근 글

티스토리

반응형
hELLO · Designed By 정상우.
jhs0129

프로그래밍

공부기록/Spring

Spring - 예외처리

2022. 2. 6. 16:39
320x100
반응형

서블릿 예외처리

  • 예외가 발생할 경우 ex) RuntimeException...
  • response.sendError()로 예외를 전달 할 경우
  • --> 당장 예외가 발생하는 것이 아니라 서블릿 컨테이너에 전달, 응답전에 컨테이너가 확인

어플리케이션 내에서 예외처리가 되지 않을경우(try~catch) WAS까지 예외 전달 되어 예외페이지 출력된다

예외페이지 등록

예외페이지 등록

  • web.xml
<web-app>
    <error-page>
        <error-code>404</error-code>
        <location>/error-page/404.html</location>
    </error-page>
</web-app>
  • java
@Component
public class WebServerCustomizer 
    implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> {

    @Override
    public void customize(ConfigurableWebServerFactory factory) {
        /* 
        * HttpStatus.NOT_FOUND(404에러)발생시 
        * /error-page/404 경로로 이동
        */
        ErrorPage errorPage404 = 
            new ErrorPage(HttpStatus.NOT_FOUND, "/error-page/404");

        //페이지 등록
        factory.addErrorPages(errorPage404);
    }
}

요청 흐름

  1. 컨트롤러(예외발생) -> 인터셉터, 서블릿, 필터 -> WAS
  2. WAS 지정해둔 경로로 오류정보를 request에포함하여 다시 요청

-> 필터, 서블릿, 인터셉터 -> 컨트롤러 지정경로 호출-> view

필터나 인터셉터가 다시한번 호출 되는것은 너무 비효율적

처음 요청의 dispatcherType = REQUEST,

예외 발생되어 다시 호출 된 것의 dispatcherType = ERROR

DispatcherType

  • REQUEST: 클라이언트 요청
  • ERROR: 오류발생시 요청
  • FORWARD: 서블릿에서 다른 서블릿으로 호출
  • INCLUDE
  • ASYNC

필터 재호출 방지

필터를 등록하는 과정에서 DispatcherType을 등록을 하여 해당 type에 대해서만 필터 호출

FilterRegistrationBean<Filter> filterRegistrationBean 
    = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(new LogFilter());
filterRegistrationBean.setOrder(1);
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setDispatcherTypes(
    DispatcherType.REQUEST, DispatcherType.ERROR
);

REQUEST, ERROR타입에 대해서 필터를 호출한다

Error페이지에서는 호출을 하기를 원치 않는다면 제거하면 된다

인터셉터 재호출 방지

인터셉터는 dispatcherType에 무관하게 항상 호출

단지 에러페이지 호출 경로를 제외를 해주면 된다

registry.addInterceptor(new LogInterceptor())
        .order(1)
        .addPathPatterns("/**")
        .excludePathPatterns("/error-page/**");
        //에러 페이지에 대한 모든 호출 제외

스프링 예외처리

@ExceptionHandler

처리하고 싶은 예외에 대해서 지정을 해주면 된다(여러개 지정가능)

@Controller, @RestController가 적용된 bean내에서 발생한 예외에 대해서 하나의 메서드에서 처리한다

@ExceptionHandler({IllegalArgumentException.class}/* 생략가능*/)
public String illegalExHandle(IllegalArgumentException e) {
    log.error("[exceptionHandle] ex", e);
    return  "error-page";
}

위 코드는 IllegalArgumentException에러를 처리하는 메서드이다

예외를 생략을 하면 파라미터로 넘어온 예외에 대해서 처리한다

주의사항

@ExceptionHandler메서드를 통해서 예외를 처리하면 기본적으로 정상적으로 처리가 된것으로 되어 200코드가 전송이 된다

다른 응답 코드를 전송하고 싶다면 response.setStatus를 이용하여 응답코드를 지정을 해 주거나
@ResponseStatus를 이용하여 응답코드를 지정을 해 줄 수 있다

@ResponseStatus은 예외의 응답코드 또한 지정이 가능하다

@ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "error.bad")
public class BadRequestException extends RuntimeException{
}

@ControllerAdvice, @RestControllerAdvice

@ExceptionHandler를 사용을 하면 해당 컨트롤러에서만 예외에 대한 처리가 가능하다

그리고 컨트롤러에 경로에 대한 처리로직과 예외 처리로직이 같이 있으면서 너무 복잡해 잔다

그래서 예외 처리를 글로벌하게 적용을 하고 예외로직을 분리하고자 해당 어노테이션이 사용된다

단순히 예외처리 bean을 등록을 하여 사용을 한다고 생각을 하면된다

공통설정 적용 지정

속성 설명
value basePackage지정
annotations 해당 어노테이션이 있는 컨트롤러
assignable Types 특정 타입과 하위 타입컨트롤러 지정

스프링부트 예외처리

BasicErrorController에 맞게 오류페이지 화면만 처리하면 된다

경로: /error/xxx.html

API예외처리

기존 html화면을 보여주는 것이 아니라 JSON으로 클라이언트에게 전송을 해줘야 한다

서블릿 이용

@RequestMapping(value = "/error-page/500", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Map<String, Object>> errorPage(
    HttpServletRequest request, HttpServletResponse response) 
{
    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));
}

스프링

위에서 봤던 @ExceptionHandler를 사용을 하면된다

단지 차이점이라고 하면 API통신을 하기 때문에 html전송이 아닌 DTO를 통한 객체를 JSON으로 변환하여 전송을 해야한다 @Controller에서 @RestController로 변경이 된것이다

또한 @ResponseStatus를 통해 응답 코드를 지정해 줄 수 있다

참고

인프런_스프링 MVC 2편 - 백엔드 웹개발 핵심 기술_김영한 님 강의

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

 

스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 인프런 | 강의

웹 애플리케이션 개발에 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. MVC 2편에서는 MVC 1편의 핵심 원리와 구조 위에 실무 웹 개발에 필요한 모든 활용 기술들을 학습할 수 있

www.inflearn.com

 

320x100
반응형

'공부기록 > Spring' 카테고리의 다른 글

Spring boot CORS 설정  (0) 2022.08.03
DTO관련 고민  (0) 2022.07.13
Spring-filter interceptor  (0) 2022.02.03
Spring - 로그인 처리 세션쿠키  (0) 2022.01.28
Spring-MVC4 에러검증2  (0) 2022.01.22
    '공부기록/Spring' 카테고리의 다른 글
    • Spring boot CORS 설정
    • DTO관련 고민
    • Spring-filter interceptor
    • Spring - 로그인 처리 세션쿠키
    jhs0129
    jhs0129
    공부기록 남기기

    티스토리툴바