<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)雅...

          共 17486字,需瀏覽 35分鐘

           ·

          2021-05-20 22:26

          本篇文章主要介紹的是SpringBoot項(xiàng)目進(jìn)行全局異常的處理。

          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>

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

          代碼編寫

          SpringBoot的項(xiàng)目已經(jīng)對有一定的異常處理了,但是對于我們開發(fā)者而言可能就不太合適了,因此我們需要對這些異常進(jìn)行統(tǒng)一的捕獲并處理。SpringBoot中有一個(gè)ControllerAdvice的注解,使用該注解表示開啟了全局異常的捕獲,我們只需在自定義一個(gè)方法使用ExceptionHandler注解然后定義捕獲異常的類型即可對這些捕獲的異常進(jìn)行統(tǒng)一的處理。

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

          示例代碼:

          @ControllerAdvice
          public class MyExceptionHandler {

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

          上述的示例中,我們對捕獲的異常進(jìn)行簡單的二次處理,返回異常的信息,雖然這種能夠讓我們知道異常的原因,但是在很多的情況下來說,可能還是不夠人性化,不符合我們的要求。那么我們這里可以通過自定義的異常類以及枚舉類來實(shí)現(xiàn)我們想要的那種數(shù)據(jù)吧。

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

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

          public interface BaseErrorInfoInterface {
              /** 錯(cuò)誤碼*/
            String getResultCode();

           /** 錯(cuò)誤描述*/
            String getResultMsg();
          }

          自定義枚舉類

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

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

           /** 錯(cuò)誤碼 */
           private String resultCode;

           /** 錯(cuò)誤描述 */
           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;
           }

          }

          自定義異常類

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

          public class BizException extends RuntimeException {

           private static final long serialVersionUID = 1L;

           /**
            * 錯(cuò)誤碼
            */

           protected String errorCode;
           /**
            * 錯(cuò)誤信息
            */

           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);
           }

          }

          自定義全局異常處理類

          最后我們在來編寫一個(gè)自定義全局異常處理的類。代碼如下:

          @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);
              }
          }

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

          實(shí)體類

          又是萬能的用戶表 ()

          代碼如下:

          public class User implements Serializable{
           private static final long serialVersionUID = 1L;
           /** 編號(hào) */
            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)格實(shí)現(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("開始新增...");
               //如果姓名為空就手動(dòng)拋出一個(gè)自定義的異常!
                  if(user.getName()==null){
                      throw  new BizException("-1","用戶姓名不能為空!");
                  }
                  return true;
              }

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

              @DeleteMapping("/user")
              public boolean delete(@RequestBody User user)  {
                  System.out.println("開始刪除...");
                  //這里故意造成一個(gè)異常,并且不進(jìn)行處理
                  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項(xiàng)目基本一樣。

          代碼如下:

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

          功能測試

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

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

          GET [http://localhost:8181/api/user](http://localhost:8181/api/user)

          返回參數(shù)為:

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

          示例圖:

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

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

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

          POST [http://localhost:8181/api/user](http://localhost:8181/api/user)

          Body參數(shù)為:

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

          返回參數(shù)為:

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

          示例圖:

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

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

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

          PUT [http://localhost:8181/api/user](http://localhost:8181/api/user)

          Body參數(shù)為:

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

          返回參數(shù)為:

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

          示例圖:

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

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

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

          DELETE [http://localhost:8181/api/user](http://localhost:8181/api/user)

          Body參數(shù)為:

          {"id":1}

          返回參數(shù)為:

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

          這里可以看到它使用了我們在自定義全局異常處理類中的Exception異常處理的方法。到這里,測試就結(jié)束了。順便再說一下,自義定全局異常處理除了可以處理上述的數(shù)據(jù)格式之外,也可以處理頁面的跳轉(zhuǎn),只需在新增的異常方法的返回處理上填寫該跳轉(zhuǎn)的路徑并不使用ResponseBody 注解即可。細(xì)心的同學(xué)也許發(fā)現(xiàn)了在GlobalExceptionHandler類中使用的是ControllerAdvice注解,而非RestControllerAdvice注解,如果是用的RestControllerAdvice注解,它會(huì)將數(shù)據(jù)自動(dòng)轉(zhuǎn)換成JSON格式,這種于ControllerRestController類似,所以我們在使用全局異常處理的之后可以進(jìn)行靈活的選擇處理。

          來源 | https://www.cnblogs.com/xuwujing/p/10933082.html


          END



          免費(fèi)領(lǐng)取 1000+ 道面試資料!!小編這里有一份面試寶典《Java 核心知識(shí)點(diǎn).pdf》,覆蓋了 JVM,鎖、高并發(fā)、Spring原理、微服務(wù)、數(shù)據(jù)庫、Zookeep人、數(shù)據(jù)結(jié)構(gòu)等等知識(shí)點(diǎn),包含 Java 后端知識(shí)點(diǎn) 1000+ 個(gè),部分如下:

          如何獲取?加小編微信,回復(fù)【1024】

          瀏覽 45
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  操骚B视频 | 日韩黄色小电影 | 欧美激情性爱网站 | 欧美日韩一区二区A片综合 | 欧美一级A片免费看 |