1. 程式人生 > >springMVC的幾種異常處理方式

springMVC的幾種異常處理方式

1.web.xml中異常處理

通常為了給使用者提供良好的人機介面,我們都會為整個web應用,提供處理異常或者 錯誤的通用頁面,而這些通用頁面需要在web.xml中進行配置。
主要是兩種方式:其一根據HTTP響應狀態碼;其二是根據異常類名進行配置。

<error-page> 
     <exception-type>完整的異常類名</exception-type> 
     <location>以”/”開頭的異常處理頁面路徑</location> 
  </error-page> 
  <error-page> 
     <error-code>HTTP響應狀態碼</error-code> 
     <location>以”/”開頭的異常處理頁面路徑</location> 
  </error-page> 

專案案例:

@Controller
@RequestMapping(value="/exception")
public class TestException {

	@RequestMapping("/exception/{id}")
    @ResponseBody
    public Object hello(@PathVariable String id)  {

        if (id.equals("1")) {//NullPointerException控制值異常
            throw new NullPointerException("空指標異常");
        } else if (id.equals("2")) {//數學運算異常
            int value = 1 / 0;
            return "java.lang.ArithmeticException";
        } else {
            return "ok";
        }
    }

在這裡插入圖片描述
錯誤展示頁面和頁面對應錯誤資訊
error_web_404.jsp :對應404錯誤
error_web_null.jsp :對應空指標異常
error_spring_404.jsp :對應404錯誤
error_spring_null.jsp :對應空指標異常

如下圖程式碼,相應的錯誤資訊指向對應的錯誤提示頁面

	<!-- 異常處理 -->
	<!-- 接收空指標錯誤 -->
	<error-page>
		<exception-type>java.lang.NullPointerException</exception-type>
		<location>/WEB-INF/views/commons/error/error_web_null.jsp</location>
	</error-page>
	<!-- 404 頁面不存在錯誤 -->
	<error-page>
		<error-code>404</error-code>
		<location>/WEB-INF/views/commons/error/error_web_404.jsp</location>
	</error-page>
	<!-- 接收405錯誤 -->
	<error-page>
		<error-code>405</error-code>
		<location>/WEB-INF/views/commons/error/error405.jsp</location>
	</error-page>
	<!--  500 伺服器內部錯誤 -->
	<error-page>
		<error-code>500</error-code>
		<location>/WEB-INF/views/commons/error/error500.jsp</location>
	</error-page>

結果分析:web.xml中接收到空指標異常,指向error_web_null.jsp頁面

嚴重: Servlet.service() for servlet [spring] in context with path [/maven-springmvc-spring-springjdbc] threw exception [Request processing failed; nested exception is java.lang.ArithmeticException: / by zero] with root cause
java.lang.ArithmeticException: / by zero
at com.controller.test.exception.TestException.hello(TestException.java:28)

結果分析:頁面未跳轉到任何錯誤提示頁面,這是因為我們沒有在web.xml中配置ava.lang.ArithmeticException相關錯誤的異常處理介面

備註:在web.xml中配置的異常處理資訊,使用error-page節點。

2.在springmvc上配置全域性異常(配置檔案的方式)

在spring-servlet.xml(springmvc的配置檔案)中配置

 <!-- Spring MVC提供的簡單異常處理器SimpleMappingExceptionResolver-全域性異常配置 start -->     
      <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
       <!--   預設的錯誤資訊頁面 -->
        <property name="defaultErrorView" value="error"/>
        <property name="exceptionMappings">
            <props>
                <prop key="java.lang.NullPointerException">commons/error/error_spring_null</prop>
                <prop key="java.lang.ArithmeticException">commons/error/error_spring_math</prop>
            </props>
        </property>
    </bean>   
     <!-- 全域性異常配置 end -->     

TestException .java 異常測試類

@Controller
@RequestMapping(value="/exception")
public class TestException {

	@RequestMapping("/exception/{id}")
    @ResponseBody
    public Object hello(@PathVariable String id)  {

        if (id.equals("1")) {//NullPointerException控制值異常
            throw new NullPointerException("空指標異常");
        } else if (id.equals("2")) {//數學運算異常
            int value = 1 / 0;
            return "java.lang.ArithmeticException";
        } else {
            return "ok";
        }
    }

在這裡插入圖片描述
錯誤展示頁面和頁面對應錯誤資訊
error.jsp :預設異常處理頁面
error_spring_404.jsp :對應404錯誤
error_spring_null.jsp :對應空指標異常

總結點
如果同時使用web.xml和spring-servlet.xml配置同樣的異常,會出現什麼結果,web.xml 和spring-servlet.xml配置會不會衝突?

這涉及到web.xml中元素的載入順序
元素節點的載入順序與它們在 web.xml 檔案中的先後順序無關,通常是
ServletContext -> listener -> filter -> servlet---->------>error-page
web.xml中部分程式碼段

	<!-- springmvc -->
	<servlet>
		<servlet-name>spring</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!-- 自定義spring mvc的配置檔名稱和路徑 -->
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:springMVC/spring-servlet.xml</param-value>
		</init-param>
		<!-- 自定義啟動順序,讓這個Servlet隨Servlet容器一起啟動 -->
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>spring</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
		<!-- 異常處理 -->
	<!-- 接收空指標錯誤 -->
	<error-page>
		<exception-type>java.lang.NullPointerException</exception-type>
		<location>/WEB-INF/views/commons/error/error_web_null.jsp</location>
	</error-page>
	<!-- 404 頁面不存在錯誤 -->
	<error-page>
		<error-code>404</error-code>
		<location>/WEB-INF/views/commons/error/error_web_404.jsp</location>
	</error-page>
	<!-- 接收405錯誤 -->
	<error-page>
		<error-code>405</error-code>
		<location>/WEB-INF/views/commons/error/error405.jsp</location>
	</error-page>
	<!--  500 伺服器內部錯誤 -->
	<error-page>
		<error-code>500</error-code>
		<location>/WEB-INF/views/commons/error/error500.jsp</location>
	</error-page>

結果顯而易見,spring-servlet.xml的載入順序比error-page的快,異常會當有相同配置的錯誤時,會優先spring-servlet.xml中配置。只有當spring-servlet.xml沒有處理的錯誤異常,才會在web.xml的error-page節點中查詢對應異常。

spring-servlet.xml採用配置檔案的方式的缺點:配置檔案可以根據丟擲的異常類的類資訊配置錯誤的頁面。但是這樣我們無法手動對其定製異常。
故出現第三種方式

3.第三種方式採用自定義異常類,定製異常集中處理

ExceptionUtil .java 自定義的異常處理類

//自己手動編寫Java程式碼來實現定製異常資訊處理
package com.util.exception;
/**
 * 所屬類別:工具類
 * 用途:自定義的異常類
 * @author yilei
 * version:1.0
 */
public class ExceptionUtil extends RuntimeException {
	public ExceptionUtil(String string) {
		super(string);
	}

}


在spring-servlet.xml ,相比於第二種方法多了com.util.exception.ExceptionUtil,可以配置自定義異常處理類進行接收異常

     <!-- Spring MVC提供的簡單異常處理器SimpleMappingExceptionResolver-全域性異常配置 start -->     
      <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
       <!--  預設的錯誤資訊頁面-->
        <property name="defaultErrorView" value=">commons/error/error"/>
        <property name="exceptionMappings">
            <props>
                <!-- 自定義的異常類 -->
                <prop key="com.util.exception.ExceptionUtil">commons/error/error_spring_ExceptionUtil</prop> 
                <!-- 空指標異常 -->
                <prop key="java.lang.NullPointerException">commons/error/error_spring_null</prop>
                <!-- 數學算術異常 -->
                <prop key="java.lang.ArithmeticException">commons/error/error_spring_math</prop>
            </props>
        </property>
    </bean>    
     <!-- 全域性異常配置 end -->   

error_spring_ExceptionUtil.jsp 自定義異常處理jsp頁面

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
error_spring_ExceptionUtil.jsp<br>
spirngmvc配置異常-自定義異常
</body>
</html>

TestException.java 進行異常測試的類,throw new ExceptionUtil(“自定義有異常”);這段程式碼用於丟擲自定義異常類,springmvc中配置自動跳轉到commons/error/error_spring_ExceptionUtil頁面

package com.controller.test.exception;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.util.exception.ExceptionUtil;

@Controller
@RequestMapping(value = "/exception")
public class TestException   {

	@RequestMapping("/exception/{id}")
	@ResponseBody
	public Object hello(@PathVariable String id) {
        if(id.equals("0")){
        	 throw new ExceptionUtil("自定義有異常");
        }else if (id.equals("1")) {// NullPointerException控制值異常
			throw new NullPointerException("空指標異常");
		} else if (id.equals("2")) {// 數學運算異常
			int value = 1 / 0;
			return "java.lang.ArithmeticException";
		} else {
			return "ok";
		}
	}
}

4.第四種方式去實現自定義異常處理(基於註解的方式)

ExceptionUtil .java 自定義的異常處理類

//自己手動編寫Java程式碼來實現定製異常資訊處理
package com.util.exception;
/**
 * 所屬類別:工具類
 * 用途:自定義的異常類
 * @author yilei
 * version:1.0
 */
public class ExceptionUtil extends RuntimeException {
	public ExceptionUtil(String string) {
		super(string);
	}

}


TestException.java 異常測試類,使用註解ExceptionHandler來標識,在每個需要使用此異常處理的類中新增handleLocalException方法,在使用 throw new ExceptionUtil(“自定義有異常”);程式碼時候,就算同時配置上面第三種方法來自定義了異常處理介面,但是也不會生效,而是由方法handleLocalException中決定異常處理結果,本類中最終有error.jsp頁面來進行異常顯示。

package com.controller.test.exception;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.util.exception.ExceptionUtil;

@Controller
@RequestMapping(value = "/exception")
public class TestException   {

	@RequestMapping("/exception/{id}")
	@ResponseBody
	public Object hello(@PathVariable String id) {
        if(id.equals("0")){
        	 throw new ExceptionUtil("自定義有異常");
        }else if (id.equals("1")) {// NullPointerException控制值異常
			throw new NullPointerException("空指標異常");
		} else if (id.equals("2")) {// 數學運算異常
			int value = 1 / 0;
			return "java.lang.ArithmeticException";
		} else {
			return "ok";
		}
	}
	
    //異常處理,基於註解的方式,但是需要進行自定義異常的類中都寫一個相同的方法才可生效。如果使用這種方式。
    @ExceptionHandler(value={ExceptionUtil.class})
    public String handleLocalException(ExceptionUtil e, HttpServletRequest req){
        req.setAttribute("error", e);
        return "error/error";
    }

}

error.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="sf" %>
<!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=utf-8">
<title>
    異常丟擲處理
</title>
</head>
<body>
    <h1>${error.message}</h1>
</body>
</html>

**

總結

**
第一種web.xml配置和第二種基於springmvc中配置的方式是最常見的異常處理方法,通常專案中是結合一起使用

第三種和第四中方式主要是為了定製異常,為了滿足專案上一些特殊需求,
相對第四種方式,更建議採用第三種的方式來自定義異常處理,主要是因為第四種(採用註解的方式),需要在每個使用了自定義異常類中都需要類似以下程式碼的方法來處理異常,對程式來說比較冗餘。

    //異常處理,基於註解的方式,但是需要進行自定義異常的類中都寫一個相同的方法才可生效。如果使用這種方式。
    @ExceptionHandler(value={ExceptionUtil.class})
    public String handleLocalException(ExceptionUtil e, HttpServletRequest req){
        req.setAttribute("error", e);
        return "error/error";
    }

而第三種,在第二種方法的基礎上,實現全域性的配置,更便捷,因此,如果需要使用自定義異常的話,建議使用第三種方式,同時第一種和第二種相結合。