前言 回顧之前的兩篇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.源碼下載