成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

開(kāi)發(fā) 后端
本篇文章主要介紹的是 Spring Boot 項(xiàng)目進(jìn)行全局異常的處理。

SpringBoot全局異常準(zhǔn)備

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

開(kāi)發(fā)準(zhǔn)備

環(huán)境要求:

JDK:1.8

SpringBoot:1.5.17.RELEASE

首先還是Maven的相關(guān)依賴(lài): 

  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 依賴(lài) 核心 -->  
  15.     <dependency>  
  16.         <groupId>org.springframework.boot</groupId>  
  17.         <artifactId>spring-boot-starter-web</artifactId>  
  18.     </dependency>  
  19.     <!-- Spring Boot Test 依賴(lài) -->  
  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> 

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

代碼編寫(xiě)

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

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

我們根據(jù)下面的這個(gè)示例來(lái)看該注解是如何使用吧。Spring Boot 基礎(chǔ)就不介紹了,看睛這個(gè):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.     }  

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

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

自定義基礎(chǔ)接口類(lèi)

首先定義一個(gè)基礎(chǔ)的接口類(lèi),自定義的錯(cuò)誤描述枚舉類(lèi)需實(shí)現(xiàn)該接口。

代碼如下: 

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

自定義枚舉類(lèi)

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

代碼如下: 

  1. public enum CommonEnum implements BaseErrorInfoInterface {  
  2.  // 數(shù)據(jù)操作錯(cuò)誤定義  
  3.  SUCCESS("200", "成功!"),   
  4.  BODY_NOT_MATCH("400","請(qǐng)求的數(shù)據(jù)格式不符!"),  
  5.  SIGNATURE_NOT_MATCH("401","請(qǐng)求的數(shù)字簽名不匹配!"),  
  6.  NOT_FOUND("404", "未找到該資源!"),   
  7.  INTERNAL_SERVER_ERROR("500", "服務(wù)器內(nèi)部錯(cuò)誤!"),  
  8.  SERVER_BUSY("503","服務(wù)器正忙,請(qǐng)稍后再試!")  
  9.  ;  
  10.  /** 錯(cuò)誤碼 */  
  11.  private String resultCode;  
  12.  /** 錯(cuò)誤描述 */  
  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.   

自定義異常類(lèi)

然后我們?cè)趤?lái)自定義一個(gè)異常類(lèi),用于處理我們發(fā)生的業(yè)務(wù)異常。

代碼如下: 

  1. public class BizException extends RuntimeException {  
  2.  private static final long serialVersionUID = 1L 
  3.  /**  
  4.   * 錯(cuò)誤碼  
  5.   */  
  6.  protected String errorCode;  
  7.  /**  
  8.   * 錯(cuò)誤信息  
  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ù)據(jù)格式

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

代碼如下: 

  1. public class ResultBody {  
  2.  /**  
  3.   * 響應(yīng)代碼  
  4.   */  
  5.  private String code;  
  6.  /**  
  7.   * 響應(yīng)消息  
  8.   */  
  9.  private String message;  
  10.  /** 
  11.   * 響應(yīng)結(jié)果  
  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.  }  

自定義全局異常處理類(lèi)

最后我們?cè)趤?lái)編寫(xiě)一個(gè)自定義全局異常處理的類(lèi)。

代碼如下: 

  1. @ControllerAdvice  
  2. public class GlobalExceptionHandler {  
  3.  private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);   
  4.  /**  
  5.   * 處理自定義的業(yè)務(wù)異常  
  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è)務(wù)異常!原因是:{}",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.     }  

因?yàn)檫@里我們只是用于做全局異常處理的功能實(shí)現(xiàn)以及測(cè)試,所以這里我們只需在添加一個(gè)實(shí)體類(lèi)和一個(gè)控制層類(lèi)即可。

實(shí)體類(lèi)

又是萬(wàn)能的用戶(hù)表 (▽)

代碼如下: 

  1. public class User implements Serializable{  
  2.  private static final long serialVersionUID = 1L 
  3.  /** 編號(hào) */  
  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 控制層

控制層這邊也比較簡(jiǎn)單,使用Restful風(fēng)格實(shí)現(xiàn)的CRUD功能,不同的是這里我故意弄出了一些異常,好讓這些異常被捕獲到然后處理。這些異常中,有自定義的異常拋出,也有空指針的異常拋出,當(dāng)然也有不可預(yù)知的異常拋出(這里我用類(lèi)型轉(zhuǎn)換異常代替),那么我們?cè)谕瓿纱a編寫(xiě)之后,看看這些異常是否能夠被捕獲處理成功吧!

代碼如下: 

  1. @RestController  
  2. @RequestMapping(value = "/api" 
  3. public class UserRestController {  
  4.  @PostMapping("/user")  
  5.     public boolean insert(@RequestBody User user) {  
  6.      System.out.println("開(kāi)始新增...");  
  7.      //如果姓名為空就手動(dòng)拋出一個(gè)自定義的異常!  
  8.         if(user.getName()==null){  
  9.             throw  new BizException("-1","用戶(hù)姓名不能為空!");  
  10.         }  
  11.         return true;  
  12.     }  
  13.     @PutMapping("/user")  
  14.     public boolean update(@RequestBody User user) {  
  15.      System.out.println("開(kāi)始更新...");  
  16.        //這里故意造成一個(gè)空指針的異常,并且不進(jìn)行處理  
  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("開(kāi)始刪除...");  
  24.         //這里故意造成一個(gè)異常,并且不進(jìn)行處理  
  25.         Integer.parseInt("abc123");  
  26.         return true;  
  27.     }  
  28.     @GetMapping("/user")  
  29.     public List<User> findByUser(User user) {  
  30.      System.out.println("開(kāi)始查詢(xún)...");  
  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項(xiàng)目基本一樣。

代碼如下: 

  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("程序正在運(yùn)行...");  
  8.     }  

功能測(cè)試

我們成功啟動(dòng)該程序之后,使用Postman工具來(lái)進(jìn)行接口測(cè)試。

首先進(jìn)行查詢(xún),查看程序正常運(yùn)行是否ok,使用GET 方式進(jìn)行請(qǐng)求。

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

返回參數(shù)為:

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

示例圖:

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

然后我們?cè)賮?lái)測(cè)試下自定義的異常是否能夠被正確的捕獲并處理。

使用POST方式進(jìn)行請(qǐng)求

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

Body參數(shù)為:

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

返回參數(shù)為:

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

示例圖:

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

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

使用PUT方式進(jìn)行請(qǐng)求。

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

Body參數(shù)為:

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

返回參數(shù)為:

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

示例圖:

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

那么我們?cè)趤?lái)試試未指定其異常的處理,看該異常是否能夠被捕獲。

使用DELETE方式進(jìn)行請(qǐng)求。

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

Body參數(shù)為:

{"id":1}

返回參數(shù)為:

{"code":"500","message":"服務(wù)器內(nèi)部錯(cuò)誤!","result":null}

這里可以看到它使用了我們?cè)谧远x全局異常處理類(lèi)中的Exception異常處理的方法。

到這里,測(cè)試就結(jié)束了。

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

細(xì)心的同學(xué)也許發(fā)現(xiàn)了在GlobalExceptionHandler類(lèi)中使用的是ControllerAdvice注解,而非RestControllerAdvice注解,如果是用的RestControllerAdvice注解,它會(huì)將數(shù)據(jù)自動(dòng)轉(zhuǎn)換成JSON格式,這種于Controller和RestController類(lèi)似,所以我們?cè)谑褂萌之惓L幚淼闹罂梢赃M(jìn)行靈活的選擇處理。

 

責(zé)任編輯:龐桂玉 來(lái)源: Java技術(shù)棧
相關(guān)推薦

2024-10-16 12:23:55

技巧Spring驗(yàn)證

2020-03-16 17:20:02

異常處理Spring Boot

2022-10-26 07:14:25

Spring 6Spring業(yè)務(wù)

2019-01-24 16:11:19

前端全局異常數(shù)據(jù)校驗(yàn)

2024-08-02 09:15:22

Spring捕捉格式

2025-02-07 09:11:04

JSON對(duì)象策略

2022-04-08 16:27:48

SpringBoot異常處理

2025-02-05 14:28:19

2017-06-26 09:40:50

Python代碼寫(xiě)法

2017-07-07 16:57:35

代碼Python

2024-09-27 12:27:31

2023-10-10 13:23:18

空指針異常Java

2023-08-01 08:54:02

接口冪等網(wǎng)絡(luò)

2024-10-28 08:32:22

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

2024-12-18 16:19:51

2022-03-04 08:31:07

Spring異常處理

2023-09-24 13:55:42

Spring應(yīng)用程序

2021-04-30 07:34:01

Spring BootController項(xiàng)目

2025-02-13 00:34:22

Spring對(duì)象系統(tǒng)

2023-12-27 07:53:08

全局異常處理處理應(yīng)用
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 亚洲 一区 | 欧美久久电影 | 日韩爱爱网 | 天天操人人干 | 久久新 | 亚洲精品一区中文字幕 | 国产精品一区二区福利视频 | 日韩在线视频免费观看 | 一区二区三区亚洲视频 | 伊人网一区 | 成年人在线播放 | 一区二区国产精品 | 免费看一区二区三区 | 国产精品久久久久久久久 | 精品国产伦一区二区三区观看方式 | av网站免费观看 | 日韩欧美在线视频 | 国产成人久久精品一区二区三区 | 91一区二区三区在线观看 | 日本人做爰大片免费观看一老师 | 成人av观看| 91人人看 | 亚洲乱码国产乱码精品精98午夜 | 国产精品观看 | 九九热热九九 | 亚洲久久在线 | 日韩福利在线 | 国产精品视频一区二区三区四蜜臂 | 亚洲三级在线 | 精品国产一区二区三区久久久四川 | 午夜免费 | 国产视频久 | 日韩一级一区 | 二区视频| 91精品国产综合久久久久蜜臀 | 欧美一区二区免费 | 国产免费一区 | 久久精品国产99国产精品 | 麻豆精品一区二区三区在线观看 | 欧美成人激情 | 亚洲黄色一级 |