<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>

          ?Spring Cloud:統(tǒng)一異常處理

          共 27503字,需瀏覽 56分鐘

           ·

          2021-02-28 19:42

          作者:BNDong

          www.cnblogs.com/bndong/p/10135370.html

          在啟動應用時會發(fā)現(xiàn)在控制臺打印的日志中出現(xiàn)了兩個路徑為 {[/error]} 的訪問地址,當系統(tǒng)中發(fā)送異常錯誤時,Spring Boot 會根據請求方式分別跳轉到以 JSON 格式或以界面顯示的 /error 地址中顯示錯誤信息。

          2018-12-18 09:36:24.627  INFO 19040 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" ...
          2018-12-18 09:36:24.632  INFO 19040 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" ...

          默認異常處理

          使用 AJAX 方式請求時返回的 JSON 格式錯誤信息。

          {
              "timestamp""2018-12-18T01:50:51.196+0000",
              "status": 404,
              "error""Not Found",
              "message""No handler found for GET /err404",
              "path""/err404"
          }

          使用瀏覽器請求時返回的錯誤信息界面。

          自定義異常處理

          引入依賴

          <dependency>
              <groupId>com.alibaba</groupId>
              <artifactId>fastjson</artifactId>
              <version>1.2.54</version>
          </dependency>
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-freemarker</artifactId>
          </dependency>

          fastjson 是 JSON 序列化依賴, spring-boot-starter-freemarker 是一個模板引擎,用于我們設置錯誤輸出模板。

          增加配置

          properties

          # 出現(xiàn)錯誤時, 直接拋出異常(便于異常統(tǒng)一處理,否則捕獲不到404)
          spring.mvc.throw-exception-if-no-handler-found=true
          # 不要為工程中的資源文件建立映射
          spring.resources.add-mappings=false

          yml

          spring:
            # 出現(xiàn)錯誤時, 直接拋出異常(便于異常統(tǒng)一處理,否則捕獲不到404)
            mvc:
              throw-exception-if-no-handler-found: true
            # 不要為工程中的資源文件建立映射
            resources:
              add-mappings: false

          新建錯誤信息實體

          /**
           * 信息實體
           */
          public class ExceptionEntity implements Serializable {

              private static final long serialVersionUID = 1L;

              private String message;

              private int    code;

              private String error;

              private String path;

              @JSONField(format = "yyyy-MM-dd hh:mm:ss")
              private Date timestamp = new Date();

              public static long getSerialVersionUID() {
                  return serialVersionUID;
              }

              public String getMessage() {
                  return message;
              }

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

              public int getCode() {
                  return code;
              }

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

              public String getError() {
                  return error;
              }

              public void setError(String error) {
                  this.error = error;
              }

              public String getPath() {
                  return path;
              }

              public void setPath(String path) {
                  this.path = path;
              }

              public Date getTimestamp() {
                  return timestamp;
              }

              public void setTimestamp(Date timestamp) {
                  this.timestamp = timestamp;
              }
          }

          新建自定義異常

          /**
           * 自定義異常
           */
          public class BasicException extends RuntimeException {

              private static final long serialVersionUID = 1L;

              private int code = 0;

              public BasicException(int code, String message) {
                  super(message);
                  this.code = code;
              }

              public int getCode() {
                  return this.code;
              }
          }
          /**
           * 業(yè)務異常
           */
          public class BusinessException extends BasicException {

              private static final long serialVersionUID = 1L;

              public BusinessException(int code, String message) {
                  super(code, message);
              }
          }

          BasicException 繼承了 RuntimeException ,并在原有的 Message 基礎上增加了錯誤碼 code 的內容。而 BusinessException 則是在業(yè)務中具體使用的自定義異常類,起到了對不同的異常信息進行分類的作用。

          新建 error.ftl 模板文件

          位置:/src/main/resources/templates/ 用于顯示錯誤信息

          <!DOCTYPE html>
          <html>
          <head>
              <meta name="robots" content="noindex,nofollow" />
              <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
              <style>
                  h2{
                      color: #4288ce;
                      font-weight: 400;
                      padding: 6px 0;
                      margin: 6px 0 0;
                      font-size: 18px;
                      border-bottom: 1px solid #eee;
                  }

                  /* Exception Variables */
                  .exception-var table{
                      width: 100%;
                      max-width: 500px;
                      margin: 12px 0;
                      box-sizing: border-box;
                      table-layout:fixed;
                      word-wrap:break-word;
                  }
                  .exception-var table caption{
                      text-align: left;
                      font-size: 16px;
                      font-weight: bold;
                      padding: 6px 0;
                  }
                  .exception-var table caption small{
                      font-weight: 300;
                      display: inline-block;
                      margin-left: 10px;
                      color: #ccc;
                  }
                  .exception-var table tbody{
                      font-size: 13px;
                      font-family: Consolas,"Liberation Mono",Courier,"微軟雅黑";
                  }
                  .exception-var table td{
                      padding: 0 6px;
                      vertical-align: top;
                      word-break: break-all;
                  }
                  .exception-var table td:first-child{
                      width: 28%;
                      font-weight: bold;
                      white-space: nowrap;
                  }
                  .exception-var table td pre{
                      margin: 0;
                  }
              </style>
          </head>
          <body>

          <div class="exception-var">
              <h2>Exception Datas</h2>
              <table>
                  <tbody>
                  <tr>
                      <td>Code</td>
                      <td>
                          ${(exception.code)!}
                      </td>
                  </tr>
                  <tr>
                      <td>Time</td>
                      <td>
                          ${(exception.timestamp?datetime)!}
                      </td>
                  </tr>
                  <tr>
                      <td>Path</td>
                      <td>
                          ${(exception.path)!}
                      </td>
                  </tr>
                  <tr>
                      <td>Exception</td>
                      <td>
                          ${(exception.error)!}
                      </td>
                  </tr>
                  <tr>
                      <td>Message</td>
                      <td>
                          ${(exception.message)!}
                      </td>
                  </tr>
                  </tbody>
              </table>
          </div>
          </body>
          </html>

          編寫全局異??刂祁?span style="display: none;">

          /**
           * 全局異??刂祁?br> */
          @ControllerAdvice
          public class GlobalExceptionHandler {

              /**
               * 404異常處理
               */
              @ExceptionHandler(value = NoHandlerFoundException.class)
              @ResponseStatus(HttpStatus.NOT_FOUND)
              public ModelAndView errorHandler(HttpServletRequest request, NoHandlerFoundException exception, HttpServletResponse response) {
                  return commonHandler(request, response,
                          exception.getClass().getSimpleName(),
                          HttpStatus.NOT_FOUND.value(),
                          exception.getMessage());
              }

              /**
               * 405異常處理
               */
              @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
              public ModelAndView errorHandler(HttpServletRequest request, HttpRequestMethodNotSupportedException exception, HttpServletResponse response) {
                  return commonHandler(request, response,
                          exception.getClass().getSimpleName(),
                          HttpStatus.METHOD_NOT_ALLOWED.value(),
                          exception.getMessage());
              }

              /**
               * 415異常處理
               */
              @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
              public ModelAndView errorHandler(HttpServletRequest request, HttpMediaTypeNotSupportedException exception, HttpServletResponse response) {
                  return commonHandler(request, response,
                          exception.getClass().getSimpleName(),
                          HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(),
                          exception.getMessage());
              }

              /**
               * 500異常處理
               */
              @ExceptionHandler(value = Exception.class)
              public ModelAndView errorHandler (HttpServletRequest request, Exception exception, HttpServletResponse response) {
                  return commonHandler(request, response,
                          exception.getClass().getSimpleName(),
                          HttpStatus.INTERNAL_SERVER_ERROR.value(),
                          exception.getMessage());
              }

              /**
               * 業(yè)務異常處理
               */
              @ExceptionHandler(value = BasicException.class)
              private ModelAndView errorHandler (HttpServletRequest request, BasicException exception, HttpServletResponse response) {
                  return commonHandler(request, response,
                          exception.getClass().getSimpleName(),
                          exception.getCode(),
                          exception.getMessage());
              }

              /**
               * 表單驗證異常處理
               */
              @ExceptionHandler(value = BindException.class)
              @ResponseBody
              public ExceptionEntity validExceptionHandler(BindException exception, HttpServletRequest request, HttpServletResponse response) {
                  List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
                  Map<String,String> errors = new HashMap<>();
                  for (FieldError error:fieldErrors) {
                      errors.put(error.getField(), error.getDefaultMessage());
                  }
                  ExceptionEntity entity = new ExceptionEntity();
                  entity.setMessage(JSON.toJSONString(errors));
                  entity.setPath(request.getRequestURI());
                  entity.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
                  entity.setError(exception.getClass().getSimpleName());
                  response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
                  return entity;
              }

              /**
               * 異常處理數據處理
               */
              private ModelAndView commonHandler (HttpServletRequest request, HttpServletResponse response,
                                                      String error, int httpCode, String message) {
                  ExceptionEntity entity = new ExceptionEntity();
                  entity.setPath(request.getRequestURI());
                  entity.setError(error);
                  entity.setCode(httpCode);
                  entity.setMessage(message);
                  return determineOutput(request, response, entity);
              }

              /**
               * 異常輸出處理
               */
              private ModelAndView determineOutput(HttpServletRequest request, HttpServletResponse response, ExceptionEntity entity) {
                  if (!(
                          request.getHeader("accept").contains("application/json")
                          || (request.getHeader("X-Requested-With") != null && request.getHeader("X-Requested-With").contains("XMLHttpRequest"))
                  )) {
                      ModelAndView modelAndView = new ModelAndView("error");
                      modelAndView.addObject("exception", entity);
                      return modelAndView;
                  } else {
                      response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
                      response.setCharacterEncoding("UTF8");
                      response.setHeader("Content-Type""application/json");
                      try {
                          response.getWriter().write(ResultJsonTools.build(
                                  ResponseCodeConstant.SYSTEM_ERROR,
                                  ResponseMessageConstant.APP_EXCEPTION,
                                  JSONObject.parseObject(JSON.toJSONString(entity))
                          ));
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                      return null;
                  }
              }
          }

          @ControllerAdvice

          作用于類上,用于標識該類用于處理全局異常。

          @ExceptionHandler

          作用于方法上,用于對攔截的異常類型進行處理。value 屬性用于指定具體的攔截異常類型,如果有多個 ExceptionHandler 存在,則需要指定不同的 value 類型,由于異常類擁有繼承關系,所以 ExceptionHandler 會首先執(zhí)行在繼承樹中靠前的異常類型。

          BindException

          該異常來自于表單驗證框架 Hibernate validation,當字段驗證未通過時會拋出此異常。

          編寫測試 Controller

          @RestController
          public class TestController {

              @RequestMapping(value = "err")
              public void error(){
                  throw new BusinessException(400, "業(yè)務異常錯誤信息");
              }

              @RequestMapping(value = "err2")
              public void error2(){
                  throw new NullPointerException("手動拋出異常信息");
              }

              @RequestMapping(value = "err3")
              public int error3(){
                  int a = 10 / 0;
                  return a;
              }
          }

          使用 AJAX 方式請求時返回的 JSON 格式錯誤信息。

          # /err
          {
              "msg""應用程序異常",
              "code": -1,
              "status_code": 0,
              "data": {
                  "path""/err",
                  "code": 400,
                  "error""BusinessException",
                  "message""業(yè)務異常錯誤信息",
                  "timestamp""2018-12-18 11:09:00"
              }
          }

          # /err2
          {
              "msg""應用程序異常",
              "code": -1,
              "status_code": 0,
              "data": {
                  "path""/err2",
                  "code": 500,
                  "error""NullPointerException",
                  "message""手動拋出異常信息",
                  "timestamp""2018-12-18 11:15:15"
              }
          }

          # /err3
          {
              "msg""應用程序異常",
              "code": -1,
              "status_code": 0,
              "data": {
                  "path""/err3",
                  "code": 500,
                  "error""ArithmeticException",
                  "message""/ by zero",
                  "timestamp""2018-12-18 11:15:46"
              }
          }

          # /err404
          {
              "msg""應用程序異常",
              "code": -1,
              "status_code": 0,
              "data": {
                  "path""/err404",
                  "code": 404,
                  "error""NoHandlerFoundException",
                  "message""No handler found for GET /err404",
                  "timestamp""2018-12-18 11:16:11"
              }
          }

          使用瀏覽器請求時返回的錯誤信息界面。

          示例代碼:https://github.com/BNDong/spring-cloud-examples/tree/master/spring-cloud-zuul/cloud-zuul

          參考資料

          《微服務 分布式架構開發(fā)實戰(zhàn)》 龔鵬 著

          https://www.jianshu.com/p/1a49fa436623


          點擊閱讀全文前往微服務電商教程
          瀏覽 62
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  国产乱码操逼片 | 色网在线 | 理伦无码| 激情人妻网站 | AV手机网 |