参考:https://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-error-handling
spring boot 提供了默认的/error路径,并展示一个全局的错误页面。 以下几种方式用来自定义错误处理:
(1)实现 ErrorController
接口或者继承BasicErrorController类
BasicErrorController类如下:
package org.springframework.boot.autoconfigure.web.servlet.error; import java.util.Collections; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.boot.autoconfigure.web.ErrorProperties; import org.springframework.boot.autoconfigure.web.ErrorProperties.IncludeStacktrace; import org.springframework.boot.web.servlet.error.ErrorAttributes; import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.util.Assert; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; /** * Basic global error {@link Controller}, rendering {@link ErrorAttributes}. More specific * errors can be handled either using Spring MVC abstractions (e.g. * {@code @ExceptionHandler}) or by adding servlet * {@link AbstractServletWebServerFactory#setErrorPages server error pages}. * * @author Dave Syer * @author Phillip Webb * @author Michael Stummvoll * @author Stephane Nicoll * @see ErrorAttributes * @see ErrorProperties */ @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 BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties, List<ErrorViewResolver> errorViewResolvers) { super(errorAttributes, errorViewResolvers); Assert.notNull(errorProperties, "ErrorProperties must not be null"); this.errorProperties = errorProperties; } @Override public String getErrorPath() { return this.errorProperties.getPath(); }
//当为网页请求时返回error页面 @RequestMapping(produces = "text/html") public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { HttpStatus status = getStatus(request); Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes( request, isIncludeStackTrace(request, MediaType.TEXT_HTML))); response.setStatus(status.value()); ModelAndView modelAndView = resolveErrorView(request, response, status, model); return (modelAndView != null) ? modelAndView : new ModelAndView("error", model); }
//当为其他请求时,返回ResponseEntity @RequestMapping @ResponseBody public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL)); HttpStatus status = getStatus(request); return new ResponseEntity<>(body, status); } /** * Determine if the stacktrace attribute should be included. * @param request the source request * @param produces the media type produced (or {@code MediaType.ALL}) * @return if the stacktrace attribute should be included */ protected boolean isIncludeStackTrace(HttpServletRequest request, MediaType produces) { IncludeStacktrace include = getErrorProperties().getIncludeStacktrace(); if (include == IncludeStacktrace.ALWAYS) { return true; } if (include == IncludeStacktrace.ON_TRACE_PARAM) { return getTraceParameter(request); } return false; } /** * Provide access to the error properties. * @return the error properties */ protected ErrorProperties getErrorProperties() { return this.errorProperties; } }
通过errorHtml和error方法来处理异常。这两个方法中都有一个关键的方法getErrorAttributes,这个方法是其父类AbstractErrorController的方法,代码如下:
public abstract class AbstractErrorController implements ErrorController { private final ErrorAttributes errorAttributes; protected Map<String, Object> getErrorAttributes(HttpServletRequest request,boolean includeStackTrace) { WebRequest webRequest = new ServletWebRequest(request); return this.errorAttributes.getErrorAttributes(webRequest, includeStackTrace); }
... }
可以看出,上述方法调用的其实是ErrorAttributes的getErrorAttributes方法,所以可以直接实现ErrorAttributes 接口,即第二种方法。
(2)实现ErrorAttributes 接口或者继承DefaultErrorAttributes类
继承DefaultErrorAttributes类并重写的getErrorAttributes方法
(3)使用@ControllerAdvice注解
例如:
@ControllerAdvice(basePackageClasses = FooController.class) public class FooControllerAdvice extends ResponseEntityExceptionHandler { @ExceptionHandler(YourException.class) @ResponseBody ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) { HttpStatus status = getStatus(request); return new ResponseEntity<>(new CustomErrorType(status.value(), ex.getMessage()), status); } private HttpStatus getStatus(HttpServletRequest request) { Integer statusCode = (Integer) reques通过e("javax.servlet.error.status_code"); if (statusCode == null) { return HttpStatus.INTERNAL_SERVER_ERROR; } return HttpStatus.valueOf(statusCode); } }
如果和FooControllerAdvice 在同一个包下的controller类抛出YourException异常,那么就会返回CustomErrorType类型的json。