自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Spring Boot全局異常處理,這樣寫才優(yōu)雅...

開發(fā) 后端
本篇文章主要介紹的是 Spring Boot 項目進行全局異常的處理。

SpringBoot全局異常準備

說明:如果想直接獲取工程那么可以直接跳到底部,通過鏈接下載工程代碼。

開發(fā)準備

環(huán)境要求:

JDK:1.8

SpringBoot:1.5.17.RELEASE

首先還是Maven的相關依賴: 

  1. <properties>  
  2.       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
  3.       <java.version>1.8</java.version>  
  4.       <maven.compiler.source>1.8</maven.compiler.source>  
  5.       <maven.compiler.target>1.8</maven.compiler.target>  
  6. </properties>  
  7. <parent>  
  8.     <groupId>org.springframework.boot</groupId>  
  9.     <artifactId>spring-boot-starter-parent</artifactId>  
  10.     <version>1.5.17.RELEASE</version>  
  11.     <relativePath />  
  12. </parent>  
  13. <dependencies>  
  14.     <!-- Spring Boot Web 依賴 核心 -->  
  15.     <dependency>  
  16.         <groupId>org.springframework.boot</groupId>  
  17.         <artifactId>spring-boot-starter-web</artifactId>  
  18.     </dependency>  
  19.     <!-- Spring Boot Test 依賴 -->  
  20.     <dependency>  
  21.         <groupId>org.springframework.boot</groupId>  
  22.         <artifactId>spring-boot-starter-test</artifactId>  
  23.         <scope>test</scope>  
  24.     </dependency>  
  25.     <dependency>  
  26.         <groupId>com.alibaba</groupId>  
  27.         <artifactId>fastjson</artifactId>  
  28.         <version>1.2.41</version>  
  29.     </dependency>  
  30. </dependencies> 

配置文件這塊基本不需要更改,全局異常的處理只需在代碼中實現(xiàn)即可。

代碼編寫

SpringBoot的項目已經對有一定的異常處理了,但是對于我們開發(fā)者而言可能就不太合適了,因此我們需要對這些異常進行統(tǒng)一的捕獲并處理。

SpringBoot中有一個ControllerAdvice的注解,使用該注解表示開啟了全局異常的捕獲,我們只需在自定義一個方法使用ExceptionHandler注解然后定義捕獲異常的類型即可對這些捕獲的異常進行統(tǒng)一的處理。

我們根據下面的這個示例來看該注解是如何使用吧。Spring Boot 基礎就不介紹了,看睛這個:https://github.com/javastacks/spring-boot-best-practice

示例代碼: 

  1. @ControllerAdvice  
  2. public class MyExceptionHandler {  
  3.  @ExceptionHandler(value =Exception.class)  
  4.  public String exceptionHandler(Exception e){  
  5.   System.out.println("未知異常!原因是:"+e);  
  6.         return e.getMessage();  
  7.     }  

上述的示例中,我們對捕獲的異常進行簡單的二次處理,返回異常的信息,雖然這種能夠讓我們知道異常的原因,但是在很多的情況下來說,可能還是不夠人性化,不符合我們的要求。

那么我們這里可以通過自定義的異常類以及枚舉類來實現(xiàn)我們想要的那種數(shù)據吧。

自定義基礎接口類

首先定義一個基礎的接口類,自定義的錯誤描述枚舉類需實現(xiàn)該接口。

代碼如下: 

  1. public interface BaseErrorInfoInterface {  
  2.   /** 錯誤碼*/  
  3.   String getResultCode();  
  4.  /** 錯誤描述*/  
  5.   String getResultMsg();  

自定義枚舉類

然后我們這里在自定義一個枚舉類,并實現(xiàn)該接口。

代碼如下: 

  1. public enum CommonEnum implements BaseErrorInfoInterface {  
  2.  // 數(shù)據操作錯誤定義  
  3.  SUCCESS("200", "成功!"),   
  4.  BODY_NOT_MATCH("400","請求的數(shù)據格式不符!"),  
  5.  SIGNATURE_NOT_MATCH("401","請求的數(shù)字簽名不匹配!"),  
  6.  NOT_FOUND("404", "未找到該資源!"),   
  7.  INTERNAL_SERVER_ERROR("500", "服務器內部錯誤!"),  
  8.  SERVER_BUSY("503","服務器正忙,請稍后再試!")  
  9.  ;  
  10.  /** 錯誤碼 */  
  11.  private String resultCode;  
  12.  /** 錯誤描述 */  
  13.  private String resultMsg;  
  14.  CommonEnum(String resultCode, String resultMsg) {  
  15.   this.resultCode = resultCode;  
  16.   this.resultMsg = resultMsg;  
  17.  }  
  18.  @Override  
  19.  public String getResultCode() {  
  20.   return resultCode;  
  21.  }  
  22.  @Override  
  23.  public String getResultMsg() {  
  24.   return resultMsg; 
  25.   

自定義異常類

然后我們在來自定義一個異常類,用于處理我們發(fā)生的業(yè)務異常。

代碼如下: 

  1. public class BizException extends RuntimeException {  
  2.  private static final long serialVersionUID = 1L 
  3.  /**  
  4.   * 錯誤碼  
  5.   */  
  6.  protected String errorCode;  
  7.  /**  
  8.   * 錯誤信息  
  9.   */  
  10.  protected String errorMsg;  
  11.  public BizException() {  
  12.   super();  
  13.  }  
  14.  public BizException(BaseErrorInfoInterface errorInfoInterface) {  
  15.   super(errorInfoInterface.getResultCode());  
  16.   this.errorCode = errorInfoInterface.getResultCode();  
  17.   this.errorMsg = errorInfoInterface.getResultMsg();  
  18.  }  
  19.  public BizException(BaseErrorInfoInterface errorInfoInterface, Throwable cause) {  
  20.   super(errorInfoInterface.getResultCode(), cause);  
  21.   this.errorCode = errorInfoInterface.getResultCode();  
  22.   this.errorMsg = errorInfoInterface.getResultMsg();  
  23.  }  
  24.  public BizException(String errorMsg) {  
  25.   super(errorMsg);  
  26.   this.errorMsg = errorMsg;  
  27.  }  
  28.  public BizException(String errorCode, String errorMsg) {  
  29.   super(errorCode);  
  30.   this.errorCode = errorCode;  
  31.   this.errorMsg = errorMsg;  
  32.  }  
  33.  public BizException(String errorCode, String errorMsg, Throwable cause) {  
  34.   super(errorCode, cause);  
  35.   this.errorCode = errorCode;  
  36.   this.errorMsg = errorMsg;  
  37.  }   
  38.  public String getErrorCode() {  
  39.   return errorCode;  
  40.  }  
  41.  public void setErrorCode(String errorCode) {  
  42.   this.errorCode = errorCode;  
  43.  }  
  44.  public String getErrorMsg() {  
  45.   return errorMsg;  
  46.  }  
  47.  public void setErrorMsg(String errorMsg) {  
  48.   this.errorMsg = errorMsg;  
  49.  }  
  50.  public String getMessage() {  
  51.   return errorMsg;  
  52.  }  
  53.  @Override  
  54.  public Throwable fillInStackTrace() {  
  55.   return this; 
  56.  }  

自定義數(shù)據格式

順便這里我們定義一下數(shù)據的傳輸格式。

代碼如下: 

  1. public class ResultBody {  
  2.  /**  
  3.   * 響應代碼  
  4.   */  
  5.  private String code;  
  6.  /**  
  7.   * 響應消息  
  8.   */  
  9.  private String message;  
  10.  /** 
  11.   * 響應結果  
  12.   */  
  13.  private Object result;  
  14.  public ResultBody() {  
  15.  }  
  16.  public ResultBody(BaseErrorInfoInterface errorInfo) {  
  17.   this.code = errorInfo.getResultCode();  
  18.   this.message = errorInfo.getResultMsg();  
  19.  }  
  20.  public String getCode() {  
  21.   return code; 
  22.  }  
  23.  public void setCode(String code) {  
  24.   this.code = code;  
  25.  }  
  26.  public String getMessage() {  
  27.   return message; 
  28.  }  
  29.  public void setMessage(String message) {  
  30.   this.message = message;  
  31.  }  
  32.  public Object getResult() { 
  33.   return result; 
  34.  }  
  35.  public void setResult(Object result) {  
  36.   this.result = result;  
  37.  }  
  38.  /**  
  39.   * 成功  
  40.   *   
  41.   * @return  
  42.   */  
  43.  public static ResultBody success() {  
  44.   return success(null);  
  45.  }  
  46.  /**  
  47.   * 成功  
  48.   * @param data  
  49.   * @return  
  50.   */  
  51.  public static ResultBody success(Object data) {  
  52.   ResultBody rb = new ResultBody();  
  53.   rb.setCode(CommonEnum.SUCCESS.getResultCode());  
  54.   rb.setMessage(CommonEnum.SUCCESS.getResultMsg());  
  55.   rb.setResult(data);  
  56.   return rb;  
  57.  }  
  58.  /**  
  59.   * 失敗  
  60.   */  
  61.  public static ResultBody error(BaseErrorInfoInterface errorInfo) {  
  62.   ResultBody rb = new ResultBody();  
  63.   rb.setCode(errorInfo.getResultCode());  
  64.   rb.setMessage(errorInfo.getResultMsg());  
  65.   rb.setResult(null);  
  66.   return rb;  
  67.  }  
  68.  /**  
  69.   * 失敗  
  70.   */  
  71.  public static ResultBody error(String code, String message) {  
  72.   ResultBody rb = new ResultBody();  
  73.   rb.setCode(code);  
  74.   rb.setMessage(message);  
  75.   rb.setResult(null);  
  76.   return rb;  
  77.  }  
  78.  /**  
  79.   * 失敗  
  80.   */  
  81.  public static ResultBody error( String message) {  
  82.   ResultBody rb = new ResultBody();  
  83.   rb.setCode("-1");  
  84.   rb.setMessage(message);  
  85.   rb.setResult(null);  
  86.   return rb;  
  87.  }  
  88.  @Override  
  89.  public String toString() {  
  90.   return JSONObject.toJSONString(this);  
  91.  }  

自定義全局異常處理類

最后我們在來編寫一個自定義全局異常處理的類。

代碼如下: 

  1. @ControllerAdvice  
  2. public class GlobalExceptionHandler {  
  3.  private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);   
  4.  /**  
  5.   * 處理自定義的業(yè)務異常  
  6.   * @param req  
  7.   * @param e  
  8.   * @return  
  9.   */  
  10.     @ExceptionHandler(value = BizException.class)   
  11.     @ResponseBody    
  12.  public  ResultBody bizExceptionHandler(HttpServletRequest req, BizException e){  
  13.      logger.error("發(fā)生業(yè)務異常!原因是:{}",e.getErrorMsg());  
  14.      return ResultBody.error(e.getErrorCode(),e.getErrorMsg());  
  15.     }  
  16.  /**  
  17.   * 處理空指針的異常  
  18.   * @param req  
  19.   * @param e  
  20.   * @return  
  21.   */  
  22.  @ExceptionHandler(value =NullPointerException.class)  
  23.  @ResponseBody 
  24.  public ResultBody exceptionHandler(HttpServletRequest req, NullPointerException e){  
  25.   logger.error("發(fā)生空指針異常!原因是:",e); 
  26.   return ResultBody.error(CommonEnum.BODY_NOT_MATCH);  
  27.  }  
  28.     /**  
  29.         * 處理其他異常  
  30.      * @param req  
  31.      * @param e  
  32.      * @return  
  33.      */  
  34.     @ExceptionHandler(value =Exception.class)  
  35.  @ResponseBody  
  36.  public ResultBody exceptionHandler(HttpServletRequest req, Exception e){  
  37.      logger.error("未知異常!原因是:",e);  
  38.         return ResultBody.error(CommonEnum.INTERNAL_SERVER_ERROR);  
  39.     }  

因為這里我們只是用于做全局異常處理的功能實現(xiàn)以及測試,所以這里我們只需在添加一個實體類和一個控制層類即可。

實體類

又是萬能的用戶表 (▽)

代碼如下: 

  1. public class User implements Serializable{  
  2.  private static final long serialVersionUID = 1L 
  3.  /** 編號 */  
  4.   private int id;  
  5.   /** 姓名 */  
  6.   private String name;  
  7.   /** 年齡 */  
  8.   private int age;   
  9.   public User(){  
  10.   }  
  11.  public int getId() {  
  12.   return id;  
  13.  }   
  14.  public void setId(int id) {  
  15.   this.id = id;  
  16.  }  
  17.  public String getName() {  
  18.   return name;  
  19.  } 
  20.  public void setName(String name) {  
  21.   this.name = name;  
  22.  } 
  23.  public int getAge() {  
  24.   return age;  
  25.  } 
  26.  public void setAge(int age) {  
  27.   this.age = age;  
  28.  }  
  29.  public String toString() {  
  30.   return JSONObject.toJSONString(this);  
  31.  }  

Controller 控制層

控制層這邊也比較簡單,使用Restful風格實現(xiàn)的CRUD功能,不同的是這里我故意弄出了一些異常,好讓這些異常被捕獲到然后處理。這些異常中,有自定義的異常拋出,也有空指針的異常拋出,當然也有不可預知的異常拋出(這里我用類型轉換異常代替),那么我們在完成代碼編寫之后,看看這些異常是否能夠被捕獲處理成功吧!

代碼如下: 

  1. @RestController  
  2. @RequestMapping(value = "/api" 
  3. public class UserRestController {  
  4.  @PostMapping("/user")  
  5.     public boolean insert(@RequestBody User user) {  
  6.      System.out.println("開始新增...");  
  7.      //如果姓名為空就手動拋出一個自定義的異常!  
  8.         if(user.getName()==null){  
  9.             throw  new BizException("-1","用戶姓名不能為空!");  
  10.         }  
  11.         return true;  
  12.     }  
  13.     @PutMapping("/user")  
  14.     public boolean update(@RequestBody User user) {  
  15.      System.out.println("開始更新...");  
  16.        //這里故意造成一個空指針的異常,并且不進行處理  
  17.         String str=null 
  18.         str.equals("111");  
  19.         return true;  
  20.     }  
  21.     @DeleteMapping("/user")  
  22.     public boolean delete(@RequestBody User user)  {  
  23.         System.out.println("開始刪除...");  
  24.         //這里故意造成一個異常,并且不進行處理  
  25.         Integer.parseInt("abc123");  
  26.         return true;  
  27.     }  
  28.     @GetMapping("/user")  
  29.     public List<User> findByUser(User user) {  
  30.      System.out.println("開始查詢...");  
  31.         List<User> userList =new ArrayList<>();  
  32.         User user2=new User();  
  33.         user2.setId(1L);  
  34.         user2.setName("xuwujing"); 
  35.         user2.setAge(18);  
  36.         userList.add(user2);  
  37.         return userList;  
  38.     }  

App 入口

和普通的SpringBoot項目基本一樣。

代碼如下: 

  1. @SpringBootApplication  
  2. public class App  
  3.  
  4.     public static void main( String[] args )  
  5.     {  
  6.       SpringApplication.run(App.class, args);  
  7.       System.out.println("程序正在運行...");  
  8.     }  

功能測試

我們成功啟動該程序之后,使用Postman工具來進行接口測試。

首先進行查詢,查看程序正常運行是否ok,使用GET 方式進行請求。

GET http://localhost:8181/api/user

返回參數(shù)為:

{"id":1,"name":"xuwujing","age":18}

示例圖:

可以看到程序正常返回,并沒有因自定義的全局異常而影響。

然后我們再來測試下自定義的異常是否能夠被正確的捕獲并處理。

使用POST方式進行請求

POST http://localhost:8181/api/user

Body參數(shù)為:

{"id":1,"age":18}

返回參數(shù)為:

{"code":"-1","message":"用戶姓名不能為空!","result":null}

示例圖:

可以看出將我們拋出的異常進行數(shù)據封裝,然后將異常返回出來。

然后我們再來測試下空指針異常是否能夠被正確的捕獲并處理。在自定義全局異常中,我們除了定義空指針的異常處理,也定義最高級別之一的Exception異常,那么這里發(fā)生了空指針異常之后,它是回優(yōu)先使用哪一個呢?這里我們來測試下。

使用PUT方式進行請求。

PUT http://localhost:8181/api/user

Body參數(shù)為:

{"id":1,"age":18}

返回參數(shù)為:

{"code":"400","message":"請求的數(shù)據格式不符!","result":null}

示例圖:

我們可以看到這里的的確是返回空指針的異常護理,可以得出全局異常處理優(yōu)先處理子類的異常。

那么我們在來試試未指定其異常的處理,看該異常是否能夠被捕獲。

使用DELETE方式進行請求。

DELETE http://localhost:8181/api/user

Body參數(shù)為:

{"id":1}

返回參數(shù)為:

{"code":"500","message":"服務器內部錯誤!","result":null}

這里可以看到它使用了我們在自定義全局異常處理類中的Exception異常處理的方法。

到這里,測試就結束了。

順便再說一下,自義定全局異常處理除了可以處理上述的數(shù)據格式之外,也可以處理頁面的跳轉,只需在新增的異常方法的返回處理上填寫該跳轉的路徑并不使用ResponseBody 注解即可。

細心的同學也許發(fā)現(xiàn)了在GlobalExceptionHandler類中使用的是ControllerAdvice注解,而非RestControllerAdvice注解,如果是用的RestControllerAdvice注解,它會將數(shù)據自動轉換成JSON格式,這種于Controller和RestController類似,所以我們在使用全局異常處理的之后可以進行靈活的選擇處理。

 

責任編輯:龐桂玉 來源: Java技術棧
相關推薦

2020-03-16 17:20:02

異常處理Spring Boot

2024-10-16 12:23:55

技巧Spring驗證

2022-10-26 07:14:25

Spring 6Spring業(yè)務

2019-01-24 16:11:19

前端全局異常數(shù)據校驗

2024-08-02 09:15:22

Spring捕捉格式

2025-02-07 09:11:04

JSON對象策略

2022-04-08 16:27:48

SpringBoot異常處理

2025-02-05 14:28:19

2024-09-27 12:27:31

2024-10-28 08:32:22

統(tǒng)一接口響應SpringBoot響應框架

2023-10-10 13:23:18

空指針異常Java

2024-12-18 16:19:51

2017-06-26 09:40:50

Python代碼寫法

2017-07-07 16:57:35

代碼Python

2023-08-01 08:54:02

接口冪等網絡

2022-03-04 08:31:07

Spring異常處理

2023-09-24 13:55:42

Spring應用程序

2025-02-13 00:34:22

Spring對象系統(tǒng)

2021-04-30 07:34:01

Spring BootController項目

2023-12-27 07:53:08

全局異常處理處理應用
點贊
收藏

51CTO技術棧公眾號