前言

回顾之前的两篇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, , bytes.Length);
// 设置当前流的位置为流的开始
stream.Seek(, 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.源码下载

基于.NetCore3.1搭建项目系列 —— 使用Swagger导出文档 (番外篇)的更多相关文章

  1. 基于.NetCore3.1搭建项目系列 —— 使用Swagger导出文档 (补充篇)

    前言 在上一篇导出文档番外篇中,我们已经熟悉了怎样根据json数据导出word的文档,生成接口文档,而在这一篇,将对上一篇进行完善补充,增加多种导出方式,实现更加完善的导出功能. 回顾 1. 获取Sw ...

  2. 基于.NetCore3.1搭建项目系列 —— 使用Swagger做Api文档 (上篇)

    前言 为什么在开发中,接口文档越来越成为前后端开发人员沟通的枢纽呢? 随着业务的发张,项目越来越多,而对于支撑整个项目架构体系而言,我们对系统业务的水平拆分,垂直分层,让业务系统更加清晰,从而产生一系 ...

  3. 基于.NetCore3.1搭建项目系列 —— 使用Swagger做Api文档 (下篇)

    前言 回顾上一篇文章<使用Swagger做Api文档 >,文中介绍了在.net core 3.1中,利用Swagger轻量级框架,如何引入程序包,配置服务,注册中间件,一步一步的实现,最终 ...

  4. JavaWeb项目中集成Swagger API文档

    1.增加依赖 <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-sw ...

  5. ABP框架搭建项目系列教程基础版完结篇

    返回总目录<一步一步使用ABP框架搭建正式项目系列教程> 经过前面十二篇的基础教程,现在终于该做个总结了. 回顾 第一篇,我们建议新手朋友们先通过ABP官网的启动模板生成解决方案,因为这样 ...

  6. 分享一个集成在项目中的REST APIs文档框架swagger

    1 为什么是使用swagger? 1-1 当后台开发人员开发好接口,是不是还要重新书写一份接口文档提给前端人员,当然对于程序员最不喜欢的就是书写文档(当然文档是必须的,有利于项目的维护) 1-2 当后 ...

  7. 使用Swagger 搭建高可读性ASP.Net WebApi文档

    一.前言 在最近一个商城项目中,使用WebApi搭建API项目.但开发过程中,前后端工程师对于沟通接口的使用,是非常耗时的.之前也有用过Swagger构建WebApi文档,但是API文档的可读性并不高 ...

  8. springboot+swagger接口文档企业实践(上)

    目录 1.引言 2.swagger简介 2.1 swagger 介绍 2.2 springfox.swagger与springboot 3. 使用springboot+swagger构建接口文档 3. ...

  9. Spring系列(零) Spring Framework 文档中文翻译

    Spring 框架文档(核心篇1和2) Version 5.1.3.RELEASE 最新的, 更新的笔记, 支持的版本和其他主题,独立的发布版本等, 是在Github Wiki 项目维护的. 总览 历 ...

随机推荐

  1. 一文看懂js中元素偏移量(offsetLeft,offsetTop,offsetWidth,offsetHeight)

    偏移量(offset dimension) 偏移量:包括元素在屏幕上占用的所有可见空间,元素的可见大小有其高度,宽度决定,包括所有内边距,滚动条和边框大小(注意,不包括外边距). 以下4个属性可以获取 ...

  2. 一起了解 .Net Foundation 项目 No.13

    .Net 基金会中包含有很多优秀的项目,今天就和笔者一起了解一下其中的一些优秀作品吧. 中文介绍 中文介绍内容翻译自英文介绍,主要采用意译.如与原文存在出入,请以原文为准. MVVM Light To ...

  3. 简单说 通过CSS的滤镜 实现 火焰效果

    说明 上次我们了解了一些css滤镜的基础知识, 简单说 CSS滤镜 filter属性 这次我们就来用css的滤镜实现一个 火焰的效果. 解释 要实现上面的火焰效果,我们先来了解一些必要的东西. 上次我 ...

  4. .NET异步程序设计之async&await

    目录 0.背景引入 1.async和await基本语法 2.异步方法的执行顺序 3.取消一个异步操作 4.同步和异步等待任务 5.异步操作中的异常处理 6.多线程和异步的区分 7. 在 .NET MV ...

  5. vue iview modal弹出框 form表单验证

    一.ref="addApply" :model="addApply" :rules="ruleValidate"   不要忘记prop 二. ...

  6. frida入门总结

    一.Frida概述     Frida是一款轻量级HOOK框架,可用于多平台上,例如android.windows.ios等.     frida分为两部分,服务端运行在目标机上,通过注入进程的方式来 ...

  7. 第一篇博客 C+++知识点总结一

    1.成员 1.比较特殊的成员类型:protected. 保护成员在本类中和private类型的成员作用一模一样.区别在于保护成员可以由本类的派生类的成员函数访问,但是私有成员在其派生类中无法访问. 2 ...

  8. PHP eval变量延迟赋值

    $str = 'and {$prev}name like \'%五子棋%\'';$prev = "table.";eval("\$str = \"$str\&q ...

  9. MySQL使用前查看状态

    1.检查MySQL服务器是否启动:ps -ef | grep mysqld 如果MySql已经启动,以上命令将输出mysql进程列表,如下所示:mysql下一行 如果mysql未启动,你可以使用以下命 ...

  10. 自定义添加$_SERVER中的变量

    如何根据自己项目中的需求自定义$_SERVER中的变量呢?比如$_SERVER['XU_TEXT_PARAM'],这个超全局变量输出肯定是会报错的.那如何自定义它,让它输出我们想要输出的值呢? 1.在 ...