重写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来记录到文件,从这里可体现此方式更强大,处理也较集中统一.
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