spring boot默认异常处理机制精讲 以及如何自定义异常消息,页面

spring boot默认处理机制精讲 以及如何自定义异常消息,页面

SpringBoot默认的错误处理机制

默认效果:

​ 1)、浏览器,返回一个默认的错误页面
spring boot默认异常处理机制精讲 以及如何自定义异常消息,页面
2)、如果是其他客户端,默认响应一个json数据
spring boot默认异常处理机制精讲 以及如何自定义异常消息,页面

原理

在spring boot中,关于错误的自动配置类是 ErrorMvcAutoConfiguration
这个自动配置类, 给容器中加入了这几个关键组件:

  1. ErrorPageCustomizer
    这个类的作用是定制错误的响应规则。在它的的registerErrorPages方法里的getPath方法指定了处理错误默认发送的请求为/error请求
  2. BasicErrorController
    这个类就是来处理/error请求的,它有如下两个方法:这个类就是来处理/error请求的,它有如下两个方法:
@RequestMapping(produces = "text/html") // 指定响应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);
	}

	@RequestMapping
	@ResponseBody // 指定响应json数据
	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<Map<String, Object>>(body, status);
	}

spring boot 默认处理/error请求时,会根据响应头来判断发送请求的是浏览器还是app,然后响应HTML或者json数据。
浏览器这部分代码处理完请求之后返回了一个ModelAndView 指定响应的页面,这个页面回去resolveErrorView这个方法里面找。

protected ModelAndView resolveErrorView(HttpServletRequest request,
			HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
		for (ErrorViewResolver resolver : this.errorViewResolvers) {
			ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
			if (modelAndView != null) {
				return modelAndView;
			}
		}
		return null;
	}

这个方法遍历所有的ErrorViewResolver,从这里面找返回的页面。在没有指定的情况下,默认来到了第三个注入的组件

  1. DefaultErrorViewResolver
    这个组件的作用是指定浏览器响应的错误页面。这个组件的作用是指定浏览器响应的错误页面。
    我们来看他是如何指定的:
	@Override
	public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,
			Map<String, Object> model) {
			// 将状态码转换为视图名称
		ModelAndView modelAndView = resolve(String.valueOf(status), model);
		if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
			modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
		}
		return modelAndView;
	}

可以看出,默认是将响应的状态码指定为视图名称,也就是说我们如果想自定义浏览器的错误响应页面,只需要在静态资源文件夹下创建4xx, 5xx等页面,当发生对应状态码异常时就会来到对应页面。

如何定制错误信息

定制浏览器错误页面

  • 没有模板引擎的情况下
    error/状态码 :将错误页面命名为 错误状态码.html 放在静态资源文件夹里面的 error文件夹下,发生此状态码的错误就会来到对应的页面。
    ps:如果建立名为4xx.html的文件,当发生以4开头的状态码错误时,在没有被精确匹配的情况下,就会来到这个页面。
  • 有模板引擎的情况下
    当然要把错误状态码.html文件放在模板引擎文件夹下。
    有模板引擎的优势在于:你可在错误页面获取一些讯息:
    • status:状态码
    • timestamp:时间戳
    • error:错误提示
    • exception:异常对象
    • message:异常消息
    • errors:JSR303数据校验的错误都在这里
  • 如果以上两个地方都没找到,就会来到默认一开始的页面。

定制json错误消息

假设我们现在有一个UserNotExistException

public class UserNotExistException extends RuntimeException {

    private String id;

    public String getId() {
        return id;
    }

    public UserNotExistException(String id) {
        super("用户不存在");
        this.id = id;
    }
}

我们可以利用springMvc的ControllerAdvice来定制这个异常的处理

@ControllerAdvice // 这是一个专门处理异常的Controller
public class ControllerExceptionHandler {

    @ExceptionHandler(UserNotExistException.class) // 这个方法处理UserNotExistException异常
    @ResponseBody // 已json的形式返回
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) // 指定响应的错误状态码为404,不指定默认是200
    public Map<String, Object> handleUserNotExistException(UserNotExistException ex) {
        Map<String, Object> result = new HashMap<>();
        result.put("id", ex.getId());
        result.put("message", ex.getMessage());
        return result;
    }
}

这么写,我们app端访问该异常时能够正确返回我们定制的json数据。
spring boot默认异常处理机制精讲 以及如何自定义异常消息,页面
但是存在一个问题:浏览器出现该异常时返回的也是json数据,而不是我们定制的404.html页面,失去了spring boot默认的自适应效果。
spring boot默认异常处理机制精讲 以及如何自定义异常消息,页面

如何达到自适应效果