1. 程式人生 > 實用技巧 >C#Timer任務結束後再開啟下次任務demo

C#Timer任務結束後再開啟下次任務demo

當客戶端/前端向服務端傳送一個請求後,這個請求並不是每次都能完全正確的處理,比如出現一些資源不存在、引數錯誤或者內部錯誤等資訊的時候,就需要將異常反饋給客戶端或者前端。那麼這就需要程式有完整的異常處理機制。

在 Java 中所有異常的基類都是 Throwable 延伸出來,但通常不使用 Throwable,在該基類延伸出來 Error 和 Exception 兩種異常,嚴格意義上講 Error 不屬於異常,而是錯誤,Exception 才是異常,兩者有什麼區別呢?所謂錯誤就是應用發生錯誤的是就啟動不起來,一般都是作業系統或者是 JVM 級別上發生的錯誤,一旦發生錯誤,我們是無法通過程式碼來進行處理的;但是 Exception 一般是我們可以通過程式碼來進行處理的,例如我們平時查詢資料庫沒有找到某一條記錄,就是一個典型的空異常,再比如我們進行計算的時候,分母為 0, 也會報一個異常。

Error 在平常工作我們是不需要處理,重點就是 Exception,Exception 又分為兩種,一種是 CheckedException 異常,另一種是 RuntimeException 異常;這兩個異常的區別是 CheckedException 要求必須在程式碼中進行處理,如果不處理,程式連編譯都無法通過;RuntimeException不要求強制進行處理,因為這個異常屬於執行的異常,不一定在編譯階段就能發現。如下面示例程式碼:

Exception:

這裡 throw new Exception(), 要麼進行 try...catch, 要麼使用 throws Exception 丟擲去,否則就會提示報錯,程式無法編譯通過。

下圖示例,RuntimeException,即使不做任何處理也不會報錯,是可以正常編譯的

RuntimeException 是一個繼承了 Exception 異常類的具體類,CheckException 是沒有這個類的,例如我們自定義一個 HttpException extends RuntimeException,那麼這個HttpException 就是一個執行時異常,如果一個 APIException extends Exception,那麼就是一個 CheckException 異常。

介紹完了異常的基礎知識後,我們如何進行統一異常處理?

1、定義統一返給前端的格式

統一返回給前端的格式是一個 JSON 型別,包含有自定義的 code 碼、異常資訊以及請求資訊

@Getter
@Setter
public class UnifyResponse {
    private Integer code;
    private String message;
    private String request;

    public UnifyResponse(Integer code, String message, String request) {
        this.code = code;
        this.message = message;
        this.request = request;
    }
}

2、自定義一個 HttpException 類,用於處理已知異常

@Getter
public class HttpException extends RuntimeException {
    protected Integer code;
    protected Integer httpStatusCode = 500;
}

這裡可以根據 HttpStatus 進行定義出來具體的異常類,例如 404 為資源找不到,401 為無許可權等

public class NotFoundException extends HttpException {
    public NotFoundException(int code) {
        this.code = code;
        this.httpStatusCode = 404;
    }
}
public class ForbiddenException extends HttpException {
    public ForbiddenException(int code) {
        this.code = code;
        this.httpStatusCode = 401;
    }
}

需要注意的是在 HttpException 中只聲明瞭連個變數,code 和 httpStatus,並沒有 message(錯誤資訊),是因為這裡我們將錯誤資訊封裝到了一個配置檔案中,然後通過類讀取配置檔案,根據 code 碼來獲取到對應的 message

3、resources下建立一個config/exception-code.properties

gabriel.codes[10000]=通用異常
gabriel.codes[10001]=通用引數錯誤

4、建立類獲取配置檔案資訊

package com.gx.missyou.core.configuration;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * 該類主要用於根據 code 值獲取異常的 message 訊息
 * SpringBoot 中通過 @PropertySource 註解將類與配置檔案進行關聯
 * 用法:@PropertySource(classpath:config/exception-code.properties)
 * <p>
 * 如何將該類中的私有欄位 codes 與配置檔案中所有的配置相關聯?
 * 1. 配置檔案中的 gabriel.codes["xxxxx"] 這裡的 codes 會和私有變數 Map<Integer, String> codes
 * 中的 codes  自動關聯
 * 2. 通過 @ConfigurationProperties(prefix="gabriel") 進行配置字首,這裡的 gabriel 必須要和配置
 * 檔案中的 gabriel.codes[10000] = "通用異常" 字首 gabriel 保持一致
 * <p>
 * 注意:SpringBoot 自動將配置檔案和類進行關聯的時候,類是必須要在容器中才可以的,所以在類上必須要新增
 * 一個 @Component 註解
 */
@PropertySource(value = "classpath:/config/exception-code.properties")
@ConfigurationProperties(prefix = "gabriel")
@Component
public class ExceptionCodeConfiguration {

    private Map<Integer, String> codes = new HashMap<>();

    public Map<Integer, String> getCodes() {
        return codes;
    }

    public void setCodes(Map<Integer, String> codes) {
        this.codes = codes;
    }

    public String getMessages(int code) {
        return codes.get(code);
    }
}

5、完善統一捕獲異常檔案

@ControllerAdvice
public class GlobalExceptionAdvice {

    @Autowired
    private ExceptionCodeConfiguration codeConfiguration;

    // 處理未知異常
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
    public UnifyResponse handleException(HttpServletRequest request, Exception e) {
        System.out.println("this is handleException");
        String uri = request.getRequestURI();
        String method = request.getMethod();
        System.out.println("異常原因:" + e);

        return new UnifyResponse(9999, "伺服器內部異常", method + " " + uri);
    }

    // 處理已知異常(自定義異常)
    @ExceptionHandler(HttpException.class)
    public ResponseEntity<UnifyResponse> handleHttpException(HttpServletRequest request, HttpException e) {
        String requestUrl = request.getRequestURI();
        String method = request.getMethod();

        String messages = codeConfiguration.getMessages(e.getCode());

        // 組裝 ResponseEntity
        UnifyResponse message = new UnifyResponse(e.getCode(), messages, method + " " + requestUrl);
        // 設定 HttpHeaders
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        // 設定 HttpStatus
        HttpStatus httpStatus = HttpStatus.resolve(e.getHttpStatusCode());

        assert httpStatus != null;
        return new ResponseEntity<>(message, headers, httpStatus);
    }
}