<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          看看別人家 SpringBoot 的全局異常處理,多么優(yōu)雅....

          共 17624字,需瀏覽 36分鐘

           ·

          2021-04-22 08:25

          點擊上方“程序員大白”,選擇“星標(biāo)”公眾號

          重磅干貨,第一時間送達

          來源:cnblogs.com/xuwujing/p/10933082.html

          前言

          本篇文章主要介紹的是SpringBoot項目進行全局異常的處理。

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

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

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

          環(huán)境要求

          • JDK:1.8
          • SpringBoot:1.5.17.RELEASE

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

            <properties>
                  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                  <java.version>1.8</java.version>
                  <maven.compiler.source>1.8</maven.compiler.source>
                  <maven.compiler.target>1.8</maven.compiler.target>
              </properties>
              <parent>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-parent</artifactId>
                  <version>1.5.17.RELEASE</version>
                  <relativePath />
              </parent>
              <dependencies>
                  <!-- Spring Boot Web 依賴 核心 -->
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-web</artifactId>
                  </dependency>
                  <!-- Spring Boot Test 依賴 -->
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-test</artifactId>
                      <scope>test</scope>
                  </dependency>

                  <dependency>
                      <groupId>com.alibaba</groupId>
                      <artifactId>fastjson</artifactId>
                      <version>1.2.41</version>
                  </dependency>
              </dependencies>

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

          代碼編寫

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

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

          我們根據(jù)下面的這個示例來看該注解是如何使用吧。

          示例代碼:

          @ControllerAdvice
          public class MyExceptionHandler {

              @ExceptionHandler(value =Exception.class)
           public String exceptionHandler(Exception e)
          {
            System.out.println("未知異常!原因是:"+e);
                  return e.getMessage();
              }
          }

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

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

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

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

          代碼如下:

          public interface BaseErrorInfoInterface {
              /** 錯誤碼*/
            String getResultCode();
           
           /** 錯誤描述*/
            String getResultMsg();
          }

          自定義枚舉類

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

          代碼如下:

          public enum CommonEnum implements BaseErrorInfoInterface {
           // 數(shù)據(jù)操作錯誤定義
           SUCCESS("200""成功!"), 
           BODY_NOT_MATCH("400","請求的數(shù)據(jù)格式不符!"),
           SIGNATURE_NOT_MATCH("401","請求的數(shù)字簽名不匹配!"),
           NOT_FOUND("404""未找到該資源!"), 
           INTERNAL_SERVER_ERROR("500""服務(wù)器內(nèi)部錯誤!"),
           SERVER_BUSY("503","服務(wù)器正忙,請稍后再試!")
           ;

           /** 錯誤碼 */
           private String resultCode;

           /** 錯誤描述 */
           private String resultMsg;

           CommonEnum(String resultCode, String resultMsg) {
            this.resultCode = resultCode;
            this.resultMsg = resultMsg;
           }

           @Override
           public String getResultCode() {
            return resultCode;
           }

           @Override
           public String getResultMsg() {
            return resultMsg;
           }

          }

          自定義異常類

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

          代碼如下:

          public class BizException extends RuntimeException {

           private static final long serialVersionUID = 1L;

           /**
            * 錯誤碼
            */

           protected String errorCode;
           /**
            * 錯誤信息
            */

           protected String errorMsg;

           public BizException() {
            super();
           }

           public BizException(BaseErrorInfoInterface errorInfoInterface) {
            super(errorInfoInterface.getResultCode());
            this.errorCode = errorInfoInterface.getResultCode();
            this.errorMsg = errorInfoInterface.getResultMsg();
           }
           
           public BizException(BaseErrorInfoInterface errorInfoInterface, Throwable cause) {
            super(errorInfoInterface.getResultCode(), cause);
            this.errorCode = errorInfoInterface.getResultCode();
            this.errorMsg = errorInfoInterface.getResultMsg();
           }
           
           public BizException(String errorMsg) {
            super(errorMsg);
            this.errorMsg = errorMsg;
           }
           
           public BizException(String errorCode, String errorMsg) {
            super(errorCode);
            this.errorCode = errorCode;
            this.errorMsg = errorMsg;
           }

           public BizException(String errorCode, String errorMsg, Throwable cause) {
            super(errorCode, cause);
            this.errorCode = errorCode;
            this.errorMsg = errorMsg;
           }
           

           public String getErrorCode() {
            return errorCode;
           }

           public void setErrorCode(String errorCode) {
            this.errorCode = errorCode;
           }

           public String getErrorMsg() {
            return errorMsg;
           }

           public void setErrorMsg(String errorMsg) {
            this.errorMsg = errorMsg;
           }

           public String getMessage() {
            return errorMsg;
           }

           @Override
           public Throwable fillInStackTrace() {
            return this;
           }

          }

          自定義數(shù)據(jù)格式

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

          代碼如下:

          public class ResultBody {
           /**
            * 響應(yīng)代碼
            */

           private String code;

           /**
            * 響應(yīng)消息
            */

           private String message;

           /**
            * 響應(yīng)結(jié)果
            */

           private Object result;

           public ResultBody() {
           }

           public ResultBody(BaseErrorInfoInterface errorInfo) {
            this.code = errorInfo.getResultCode();
            this.message = errorInfo.getResultMsg();
           }

           public String getCode() {
            return code;
           }

           public void setCode(String code) {
            this.code = code;
           }

           public String getMessage() {
            return message;
           }

           public void setMessage(String message) {
            this.message = message;
           }

           public Object getResult() {
            return result;
           }

           public void setResult(Object result) {
            this.result = result;
           }

           /**
            * 成功
            * 
            * @return
            */

           public static ResultBody success() {
            return success(null);
           }

           /**
            * 成功
            * @param data
            * @return
            */

           public static ResultBody success(Object data) {
            ResultBody rb = new ResultBody();
            rb.setCode(CommonEnum.SUCCESS.getResultCode());
            rb.setMessage(CommonEnum.SUCCESS.getResultMsg());
            rb.setResult(data);
            return rb;
           }

           /**
            * 失敗
            */

           public static ResultBody error(BaseErrorInfoInterface errorInfo) {
            ResultBody rb = new ResultBody();
            rb.setCode(errorInfo.getResultCode());
            rb.setMessage(errorInfo.getResultMsg());
            rb.setResult(null);
            return rb;
           }

           /**
            * 失敗
            */

           public static ResultBody error(String code, String message) {
            ResultBody rb = new ResultBody();
            rb.setCode(code);
            rb.setMessage(message);
            rb.setResult(null);
            return rb;
           }

           /**
            * 失敗
            */

           public static ResultBody error( String message) {
            ResultBody rb = new ResultBody();
            rb.setCode("-1");
            rb.setMessage(message);
            rb.setResult(null);
            return rb;
           }

           @Override
           public String toString() {
            return JSONObject.toJSONString(this);
           }

          }

          自定義全局異常處理類

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

          代碼如下:

          @ControllerAdvice
          public class GlobalExceptionHandler {
           private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
           
           /**
            * 處理自定義的業(yè)務(wù)異常
            * @param req
            * @param e
            * @return
            */

              @ExceptionHandler(value = BizException.class)  
              @ResponseBody  
           public  ResultBody bizExceptionHandler(HttpServletRequest reqBizException e)
          {
               logger.error("發(fā)生業(yè)務(wù)異常!原因是:{}",e.getErrorMsg());
               return ResultBody.error(e.getErrorCode(),e.getErrorMsg());
              }

           /**
            * 處理空指針的異常
            * @param req
            * @param e
            * @return
            */

           @ExceptionHandler(value =NullPointerException.class)
           @ResponseBody
           public ResultBody exceptionHandler(HttpServletRequest reqNullPointerException e)
          {
            logger.error("發(fā)生空指針異常!原因是:",e);
            return ResultBody.error(CommonEnum.BODY_NOT_MATCH);
           }


              /**
                  * 處理其他異常
               * @param req
               * @param e
               * @return
               */

              @ExceptionHandler(value =Exception.class)
           @ResponseBody
           public ResultBody exceptionHandler(HttpServletRequest reqException e)
          {
               logger.error("未知異常!原因是:",e);
                  return ResultBody.error(CommonEnum.INTERNAL_SERVER_ERROR);
              }
          }

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

          實體類

          又是萬能的用戶表 (▽)

          代碼如下:

          public class User implements Serializable{
           private static final long serialVersionUID = 1L;
           /** 編號 */
            private int id;
            /** 姓名 */
            private String name;
            /** 年齡 */
            private int age;
            
            public User(){
            }

           public int getId() {
            return id;
           }
           
           public void setId(int id) {
            this.id = id;
           }

           public String getName() {
            return name;
           }

           public void setName(String name) {
            this.name = name;
           }

           public int getAge() {
            return age;
           }

           public void setAge(int age) {
            this.age = age;
           }

           public String toString() {
            return JSONObject.toJSONString(this);
           }
          }

          Controller 控制層

          控制層這邊也比較簡單,使用Restful風(fēng)格實現(xiàn)的CRUD功能,不同的是這里我故意弄出了一些異常,好讓這些異常被捕獲到然后處理。

          這些異常中,有自定義的異常拋出,也有空指針的異常拋出,當(dāng)然也有不可預(yù)知的異常拋出(這里我用類型轉(zhuǎn)換異常代替),那么我們在完成代碼編寫之后,看看這些異常是否能夠被捕獲處理成功吧!

          代碼如下:

          @RestController
          @RequestMapping(value = "/api")
          public class UserRestController {

           @PostMapping("/user")
              public boolean insert(@RequestBody User user) {
               System.out.println("開始新增...");
               //如果姓名為空就手動拋出一個自定義的異常!
                  if(user.getName()==null){
                      throw  new BizException("-1","用戶姓名不能為空!");
                  }
                  return true;
              }

              @PutMapping("/user")
              public boolean update(@RequestBody User user) {
               System.out.println("開始更新...");
                 //這里故意造成一個空指針的異常,并且不進行處理
                  String str=null;
                  str.equals("111");
                  return true;
              }

              @DeleteMapping("/user")
              public boolean delete(@RequestBody User user)  {
                  System.out.println("開始刪除...");
                  //這里故意造成一個異常,并且不進行處理
                  Integer.parseInt("abc123");
                  return true;
              }

              @GetMapping("/user")
              public List<User> findByUser(User user) {
               System.out.println("開始查詢...");
                  List<User> userList =new ArrayList<>();
                  User user2=new User();
                  user2.setId(1L);
                  user2.setName("xuwujing");
                  user2.setAge(18);
                  userList.add(user2);
                  return userList;
              }
              
          }

          App 入口

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

          代碼如下:

          @SpringBootApplication
          public class App 
          {
              public static void main( String[] args )
              
          {
            SpringApplication.run(App.classargs);
            System.out.println("程序正在運行...");
              }
          }

          功能測試

          我們成功啟動該程序之后,使用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ù)據(jù)封裝,然后將異常返回出來。

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

          使用PUT方式進行請求。

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

          Body參數(shù)為:

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

          返回參數(shù)為:

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

          示例圖:

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

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

          使用DELETE方式進行請求。

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

          Body參數(shù)為:

          {"id":1}

          返回參數(shù)為:

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

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

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

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

          其它

          關(guān)于SpringBoot優(yōu)雅的全局異常處理的文章就講解到這里了,如有不妥,歡迎指正!

          項目地址

          SpringBoot全局異常的處理項目工程地址:

          https://github.com/xuwujing/springBoot-study/tree/master/springboot-exceptionHandler


          國產(chǎn)小眾瀏覽器因屏蔽視頻廣告,被索賠100萬(后續(xù))

          年輕人“不講武德”:因看黃片上癮,把網(wǎng)站和786名女主播起訴了

          中國聯(lián)通官網(wǎng)被發(fā)現(xiàn)含木馬腳本,可向用戶推廣色情APP

          張一鳴:每個逆襲的年輕人,都具備的底層能力


          關(guān)


          學(xué)西學(xué)學(xué)質(zhì)結(jié)關(guān)[]學(xué)習(xí)


          瀏覽 45
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄片免费播放 | 操逼www | 在线免费观看黄色视频网站 | 大香蕉插逼 | 黄网在线免费看 |