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

前言

  回顧以前的兩篇Swagger作Api接口文檔,咱們大致上學會了如何在net core3.1的項目基礎上,搭建一套自動生產API接口說明文檔的框架。css

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

                                 

  但是這個時候,若是接口數量上百個,甚至更多,一個一個手動輸入word,那將是一筆耗時的工做。但卻有什麼辦法能夠解決呢?  git

  對了,利用Swagge生成的Json文件轉換爲word文檔不就能夠了嗎?github

思路

  1. 獲取Swagger接口文檔的Json文件web

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

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

模板

   文檔模板

 

URLapi

/api/Movie/AddMovieapp

請求方式框架

Post

參數名

參數類型

是否必填

說明

id

Query

False

影視ID

Name

Query

False

電影名稱

Type

Query

False

電影類型

狀態碼

說明

200

Success

示例

請求參數

 

返回值

 

開始

1、根據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,後面能夠直接使用這個方法

2、文件數據填充到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;
        }

3、根據生成的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;
        }
    }

4、最終效果

將html轉換爲word後,咱們就能夠看到帶有 .doc 的效果了!差很少是以下效果

總結

  1. 到這基本就結束了,經過簡易的幾個接口的方式,展現瞭如何經過將Swagger接口文檔生成word文檔。能夠根據本身的html模板生成各式的word樣式文檔說明。

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

  3.後續還會不斷修改和完善,能夠更多的生成不一樣的文件類型和按需生成不一樣版本的接口文檔,持續更新。。。

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

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

  6.源碼下載

相關文章
相關標籤/搜索