往期推薦html
SpringBoot系列(一)idea新建Springboot項目前端
SpringBoot系列(五)Mybatis整合完整詳細版spring
SpringBoot系列(六)集成thymeleaf詳解版json
Springboot系列(七) 集成接口文檔swagger,使用,測試後端
SpringBoot系列(八)分分鐘學會Springboot多種解決跨域方式跨域
SpringBoot系列(九)單,多文件上傳的正確姿式瀏覽器
目錄
引言:
平常開發過程當中,不免有的程序會由於某些緣由拋出異常,而這些異常通常都是利用try ,catch的方式處理異常或者throw,throws的方式拋出異常無論。這種方法對於程序員來講處理也比較麻煩,對客戶來講也不太友好,因此咱們但願既能方便程序員編寫代碼,不用過多的本身去處理各類異常編寫重複的代碼又能提高用戶的體驗,這時候全局異常處理就顯得很重要也很便捷了,是一種不錯的選擇。
由於如今主流的都是先後端分離的項目,因此咱們的異常處理也根據先後端分離來說述。
Springboot對於異常的處理也作了不錯的支持,它提供了一個 @ControllerAdvice註解以及 @ExceptionHandler註解,前者是用來開啓全局的異常捕獲,後者則是說明捕獲哪些異常,對那些異常進行處理。
@ControllerAdvice public class MyExceptionHandler { @ExceptionHandler(value =Exception.class) public String exceptionHandler(Exception e){ System.out.println("發生了一個異常"+e); return e.getMessage(); } }
上面這段代碼就是說,只要是代碼運行過程當中有異常就會進行捕獲,並輸出出這個異常。而後咱們隨便編寫一個會發生異常的代碼,測試出來的異常是這樣的。
這對於咱們先後端分離來講並很差,先後端分離以後惟一的交互就是json了,咱們也但願將後端的異常變成json返回給前端處理。下面咱們看看統一結果處理。
代碼:
public class Result<T> { //是否成功 private Boolean success; //狀態碼 private Integer code; //提示信息 private String msg; //數據 private T data; public Result() { } //自定義返回結果的構造方法 public Result(Boolean success,Integer code, String msg,T data) { this.success = success; this.code = code; this.msg = msg; this.data = data; } //自定義異常返回的結果 public static Result defineError(DefinitionException de){ Result result = new Result(); result.setSuccess(false); result.setCode(de.getErrorCode()); result.setMsg(de.getErrorMsg()); result.setData(null); return result; } //其餘異常處理方法返回的結果 public static Result otherError(ErrorEnum errorEnum){ Result result = new Result(); result.setMsg(errorEnum.getErrorMsg()); result.setCode(errorEnum.getErrorCode()); result.setSuccess(false); result.setData(null); return result; } }
說明:其中省略了get,set方法。另外方法之中包含了一個自定義的枚舉。代碼以下:
public enum ErrorEnum { // 數據操做錯誤定義 SUCCESS(200, "nice"), NO_PERMISSION(403,"你沒得權限"), NO_AUTH(401,"你能不能先登陸一下"), NOT_FOUND(404, "未找到該資源!"), INTERNAL_SERVER_ERROR(500, "服務器跑路了"), ; /** 錯誤碼 */ private Integer errorCode; /** 錯誤信息 */ private String errorMsg; ErrorEnum(Integer errorCode, String errorMsg) { this.errorCode = errorCode; this.errorMsg = errorMsg; } public Integer getErrorCode() { return errorCode; } public String getErrorMsg() { return errorMsg; } }
說明:枚舉類中定義了常見的錯誤碼以及錯誤的提示信息。這裏咱們就定義好了統一的結果返回,其中裏面的靜態方法是用來當程序異常的時候轉換成異常返回規定的格式。
而後咱們須要自定義異常處理類。代碼以下:
public class DefinitionException extends RuntimeException{ protected Integer errorCode; protected String errorMsg; public DefinitionException(){ } public DefinitionException(Integer errorCode, String errorMsg) { this.errorCode = errorCode; this.errorMsg = errorMsg; } public Integer getErrorCode() { return errorCode; } public void setErrorCode(Integer errorCode) { this.errorCode = errorCode; } public String getErrorMsg() { return errorMsg; } public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } }
其中包含了錯誤的狀態碼,錯誤的提示信息。而後咱們能夠自定義一個全局異常處理類,來處理各類異常,包括本身定義的異常和內部異常。這樣能夠簡化很多代碼,不用本身對每一個異常都使用try,catch的方式來實現。
@ControllerAdvice public class GlobalExceptionHandler { /** * 處理自定義異常 * */ @ExceptionHandler(value = DefinitionException.class) @ResponseBody public Result bizExceptionHandler(DefinitionException e) { return Result.defineError(e); } /** * 處理其餘異常 * */ @ExceptionHandler(value = Exception.class) @ResponseBody public Result exceptionHandler( Exception e) { return Result.otherError(ErrorEnum.INTERNAL_SERVER_ERROR); } }
說明:每一個方法上面加上一個 @ResponseBody的註解,用於將對象解析成json,方便先後端的交互,也可使用 @ResponseBody放在異常類上面。
controller代碼:
@RestController @RequestMapping("/result") public class ResultController { @GetMapping("/getStudent") public Result getStudent(){ Student student = new Student(); student.setAge(21); student.setId(111); student.setName("學習筆記"); Result result = new Result(); result.setCode(200); result.setSuccess(true); result.setData(student); result.setMsg("學生列表信息"); return result; } @RequestMapping("/getDeException") public Result DeException(){ throw new DefinitionException(400,"我出錯了"); } @RequestMapping("/getException") public Result Exception(){ Result result = new Result(); int a=1/0; return result; } }
其中的Student類就是前面一直在用的類了。包含三個屬性。其中省略了get,set方法。
public class Student { /** * 惟一標識id */ private Integer id; /** * 姓名 */ private String name; /** * 年齡 */ private Integer age; }
而後啓動項目,來挨個測試。首先測試正常沒有異常發生的數據。瀏覽器輸入:localhost:8095/result/getStudent
能夠看到數據是正常返回json串。沒有異常。而後咱們測試第二個自定義異常處理接口。瀏覽器輸入localhost:8095/result/getDeException。
能夠看到這個自定義的異常是捕獲到了,而且返回了一個json串。最後咱們測試一下其餘的異常。瀏覽器輸入:localhost:8095/result/getException
到這裏咱們就處理完了異常而且正確的返回了前端。
這裏說一下,測試接口又不少方法,可使用postman,或者idea自帶的接口測試工具都很好用。
可是,你可能會發現一個問題,這種方法是不能處理404異常的,捕獲不到。該怎麼辦呢?
默認狀況下,SpringBoot是不會拋出404異常的,因此@ControllerAdvice也不能捕獲到404異常。咱們能夠經過如下配置來讓這個註解能捕獲到404異常。
spring.mvc.throw-exception-if-no-handler-found=true spring.resources.add-mappings=false
其中第一句是表示:當發現404異常時直接拋出異常。第二句關閉默認的靜態資源路徑映射。這樣404錯誤也能被捕獲到,可是這個配置會讓你的靜態資源訪問出現問題,也就是不適合先後端不分離的狀況。
可是咱們能夠加上以下配置,就能正常訪問靜態資源了。
@Configuration public class ResourceConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { //能夠訪問localhost:8095/static/images/image.jpg registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/"); } }
本文講解了如何處理捕獲全局異常以及怎麼自定義異常,順便說明了統一結果的返回格式,並特殊處理的404,not found的異常,將其做爲統一結果返回。若是你以爲本文有用,點個贊吧!