1. 程式人生 > >Springboot 系列(十六)你真的瞭解 Swagger 文件嗎?

Springboot 系列(十六)你真的瞭解 Swagger 文件嗎?

前言

目前來說,在 Java 領域使用 Springboot 構建微服務是比較流行的,在構建微服務時,我們大多數會選擇暴漏一個 REST API 以供呼叫。又或者公司採用前後端分離的開發模式,讓前端和後端的工作由完全不同的工程師進行開發完成。不管是微服務還是這種前後端分離開發,維持一份完整的及時更新的 REST API 文件,會極大的提高我們的工作效率。而傳統的文件更新方式(如手動編寫),很難保證文件的及時性,經常會年久失修,失去應有的意義。因此選擇一種新的 API 文件維護方式很有必要,這也是這篇文章要介紹的內容。

1. OpenAPI 規範介紹

OpenAPI Specification

簡稱 OAS,中文也稱 OpenAPI 描述規範,使用 OpenAPI 檔案可以描述整個 API,它制定了一套的適合通用的與語言無關的 REST API 描述規範,如 API 路徑規範、請求方法規範、請求引數規範、返回格式規範等各種相關資訊,使人類和計算機都可以不需要訪問原始碼就可以理解和使用服務的功能。

下面是 OpenAPI 規範中建議的 API 設計規範,基本路徑設計規範。

https://api.example.com/v1/users?role=admin&status=active
\________________________/\____/ \______________________/
         server URL       endpoint    query parameters
                            path

對於傳參的設計也有規範,可以像下面這樣:

  • 路徑引數, 例如 /users/{id}
  • 查詢引數, 例如 /users?role=未讀程式碼
  • header 引數, 例如 X-MyHeader: Value
  • cookie 引數, 例如 Cookie: debug=0; csrftoken=BUSe35dohU3O1MZvDCU

OpenAPI 規範的東西遠遠不止這些,目前 OpenAPI 規範最新版本是 3.0.2,如果你想了解更多的 OpenAPI 規範,可以訪問下面的連結。
OpenAPI Specification (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md)

2. Swagger 介紹

很多人都以為 Swagger 只是一個介面文件生成框架,其實並不是。 Swagger 是一個圍繞著 OpenAPI Specification(OAS,中文也稱 OpenAPI規範)構建的一組開源工具。可以幫助你從 API 的設計到 API 文件的輸出再到 API 的測試,直至最後的 API 部署等整個 API 的開發週期提供相應的解決方案,是一個龐大的專案。 Swagger 不僅免費,而且開源,不管你是企業使用者還是個人玩家,都可以使用 Swagger 提供的方案構建令人驚豔的 REST API

Swagger 有幾個主要的產品。

  • Swagger Editor – 一個基於瀏覽器的 Open API 規範編輯器。
  • Swagger UI – 一個將 OpenAPI 規範呈現為可互動線上文件的工具。
  • Swagger Codegen – 一個根據 OpenAPI 生成呼叫程式碼的工具。

如果你想了解更多資訊,可以訪問 Swagger 官方網站 https://swagger.io。

3. Springfox 介紹

源於 Java 中 Spring 框架的流行,讓一個叫做 Marrty Pitt 的老外有了為 SpringMVC 新增介面描述的想法,因此他建立了一個遵守 OpenAPI 規範(OAS)的專案,取名為 swagger-springmvc,這個專案可以讓 Spring 專案自動生成 JSON 格式的 OpenAPI 文件。這個框架也仿照了 Spring 專案的開發習慣,使用註解來進行資訊配置。

後來這個專案發展成為 Springfox,再後來擴展出 springfox-swagger2 ,為了讓 JSON 格式的 API 文件更好的呈現,又出現了 springfox-swagger-ui 用來展示和測試生成的 OpenAPI 。這裡的 springfox-swagger-ui 其實就是上面介紹的 Swagger-ui,只是它被通過 webjar 的方式打包到 jar 包內,並通過 maven 的方式引入進來。

上面提到了 Springfox-swagger2 也是通過註解進行資訊配置的,那麼是怎麼使用的呢?下面列舉常用的一些註解,這些註解在下面的 Springboot 整合 Swagger 中會用到。

註解 示例 描述
@ApiModel @ApiModel(value = "使用者物件") 描述一個實體物件
@ApiModelProperty @ApiModelProperty(value = "使用者ID", required = true, example = "1000") 描述屬性資訊,執行描述,是否必須,給出示例
@Api @Api(value = "使用者操作 API(v1)", tags = "使用者操作介面") 用在介面類上,為介面類新增描述
@ApiOperation @ApiOperation(value = "新增使用者") 描述類的一個方法或者說一個介面
@ApiParam @ApiParam(value = "使用者名稱", required = true) 描述單個引數

更多的 Springfox 介紹,可以訪問 Springfox 官方網站。

Springfox Reference Documentation (http://springfox.github.io)

4. Springboot 整合 Swagger

就目前來說 ,Springboot 框架是非常流行的微服務框架,在微服務框架下,很多時候我們都是直接提供 REST API 的。REST API 如果沒有文件的話,使用者就很頭疼了。不過不用擔心,上面說了有一位叫 Marrty Pitt 的老外已經建立了一個發展成為 Springfox 的專案,可以方便的提供 JSON 格式的 OpenAPI 規範和文件支援。且擴展出了 springfox-swagger-ui 用於頁面的展示。

需要注意的是,這裡使用的所謂的 Swagger 其實和真正的 Swagger 並不是一個東西,這裡使用的是 Springfox 提供的 Swagger 實現。它們都是基於 OpenAPI 規範進行 API 構建。所以也都可以 Swagger-ui 進行 API 的頁面呈現。

4.1. 建立專案

如何建立一個 Springboot 專案這裡不提,你可以直接從 Springboot 官方 下載一個標準專案,也可以使用 idea 快速建立一個 Springboot 專案,也可以順便拷貝一個 Springboot 專案過來測試,總之,方式多種多樣,任你選擇。

下面演示如何在 Springboot 專案中使用 swagger2。

4.2. 引入依賴

這裡主要是引入了 springfox-swagger2,可以通過註解生成 JSON 格式的 OpenAPI 介面文件,然後由於 Springfox 需要依賴 jackson,所以引入之。springfox-swagger-ui 可以把生成的 OpenAPI 介面文件顯示為頁面。Lombok 的引入可以通過註解為實體類生成 get/set 方法。

<dependencies> 
    <!-- Spring Boot web 開發整合 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <artifactId>spring-boot-starter-json</artifactId>
                <groupId>org.springframework.boot</groupId>
            </exclusion>
        </exclusions>
    </dependency>

    <!-- 引入swagger2的依賴-->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.9.2</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.9.2</version>
    </dependency>
    
    <!-- jackson相關依賴 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.5.4</version>
    </dependency>

    <!-- Lombok 工具 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

4.3. 配置 Springfox-swagger

Springfox-swagger 的配置通過一個 Docket 來包裝,Docket 裡的 apiInfo 方法可以傳入關於介面總體的描述資訊。而 apis 方法可以指定要掃描的包的具體路徑。在類上新增 @Configuration 宣告這是一個配置類,最後使用 @EnableSwagger2 開啟 Springfox-swagger2。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * <p>
 * Springfox-swagger2 配置
 *
 * @Author niujinpeng
 * @Date 2019/11/19 23:17
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("net.codingme.boot.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("未讀程式碼 API")
                .description("公眾號:未讀程式碼(weidudaima) springboot-swagger2 線上藉口文件")
                .termsOfServiceUrl("https://www.codingme.net")
                .contact("達西呀")
                .version("1.0")
                .build();
    }
}

4.4. 程式碼編寫

文章不會把所有程式碼一一列出來,這沒有太大意義,所以只貼出主要程式碼,完整程式碼會上傳到 Github,並在文章底部附上 Github 連結。

引數實體類 User.java,使用 @ApiModel@ApiModelProperty 描述引數物件,使用 @NotNull 進行資料校驗,使用 @Data 為引數實體類自動生成 get/set 方法。

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;

import javax.validation.constraints.NotNull;
import java.util.Date;

/**
 * <p>
 * 使用者實體類
 *
 * @Author niujinpeng
 * @Date 2018/12/19 17:13
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "使用者物件")
public class User {

    /**
     * 使用者ID
     *
     * @Id 主鍵
     * @GeneratedValue 自增主鍵
     */
    @NotNull(message = "使用者 ID 不能為空")
    @ApiModelProperty(value = "使用者ID", required = true, example = "1000")
    private Integer id;

    /**
     * 使用者名稱
     */
    @NotNull(message = "使用者名稱不能為空")
    @ApiModelProperty(value = "使用者名稱", required = true)
    private String username;
    /**
     * 密碼
     */
    @NotNull(message = "密碼不能為空")
    @ApiModelProperty(value = "使用者密碼", required = true)
    private String password;
    /**
     * 年齡
     */
    @ApiModelProperty(value = "使用者年齡", example = "18")
    private Integer age;
    /**
     * 生日
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss")
    @ApiModelProperty(value = "使用者生日")
    private Date birthday;
    /**
     * 技能
     */
    @ApiModelProperty(value = "使用者技能")
    private String skills;
}

編寫 Controller 層,使用 @Api 描述介面類,使用 @ApiOperation 描述介面,使用 @ApiParam 描述介面引數。程式碼中在查詢使用者資訊的兩個介面上都添加了 tags = "使用者查詢" 標記,這樣這兩個方法在生成 Swagger 介面文件時候會分到一個共同的標籤組裡。

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import net.codingme.boot.domain.Response;
import net.codingme.boot.domain.User;
import net.codingme.boot.enums.ResponseEnum;
import net.codingme.boot.utils.ResponseUtill;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 使用者操作
 *
 * @Author niujinpeng
 * @Date 2019/11/19 23:17
 */

@Slf4j
@RestController(value = "/v1")
@Api(value = "使用者操作 API(v1)", tags = "使用者操作介面")
public class UserController {

    @ApiOperation(value = "新增使用者")
    @PostMapping(value = "/user")
    public Response create(@Valid User user, BindingResult bindingResult) throws Exception {
        if (bindingResult.hasErrors()) {
            String message = bindingResult.getFieldError().getDefaultMessage();
            log.info(message);
            return ResponseUtill.error(ResponseEnum.ERROR.getCode(), message);
        } else {
            // 新增使用者資訊 do something
            return ResponseUtill.success("使用者[" + user.getUsername() + "]資訊已新增");
        }
    }

    @ApiOperation(value = "刪除使用者")
    @DeleteMapping(value = "/user/{username}")
    public Response delete(@PathVariable("username")
                           @ApiParam(value = "使用者名稱", required = true) String name) throws Exception {
        // 刪除使用者資訊 do something
        return ResponseUtill.success("使用者[" + name + "]資訊已刪除");
    }

    @ApiOperation(value = "修改使用者")
    @PutMapping(value = "/user")
    public Response update(@Valid User user, BindingResult bindingResult) throws Exception {
        if (bindingResult.hasErrors()) {
            String message = bindingResult.getFieldError().getDefaultMessage();
            log.info(message);
            return ResponseUtill.error(ResponseEnum.ERROR.getCode(), message);
        } else {
            String username = user.getUsername();
            return ResponseUtill.success("使用者[" + username + "]資訊已修改");
        }
    }

    @ApiOperation(value = "獲取單個使用者資訊", tags = "使用者查詢")
    @GetMapping(value = "/user/{username}")
    public Response get(@PathVariable("username")
                        @NotNull(message = "使用者名稱稱不能為空")
                        @ApiParam(value = "使用者名稱", required = true) String username) throws Exception {
        // 查詢使用者資訊 do something
        User user = new User();
        user.setId(10000);
        user.setUsername(username);
        user.setAge(99);
        user.setSkills("cnp");
        return ResponseUtill.success(user);
    }

    @ApiOperation(value = "獲取使用者列表", tags = "使用者查詢")
    @GetMapping(value = "/user")
    public Response selectAll() throws Exception {
        // 查詢使用者資訊列表 do something
        User user = new User();
        user.setId(10000);
        user.setUsername("未讀程式碼");
        user.setAge(99);
        user.setSkills("cnp");
        List<User> userList = new ArrayList<>();
        userList.add(user);
        return ResponseUtill.success(userList);
    }
}

最後,為了讓程式碼變得更加符合規範和好用,使用一個統一的類進行介面響應。

@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "響應資訊")
public class Response {
    /**
     * 響應碼
     */
    @ApiModelProperty(value = "響應碼")
    private String code;
    /**
     * 響應資訊
     */
    @ApiModelProperty(value = "響應資訊")
    private String message;

    /**
     * 響應資料
     */
    @ApiModelProperty(value = "響應資料")
    private Collection content;
}

4.5. 執行訪問

直接啟動 Springboog 專案,可以看到控制檯輸出掃描到的各個介面的訪問路徑,其中就有 /2/api-docs

這個也就是生成的 OpenAPI 規範的描述 JSON 訪問路徑,訪問可以看到。

因為上面我們在引入依賴時,也引入了 springfox-swagger-ui 包,所以還可以訪問 API 的頁面文件。訪問路徑是 /swagger-ui.html,訪問看到的效果可以看下圖。

也可以看到使用者查詢的兩個方法會歸到了一起,原因就是這兩個方法的註解上使用相同的 tag 屬性。

4.7. 呼叫測試

springfox-swagger-ui 不僅是生成了 API 文件,還提供了呼叫測試功能。下面是在頁面上測試獲取單個使用者資訊的過程。

  1. 點選介面 [/user/{username}] 獲取單個使用者資訊。
  2. 點選 **Try it out** 進入測試傳參頁面。
  3. 輸入引數,點選 Execute 藍色按鈕執行呼叫。
  4. 檢視返回資訊。

下面是測試時的響應截圖。

5. 常見報錯

如果你在程式執行中經常發現像下面這樣的報錯。

java.lang.NumberFormatException: For input string: ""
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) ~[na:1.8.0_111]
    at java.lang.Long.parseLong(Long.java:601) ~[na:1.8.0_111]
    at java.lang.Long.valueOf(Long.java:803) ~[na:1.8.0_111]
    at io.swagger.models.parameters.AbstractSerializableParameter.getExample(AbstractSerializableParameter.java:412) ~[swagger-models-1.5.20.jar:1.5.20]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_111]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_111]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_111]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_111]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:536) [jackson-databind-2.5.4.jar:2.5.4]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:666) [jackson-databind-2.5.4.jar:2.5.4]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:156) [jackson-databind-2.5.4.jar:2.5.4]
    at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:113) [jackson-databind-2.5.4.jar:2.5.4]

那麼你需要檢查使用了 @ApiModelProperty 註解且欄位型別為數字型別的屬性上,@ApiModelProperty 註解是否設定了 example 值,如果沒有,那就需要設定一下,像下面這樣。

@NotNull(message = "使用者 ID 不能為空")
@ApiModelProperty(value = "使用者ID", required = true, example = "1000")
private Integer id;

文中程式碼都已經上傳到 https://github.com/niumoo/springboot

參考文件

  • OpenAPI Specification
  • Swagger Documentation
  • Springfox Reference Documentation

<完>
個人網站:https://www.codingme.net
如果你喜歡這篇文章,可以關注公眾號,一起成長。
關注公眾號回覆資源可以沒有套路的獲取全網最火的的 Java 核心知識整理&面試核心資料。

相關推薦

Springboot 系列真的瞭解 Swagger

前言 目前來說,在 Java 領域使用 Springboot 構建微服務是比較流行的,在構建微服務時,我們大多數會選擇暴漏一個 REST API 以供呼叫。又或者公司採用前後端分離的開發模式,讓前端和後端的工作由完全不同的工程師進行開發完成。不管是微服務還是這種前後端分離開發,維持一份完整的及時更新的 RES

Springboot 系列迅速啟用 HTTPS 加密的網站

1. 獲取 HTTPS 證書 正常情況下 HTTPS 證書需要從證書授權中心獲得,這樣獲得的證書才具有公信力,也會被各種瀏覽器客戶端所認可。常見的證書品牌如 Symantec,GeoTrustm,TrustAsia,Symantec 等。不過在 Springboot 的 HTTPS 實驗中就沒有必要去申請了,

Springboot 系列迅速使用 Spring Boot Admin 監控的 Spring Boot 程式

1. Spring Boot Admin 是什麼 Spring Boot Admin 是由 codecentric 組織開發的開源專案,使用 Spring Boot Admin 可以管理和監控你的 Spring Boot 專案。它分為客戶端和服務端兩部分,客戶端新增到你的 Spring Boot 應用增加暴漏

Springboot 系列迅速使用 Spring Boot Admin 監控的 Spring Boot 程式,支援異常郵件通知

1. Spring Boot Admin 是什麼 Spring Boot Admin 是由 codecentric 組織開發的開源專案,使用 Spring Boot Admin 可以管理和監控你的 Spring Boot 專案。它分為客戶端和服務端兩部分,客戶端新增到你的 Spring Boot 應用增加暴漏

企業分布式微服務雲SpringCloud SpringBoot mybatis Spring Boot中使用LDAP來統一管理用戶信息

數據庫表 repo on() intellij attr ads get 可選 mail LDAP簡介 LDAP(輕量級目錄訪問協議,Lightweight Directory Access Protocol)是實現提供被稱為目錄服務的信息服務。目錄服務是一種特殊的數據庫系

Java 設計模式系列觀察者模式(Observer)

for out 其中 如果 observer 業務 ets 同時 hang Java 設計模式系列(十六)觀察者模式(Observer) 觀察者模式是對象的行為模式,又叫發布-訂閱(Publish/Subscribe)模式、模型-視圖(Model/View)模式、源-監聽

劍指offer系列翻轉單詞順序列,撲克牌順子,孩子們的遊戲圓圈中最後剩下的數

翻轉單詞順序列 題目描述 牛客最近來了一個新員工Fish,每天早晨總是會拿著一本英文雜誌,寫些句子在本子上。同事Cat對Fish寫的內容頗感興趣,有一天他向Fish借來翻看,但卻讀不懂它的意思。例如,“student. a am I”。後來才意識到,這傢伙原來把句子單詞的順序翻轉了,正確的句

linux系列:which命令

1、命令格式:   which 可執行檔名稱 2、命令功能:   which指令會在PATH變數指定的路徑中,搜尋某個系統命令的位置,並且返回第一個搜尋結果。 3、命令引數: -n  指定檔名長度,指定的長度必須大於或等於所有檔案中最長的檔名。 -p  與-n引數相同,但此處的包括了檔案的路

springboot乾貨——使用@Async實現非同步呼叫

非同步呼叫針對的是同步呼叫,一般在程式碼中我們使用同步呼叫相對較多,即請求程式碼立即返回結果或者說執行程式碼,非同步呼叫則是指請求之後不會裡面返回結果或者是呼叫程式碼。 接下來我們用例項來看下什麼是同步呼叫: 新建一個springboot專案後建立對應的task類: pa

Flask1.0.2系列 擴充套件

英文原文地址:http://flask.pocoo.org/docs/1.0/extensions/ 若有翻譯錯誤或者不盡人意之處,請指出,謝謝~         擴充套件是為Flask應用程式新增功能的額外的包。舉個栗子,一個擴充

CM+CDH構建企業大資料平臺系列

完整視訊+圖文資料獲取及技術答疑請加:大講臺大資料研習社⑦ :695520445                        安裝Cloudera Manager Server四、安裝Cloudera

企業分散式微服務雲SpringCloud SpringBoot mybatis Spring Boot中使用LDAP來統一管理使用者資訊

LDAP簡介LDAP(輕量級目錄訪問協議,Lightweight Directory Access Protocol)是實現提供被稱為目錄服務的資訊服務。目錄服務是一種特殊的資料庫系統,其專門針對讀取,瀏覽和搜尋操作進行了特定的優化。目錄一般用來包含描述性的,基於屬性的資訊並

Spark 系列—— Spark Streaming 整合 Kafka

一、版本說明 Spark 針對 Kafka 的不同版本,提供了兩套整合方案:spark-streaming-kafka-0-8 和 spark-streaming-kafka-0-10,其主要區別如下: spark-streaming-kafka-0-8 spark-streaming-kafka-0

Springboot 系列如何編寫自己的 Springboot starter

1. 前言 Springboot 中的自動配置確實方便,減少了我們開發上的複雜性,那麼自動配置原理是什麼呢?之前我也寫過了一篇文章進行了分析。 Springboot 系列(三)Spring Boot 自動配置。 由於自動配置用到了配置檔案的繫結,如果你還不知道常見的配置檔案的用法,可以參考這篇文章。 S

Golang 入門系列鎖的使用場景主要涉及到哪些?讀寫鎖為什麼會比普通鎖快

前面已經講過很多Golang系列知識,感興趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html, 接下來要說的是golang的鎖的使用場景主要涉及到哪些?讀寫鎖為什麼會比普通鎖快。   一、什麼場景下需要用到鎖

Selenium系列 - Web UI 自動化基礎實戰3

如果你還想從頭學起Selenium,可以看看這個系列的文章哦! https://www.cnblogs.com/poloyy/category/1680176.html   其次,如果你不懂前端基礎知識,需要自己去補充哦,博主暫時沒有總結(雖然我也會,所以我學selenium就不用複習前端了哈哈哈.

SpringBoot系列整合郵件傳送服務及郵件傳送的幾種方式

**往期推薦** [SpringBoot系列(一)idea新建Springboot專案](https://www.cnblogs.com/swzx-1213/p/12345330.html) [SpringBoot系列(二)入門知識](https://www.cnblogs.com/swzx-1213/p

Quartz.Net系列:Misfire策略在SimpleScheduler和CronScheduler中的使用

1.場景 ①因為工作執行緒都在忙碌,所以導致某些Trigger得不到觸發 也就是預設10個工作執行緒而我有15個Trigger同時觸發 這就導致有5個不能被觸發,而不幸的是Trigger所關聯的Job執行時間特別長 如果某些Trigger超過指定的閾值那麼就不會觸發 ②Scheduler掛掉了。。。某些時刻又

Linux命令 打包或解壓 tar

常用 特定 -- 返回 相關信息 href -c 壓縮文件 標識 目錄 1.命令簡介 2.常用參數介紹 3.實例 4.直達底部 命令簡介 tar 命令用於將文件打包或解壓,擴展名一般為 ".tar" ,指定特定的參數可以調用 gzip 或 bzip2 制作壓縮包或解

Linux命令 壓縮或解壓縮和目錄 gzip gunzip

配置 硬鏈接 名稱 log logs 壓縮文件 mark 底部 linux 目錄 1.命令簡介 2.常用參數介紹 3.實例 4.直達底部 命令簡介 和 zip 命令類似,gzip 用於文件的壓縮,gzip壓縮後的文件擴展名為 ".gz",gzip默認壓縮後會刪除源文