Spring boot Web MVC : 缺省错误视图解析器 DefaultErrorViewResolver

DefaultErrorViewResolverSpringboot缺省实现的一个错误视图解析器ErrorViewResolver。它基于一些常见的约定,尝试根据HTTP错误状态码解析出错误处理视图。它会在目录/error下针对提供的HTTP错误状态码搜索模板或者静态资源,比如,给定了HTTP状态码404,它会尝试搜索如下模板或者静态资源:

  • /<templates>/error/404.<ext> – 这里<templates>表示所配置的模板所在目录,<ext>表示所用的模板的文件名
  • /<static>/error/404.html – 这里<static>表示静态资源文件所在路径
  • /<templates>/error/4xx.<ext>
  • /<static>/error/4xx.html

源代码

package org.springframework.boot.autoconfigure.web.servlet.error;

// 省略 imports


public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {

	private static final Map<Series, String> SERIES_VIEWS;

	static {
       // HTTP 错误状态码所在状态码段所对应的视图名称 
		Map<Series, String> views = new EnumMap<>(Series.class);
		views.put(Series.CLIENT_ERROR, "4xx");
		views.put(Series.SERVER_ERROR, "5xx");
		SERIES_VIEWS = Collections.unmodifiableMap(views);
	}

	private ApplicationContext applicationContext;

	private final ResourceProperties resourceProperties;

	private final TemplateAvailabilityProviders templateAvailabilityProviders;

	private int order = Ordered.LOWEST_PRECEDENCE;

	/**
	 * Create a new  DefaultErrorViewResolver instance.
	 * @param applicationContext the source application context
	 * @param resourceProperties resource properties 配置参数属性,对应 spring.resources.*
	 */
	public DefaultErrorViewResolver(ApplicationContext applicationContext,
			ResourceProperties resourceProperties) {
		Assert.notNull(applicationContext, "ApplicationContext must not be null");
		Assert.notNull(resourceProperties, "ResourceProperties must not be null");
		this.applicationContext = applicationContext;
		this.resourceProperties = resourceProperties;
       // 根据当前应用上下文检测所使用的模板技术的工具 
		this.templateAvailabilityProviders = new TemplateAvailabilityProviders(
				applicationContext);
	}

	DefaultErrorViewResolver(ApplicationContext applicationContext,
			ResourceProperties resourceProperties,
			TemplateAvailabilityProviders templateAvailabilityProviders) {
		Assert.notNull(applicationContext, "ApplicationContext must not be null");
		Assert.notNull(resourceProperties, "ResourceProperties must not be null");
		this.applicationContext = applicationContext;
		this.resourceProperties = resourceProperties;
		this.templateAvailabilityProviders = templateAvailabilityProviders;
	}

    // 接口 ErrorViewResolver 约定的方法,根据HTTP错误状态码尝试解析出一个错误处理视图,最终
    // 以 ModelAndView 对象形式返回
	@Override
	public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,
			Map<String, Object> model) {
        // 先严格使用所提供的HTTP错误状态字status作为视图名称解析相应的错误处理视图
		ModelAndView modelAndView = resolve(String.valueOf(status.value()), model);
        
       // 如果严格使用所提供的HTTP错误状态字status作为视图名称没有找到相应的错误处理视图,
       // 现在尝试根据HTTP错误状态字status所在的HTTP状态字段(比如 404 对应 4xx, 500 对应 5xx)
       // 作为视图名称解析相应的错误处理视图
		if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
			modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
		}
		return modelAndView;
	}

	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 int getOrder() {
		return this.order;
	}

	public void setOrder(int order) {
		this.order = order;
	}

	/**
	 * View backed by an HTML resource.
     * 对应一个HTML静态资源文件的View实现。render动作其实就是把静态资源文件内容输出到 response,
     * 所使用的 ContentType 时 text/html
	 */
	private static class HtmlResourceView implements View {

		private Resource resource;

		HtmlResourceView(Resource resource) {
			this.resource = resource;
		}

		@Override
		public String getContentType() {
			return MediaType.TEXT_HTML_VALUE;
		}

		@Override
		public void render(Map<String, ?> model, HttpServletRequest request,
				HttpServletResponse response) throws Exception {
			response.setContentType(getContentType());
			FileCopyUtils.copy(this.resource.getInputStream(),
					response.getOutputStream());
		}

	}

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值