spring mvc异常处理(二)

参数资料:https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
spring mvc异常处理(一)介绍了spring mvc的一种比较简单处理方式,此文将介绍spring mvc让DispatcherServlet来处理错误与异常.
可先看看exception-handling-in-spring-mvc,里面详细介绍异常的处理,还提到什么时候用什么:
1.对于自己写的异常,考虑使用@ResponseStatus.
2.对于所有其它的异常,可以使用@ControllerAdvice类的@ExceptionHandler方法来处理,也可以配置SimpleMappingExceptionResolver来处理,这种情况,使用SimpleMappingExceptionResolver比使用@ControllerAdvice要简单.
3.对于特有的异常处理使用@ExceptionHandler方法加入到当前的Controller类处理.
警告:在同一个应用混合多种方式来使用就要小心,如果同一个异常使用多于一个方法来处理,你可能会得到你不想要的行为.在Controller上的@ExceptionHandler方法总是优先于@ControllerAdvice实例的那些方法.多个controller-advices,什么顺序来处理也是不确定的.


下面是应用例子:
1.对于找不到Handler来处理某个请求,还是让DispatcherServlet来抛异常,用来处理404.即将DispatcherServlet的throwExceptionIfNoHandlerFound设为true.可在DispatcherServletInitializer(继承自AbstractAnnotationConfigDispatcherServletInitializer的自定义配置类)重写registerDispatcherServlet,或者重写customizeRegistration设置初始化参数.

重写registerDispatcherServlet

@Override
protected void registerDispatcherServlet(ServletContext servletContext){
	String servletName = getServletName();
	Assert.hasLength(servletName, "getServletName() may not return empty or null");

	WebApplicationContext servletAppContext = createServletApplicationContext();
	Assert.notNull(servletAppContext,
			"createServletApplicationContext() did not return an application " +
					"context for servlet [" + servletName + "]");

	DispatcherServlet dispatcherServlet = new DispatcherServlet(servletAppContext);
	//这里设置
	dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
	ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
	Assert.notNull(registration,
			"Failed to register servlet with name '" + servletName + "'." +
					"Check if there is another servlet registered under the same name.");

	registration.setLoadOnStartup(1);
	registration.addMapping(getServletMappings());
	registration.setAsyncSupported(isAsyncSupported());

	Filter[] filters = getServletFilters();
	if (!ObjectUtils.isEmpty(filters)) {
		for (Filter filter : filters) {
			registerServletFilter(servletContext, filter);
		}
	}

	customizeRegistration(registration);
}
通过重写customizeRegistration来设置
@Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
	registration.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}
2.此步没有什么可做,但有可不要做的步骤,并理解其中源由.注意不要重写configureDefaultServletHandling来启用DefaultServletHandlerConfigurer.因为一旦启用了DefaultServletHandlerConfigurer,那么任意一个url,spring mvc都会有HandlerExecutionChain来处理,在DispatcherServlet.doDispatch方法内
...
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
	noHandlerFound(processedRequest, response);
	return;
}
...
即永远不会进入这个if里面,而继续往下走,最终还没有找到对应的ModelView来处理,最后还会回到了servlet容器默认处理.假设进入这个if里面,再来看看noHandlerFound方法:
protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
	if (pageNotFoundLogger.isWarnEnabled()) {
		pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + getRequestUri(request) +
				"] in DispatcherServlet with name '" + getServletName() + "'");
	}
	if (this.throwExceptionIfNoHandlerFound) {
		ServletServerHttpRequest sshr = new ServletServerHttpRequest(request);
		throw new NoHandlerFoundException(
				sshr.getMethod().name(), sshr.getServletRequest().getRequestURI(), sshr.getHeaders());
	}
	else {
		response.sendError(HttpServletResponse.SC_NOT_FOUND);
	}
}

这里就可看到我们为什么要设置throwExceptionIfNoHandlerFound为true的原因了,否则还是回到了servlet容器默认处理.

如果不得不要启用DefaultServletHttpRequestHandler,或许http://stackoverflow.com/questions/18250069/404-error-page-is-not-being-found的第二个回答是一种解决思路.

3.在MvcConfig注册SimpleMappingExceptionResolver Bean.
@Bean
public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
	SimpleMappingExceptionResolver resolver = new MySimpleMappingExceptionResolver();
	resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
	Properties mappings = new Properties();
	//key是异常类型,value是返回的视图名称
	mappings.setProperty(NoHandlerFoundException.class.getName(), "exception/404");
	mappings.setProperty(DataAccessException.class.getName(), "exception/database");
	resolver.setExceptionMappings(mappings);// None by default
	resolver.setDefaultErrorView("exception/500");// No default
	resolver.setExceptionAttribute("exception"); // Default is "exception"
	resolver.setWarnLogCategory(getClass().getName()); // No default
	return resolver;
}
前面的参考资料会详细介绍,注意这里的setOrder设为最优先处理,因为ExceptionResolver很可能不止一个,造成异常给其它的ExceptionResolver处理了.这里的setWarnLogCategory可以将异常交给log4j来记录到文件,从这里可体现此方式更强大,处理也较集中统一.
至于继承SimpleMappingExceptionResolver来重写doResolveException方法,是为了方便知道请求的url.下面是MySimpleMappingExceptionResolver
public class MySimpleMappingExceptionResolver extends SimpleMappingExceptionResolver {
	@Override
	protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
		ModelAndView result = super.doResolveException(request, response, handler, ex);
		result.addObject("url",request.getRequestURI());
		return result;
	}
}

4.404没有异常要处理,就不必贴代码了.页面WEB-INF/exception/500.jsp内容:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title></title>
</head>
<body>
500
<!--
Failed URL: ${url}
Exception: ${exception.message}
<c:forEach items="${exception.stackTrace}" var="ste">${ste}</c:forEach>
-->
</body>
</html>
5.测试:不存在映射的url(抛404)和主动在Controller方法抛的异常(抛500).

源码:http://download.csdn.net/detail/xiejx618/8257065



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值