基於.NetCore3.1搭建項目系列 —— 使用Swagger導出文檔 (番外篇)

来源:https://www.cnblogs.com/i3yuan/archive/2020/04/05/12633768.html
-Advertisement-
Play Games

前言 回顧之前的兩篇Swagger做Api介面文檔,我們大體上學會瞭如何在net core3.1的項目基礎上,搭建一套自動生產API介面說明文檔的框架。 本來在Swagger的基礎上,前後端開發人員在開發生產期間,可以藉此進行更加便捷的溝通交流。可是總有些時候,遇到一些難纏的,又不講道理,偏偏覺得將 ...


前言

  回顧之前的兩篇Swagger做Api介面文檔,我們大體上學會瞭如何在net core3.1的項目基礎上,搭建一套自動生產API介面說明文檔的框架。

  本來在Swagger的基礎上,前後端開發人員在開發生產期間,可以藉此進行更加便捷的溝通交流。可是總有些時候,遇到一些難纏的,又不講道理,偏偏覺得將Swagger文檔地址丟給客戶會不夠正式!死活要一份word文檔。

                                 

  可是這個時候,如果介面數量上百個,甚至更多,一個一個手動輸入word,那將是一筆耗時的工作。但卻有什麼辦法可以解決呢?  

  對了,利用Swagge生成的Json文件轉換為word文檔不就可以了嗎?

思路

  1. 獲取Swagger介面文檔的Json文件

  2. 解析Json文件數據填充到Html的表格中

  3.根據生成的html轉work文檔

模板

   文檔模板

 

URL

/api/Movie/AddMovie

請求方式

Post

參數名

參數類型

是否必填

說明

id

Query

False

影視ID

Name

Query

False

電影名稱

Type

Query

False

電影類型

狀態碼

說明

200

Success

示例

請求參數

 

返回值

 

開始

一、根據Swagger版本獲取Json數據

1.通過Swagger源碼文件可以看到

 可以拿到swagger生成的文檔數據,所以我們可以新建一個控制器SwaggerController.cs,

        private readonly SwaggerGenerator _swaggerGenerator;
        public SwaggerController(SwaggerGenerator swaggerGenerator)
        {
            _swaggerGenerator = swaggerGenerator;
        }
        /// <summary>
        /// 導出文件
        /// </summary>
        /// <param name="type">文件類型</param>
        /// <param name="version">版本號V1</param>
        /// <returns></returns>
        [HttpGet]
        public FileResult ExportWord(string type,string version)
        {
            string contenttype = string.Empty;

            var model = _swaggerGenerator.GetSwagger(version); //1. 根據指定版本獲取指定版本的json對象。
        }

2. 在Startup.cs文件中,利用net core的ioc容器,註入SwaggerGenerator實例化,這樣在後面的調用中可以直接使用這個方法

            services.AddScoped<SwaggerGenerator>(); //註入SwaggerGenerator,後面可以直接使用這個方法

二、文件數據填充到Html的表格中

根據上面獲取的model文件數據,這個時候,我們利用Razor文件,結合html的table模板,將數據遍歷填充到頁面中,生成完整的頁面

Html模板

@using Swashbuckle.AspNetCore.Swagger;
<!DOCTYPE html>
<html>
<head>
    <title>Swagger API文檔代碼文件</title>
    <style type='text/css'>

        table, table td, table th {
            border: 1px solid #000000;
            border-collapse: collapse;
        }

        table {
            table-layout: fixed;
            word-break: break-all;
        }

        tr {
            height: 20px;
            font-size: 12px;
        }
    </style>
</head>
<body>
    <div style='width:1000px; margin: 0 auto'>
        <span><i>Word介面文檔</i></span>
        <h1 align="center">@Model.Info.Title</h1>
        <h1 align="center">介面文檔 @Model.Info.Version</h1>
        <h4>聯繫方式</h4>
        <span>作者:@Model.Info.Contact.Name</span>
        <br>
        <a href="mailto:@Model.Info.Contact.Email" rel="noopener noreferrer" class="link">Send email to Xunit.Core</a>
        <br>
        <a href="@Model.Info.Contact.Url" target="_blank" rel="noopener noreferrer" class="link">@Model.Info.Contact.Name - Website</a>
        <br>
        <h3>介面描述</h3>
        <span>@Model.Info.Description</span>
        <br>
        <table border='1' cellspacing='0' cellpadding='0' style="table-layout: fixed; word-break: break-all;border: 1px solid #000000;border-collapse: collapse;" width='100%'>
            <tr style="border: 1px solid #000000;border-collapse: collapse;">
                <td align="center" style="background-color: rgb(84, 127, 177);">說明</td>
                <td></td>
            </tr>
            <tr style="border: 1px solid #000000;border-collapse: collapse;">
                <td align="center" style="background-color: rgb(84, 127, 177);">類型</td>
                <td></td>
            </tr>

        </table>
        @foreach (var item in Model.Paths)
        {
            if (item.Value.Operations != null)
            {
                foreach (var operation in item.Value.Operations)
                {
                    <h3>@operation.Value.Summary</h3>
                    <table border='1' cellspacing='0' cellpadding='0' width='100%' style="table-layout: fixed; word-break: break-all;border: 1px solid #000000;border-collapse: collapse;">
                        <tr style="background-color: rgb(84, 127, 177);" align="center">
                            <td colspan='5'></td>
                        </tr>
                     
                        <tr style="border: 1px solid #000000;border-collapse: collapse;">
                            <td style="border: 1px solid #000000;border-collapse: collapse;">URL</td>
                            <td colspan='4'>@item.Key</td>
                        </tr>
                        <tr style="border: 1px solid #000000;border-collapse: collapse;">
                            <td style="border: 1px solid #000000;border-collapse: collapse;">請求方式</td>
                            <td colspan='4'>
                                @operation.Key
                            </td>
                        </tr>
                       
                        @if (operation.Value.Parameters != null && operation.Value.Parameters.Count > 0)
                        {
                            <tr style="background-color: rgb(84, 127, 177);" align='center'>
                                <td style="border: 1px solid #000000;border-collapse: collapse;">參數名</td>
                                <td style="border: 1px solid #000000;border-collapse: collapse;">參數類型</td>
                                <td style="border: 1px solid #000000;border-collapse: collapse;">是否必填</td>
                                <td style="border: 1px solid #000000;border-collapse: collapse;" colspan='2'>說明</td>
                            </tr>
                            @foreach (var param in operation.Value.Parameters)
                            {
                                <tr align='center' style="border: 1px solid #000000;border-collapse: collapse;">
                                    <td style="border: 1px solid #000000;border-collapse: collapse;">@param.Name</td>
                                    <td style="border: 1px solid #000000;border-collapse: collapse;">@param.In</td>
                                    <td style="border: 1px solid #000000;border-collapse: collapse;">@param.Required</td>
                                    <td style="border: 1px solid #000000;border-collapse: collapse;" colspan='2'>@param.Description</td>
                                </tr>
                            }
                        }

                        <tr style="background-color: rgb(84, 127, 177);" align='center'>
                            <td style="border: 1px solid #000000;border-collapse: collapse;">狀態碼</td>
                            <td style="border: 1px solid #000000;border-collapse: collapse;" colspan='4'>說明</td>
                        </tr>
                        @if (operation.Value.Responses != null && operation.Value.Responses.Count > 0)
                        {
                            foreach (var response in operation.Value.Responses)
                            {
                                <tr align='center' style="border: 1px solid #000000;border-collapse: collapse;">
                                    <td style="border: 1px solid #000000;border-collapse: collapse;">@response.Key</td>
                                    <td style="border: 1px solid #000000;border-collapse: collapse;" colspan='4'>@response.Value.Description</td>
                                </tr>

                            }
                        }
                        <tr style="background-color: rgb(84, 127, 177);">
                            <td style="border: 1px solid #000000;border-collapse: collapse;" colspan='5'>示例</td>
                        </tr>
                        <tr style="height: 40px;" style="border: 1px solid #000000;border-collapse: collapse;">
                            <td style="background-color: rgb(84, 127, 177);">請求參數</td>
                            <td style="border: 1px solid #000000;border-collapse: collapse;" colspan='4'></td>
                        </tr>
                        <tr style="height: 40px;" style="border: 1px solid #000000;border-collapse: collapse;">
                            <td style="background-color: rgb(84, 127, 177);">返回值</td>
                            <td style="border: 1px solid #000000;border-collapse: collapse;" colspan='4'></td>
                        </tr>
                    </table>
                    <br>
                }

            }
            
        }
    </div>
</body>
</html>

將數據遍歷到靜態頁面中,

        /// <summary>
        /// 將數據遍歷靜態頁面中
        /// </summary>
        /// <param name="templatePath">靜態頁面地址</param>
        /// <param name="model">獲取到的文件數據</param>
        /// <returns></returns>
        public static string GeneritorSwaggerHtml(string templatePath, OpenApiDocument model)
        {
            var template = System.IO.File.ReadAllText(templatePath);
            var result = Engine.Razor.RunCompile(template, "i3yuan", typeof(OpenApiDocument), model);
            return result;
        }

三、根據生成的html轉work文檔

        /// <summary>
        /// 靜態頁面轉文件
        /// </summary>
        /// <param name="html">靜態頁面html</param>
        /// <param name="type">文件類型</param>
        /// <param name="contenttype">上下文類型</param>
        /// <returns></returns>
        public Stream SwaggerConversHtml(string html, string type, out string contenttype)
        {
            string fileName = Guid.NewGuid().ToString() + type;
            //文件存放路徑
            string webRootPath = _hostingEnvironment.WebRootPath;
            string path = webRootPath + @"\Files\TempFiles\";
            var addrUrl = path + $"{fileName}";
            FileStream fileStream = null;
            var provider = new FileExtensionContentTypeProvider();
            contenttype = provider.Mappings[type];
            try
            {
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }
                var data = Encoding.Default.GetBytes(html);
                var stream = ByteHelper.BytesToStream(data);
                //創建Document實例
                Document document = new Document();
                //載入HTML文檔
                document.LoadFromStream(stream, FileFormat.Html, XHTMLValidationType.None);
                //保存為Word
                document.SaveToFile(addrUrl, FileFormat.Docx);

                document.Close();
                fileStream = File.Open(addrUrl, FileMode.OpenOrCreate);
                var filedata = ByteHelper.StreamToBytes(fileStream);
                var outdata = ByteHelper.BytesToStream(filedata);

                return outdata;
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                if (fileStream != null)
                    fileStream.Close();
                if (File.Exists(addrUrl))
                    File.Delete(addrUrl);//刪掉文件
            }
        }
    public class ByteHelper
    {
        public static byte[] StreamToBytes(Stream stream)
        {
            byte[] bytes = new byte[stream.Length];
            stream.Read(bytes, 0, bytes.Length);
            // 設置當前流的位置為流的開始 
            stream.Seek(0, SeekOrigin.Begin);
            return bytes;
        }

        /// 將 byte[] 轉成 Stream
        public static Stream BytesToStream(byte[] bytes)
        {
            Stream stream = new MemoryStream(bytes);
            return stream;
        }
    }

四、最終效果

將html轉換為word後,我們就可以看到帶有 .doc 的效果了!差不多是如下效果

總結

  1. 到這基本就結束了,通過簡易的幾個介面的方式,展示瞭如何通過將Swagger介面文檔生成word文檔。可以根據自己的html模板生成各式的word樣式文檔說明。

  2.寫這篇番外主要是因為之前介紹了關於如何使用Swagger生成線上文檔,但實際工作中,可能也會遇到這種要各種正式word文檔的客戶,所以在此分享一些想法和思路,同時希望大家不吝指教。

  3.後續還會不斷修改和完善,可以更多的生成不同的文件類型和按需生成不同版本的介面文檔,持續更新。。。

  4 .註:搜索關註公眾號【DotNet技術谷】--回覆【文檔生成器】,可獲取本篇Swagger轉換work文件

  5. 參考資料:Spire.Doc文件 、Swagger開源地址

  6.源碼下載


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 原文: "Java Garbage Collection Algorithms [till Java 9]" 垃圾回收(Garbage collection,GC)一直是 Java 流行背後的重要特性之一。垃圾回收是 Java 中用於釋放未使用記憶體的機制。本質上,它跟蹤所有仍在使用的對象,並將其餘的 ...
  • 前言 AQS一共花了5篇文章,對裡面實現的核心源碼都做了註解 也和大家詳細描述了下,後面的幾篇文字我將和大家聊聊一下AQS的實際使用,主要會聊幾張鎖,第一篇我會和大家聊下ReentrantLock 重入鎖,雖然在講AQS中也穿插了講了一下,但是我還是深入的聊下 ==PS:前面5篇寫在了CSDN裡面 ...
  • SpringCloud版本:Finchley.SR2 SpringBoot版本:2.0.3.RELEASE 源碼地址:https://gitee.com/bingqilinpeishenme/Java Tutorials 前言 寫博客一個多月了,斷斷續續的更新,今天有小伙伴催更新了,很高興,說明我的 ...
  • 前言 最近想起半年前鴿下來的Haskell,重溫了一下忘得精光的語法,讀了幾個示常式序,挺帶感的,於是函數式編程的草就種得更深了。又去Google了一下C++與FP,找到了一份近乎完美的講義,然後被帶到C++20的ranges library,對即將發佈的C++20滿懷憧憬。此時,我猛然間意識到,看 ...
  • ​ 1.問題 1、如何理解類文件結構佈局? 2、如何應用類載入器的工作原理進行將應用輾轉騰挪? 3、熱部署與熱替換有何區別,如何隔離類衝突? 4、JVM如何管理記憶體,有何記憶體淘汰機制? 5、JVM執行引擎的工作機制是什麼? 6、JVM調優應該遵循什麼原則,使用什麼工具? 7、JPDA架構是什麼,如何 ...
  • 原文鏈接:http://www.yiidian.com/hibernate/hibernate get load.html 1 演示get和load方法的基本使用 源碼下載:https://pan.baidu.com/s/1c2HD7tm 2 分析get和load方法的區別 在hibernate中我 ...
  • Consul是HashiCorp公司推出的開源工具,Consul由Go語言開發,部署起來非常容易,只需要極少的可執行程式和配置文件,具有綠色、輕量級的特點。Consul是`分散式`的、`高可用`的、 `可橫向擴展`的用於實現分散式系統的服務發現與配置。 ...
  • 這篇文章中,我將詳細介紹ASP.NET Core OutOfProcess Hosting模型。強烈推薦你去看看我之前寫的ASP.NET Core InProcess以及ASP.NET Core中的 Kestrel Web伺服器。這篇文章我將向大家詳細介紹下麵幾個問題:怎樣在ASP.NET Core... ...
一周排行
    -Advertisement-
    Play Games
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...