歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> SpringMVC錯誤頁面配置

SpringMVC錯誤頁面配置

日期:2017/3/1 9:08:24   编辑:Linux編程

當前SpringMVC非常流行,在大多數情況,我們都需要自定義一些錯誤頁面(例如:401, 402, 403, 500…),以便更友好的提示。對於spring mvc,這些當然是支持自定義的,spring是怎麼做的? 還是去看看spring的源碼吧:

原理

DispatcherServlet

眾所周知,springmvc的入口是DispatcherServlet, 在DispatcherServlet的源碼中,不知你是否注意到了以下方法:

protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
        Object handler, Exception ex) throws Exception {

    // Check registered HandlerExceptionResolvers...
    ModelAndView exMv = null;
    for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
        exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
        if (exMv != null) {
            break;
        }
    }
    if (exMv != null) {
        if (exMv.isEmpty()) {
            request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
            return null;
        }
        // We might still need view name translation for a plain error model...
        if (!exMv.hasView()) {
            exMv.setViewName(getDefaultViewName(request));
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
        }
        WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
        return exMv;
    }

    throw ex;
}

這個方法就是springmvc對於異常的處理,其調用了HandlerExceptionResolver的resolveException方法。HandlerExceptionResolver有眾多實現類,其中,重點看看
SimpleMappingExceptionResolver(我們就是要通過它來配置自定義錯誤頁面)。

SimpleMappingExceptionResolver

public class SimpleMappingExceptionResolver extends AbstractHandlerExceptionResolver {
    ...
    private Properties exceptionMappings;

    private Class<?>[] excludedExceptions;

    private Map<String, Integer> statusCodes = new HashMap<String, Integer>();
    ...

    public void setExceptionMappings(Properties mappings) {
        this.exceptionMappings = mappings;
    }

    public void setStatusCodes(Properties statusCodes) {
        for (Enumeration<?> enumeration = statusCodes.propertyNames(); enumeration.hasMoreElements();) {
            String viewName = (String) enumeration.nextElement();
            Integer statusCode = new Integer(statusCodes.getProperty(viewName));
            this.statusCodes.put(viewName, statusCode);
        }
    }

}

@Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response,
        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;
    }
}

protected String determineViewName(Exception ex, HttpServletRequest request) {
    String viewName = null;
    if (this.excludedExceptions != null) {
        for (Class<?> excludedEx : this.excludedExceptions) {
            if (excludedEx.equals(ex.getClass())) {
                return null;
            }
        }
    }
    // Check for specific exception mappings.
    if (this.exceptionMappings != null) {
        viewName = findMatchingViewName(this.exceptionMappings, ex);
    }
    // Return default error view else, if defined.
    if (viewName == null && this.defaultErrorView != null) {
        if (logger.isDebugEnabled()) {
            logger.debug("Resolving to default view '" + this.defaultErrorView + "' for exception of type [" +
                    ex.getClass().getName() + "]");
        }
        viewName = this.defaultErrorView;
    }
    return viewName;
}

protected String findMatchingViewName(Properties exceptionMappings, Exception ex) {
    String viewName = null;
    String dominantMapping = null;
    int deepest = Integer.MAX_VALUE;
    for (Enumeration<?> names = exceptionMappings.propertyNames(); names.hasMoreElements();) {
        String exceptionMapping = (String) names.nextElement();
        int depth = getDepth(exceptionMapping, ex);
        if (depth >= 0 && (depth < deepest || (depth == deepest &&
                dominantMapping != null && exceptionMapping.length() > dominantMapping.length()))) {
            deepest = depth;
            dominantMapping = exceptionMapping;
            viewName = exceptionMappings.getProperty(exceptionMapping);
        }
    }
    if (viewName != null && logger.isDebugEnabled()) {
        logger.debug("Resolving to view '" + viewName + "' for exception of type [" + ex.getClass().getName() +
                "], based on exception mapping [" + dominantMapping + "]");
    }
    return viewName;
}

protected Integer determineStatusCode(HttpServletRequest request, String viewName) {
    if (this.statusCodes.containsKey(viewName)) {
        return this.statusCodes.get(viewName);
    }
    return this.defaultStatusCode;
}

由此可見:

SimpleMappingExceptionResolver通過 exceptionMappings和statusCodes來確立Exception、http狀態碼以及view之間的映射關系。明白這個就很簡單了,我們可以通過設置exceptionMappings、statusCodes的值來實現我們自定義的映射關系。

實戰

頁面准備

  1. 我們在WEB-INF/views/commons/error(目錄自己定)新建我們自定義的錯誤頁面,404.html, 500.html等等。

  2. SimpleMappingExceptionResolver只實現映射關系,我們還需要通過配置web.xml來實現。

    <error-page>
        <error-code>404</error-code>
        <location>/error/404.html</location>
    </error-page>
    
    <error-page>
        <error-code>500</error-code>
        <location>/error/500.html</location>
    </error-page>
    

  3. 在spring-mvc配置文件中將404.html、500.html等設置為資源文件,避免被springmvc再次攔截。

    <mvc:resources mapping="/error/**" location="/WEB-INF/views/commons/error/" />
    
  4. 配置SimpleMappingExceptionResolver。

    <bean class="org.springframework.web.servlet.handler. SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <map>
                <entry key="ResourceNotFoundException" value="common/error/resourceNotFoundError" />
                <entry key=".DataAccessException" value="common/error/dataAccessError" />
            </map>
        </property>
        <property name="statusCodes">
            <map>
                <entry key="common/error/resourceNotFoundError" value="404" />
                <entry key="common/error/dataAccessError" value="500" />
            </map>
        </property>
    </bean>    
    

到此,就實現我們需要的配置了。

SpringMVC+MyBatis集成配置 http://www.linuxidc.com/Linux/2016-09/135212.htm

SpringMVC總結篇 http://www.linuxidc.com/Linux/2016-06/132659.htm

Spring+SpringMVC企業快速開發架構搭建 http://www.linuxidc.com/Linux/2015-09/122942.htm

SpringMVC的亂碼處理 http://www.linuxidc.com/Linux/2015-07/120542.htm

Spring MVC+Spring3+Hibernate4開發環境搭建 http://www.linuxidc.com/Linux/2013-07/87119.htm

Spring MVC整合Freemarker基於注解方式 http://www.linuxidc.com/Linux/2013-02/79660.htm

基於注解的Spring MVC簡單介紹 http://www.linuxidc.com/Linux/2012-02/54896.htm

SpringMVC詳細示例實戰教程 http://www.linuxidc.com/Linux/2015-06/118461.htm

Spring MVC 框架搭建及詳解 http://www.linuxidc.com/Linux/2012-01/52740.htm

SpringMVC 異常處理 http://www.linuxidc.com/Linux/2015-06/119049.htm

SpringMVC框架入門配置 IDEA下搭建Maven項目 http://www.linuxidc.com/Linux/2016-09/134918.htm

Copyright © Linux教程網 All Rights Reserved