IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringMVC之异常处理机制 -> 正文阅读

[Java知识库]SpringMVC之异常处理机制

HandlerExceptionResolver接口

该接口是SpringMVC处理异常的祖接口。下面我们看该类的注释:

接口由对象实现,这些对象可以解决在处理程序映射或执行期间抛出的异常,在典型情况下是错误视图。实现者通常在应用程序上下文中注册为bean。
错误视图类似于JSP错误页面,但可以用于任何类型的异常,包括任何已检查的异常,以及特定处理程序的潜在细粒度映射。

该接口只有一个方法:

ModelAndView resolveException(
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);

看其注释:

尝试解决在处理程序执行期间引发的给定异常,如果合适,返回表示特定错误页的ModelAndView。
返回的ModelAndView可能为空,表示异常已成功解决,但不应呈现任何视图,例如通过设置状态代码。

可见,该接口设计的初衷是当发生异常时,返回异常界面视图。

AbstractHandlerExceptionResolver抽象实现类

两个重要属性:

    @Nullable
	private Set<?> mappedHandlers;

	@Nullable
	private Class<?>[] mappedHandlerClasses;

这两个属性用于存放出现异常的handler对象。这两个集合包含的handler出现异常后,才会进行异常处理。

抽象方法:

@Nullable
	protected abstract ModelAndView doResolveException(
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);

该方法由子类实现,来实现具体的异常处理逻辑。是个钩子方法。

接口定义的resolveException方法实现:

@Override
	@Nullable
	public ModelAndView resolveException(
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {

		if (shouldApplyTo(request, handler)) {
			prepareResponse(ex, response);
			ModelAndView result = doResolveException(request, response, handler, ex);
			if (result != null) {
				// Print debug message when warn logger is not enabled.
				if (logger.isDebugEnabled() && (this.warnLogger == null || !this.warnLogger.isWarnEnabled())) {
					logger.debug("Resolved [" + ex + "]" + (result.isEmpty() ? "" : " to " + result));
				}
				// Explicitly configured warn logger in logException method.
				logException(ex, request);
			}
			return result;
		}
		else {
			return null;
		}
	}

由代码可知,只要是判断两个Set集合是否包含发生异常的handler对象,如果包含,则调用doResolveException方法处理异常,如果没有包含,则返回null。
综上所述,AbstractHandlerExceptionResolver抽象类主要的职责是判断发生异常的handler是否需要走异常处理机制。

SimpleMappingExceptionResolver实现类

顾名思义,该类是最简单的一个异常处理实现类。核心逻辑就是根据不同的异常类型,返回到不同的ModelAndView视图上。下面看其源码:

	@Nullable
	private Properties exceptionMappings;

	@Nullable
	private Class<?>[] excludedExceptions;

上面两个属性存放异常对应异常与视图的映射关系以及排除的异常类型。可见是在按异常类型进行异常视图的匹配。

看核心方法doResolveException方法,即上述抽象类的抽象方法:

protected ModelAndView doResolveException(
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {

		// Expose ModelAndView for chosen error view.
		String viewName = determineViewName(ex, request);
		if (viewName != null) {
			// Apply HTTP status code for error views, if specified.
			// Only apply it if we're processing a top-level request.
			Integer statusCode = determineStatusCode(request, viewName);
			if (statusCode != null) {
				applyStatusCodeIfPossible(request, response, statusCode);
			}
			return getModelAndView(viewName, ex, request);
		}
		else {
			return null;
		}
	}

看几个关键步骤:

String viewName = determineViewName(ex, request);

根据异常获得该异常对应的视图。如果没有视图,则直接返回null。

Integer statusCode = determineStatusCode(request, viewName);
			if (statusCode != null) {
				applyStatusCodeIfPossible(request, response, statusCode);
			}

获取request的状态码,并传递给response对象。

return getModelAndView(viewName, ex, request);

最后,返回ModelAndView错误视图。

由上面的逻辑也可以看出,该类为何Simple了。

DefaultHandlerExceptionResolver实现类

SpringMVC默认使用的这个类作为异常处理机制,下面我们看其核心方法doResolveException方法:

protected ModelAndView doResolveException(
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {

		try {
			if (ex instanceof HttpRequestMethodNotSupportedException) {
				return handleHttpRequestMethodNotSupported(
						(HttpRequestMethodNotSupportedException) ex, request, response, handler);
			}
			else if (ex instanceof HttpMediaTypeNotSupportedException) {
				return handleHttpMediaTypeNotSupported(
						(HttpMediaTypeNotSupportedException) ex, request, response, handler);
			}
			else if (ex instanceof HttpMediaTypeNotAcceptableException) {
				return handleHttpMediaTypeNotAcceptable(
						(HttpMediaTypeNotAcceptableException) ex, request, response, handler);
			}
			else if (ex instanceof MissingPathVariableException) {
				return handleMissingPathVariable(
						(MissingPathVariableException) ex, request, response, handler);
			}
			else if (ex instanceof MissingServletRequestParameterException) {
				return handleMissingServletRequestParameter(
						(MissingServletRequestParameterException) ex, request, response, handler);
			}
			else if (ex instanceof ServletRequestBindingException) {
				return handleServletRequestBindingException(
						(ServletRequestBindingException) ex, request, response, handler);
			}
			else if (ex instanceof ConversionNotSupportedException) {
				return handleConversionNotSupported(
						(ConversionNotSupportedException) ex, request, response, handler);
			}
			else if (ex instanceof TypeMismatchException) {
				return handleTypeMismatch(
						(TypeMismatchException) ex, request, response, handler);
			}
			else if (ex instanceof HttpMessageNotReadableException) {
				return handleHttpMessageNotReadable(
						(HttpMessageNotReadableException) ex, request, response, handler);
			}
			else if (ex instanceof HttpMessageNotWritableException) {
				return handleHttpMessageNotWritable(
						(HttpMessageNotWritableException) ex, request, response, handler);
			}
			else if (ex instanceof MethodArgumentNotValidException) {
				return handleMethodArgumentNotValidException(
						(MethodArgumentNotValidException) ex, request, response, handler);
			}
			else if (ex instanceof MissingServletRequestPartException) {
				return handleMissingServletRequestPartException(
						(MissingServletRequestPartException) ex, request, response, handler);
			}
			else if (ex instanceof BindException) {
				return handleBindException((BindException) ex, request, response, handler);
			}
			else if (ex instanceof NoHandlerFoundException) {
				return handleNoHandlerFoundException(
						(NoHandlerFoundException) ex, request, response, handler);
			}
			else if (ex instanceof AsyncRequestTimeoutException) {
				return handleAsyncRequestTimeoutException(
						(AsyncRequestTimeoutException) ex, request, response, handler);
			}
		}
		catch (Exception handlerEx) {
			if (logger.isWarnEnabled()) {
				logger.warn("Failure while trying to resolve exception [" + ex.getClass().getName() + "]", handlerEx);
			}
		}
		return null;
	}

这个方法使用大量的if…else…语句进行异常类型的判断,不同的异常类型,又调用了各自异常的处理方法。很明显,这段代码可以使用策略模式进行优化。
下面,我们看其中一个异常的处理方法,其他异常的套路都是一样的:

protected ModelAndView handleMissingServletRequestPartException(MissingServletRequestPartException ex,
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {

		response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
		return new ModelAndView();
	}

可以看到,对于异常的处理方式就是将错误编号传给了response对象,然后返回了一个新建的ModelAndView对象。所有的异常都是这种处理方式。这就是如果我们使用默认错误处理机制,项目报错时,浏览器直接显示错误编号的原因。为了更好的用户体验,一般不用默认的异常处理机制。

ResponseStatusExceptionResolver实现类

@ResponseStatus注解对应的异常类,该类没什么可讲的,知道@ResponseStatus作用即可。

AbstractHandlerMethodExceptionResolver抽象类

该类是AbstractHandlerExceptionResolver抽象类的子抽象类,用于处理HandlerMethod类型的handler抛出的异常。
我们先看其匹配handler方法:
在这里插入图片描述
可以看到,如果handler是HandlerMethod类型,则获取到HandlerMethod所属的bean,然后调用其父抽象类AbstractHandlerExceptionResolver的shouldApplyTo方法,走父类的判断逻辑。所以归根结底还是根据bean,进行的异常机制的匹配。
定义的抽象方法如下:

protected abstract ModelAndView doResolveHandlerMethodException(
			HttpServletRequest request, HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception ex);

定义了针对HandlerMethod类型的handler抛出异常的处理方案。

ExceptionHandlerExceptionResolver实现类

参考:ExceptionHandlerExceptionResolver类源码解析

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章           查看所有文章
加:2021-10-06 12:04:30  更:2021-10-06 12:08:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 19:22:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码