基于.NetCore3.1搭建项目系列 —— 使用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, , 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导出文档 (番外篇)的更多相关文章
- 基于.NetCore3.1搭建项目系列 —— 使用Swagger导出文档 (补充篇)
前言 在上一篇导出文档番外篇中,我们已经熟悉了怎样根据json数据导出word的文档,生成接口文档,而在这一篇,将对上一篇进行完善补充,增加多种导出方式,实现更加完善的导出功能. 回顾 1. 获取Sw ...
- 基于.NetCore3.1搭建项目系列 —— 使用Swagger做Api文档 (上篇)
前言 为什么在开发中,接口文档越来越成为前后端开发人员沟通的枢纽呢? 随着业务的发张,项目越来越多,而对于支撑整个项目架构体系而言,我们对系统业务的水平拆分,垂直分层,让业务系统更加清晰,从而产生一系 ...
- 基于.NetCore3.1搭建项目系列 —— 使用Swagger做Api文档 (下篇)
前言 回顾上一篇文章<使用Swagger做Api文档 >,文中介绍了在.net core 3.1中,利用Swagger轻量级框架,如何引入程序包,配置服务,注册中间件,一步一步的实现,最终 ...
- JavaWeb项目中集成Swagger API文档
1.增加依赖 <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-sw ...
- ABP框架搭建项目系列教程基础版完结篇
返回总目录<一步一步使用ABP框架搭建正式项目系列教程> 经过前面十二篇的基础教程,现在终于该做个总结了. 回顾 第一篇,我们建议新手朋友们先通过ABP官网的启动模板生成解决方案,因为这样 ...
- 分享一个集成在项目中的REST APIs文档框架swagger
1 为什么是使用swagger? 1-1 当后台开发人员开发好接口,是不是还要重新书写一份接口文档提给前端人员,当然对于程序员最不喜欢的就是书写文档(当然文档是必须的,有利于项目的维护) 1-2 当后 ...
- 使用Swagger 搭建高可读性ASP.Net WebApi文档
一.前言 在最近一个商城项目中,使用WebApi搭建API项目.但开发过程中,前后端工程师对于沟通接口的使用,是非常耗时的.之前也有用过Swagger构建WebApi文档,但是API文档的可读性并不高 ...
- springboot+swagger接口文档企业实践(上)
目录 1.引言 2.swagger简介 2.1 swagger 介绍 2.2 springfox.swagger与springboot 3. 使用springboot+swagger构建接口文档 3. ...
- Spring系列(零) Spring Framework 文档中文翻译
Spring 框架文档(核心篇1和2) Version 5.1.3.RELEASE 最新的, 更新的笔记, 支持的版本和其他主题,独立的发布版本等, 是在Github Wiki 项目维护的. 总览 历 ...
随机推荐
- 一文看懂js中元素偏移量(offsetLeft,offsetTop,offsetWidth,offsetHeight)
偏移量(offset dimension) 偏移量:包括元素在屏幕上占用的所有可见空间,元素的可见大小有其高度,宽度决定,包括所有内边距,滚动条和边框大小(注意,不包括外边距). 以下4个属性可以获取 ...
- 一起了解 .Net Foundation 项目 No.13
.Net 基金会中包含有很多优秀的项目,今天就和笔者一起了解一下其中的一些优秀作品吧. 中文介绍 中文介绍内容翻译自英文介绍,主要采用意译.如与原文存在出入,请以原文为准. MVVM Light To ...
- 简单说 通过CSS的滤镜 实现 火焰效果
说明 上次我们了解了一些css滤镜的基础知识, 简单说 CSS滤镜 filter属性 这次我们就来用css的滤镜实现一个 火焰的效果. 解释 要实现上面的火焰效果,我们先来了解一些必要的东西. 上次我 ...
- .NET异步程序设计之async&await
目录 0.背景引入 1.async和await基本语法 2.异步方法的执行顺序 3.取消一个异步操作 4.同步和异步等待任务 5.异步操作中的异常处理 6.多线程和异步的区分 7. 在 .NET MV ...
- vue iview modal弹出框 form表单验证
一.ref="addApply" :model="addApply" :rules="ruleValidate" 不要忘记prop 二. ...
- frida入门总结
一.Frida概述 Frida是一款轻量级HOOK框架,可用于多平台上,例如android.windows.ios等. frida分为两部分,服务端运行在目标机上,通过注入进程的方式来 ...
- 第一篇博客 C+++知识点总结一
1.成员 1.比较特殊的成员类型:protected. 保护成员在本类中和private类型的成员作用一模一样.区别在于保护成员可以由本类的派生类的成员函数访问,但是私有成员在其派生类中无法访问. 2 ...
- PHP eval变量延迟赋值
$str = 'and {$prev}name like \'%五子棋%\'';$prev = "table.";eval("\$str = \"$str\&q ...
- MySQL使用前查看状态
1.检查MySQL服务器是否启动:ps -ef | grep mysqld 如果MySql已经启动,以上命令将输出mysql进程列表,如下所示:mysql下一行 如果mysql未启动,你可以使用以下命 ...
- 自定义添加$_SERVER中的变量
如何根据自己项目中的需求自定义$_SERVER中的变量呢?比如$_SERVER['XU_TEXT_PARAM'],这个超全局变量输出肯定是会报错的.那如何自定义它,让它输出我们想要输出的值呢? 1.在 ...