spring boot 与mvc的原理一直,所以存在view层的Resolver,可以进行配置和重写


那么问题来了:

从写之后的视图渲染器,如何对视图页面不存在的情况进行处理呢


首先,对于spring mvc的机制,404,以及500或是一些异常的处理,主要集中在controller的处理逻辑中


而视图渲染,如下例: 

重写了ViewResolver,如果这个过程中发生异常,或是反回了一个空的view,环境如何处理,如何调到异常页面

	public class MultiViewResover extends InternalResourceViewResolver {

		private static List<ViewResolver> resolvers = new ArrayList<>();

		@Override
		public View resolveViewName(String viewName, Locale locale) throws Exception {

			View view = null;
			for (ViewResolver resolver : resolvers) {

				view = resolver.resolveViewName(viewName, locale);
				if(view != null) {
					break;
				}
			}
			
	//        if(view == null) {
	//            MustacheView mustacheView = new MustacheView();
	//            mustacheView.setUrl("pages/error");
	//            view = mustacheView;
	//        }

			return view;
    }
	

查了下源码:

也就是说,如果视图是空的时候,这里会抛出ServletException

	/**
	 * Render the given ModelAndView.
	 * <p>This is the last stage in handling a request. It may involve resolving the view by name.
	 * @param mv the ModelAndView to render
	 * @param request current HTTP servlet request
	 * @param response current HTTP servlet response
	 * @throws ServletException if view is missing or cannot be resolved
	 * @throws Exception if there's a problem rendering the view
	 */
	protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
		// Determine locale for request and apply it to the response.
		Locale locale = this.localeResolver.resolveLocale(request);
		response.setLocale(locale);

		View view;
		if (mv.isReference()) {
			// We need to resolve the view name.
			view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
			if (view == null) {
				throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
						"' in servlet with name '" + getServletName() + "'");
			}
		}
		else {
			// No need to lookup: the ModelAndView object contains the actual View object.
			view = mv.getView();
			if (view == null) {
				throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
						"View object in servlet with name '" + getServletName() + "'");
			}
		}

		// Delegate to the View object for rendering.
		if (logger.isDebugEnabled()) {
			logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
		}
		try {
			if (mv.getStatus() != null) {
				response.setStatus(mv.getStatus().value());
			}
			view.render(mv.getModelInternal(), request, response);
		}
		catch (Exception ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
						getServletName() + "'", ex);
			}
			throw ex;
		}
	}

而doDispatch中对所有的异常进行了捕获:

按照这里描述,可以在interceptor的afterCompletion中进行异常的处理

				catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}

但interceptor的afterCompletion是在视图处理完成或发生异常之后的再处理工作

所以可以返回一些静态页面,但如果需要使用一些模板引擎,就需要进行繁琐的处理了

综上所述,针对于视图层异常的处理,只能有一下两种方法了:

1.跳转到一个固定的异常请求,之后进行再次渲染,这里就需要控制好自己实现的viewResolver了,需要针对于异常界面进行特殊处理

2.springboot 提供的ErrorController机制