SpringMVC異常處理的三種方式小結(jié)
1. 什么是異常
見字如意,就是編碼時所報的錯誤。異常主要分為兩種:編譯時異常和運行時異常RuntimeException。前者在編碼時如不符合規(guī)范代碼就會報紅,是肉眼也看到的錯,后者主要通過規(guī)范代碼開發(fā)、測試通過手段減少運行時異常的發(fā)生。
在Spring MVC中,異常處理是指對在請求處理過程中可能發(fā)生的異常情況進(jìn)行捕獲、處理和響應(yīng)的機制。它能將所有類型的異常處理從各處理過程解耦出來,既保證了相關(guān)處理過程的功能較單一,也實現(xiàn)了異常信息的統(tǒng)一處理和維護(hù)。
2. 為什么要全局異常處理
在開發(fā)中,不管是dao層、service層還是controller層,都有可能拋出異常。使用全局異常處理有以下幾個優(yōu)點:
- 統(tǒng)一的異常處理邏輯:通過全局異常處理,可以將應(yīng)用程序中的異常處理邏輯集中到一個地方,避免在每個具體的業(yè)務(wù)代碼中都編寫相同或類似的異常處理代碼。這樣可以提高代碼的可維護(hù)性,減少代碼冗余,使代碼更加清晰和易于理解。
- 提高系統(tǒng)的容錯性:全局異常處理可以捕獲應(yīng)用程序中的未處理異常,避免異常的傳遞導(dǎo)致應(yīng)用程序崩潰或出現(xiàn)未知錯誤。通過合理地處理異常,可以使系統(tǒng)在出現(xiàn)異常時保持穩(wěn)定并繼續(xù)正常運行,提高系統(tǒng)的容錯性和健壯性。
- 統(tǒng)一的異常返回格式:全局異常處理可以定義統(tǒng)一的異常返回格式,將異常信息以一致的方式返回給客戶端或用戶。這樣可以提供更友好和一致的錯誤提示,改善用戶體驗,并便于客戶端對異常進(jìn)行處理和展示。
- 安全性和安全漏洞的處理:全局異常處理可以捕獲和處理應(yīng)用程序中的安全漏洞或異常情況,例如未授權(quán)訪問、非法操作等。通過適當(dāng)?shù)漠惓L幚?,可以防止一些潛在的安全問題,提高系統(tǒng)的安全性和防護(hù)能力。
- 異常日志記錄和監(jiān)控:全局異常處理可以統(tǒng)一記錄應(yīng)用程序中的異常信息,包括異常類型、發(fā)生位置、請求參數(shù)等,便于后續(xù)的異常分析、故障排查和系統(tǒng)監(jiān)控。通過對異常進(jìn)行有效的記錄和監(jiān)控,可以及時發(fā)現(xiàn)和解決潛在的問題,提高系統(tǒng)的可靠性和穩(wěn)定性。
總的來說,全局異常處理能夠提高系統(tǒng)的可維護(hù)性、容錯性和安全性,提供更好的用戶體驗,方便系統(tǒng)的監(jiān)控和問題排查。在開發(fā)應(yīng)用程序時,合理利用全局異常處理機制可以有效地處理異常情況,保證應(yīng)用程序的穩(wěn)定。
3. SpringMVC異常分類
在Spring MVC中,異??梢苑譃閮深悾?strong>應(yīng)用程序異常和系統(tǒng)異常。
應(yīng)用程序異常:應(yīng)用程序異常是指由應(yīng)用程序自身業(yè)務(wù)邏輯引發(fā)的異常,通常是預(yù)期的異常情況。這些異常可以根據(jù)具體業(yè)務(wù)需求進(jìn)行分類,例如用戶輸入驗證失敗、資源未找到、權(quán)限不足等。應(yīng)用程序異??梢酝ㄟ^自定義異常類來表示,可以添加自定義的異常信息,以便更好地理解異常原因和處理異常。
系統(tǒng)異常:系統(tǒng)異常是指由系統(tǒng)運行環(huán)境或外部因素引發(fā)的異常,通常是非預(yù)期的異常情況。這些異常可能包括數(shù)據(jù)庫連接失敗、網(wǎng)絡(luò)連接異常、服務(wù)器內(nèi)部錯誤等。系統(tǒng)異常是無法通過應(yīng)用程序自身的邏輯來解決的,需要通過合適的異常處理機制來捕獲和處理。
在Spring MVC中,可以通過合理的異常分類和處理機制來對應(yīng)用程序異常和系統(tǒng)異常進(jìn)行區(qū)分和處理。通常,應(yīng)用程序異??梢酝ㄟ^ @ExceptionHandler
注解或自定義的異常處理器來處理,而系統(tǒng)異??梢酝ㄟ^全局異常處理器( HandlerExceptionResolver
接口的實現(xiàn))來捕獲和處理。這樣可以實現(xiàn)對不同類型異常的精細(xì)處理,提高系統(tǒng)的可靠性和用戶體驗。
4. 異常處理思路
系統(tǒng)的dao、service、controller出現(xiàn)異常都通過throws Exception向上拋出,最后由springmvc前端控制器交由異常處理器進(jìn)行異常處理。springmvc提供全局異常處理器(一個系統(tǒng)只有一個異常處理器)進(jìn)行統(tǒng)一異常處理。
- 確定異常處理的范圍和層級:首先,需要確定異常處理的范圍,即異常處理應(yīng)該放在哪個層級。在Spring MVC中,異常處理可以發(fā)生在Controller層、Service層或DAO層,具體取決于你的應(yīng)用架構(gòu)和需求。一般來說,應(yīng)用程序異??梢栽贑ontroller層處理,而系統(tǒng)異??梢栽谌之惓L幚砥髦刑幚?。
- 定義異常類:根據(jù)你的應(yīng)用程序需求,可以定義自定義的異常類來表示不同類型的異常。自定義異常類可以繼承自
Exception
或RuntimeException
,并添加適當(dāng)?shù)膶傩院头椒?,以便更好地描述異常信息。例如,你可以定義一個ValidationException
來表示用戶輸入驗證失敗的異常。 - 異常捕獲和處理:在代碼中,使用
try-catch
塊來捕獲可能發(fā)生的異常,并在catch
塊中進(jìn)行相應(yīng)的處理。對于應(yīng)用程序異常,可以在Controller層的方法中使用@ExceptionHandler
注解來捕獲和處理特定類型的異常。對于系統(tǒng)異常,可以在全局異常處理器中實現(xiàn)HandlerExceptionResolver
接口,并在resolveException
方法中進(jìn)行異常處理邏輯。 - 異常處理邏輯:在異常處理邏輯中,你可以根據(jù)具體的異常類型采取適當(dāng)?shù)奶幚泶胧?。例如,對于?yīng)用程序異常,可以返回特定的錯誤頁面或錯誤信息給用戶,或者記錄異常日志以便后續(xù)分析。對于系統(tǒng)異常,可以返回一個通用的錯誤頁面或錯誤信息,或者進(jìn)行一些系統(tǒng)級的異常處理操作。
- 異常信息傳遞和展示:在異常處理過程中,你可以將異常信息傳遞給前端頁面或其他組件進(jìn)行展示??梢酝ㄟ^
ModelAndView
對象、@ResponseBody
注解或其他方式來傳遞異常信息。在展示異常信息時,可以根據(jù)具體需求進(jìn)行格式化,以便用戶能夠清晰地理解異常原因。 - 單元測試和異常模擬:為了驗證異常處理的正確性,建議編寫相應(yīng)的單元測試,并模擬各種異常情況。通過單元測試,可以確保異常處理邏輯的正確性和穩(wěn)定性。
總結(jié)來說,異常處理的思路是根據(jù)異常類型進(jìn)行分類,確定異常處理的范圍和層級,定義自定義異常類,捕獲和處理異常,并根據(jù)具體情況進(jìn)行異常處理邏輯和異常信息展示。通過合理的異常處理,可以提高系統(tǒng)的可靠性。
5. 三種異常處理方式示例
在演示下面之前我們現(xiàn)在沒有進(jìn)行異常處理事如何報錯的:
1. 隨便在那個方法或者controller手動寫一個錯誤信息
2. 運行該路徑
這就是沒有經(jīng)過任何異常處理的錯誤信息,如果將這個界面回顯給客戶當(dāng)然是不可觀的,請繼續(xù)往下看。
① 配置 SimpleMappingExceptionResolver 處理器
SpringMVC中自帶了一個異常處理器叫SimpleMappingExceptionResolver,該處理器實現(xiàn)了HandlerExceptionResolver 接口,全局異常處理器都需要實現(xiàn)該接口。
1. spring-mvc.xml:
<!-- springmvc提供的簡單異常處理器 --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 定義默認(rèn)的異常處理頁面 --> <property name="defaultErrorView" value="error"/> <!-- 定義異常處理頁面用來獲取異常信息的變量名,也可不定義,默認(rèn)名為exception --> <property name="exceptionAttribute" value="xw"/> <!-- 定義需要特殊處理的異常,這是重要點 --> <property name="exceptionMappings"> <props> <prop key="java.lang.RuntimeException">error</prop> </props> <!-- 還可以定義其他的自定義異常 --> </property> </bean>
注:頁面跳轉(zhuǎn)由SpringMVC來接管了,所以此處的定義默認(rèn)的異常處理頁面都應(yīng)該配置成邏輯視圖名。
2. 創(chuàng)建error.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <%--錯誤信息--%> ${xw}<br> <img src="static/imgs/R.jpg"> </body> </html>
配置異常處理后的界面:
② 實現(xiàn) HandlerExceptionResolver 接口
1. 創(chuàng)建一個名為GlobalException的自定義異常類,它繼承自RuntimeException類。
在Java中,自定義異常類通常需要繼承自Exception類或其子類。RuntimeException是Exception的一個子類,它表示在程序執(zhí)行過程中可能會發(fā)生的異常情況。通過繼承RuntimeException類,GlobalException可以被視為一個非受檢異常(unchecked exception),即在方法簽名中不需要顯式聲明或捕獲。
GlobalException類提供了多個構(gòu)造函數(shù),用于創(chuàng)建不同類型的異常對象。每個構(gòu)造函數(shù)都調(diào)用了父類RuntimeException的相應(yīng)構(gòu)造函數(shù),以便將異常信息傳遞給父類進(jìn)行處理。
package com.ycxw.exception; public class GlobalException extends RuntimeException { public GlobalException() { } public GlobalException(String message) { super(message); } public GlobalException(String message, Throwable cause) { super(message, cause); } public GlobalException(Throwable cause) { super(cause); } public GlobalException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } }
通過提供不同的構(gòu)造函數(shù),GlobalException類可以在不同的情況下創(chuàng)建異常對象,并傳遞相關(guān)的異常信息和原因。
自定義異常類的好處在于可以根據(jù)應(yīng)用程序的需求,定義特定類型的異常,以便更好地描述和處理不同的異常情況。在代碼中,當(dāng)某個方法或操作發(fā)生異常時,可以拋出GlobalException對象,并在上層進(jìn)行相應(yīng)的異常處理邏輯。
2. 定義了一個名為GlobalExceptionHandler的類,并實現(xiàn)了HandlerExceptionResolver接口。同時,使用@Component注解將該類標(biāo)記為一個Spring組件,以便在應(yīng)用程序中進(jìn)行自動掃描和注冊。
@Component public class GlobalExceptionHandler implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { ModelAndView mv = new ModelAndView(); mv.setViewName("error"); if (e instanceof GlobalException){ GlobalException globalException = (GlobalException) e; mv.addObject("xw",globalException.getMessage()); mv.addObject("msg","全局異常...."); }else if (e instanceof RuntimeException){ RuntimeException runtimeException = (RuntimeException) e; mv.addObject("xw",runtimeException.getMessage()); mv.addObject("msg","運行時異常...."); } return mv; } }
- 這段代碼定義了一個名為GlobalExceptionHandler的類,并實現(xiàn)了HandlerExceptionResolver接口。同時,使用@Component注解將該類標(biāo)記為一個Spring組件,以便在應(yīng)用程序中進(jìn)行自動掃描和注冊。
- HandlerExceptionResolver接口是Spring MVC框架提供的用于處理異常的接口。通過實現(xiàn)該接口,可以自定義全局異常處理器,用于捕獲和處理在請求處理過程中產(chǎn)生的異常。
- 在代碼中,resolveException方法是HandlerExceptionResolver接口的一個方法,用于處理異常。它接受HttpServletRequest、HttpServletResponse、Object和Exception等參數(shù),并返回一個ModelAndView對象。
- 在方法內(nèi)部,首先創(chuàng)建了一個空的ModelAndView對象mv。然后,設(shè)置了視圖的名稱為"error",這意味著當(dāng)發(fā)生異常時,將渲染名為"error"的視圖。
- 接下來,通過instanceof判斷異常的類型,進(jìn)行不同的處理邏輯。如果異常是GlobalException類型,將異常信息和自定義的"全局異常...."消息添加到mv對象中。如果異常是RuntimeException類型,將異常信息和"運行時異常...."消息添加到mv對象中。
- 最后,將mv對象返回,以便框架將其渲染并返回給客戶端。
通過實現(xiàn)HandlerExceptionResolver接口并定義resolveException方法,可以自定義全局異常處理邏輯,并在應(yīng)用程序中統(tǒng)一處理異常情況。這樣可以提供更好的用戶體驗,并減少代碼中重復(fù)的異常處理代碼。
利用上一個報錯信息:
3. 拋出一個全局錯誤信息
③ 使用@ControllerAdvice+@ExceptionHandler實現(xiàn)全局異常
定義了一個名為GlobalExceptionResolver的類,并使用@ControllerAdvice注解將其標(biāo)記為一個全局異常處理器。
package com.ycxw.exception; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import java.util.HashMap; import java.util.Map; @ControllerAdvice public class GlobalExceptionResolver { // 返回錯誤json數(shù)據(jù) @ResponseBody @ExceptionHandler public Map handler(Exception e){ Map map = new HashMap(); if (e instanceof GlobalException){ GlobalException globalException = (GlobalException) e; map.put("xw",globalException.getMessage()); map.put("msg","全局異常...."); }else if (e instanceof RuntimeException){ RuntimeException runtimeException = (RuntimeException) e; map.put("xw",runtimeException.getMessage()); map.put("msg","運行時異常...."); }else { map.put("xw",e.getMessage()); map.put("msg","其它異常...."); } return map; } }
- @ControllerAdvice是Spring MVC框架提供的注解,用于定義全局控制器增強。通過使用@ControllerAdvice注解,可以將該類應(yīng)用于所有的控制器中,并提供統(tǒng)一的異常處理邏輯。
- 在代碼中,使用@ResponseBody注解將handler方法標(biāo)記為返回JSON數(shù)據(jù)的方法。@ExceptionHandler注解用于指定該方法處理的異常類型。
- handler方法接受一個Exception類型的參數(shù)e,并返回一個Map對象。在方法內(nèi)部,根據(jù)異常的類型進(jìn)行不同的處理邏輯。
- 如果異常是GlobalException類型,將異常信息和自定義的"全局異常...."消息添加到map對象中。如果異常是RuntimeException類型,將異常信息和"運行時異常...."消息添加到map對象中。如果異常不屬于上述兩種類型,將異常信息和"其它異常...."消息添加到map對象中。
- 最后,將map對象作為JSON數(shù)據(jù)返回給客戶端。
通過使用@ControllerAdvice注解和@ExceptionHandler注解,可以自定義全局異常處理邏輯,并將異常信息以JSON格式返回給客戶端。這樣可以提供更好的錯誤處理和異常信息展示方式。
6. 響應(yīng)封裝類
響應(yīng)封裝類的作用是將響應(yīng)數(shù)據(jù)進(jìn)行統(tǒng)一的封裝和格式化,以便在應(yīng)用程序中進(jìn)行統(tǒng)一的處理和返回給客戶端。
- 通常,在一個應(yīng)用程序中,不同的接口可能返回不同的數(shù)據(jù)結(jié)構(gòu)和格式。這樣會導(dǎo)致客戶端在處理響應(yīng)數(shù)據(jù)時需要編寫大量的重復(fù)代碼來解析和處理不同的響應(yīng)格式,增加了開發(fā)和維護(hù)的復(fù)雜性。
- 為了解決這個問題,可以使用響應(yīng)封裝類來對響應(yīng)數(shù)據(jù)進(jìn)行統(tǒng)一的封裝。響應(yīng)封裝類通常是一個自定義的類,其中包含了與響應(yīng)相關(guān)的信息,如狀態(tài)碼、消息、數(shù)據(jù)等。
- 通過將響應(yīng)數(shù)據(jù)封裝到一個固定的數(shù)據(jù)結(jié)構(gòu)中,可以使得所有的接口返回的響應(yīng)數(shù)據(jù)格式保持一致。這樣客戶端只需要針對統(tǒng)一的響應(yīng)數(shù)據(jù)結(jié)構(gòu)進(jìn)行處理,而不需要關(guān)注不同接口的具體返回格式。
- 響應(yīng)封裝類還可以提供額外的功能,如異常處理、錯誤碼定義、多語言支持等。通過在響應(yīng)封裝類中定義統(tǒng)一的異常處理邏輯,可以捕獲和處理應(yīng)用程序中的異常,并將異常信息封裝到響應(yīng)數(shù)據(jù)中返回給客戶端。同時,可以在響應(yīng)封裝類中定義錯誤碼,并根據(jù)錯誤碼進(jìn)行國際化處理,以支持多語言環(huán)境下的錯誤提示。
總之,響應(yīng)封裝類的作用是提供一個統(tǒng)一的響應(yīng)數(shù)據(jù)格式,簡化客戶端的處理邏輯,提供額外的功能如異常處理和多語言支持,并提高應(yīng)用程序的可維護(hù)性和可擴展性。
例如:
package com.ycxw.utils; import java.util.HashMap; public class R extends HashMap { public R data(String key, Object value) { this.put(key, value); return this; } public static R ok(int code, String msg) { R r = new R(); r.data("success", true).data("code", code).data("msg", msg); return r; } public static R error(int code, String msg) { R r = new R(); r.data("success", false).data("code", code).data("msg", msg); return r; } public static R ok(int code, String msg,Object data) { R r = new R(); r.data("success", true).data("code", code).data("msg", msg).data("data", data); return r; } public static R ok(int code, String msg, long count, Object data) { R r = new R(); r.data("success", true).data("code", code).data("msg", msg).data("count", count).data("data", data); return r; } }
編寫統(tǒng)一響應(yīng)方法:
// 響應(yīng)封裝類 @ResponseBody @ExceptionHandler public R handler(Exception e){ if (e instanceof GlobalException){ GlobalException globalException = (GlobalException) e; return R.ok(505,"全局異常....",globalException.getMessage()); }else if (e instanceof RuntimeException){ RuntimeException runtimeException = (RuntimeException) e; return R.ok(505,"運行時異常....",runtimeException.getMessage()); }else { return R.ok(505,"其他異常....",e.getMessage()); } }
運行測試:
到此這篇關(guān)于SpringMVC異常處理的三種方式小結(jié)的文章就介紹到這了,更多相關(guān)SpringMVC異常處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mybatis注解實現(xiàn)多數(shù)據(jù)源讀寫分離詳解
這篇文章主要給大家介紹了關(guān)于Mybatis注解實現(xiàn)多數(shù)據(jù)源讀寫分離的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Mybatis具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09在SpringBoot中整合使用Netty框架的詳細(xì)教程
這篇文章主要介紹了在SpringBoot中整合使用Netty框架的教程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-06-06基于OAuth2.0授權(quán)系統(tǒng)的驗證碼功能的實現(xiàn)
本篇教程給大家分享基于OAuth2.0授權(quán)系統(tǒng)的驗證碼功能的實現(xiàn),驗證碼功能的實現(xiàn)是采用Zuul網(wǎng)關(guān)的Filter過濾器進(jìn)行校驗驗證碼,具體實現(xiàn)代碼跟隨小編一起看看吧2021-05-05SpringBoot啟動java.nio.charset.MalformedInputException: I
本文主要介紹了SpringBoot啟動java.nio.charset.MalformedInputException: Input length = 1報錯的解決方案2023-07-07Springboot整合Swagger2和Swagger3全過程
這篇文章主要介紹了Springboot整合Swagger2和Swagger3全過程,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07mybatis(mybatis-plus)映射文件(XML文件)中特殊字符轉(zhuǎn)義的實現(xiàn)
XML 文件在解析時會將五種特殊字符進(jìn)行轉(zhuǎn)義,本文主要介紹了mybatis(mybatis-plus)映射文件(XML文件)中特殊字符轉(zhuǎn)義的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2023-12-12