SpringBoot的错误处理

SpringBoot的默认错误处理和自定义的默认处理机制

  1. 默认异常和错误的处理机制
    SpringBoot中有默认的资源文件夹,即template文件夹和static文件夹,在这两个里面添加error文件夹,并为其中的文件取上特定的名字就可以让当页面出现错误时,自动跳转到错误的页面.如果要携带错误信息的话,放在模板引擎专用的template文件夹下。
    演示:
    在这里插入图片描述
    随便输入一个不存在的页面.
    在这里插入图片描述
    原理解析:
    此种情况下,异常将被DefaultErrorViewResolver和BasicErrorController配合解决:
private ModelAndView resolve(String viewName, Map<String, Object> model) {
		String errorViewName = "error/" + viewName;//获取需要跳转的视图名
		TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName,
				this.applicationContext);
		if (provider != null) {
			return new ModelAndView(errorViewName, model);
		}
		return resolveResource(errorViewName, model);//处理错误
	}

//尝试去默认的默认资源路径下匹配解析出来的视图
	private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
		for (String location : this.resourceProperties.getStaticLocations()) {
			try {
				Resource resource = this.applicationContext.getResource(location);
				resource = resource.createRelative(viewName + ".html");
				if (resource.exists()) {
					return new ModelAndView(new HtmlResourceView(resource), model);
				}
			}
			catch (Exception ex) {
			}
		}
		return null;
	}
@Override
//在这里可以找到错误的属性
	public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
		Map<String, Object> errorAttributes = getErrorAttributes(webRequest, options.isIncluded(Include.STACK_TRACE));
		if (Boolean.TRUE.equals(this.includeException)) {
			options = options.including(Include.EXCEPTION);
		}
		if (!options.isIncluded(Include.EXCEPTION)) {
			errorAttributes.remove("exception");
		}
		if (!options.isIncluded(Include.STACK_TRACE)) {
			errorAttributes.remove("trace");
		}
		if (!options.isIncluded(Include.MESSAGE) && errorAttributes.get("message") != null) {
			errorAttributes.put("message", "");
		}
		if (!options.isIncluded(Include.BINDING_ERRORS)) {
			errorAttributes.remove("errors");
		}
		return errorAttributes;
	}

2.@ControllerAdvice和@ExceptionHandler注解配合使用
此种方法可以处理全局的异常,原理是这样可以把该类加入到可以处理异常的解析器队列中去。

@ControllerAdvice
public class FirstAdvice {

//代表可以处理数学运算异常,要想处理多个异常,可以自己添加。
    @ExceptionHandler({ArithmeticException.class})
    public ModelAndView resolveBasicException(HttpServletRequest request, HttpServletResponse response,Exception exception){
        System.out.println(exception.getClass());
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("error/4xx");
        modelAndView.addObject("msg", exception.getMessage());
        return modelAndView;
    }

}

注意这里一定要返回一个ModelAndView对象,原因是SpringBoot底层会拿所有的异常解析器去尝试解析异常,解析是否成功的标准就是是否返回一个不为空的ModelAndView对象。
我们可以看看底层的这一段代码.

	ModelAndView exMv = null;
		if (this.handlerExceptionResolvers != null) {
			for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
				exMv = resolver.resolveException(request, response, handler, ex);
				if (exMv != null) {
					break;
				}
			}
		}

可以就按带如果处理之后返回的ModelAndView对象不为空,就退出循环,否则,循环继续.

3.@ResponseStatus注解配合自定以异常的使用。

@ResponseStatus(reason = "访问的页面不存在",code = HttpStatus.LOOP_DETECTED)
public class SecondAdvice extends RuntimeException{
    public SecondAdvice() {
        super();
    }

    public SecondAdvice(String message) {
        super(message);
    }

    public SecondAdvice(String message, Throwable cause) {
        super(message, cause);
    }

    public SecondAdvice(Throwable cause) {
        super(cause);
    }

    protected SecondAdvice(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
  • code属性和value属性可以混合使用,表示处理完成之后设置的响应状态码,根据状态码选择跳转到哪个视图。
  • reason属性表示错误信息,可以通过thymeleaf模板引擎的表达式取出。
    附上底层代码的关键部分如下:
protected ModelAndView applyStatusAndReason(int statusCode, @Nullable String reason, HttpServletResponse response)
			throws IOException {

		if (!StringUtils.hasLength(reason)) {
			response.sendError(statusCode);//设置获取到的状态码
		}
		else {
			String resolvedReason = (this.messageSource != null ?
					this.messageSource.getMessage(reason, null, reason, LocaleContextHolder.getLocale()) :
					reason);//获取错误信息
			response.sendError(statusCode, resolvedReason);
		}
		return new ModelAndView();
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值