SpringBoot-ErrorController
15390 단어 SpringBoot 시리즈Spring 시리즈
Springboot 기본 오류 처리
SpringBoot 소스 코드에 이러한 ErrorController가 있습니다. SpringMvc의 잘못된 Mapping을 처리하기 위해 많은 경우에 Controller를 썼습니다. 브라우저에서 접근할 때 다음과 같은 상황이 자주 발생합니다.
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Fri Aug 04 17:49:02 HKT 2017
There was an unexpected error (type=Not Found, status=404).
No message available
사실 이것은 springmvc가 http 요청을 시작할 때 백그라운드에서 해당하는 RequestHandleMapping을 찾지 못했기 때문이다.springBoot은 기본적으로 잘못된 페이지를 되돌려주고 오류에 대한 기본 처리이다
2017-08-04 17:49:02.201 DEBUG org.springframework.web.servlet.DispatcherServlet Line:869 - DispatcherServlet with name 'dispatcherServlet' processing GET request for [/error]
2017-08-04 17:49:02.201 DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping Line:310 - Looking up handler method for path /error
2017-08-04 17:49:02.202 DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping Line:317 - Returning handler method [public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)]
2017-08-04 17:49:02.202 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory Line:251 - Returning cached instance of singleton bean 'basicErrorController'
2017-08-04 17:49:02.202 DEBUG org.springframework.web.servlet.DispatcherServlet Line:955 - Last-Modified value for [/error] is: -1
2017-08-04 17:49:02.202 DEBUG org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor Line:85 - Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
2017-08-04 17:49:02.204 DEBUG org.springframework.web.servlet.view.ContentNegotiatingViewResolver Line:263 - Requested media types are [text/html, text/html;q=0.8] based on Accept header types and producible media types [text/html])
2017-08-04 17:49:02.204 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory Line:251 - Returning cached instance of singleton bean 'error'
위의 로그에서 볼 수 있듯이 진정으로 작용하는 것은 BasicErrorController입니다.소스 코드를 보면 다음을 확인할 수 있습니다.
@RequestMapping(
produces = {"text/html"}
)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
HttpStatus status = this.getStatus(request);
Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
return modelAndView == null?new ModelAndView("error", model):modelAndView;
}
springboot에서 기본적으로 지정한 반환 내용 형식은text/html이며, request 요청 헤더의 (Accept) 형식에 지정한 형식이 포함되어야 반환합니다.
사용자 정의 JSON 형식으로 데이터 반환
ErrorController 인터페이스를 사용하면
package com.minlia.cloud.exception.handler;
import com.minlia.cloud.body.StatefulBody;
import com.minlia.cloud.body.impl.FailureResponseBody;
import com.minlia.cloud.utils.EnvironmentUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ErrorAttributes;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
/**
* Rest
*
* @author will
* @author qianyi
* @since 1.0
*/
@RestController
public class RestErrorEndpoint implements ErrorController {
private static final String PATH = "/error";
@Autowired
private ErrorAttributes errorAttributes;
// @RequestMapping(value = PATH)
@RequestMapping(value = PATH, produces = {MediaType.APPLICATION_JSON_VALUE})
StatefulBody error(HttpServletRequest request, HttpServletResponse response) {
if(!EnvironmentUtils.isProduction()) {
return buildBody(request,true);
}else{
return buildBody(request,false);
}
}
private StatefulBody buildBody(HttpServletRequest request,Boolean includeStackTrace){
Map errorAttributes = getErrorAttributes(request, includeStackTrace);
Integer status=(Integer)errorAttributes.get("status");
String path=(String)errorAttributes.get("path");
String messageFound=(String)errorAttributes.get("message");
String message="";
String trace ="";
if(!StringUtils.isEmpty(path)){
message=String.format("Requested path %s with result %s",path,messageFound);
}
if(includeStackTrace) {
trace = (String) errorAttributes.get("trace");
if(!StringUtils.isEmpty(trace)) {
message += String.format(" and trace %s", trace);
}
}
return FailureResponseBody.builder().code(0).status(status).message(message).build();
}
@Override
public String getErrorPath() {
return PATH;
}
private Map getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
RequestAttributes requestAttributes = new ServletRequestAttributes(request);
return errorAttributes.getErrorAttributes(requestAttributes, includeStackTrace);
}
}
다시 요청하면 오류 페이지가 발생하지 않도록 되돌려줍니다.
{
"timestamp":1501841693729,
"requestId":"4bzKFSZ45gMyiAB9U808gDkplVM1RAJe20170804181453211403",
"code":0,
"status":404,
"message":"Requested path /asfa with result Not Found"
}