zoukankan      html  css  js  c++  java
  • (01)Spring MVC之处理异常的两种方式及优先级

      项目开发中异常需要统一处理,总的来说有两种方式,一种是实现HandlerExceptionResolver接口,一种是使用@ExceptionHandler注解的方式。其中Spring已经为我们提供了一个实现了HandlerExceptionResolver接口的类SimpleMappingExceptionResolver,有人把它单独列为一种方式,不过我认为方式越少越好,哈哈哈哈哈,下面记录一下Spring MVC处理异常的这两种方式。

      1、实现HandlerExceptionResolver接口

      1)在spring-context.xml中配置默认的实现类SimpleMappingExceptionResolver

    <!-- 默认处理异常 -->
        <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">  
            <!-- 为所有的异常定义默认的异常处理页面,exceptionMappings未定义的异常使用本默认配置 -->  
            <property name="defaultErrorView" value="page/error/defaultError"/>  
            <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->  
                <property name="exceptionAttribute" value="ex"/>  
            <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常页文件名作为值,将不同的异常映射到不同的页面上。-->  
            <property name="exceptionMappings">  
                   <props>  
                    <prop key="IOException">page/error/ioexp</prop>  
                    <prop key="java.sql.SQLException">page/error/sqlexp</prop>  
                </props>  
            </property>  
        </bean> 

      新建测试类:TestExceptionController.java

    package com.sl.controller;
    
    import java.io.IOException;
    import java.sql.SQLException;
    
    import org.apache.log4j.Logger;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @Controller
    @RequestMapping("/testException")
    public class TestExceptionController {
        
        public static Logger logger=Logger.getLogger(TestExceptionController.class);
        
        @RequestMapping("/iOException")
        @ResponseBody
        public void getException1() throws IOException {
            throw new IOException("测试抛出io异常"); 
        }
        
        @RequestMapping("/sQLException")
        @ResponseBody
        public void getException2() throws SQLException{
            throw new SQLException("测试抛出sql异常");
        }
        
        @RequestMapping("/runtimeException")
        @ResponseBody
        public void getRuntimeException(){
            throw new RuntimeException("测试抛出runtimeException异常");
        }
        
        @RequestMapping("/classNotFoundException")
        @ResponseBody
        public void getClassNotFoundException(){
            try {
                throw new ClassNotFoundException("测试捕获classNotFoundException异常");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

      新建IO异常跳转页面:page/error/ioexp.jsp

    <%@ page language="java" contentType="text/html; charset=GBK" pageEncoding="GBK"%>
    <%@ page import="java.lang.Exception" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=GBK">
    <title>IO异常页面</title>
    </head>
    <body>
    IO异常页面<br>
        <% Exception ex = (Exception)request.getAttribute("ex"); %>
        <H2>Exception: <%= ex.getMessage()%></H2>
        <P/>
        <% ex.printStackTrace(new java.io.PrintWriter(out)); %>
    </body>
    </html>

      新建SQL异常跳转页面:page/error/sqlexp.jsp

    <%@ page language="java" contentType="text/html; charset=GBK" pageEncoding="GBK"%>
    <%@ page import="java.lang.Exception" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=GBK">
    <title>默认异常页面</title>
    </head>
    <body>
    sql异常页面<br>
        <% Exception ex = (Exception)request.getAttribute("ex"); %>
        <H2>Exception: <%= ex.getMessage()%></H2>
        <P/>
        <% ex.printStackTrace(new java.io.PrintWriter(out)); %>
    </body>
    </html>

      新建默认异常跳转页面,没有指定跳转页面的异常跳转到该页面:page/error/defaultError.jsp

    <%@ page language="java" contentType="text/html; charset=GBK" pageEncoding="GBK"%>
    <%@ page import="java.lang.Exception" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=GBK">
    <title>默认异常页面</title>
    </head>
    <body>
    默认异常页面<br>
        <% Exception ex = (Exception)request.getAttribute("ex"); %>
        <H2>Exception: <%= ex.getMessage()%></H2>
        <P/>
        <% ex.printStackTrace(new java.io.PrintWriter(out)); %>
    </body>
    </html>

      测试:http://localhost:8080/spring-web/testException/iOException

       测试:http://localhost:8080/spring-web/testException/sQLException

      测试:http://localhost:8080/spring-web/testException/runtimeException

      测试:http://localhost:8080/spring-web/testException/classNotFoundException,捕获异常,不会跳转页面

      2)自定义实现HandlerExceptionResolver接口

      新建类:CustomExceptionHandler

    package com.core.exception;
    
    import java.io.IOException;
    import java.sql.SQLException;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerExceptionResolver;
    import org.springframework.web.servlet.ModelAndView;
    
    @Component
    public class CustomExceptionHandler implements HandlerExceptionResolver{
    
        @Override  
        public ModelAndView resolveException(HttpServletRequest request,  
                HttpServletResponse response, Object object, Exception exception) {
            
            request.setAttribute("ex",exception);
            if(exception instanceof IOException){
                return new ModelAndView("page/error/ioexp2");  
            }else if(exception instanceof SQLException){  
                return new ModelAndView("page/error/sqlexp2");  
            }
            return new ModelAndView("page/error/defaultError2"); 
        }  
    }

      新建IO异常跳转页面:page/error/ioexp2.jsp,内容一样,“IO异常页面”字样改为“IO异常页面_2”以示区别。

      新建SQL异常跳转页面:page/error/sqlexp2.jsp,内容一样,“sql异常页面”字样改为“sql异常页面_2”以示区别。

      新建默认异常跳转页面:page/error/defaultError2.jsp,内容一样,“默认异常页面”字样改为“默认异常页面_2”以示区别。

      测试:http://localhost:8080/spring-web/testException/iOException

      测试:http://localhost:8080/spring-web/testException/sQLException 

      测试:http://localhost:8080/spring-web/testException/runtimeException

      测试:http://localhost:8080/spring-web/testException/classNotFoundException,捕获异常,不会跳转页面 

      2、使用@ExceptionHandler注解方式

      1)测试在本Controller中抛出异常统一处理

      新建测试类 ExceptionHandlerController.java

    package com.core.exception;
    
    import java.io.IOException;
    import java.sql.SQLException;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @Controller
    @RequestMapping("/test")
    public class ExceptionHandlerController {
        
        @ExceptionHandler(value={Exception.class})  
        public String exp3(Exception ex,HttpServletRequest request) {  
            request.setAttribute("ex", ex);  
            return "page/error/defaultError3";  
        }
    
        @ExceptionHandler(value={IOException.class})  
        public String exp(Exception ex,HttpServletRequest request) {  
            request.setAttribute("ex", ex);  
            return "page/error/ioexp3";  
        }
        
        @ExceptionHandler(value={SQLException.class})  
        public String exp2(Exception ex,HttpServletRequest request) {  
            request.setAttribute("ex", ex);  
            return "page/error/sqlexp3";   
        } 
        
        @RequestMapping("/iOException")
        @ResponseBody
        public void getException1() throws IOException {
            throw new IOException("测试抛出io异常"); 
        }
        
        @RequestMapping("/sQLException")
        @ResponseBody
        public void getException2() throws SQLException{
            throw new SQLException("测试抛出sql异常");
        }
        
        @RequestMapping("/runtimeException")
        @ResponseBody
        public void getRuntimeException(){
            throw new RuntimeException("测试抛出runtimeException异常");
        }
        
        @RequestMapping("/classNotFoundException")
        @ResponseBody
        public void getClassNotFoundException(){
            try {
                throw new ClassNotFoundException("测试捕获classNotFoundException异常");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

      新建IO异常跳转页面:page/error/ioexp3.jsp,内容一样,“IO异常页面”字样改为“IO异常页面_3”以示区别。

      新建SQL异常跳转页面:page/error/sqlexp3.jsp,内容一样,“sql异常页面”字样改为“sql异常页面_3”以示区别。

      新建默认异常跳转页面:page/error/defaultError3.jsp,内容一样,“默认异常页面”字样改为“默认异常页面_3”以示区别。

      测试:http://localhost:8080/spring-web/test/iOException

      测试:http://localhost:8080/spring-web/test/sQLException

      测试:http://localhost:8080/spring-web/test/runtimeException

      测试:http://localhost:8080/spring-web/test/classNotFoundException

      2)测试其它Controller中抛出异常统一处理 

      测试:http://localhost:8080/spring-web/testException/iOException ,发现统一异常处理没起作用

      如果用注解的方式处理全局的异常,需要在处理异常所在的Controller上添加注解@ControllerAdvice

      下面修改 ExceptionHandlerController.java,添加注解@ControllerAdvice

    @ControllerAdvice
    @Controller
    @RequestMapping("/test")
    public class ExceptionHandlerController
    ... ...

      测试外部Controller抛出的异常:http://localhost:8080/spring-web/testException/iOException

      测试内部Controller抛出的异常:http://localhost:8080/spring-web/test/iOException

      3、测试异常优先级

      新增加一种处理异常页面跳转的方式,在web.xml里面配置异常与页面跳转的关系,如下:

        <!-- 没有全局异常处理的,则跳到该页面,页面不要放在WEB-INF下,否则无法访问到 -->
          <error-page>
            <error-code>500</error-code>
            <location>/500.jsp</location>
        </error-page>
        <error-page> 
              <exception-type>java.lang.Throwable</exception-type> 
              <location>/500.jsp</location> 
        </error-page> 
        <error-page> 
              <error-code>404</error-code> 
              <location>/404.jsp</location> 
        </error-page> 

      新建页面:src/main/webapp/404.jsp

    <%@ page language="java" contentType="text/html; charset=GBK" pageEncoding="GBK"%>
    <%@ page import="java.lang.Exception" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=GBK">
    <title>404异常页面</title>
    </head>
    <body>
        <H2>这是404异常页面</H2>
    </body>
    </html>

      新建页面:src/main/webapp/500.jsp

    <%@ page language="java" contentType="text/html; charset=GBK" pageEncoding="GBK"%>
    <%@ page import="java.lang.Exception" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=GBK">
    <title>500异常页面</title>
    </head>
    <body>
        <H2>这是500异常页面</H2>
    </body>
    </html>

      下面测试一下这几种异常跳转页面的优先级,我们细分了5种:

      a、配置了SimpleMappingExceptionResolver

      b、自定义了HandlerExceptionResolver的实现类CustomExceptionHandler

      c、新建类ExceptionHandlerController,使用注解@ExceptionHandler处理该类的内部异常

      d、新建类ExceptionHandlerController,使用注解@ExceptionHandler和@ControllerAdvice处理所有类的异常

      e、web.xml中配置异常码或异常类与错误页面的关系

      下面开始测试:

      首先找满足5种情况的测试:http://localhost:8080/spring-web/test/iOException,进入到io异常页面_3,可见内部加注解方式优先级最高。

      然后找除了上面的一种,只满足4条的测试:http://localhost:8080/spring-web/testException/iOException,外部全局注解的方式第2

      然后找除了上面的两种,只满足3条的测试,去掉ExceptionHandlerController的@ControllerAdvice注解,执行下面的测试

      http://localhost:8080/spring-web/testException/iOException ,进入到IO异常页面_2,可见自定义异常实现接口第3。

      然后找除了上面的三种,只满足2条的测试,去掉自定义异常CustomExceptionHandler的注解@Component,执行下面的测试,

      http://localhost:8080/spring-web/testException/iOException ,进入到IO异常页面,可见SimpleMappingExceptionResolver第4。

      然后找除了上面的四种,只满足1条的测试,去掉spring-context.xml中配置的异常SimpleMappingExceptionResolver,执行下面的测试,

      http://localhost:8080/spring-web/testException/iOException ,进入到500页面,可见web.xml中的配置第5。

      最后,去掉web.xml中的配置,再次测试http://localhost:8080/spring-web/testException/iOException,出现了tomcat经典500异常界面:

      综上所述:

      使用@ExceptionHandler处理本Controller内部异常优先级最高;

      使用@ExceptionHandler+@ControllerAdvice处理外部Controller异常优先级第二; 

      自定义了实现了HandlerExceptionResolver接口的类优先级第三;

      spring-context.xml中配置SimpleMappingExceptionResolver优先级第四;

      web.xml配置error-page优先级第五;

      不做任何处理,会跳转到tomcat默认的异常页面;

      

       

  • 相关阅读:
    反转链表
    《Java JDK7 学习笔记》课后练习题1
    《Java JDK7 学习笔记》课后练习题2
    《java JDK7 学习笔记》课后练习题3
    SQL与NoSQL(关系型与非关系型)数据库的区别
    编程中编码的来源及发展
    JDK7学习笔记之基础类型
    《java JDK7学习笔记》之跨平台与路径设置
    《java jdk7学习笔记》之java三大平台
    VS2015安装之后加装SQL SERVER2014的步骤
  • 原文地址:https://www.cnblogs.com/javasl/p/12666555.html
Copyright © 2011-2022 走看看