spring中错误输出是 org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController
类中error
方法输出的。
@RequestMapping
public ResponseEntity
getErrorAttributes
方法返回的Map包含了错误信息,路径,状态码等信息。
看下方法如何实现的:
protected Map getErrorAttributes(HttpServletRequest request,
boolean includeStackTrace) {
WebRequest webRequest = new ServletWebRequest(request);
return this.errorAttributes.getErrorAttributes(webRequest, includeStackTrace);
}
复制代码
可以看到,他实例化ServletWebRequest
并传入getErrorAttributes
方法参数中了。
我们看下errorAttributes
这个属性是什么
public abstract class AbstractErrorController implements ErrorController {
private final ErrorAttributes errorAttributes;
private final List errorViewResolvers;
...
}
复制代码
可以看到这是个常量,我们看下类的定义:
public interface ErrorAttributes {
/**
* Returns a {@link Map} of the error attributes. The map can be used as the model of
* an error page {@link ModelAndView}, or returned as a {@link ResponseBody}.
* @param webRequest the source request
* @param includeStackTrace if stack trace elements should be included
* @return a map of error attributes
*/
Map getErrorAttributes(WebRequest webRequest,
boolean includeStackTrace) ;
/**
* Return the underlying cause of the error or {@code null} if the error cannot be
* extracted.
* @param webRequest the source request
* @return the {@link Exception} that caused the error or {@code null}
*/
Throwable getError(WebRequest webRequest);
}
复制代码
这个接口定义了两个方法。
getErrorAttributes
方法返回了Map集合,从方法文档注释我们可以知道他将出错的信息存储在了这个Map中。
getError
返回Throwable
类,并且通过文档注释知道这个方法将导致发生错误原因的Throwable
返回,并且有可能返回null
那么有了这个接口,我们可以看看它的实现类。
它的默认实现在org.springframework.boot.web.servlet.error.DefaultErrorAttributes
这。
/**
* Default implementation of {@link ErrorAttributes}. Provides the following attributes
* when possible:
*
* - timestamp - The time that the errors were extracted
* - status - The status code
* - error - The error reason
* - exception - The class name of the root exception (if configured)
* - message - The exception message
* - errors - Any {@link ObjectError}s from a {@link BindingResult} exception
*
- trace - The exception stack trace
* - path - The URL path when the exception was raised
*
*
* @author Phillip Webb
* @author Dave Syer
* @author Stephane Nicoll
* @author Vedran Pavic
* @since 2.0.0
* @see ErrorAttributes
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DefaultErrorAttributes
implements ErrorAttributes, HandlerExceptionResolver, Ordered
复制代码
从这个类的文档注释我们可以知道,他将一些错误信息放在了map中:
- timestamp 发生错误的时间
- status 状态码
- error 错误原因
- exception 发生错误的异常类名
- message 异常消息
- errors 错误信息
- trace 异常堆栈信息
- path 发生错误的路径
有了这些信息,我们可以定义自己的JSON格式的异常输出了,
但在这之前,我们需要知道这个接口(实现类)是否在IOC容器中有了。
庆幸的是,spring已经帮我们注入了:
@Bean
public static ErrorMvcAutoConfiguration.PreserveErrorControllerTargetClassPostProcessor preserveErrorControllerTargetClassPostProcessor() {
return new ErrorMvcAutoConfiguration.PreserveErrorControllerTargetClassPostProcessor();
}
复制代码
那么我们就可以写一个自定义错误处理类了:
package top.itning.server.error.handler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.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.ServletWebRequest;
import org.springframework.web.context.request.WebRequest;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* @author itning
* @date 2019/5/2 18:49
*/
@RestController
public class ErrorHandler implements ErrorController {
private final ErrorAttributes errorAttributes;
@Autowired
public ErrorHandler(ErrorAttributes errorAttributes) {
this.errorAttributes = errorAttributes;
}
@Override
public String getErrorPath() {
return "/error";
}
@RequestMapping(value = "/error", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String error(HttpServletRequest request) {
WebRequest webRequest = new ServletWebRequest(request);
Map errorAttributes = this.errorAttributes.getErrorAttributes(webRequest, true);
String msg = errorAttributes.getOrDefault("error", "not found").toString();
String code = errorAttributes.getOrDefault("status", 404).toString();
return "{\"code\":" + code + ",\"msg\":\"" + msg + "\",\"data\":\"\"}";
}
}
复制代码
在error
方法中,我们返回了JSON格式的自定义错误信息。