반응형

오류 처리는 더 견고한 서비스를 위해서 개발자에게 매우 중요합니다.

이번 시간에는 SpringBoot에서는 기본적으로 어떻게 오류 페이지를 처리하고 있는지, 어떻게 커스텀 하게 수정해서 오류 페이지를 관리하는지 알아보도록 하겠습니다.

 

1. SpringBoot에서는 기본적으로 BasicErrorController에서 오류를 관리하고 있습니다.

BasicErrorController.java

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {

	private final ErrorProperties errorProperties;

	/**
	 * Create a new {@link BasicErrorController} instance.
	 * @param errorAttributes the error attributes
	 * @param errorProperties configuration properties
	 */
	public BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties) {
		this(errorAttributes, errorProperties, Collections.emptyList());
	}

	/**
	 * Create a new {@link BasicErrorController} instance.
	 * @param errorAttributes the error attributes
	 * @param errorProperties configuration properties
	 * @param errorViewResolvers error view resolvers
	 */
	public ₩(ErrorAttributes errorAttributes, ErrorProperties errorProperties,
			List<ErrorViewResolver> errorViewResolvers) {
		super(errorAttributes, errorViewResolvers);
		Assert.notNull(errorProperties, "ErrorProperties must not be null");
		this.errorProperties = errorProperties;
	}

	@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
	public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
		HttpStatus status = getStatus(request);
		Map<String, Object> model = Collections
				.unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));
		response.setStatus(status.value());
		ModelAndView modelAndView = resolveErrorView(request, response, status, model);
		return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
	}

	@RequestMapping
	public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
		HttpStatus status = getStatus(request);
		if (status == HttpStatus.NO_CONTENT) {
			return new ResponseEntity<>(status);
		}
		Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
		return new ResponseEntity<>(body, status);
	}
   }

 - @RequestMapping("${server.error.path:${error.path:/error}}")

    -> 설정 파일에 error.path 값이 없으면 default로 /error를 사용합니다.

 - HTML로 응답을 주는 경우 errorHtml 메소드로 응답을 합니다.

 - HTML 외 응답은 error 메소드에서 처리합니다.

 

2. 에러 관련 설정 파일

application.yml

server:
  error:
    whitelabel:
      enabled: true           # 화이트 라벨 페이지 유무 (default : true) 
    include-stacktrace: never # 오류 응답에 stacktrace 내용을 포함할 지 여부 (default : always)
    path: /error              # 오류 응답을 처리할 핸들러(ErrorController) path (default : /error)

 

3. 에러 발생하면 에러 페이지 HTML을 노출시키도록 해보겠습니다.

개발 환경

  •  Spring 2.7.5
  •  Thymeleaf

 

기본적으로 오류 페이지를 노출시키는 방법은 간단합니다.

저는 Thymleaf를 사용하고 있기 때문에 resources > templates > error 디렉토리 아래에 에러 코드 이름으로

html 파일을 생성해주면 됩니다.

 * 400번대 에러코드를 모두 커버하고 싶다면 4xx.html로 생성하면 되겠습니다.

 

404.html

참 쉽죠? 이제 직접 ErrorController를 구현해서 에러 페이지에 데이터를 전달해 보도록 하겠습니다.

4. @ErrorController

WebErrorController.java

@Controller
public class WebErrorController implements ErrorController {

    @RequestMapping(value = "/error")
    public ModelAndView handleNoHandlerFoundException(HttpServletResponse response, HttpServletRequest request, Model model) {
        Object statusCode = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
        // int status = response.getStatus();

        ModelAndView modelAndView = new ModelAndView();

        if (statusCode != null) {
            Integer status = Integer.valueOf(statusCode.toString());
            if (status == HttpStatus.NOT_FOUND.value()) {
                modelAndView.addObject("errorCode", status);
                modelAndView.setViewName("/error/404");
            } else if (status == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
                modelAndView.addObject("errorCode", status);
                modelAndView.setViewName("/error/500");
            } else if (status == HttpStatus.FORBIDDEN.value()) {
                modelAndView.setViewName("/error/403");
            } else modelAndView.setViewName("/error/common");
        }

        return modelAndView;
    }
}

 - ErrorController를 구현합니다.

 - request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE), response.getStatus()으로 에러 코드를 꺼냅니다.

 

 

404.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>어이쿠 오류다!</h3>
    <h2 th:text="${errorCode}"></h2>
</body>
</html>

404.html

추가적으로

@ExceptionHandler를 사용해서 해당 애노테이션이 선언된 예외 및 하위 예외에 대해서 특정 메서드가 처리할 수 있도록 해줍니다.

상황에 맞추어서 리턴 형식을 반환할 수 있습니다.

    @ResponseStatus(HttpStatus.NOT_IMPLEMENTED)
    @ExceptionHandler(Exception.class)
    public Map<String, String> handle(Exception e) {
        Map<String, String> errorAttributes = new HashMap<>();
        errorAttributes.put("code", "NOT_IMPLEMENTED");
        errorAttributes.put("message", e.getMessage());
        return errorAttributes;
    }
728x90
반응형

+ Recent posts