vue学习记录 8
问了一下大佬侧边栏内容在哪设置的,他说项目里写了一个自动生成接口的脚本,这些接口构成目录。ಠ_ಠ
不在src,在src同级目录generate下。generate>index.js,自动生成后的各个js文件会显示在generate>config.js内。如果要另外多加接口,除了改脚本配置外,还需要 npm run swagger 。各种run指令部署在src同级目录下的package.json下“scripts”:
1 "scripts": { 2 "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 3 "start": "npm run dev", 4 "build": "node build/build.js", 5 "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml", 6 "swagger": "node generate/index.js" 7 },
generate>index.js

1 const fs = require("fs"); 2 const path = require("path"); 3 const http = require("http"); 4 const srcFolder = "/src"; 5 const config = require("./config"); 6 7 // 自动生成接口 8 config.urls.forEach(url => { 9 main(url); 10 }); 11 12 function mkdirsSync(dirname) { 13 if (fs.existsSync(dirname)) { 14 return true; 15 } else { 16 if (mkdirsSync(path.dirname(dirname))) { 17 fs.mkdirSync(dirname); 18 return true; 19 } 20 } 21 } 22 function getPath(pathUrl) { 23 return path.resolve(__dirname, pathUrl); 24 } 25 function generateTemplate(arr) { 26 return 'import httpReq from "@/utils/request";\n'; 27 } 28 29 function generateFunc(name, summary, type = "post") { 30 const arr = name.slice(1).split("/"); 31 const fun = arr[arr.length - 1]; 32 return ` 33 // ${summary || ""} 34 export function ${fun}(params){ 35 let url = "${name}"; 36 return httpReq(url, "${type}", params) 37 }\n`; 38 } 39 40 function httpgetJson(url) { 41 return new Promise((resolve, reject) => { 42 http 43 .get(url, res => { 44 console.log("res", res); 45 const { statusCode } = res; 46 const contentType = res.headers["content-type"]; 47 48 let error; 49 if (statusCode !== 200) { 50 error = new Error("请求失败。\n" + `状态码: ${statusCode}`); 51 } else if (!/^application\/json/.test(contentType)) { 52 error = new Error( 53 "无效的 content-type.\n" + 54 `期望 application/json 但获取的是 ${contentType}` 55 ); 56 } 57 if (error) { 58 console.error(error.message); 59 // 消耗响应数据以释放内存 60 res.resume(); 61 return; 62 } 63 64 res.setEncoding("utf8"); 65 let rawData = ""; 66 res.on("data", chunk => { 67 rawData += chunk; 68 }); 69 res.on("end", () => { 70 try { 71 const parsedData = JSON.parse(rawData); 72 resolve(parsedData); 73 } catch (e) { 74 reject(`错误: ${e.message}`); 75 } 76 }); 77 }) 78 .on("error", e => { 79 reject(`错误: ${e.message}`); 80 }); 81 }); 82 } 83 84 async function main(url) { 85 let mfolder = url.split("/")[3]; 86 console.log("获取远程json文件中..."); 87 const { paths } = await httpgetJson(url); 88 console.log("获取成功正在生成api文件"); 89 const obj = {}; 90 for (const name in paths) { 91 const path = paths[name]; 92 93 let folder = ""; 94 if (path.post) { 95 const tag = path.post.tags[0]; 96 if (!tag) continue; 97 const urlArray = name.slice(1).split("/"); 98 if (name.slice(1).split("/").length === 4) { 99 folder = urlArray[1]; 100 } else { 101 if (name.slice(1).split("/")[0] !== tag) continue; 102 } 103 if (obj[path.post.tags[0]]) { 104 obj[path.post.tags[0]].push({ 105 summary: path.post.summary, 106 tag, 107 name, 108 type: "post", 109 folder: folder + "/" + mfolder 110 }); 111 } else { 112 obj[path.post.tags[0]] = [ 113 { 114 summary: path.post.summary, 115 tag, 116 name, 117 type: "post", 118 folder: folder + "/" + mfolder 119 } 120 ]; 121 } 122 } else if (path.get) { 123 const tag = path.get.tags[0]; 124 console.log(tag); 125 if (!tag) continue; 126 const urlArray = name.slice(1).split("/"); 127 if (name.slice(1).split("/").length === 4) { 128 folder = urlArray[1]; 129 } else { 130 if (name.slice(1).split("/")[0] !== tag) continue; 131 } 132 if (obj[path.get.tags[0]]) { 133 obj[path.get.tags[0]].push({ 134 summary: path.get.summary, 135 tag, 136 name, 137 type: "get", 138 folder: folder + "/" + mfolder 139 }); 140 } else { 141 obj[path.get.tags[0]] = [ 142 { 143 summary: path.get.summary, 144 tag, 145 name, 146 type: "get", 147 folder: folder + "/" + mfolder 148 } 149 ]; 150 } 151 } 152 } 153 for (const tagName in obj) { 154 let jsString = ""; 155 const requestTypes = []; 156 let folder = ""; 157 for (const item of obj[tagName]) { 158 const requestType = requestTypes.filter(o => o === item.type); 159 if (requestType.length === 0) requestTypes.push(item.type); 160 jsString += generateFunc(item.name, item.summary, item.type); 161 folder = item.folder; 162 } 163 jsString = generateTemplate(requestTypes) + jsString; 164 mkdirsSync(getPath(`..${srcFolder}/api/${folder}`)); 165 fs.writeFileSync( 166 getPath(`..${srcFolder}/api/${folder}/${tagName}.js`), 167 jsString 168 ); 169 } 170 console.log("生成完毕"); 171 }
index.js前五行:
1 const fs = require("fs"); 2 const path = require("path"); 3 const http = require("http"); 4 const srcFolder = "/src"; 5 const config = require("./config");
参考网址 https://blog.csdn.net/qq_30258495/article/details/125938589
require用于引入模块,前三行是向服务器请求页面的必要模块引入
readFile(path[,option],callback(err,data)); //fs模块:读取文件 writeFile(path,data[,option],callback(err)); //fs模块:写入覆盖文件 __dirname //path模块,文件当前所处目录 path.join(__dirname , 'xx/x/x' , 'x/x/x');//path模块:拼接路径 path.basename(url); //path模块:获取路径中的文件名 path.extname(); //path模块:获取路径的扩展名 http.createServer(); //http模块:创建服务器实例 server.on('事件名',callback(request,response));//http模块:为服务器绑定事件 server.listen(端口号,callback()); //http模块:监听端口
第五行引入的是utils.js模块,参考网址 https://blog.csdn.net/baidu_36611723/article/details/82252658
1 config.urls.forEach(url => { 2 main(url); 3 });
这个要和函数main(url)一起看,main内另外嵌自建函数httpgetJson(url)。搜索
1 const requestType = requestTypes.filter(o => o === item.type); 2 if (requestType.length === 0) requestTypes.push(item.type); 3 jsString += generateFunc(item.name, item.summary, item.type); 4 folder = item.folder;
的时候发现swagger脚本教程:
参考网址 https://blog.csdn.net/weixin_39695241/article/details/111534917
内容有点简略,可能是搬运?另外搜了一下
参考网址 https://blog.csdn.net/jsrgckf/article/details/128803251 这个给了详细的样例,不过和当前项目的有出入,可以作为学习参考。
参考网址 https://www.cnblogs.com/hmit/p/11363412.html 个人推荐看这个,有更详细的swagger使用指导。
和swagger教程有点出入,大佬设定swagger管道的位置在项目XXX.Swagger > SwaggerCollectionExtensions;而网上的教程有点老,基本部署在startup.cs。
项目后端SwaggerCollectionExtensions:

1 using Microsoft.AspNetCore.Builder; 2 using Microsoft.Extensions.DependencyInjection; 3 using Microsoft.Extensions.PlatformAbstractions; 4 using Microsoft.OpenApi.Models; 5 using Swashbuckle.AspNetCore.SwaggerUI;
namespace XXX.Swagger{
public static class SwaggerCollectionExtensions{

1 /// <summary> 2 /// 注入自定义的swagger服务 3 /// </summary> 4 /// <param name="services"></param> 5 /// <param name="apiInfo"></param> 6 /// <returns></returns> 7 public static IServiceCollection AddCustomSwagger(this IServiceCollection services, IApiInfo? apiInfo){ 8 if (apiInfo != null){ 9 services.AddSwaggerGen(options =>{ 10 options.CustomSchemaIds(c => c.FullName); 11 //遍历GroupVersion所有枚举值生成接口文档 12 //Skip(1)是因为Enum第一个FieldInfo是内置的一个Int值 13 typeof(GroupVersion).GetFields().Skip(1).ToList().ForEach(f =>{ 14 //获取枚举值上的特性 15 var info = f.GetCustomAttributes(typeof(GroupInfoAttribute), false).OfType<GroupInfoAttribute>().FirstOrDefault(); 16 options.SwaggerDoc(f.Name.ToLower(), new OpenApiInfo{ 17 Title = info?.Title, 18 Version = info?.Version ?? apiInfo.Version, 19 Description = info?.Description 20 }); 21 }); 22 //判断接口归于哪个分组 23 options.DocInclusionPredicate((docName, apiDescription) =>{ 24 return docName == apiInfo?.ApiName ? true : apiDescription.GroupName == docName; 25 }); 26 27 var basePath = PlatformServices.Default.Application.ApplicationBasePath; 28 var xmlpath = Path.Combine(basePath, "XXX.Api.xml"); 29 if (File.Exists(xmlpath)){ 30 options.IncludeXmlComments(xmlpath, includeControllerXmlComments: true); 31 } 32 var modelPath = Path.Combine(basePath, "XXX.DTO.xml"); 33 if (File.Exists(modelPath)){ 34 options.IncludeXmlComments(modelPath); 35 } 36 var corePath = Path.Combine(basePath, "XXX.Core.xml"); 37 if (File.Exists(corePath)){ 38 options.IncludeXmlComments(corePath); 39 } 40 //TOKEN 41 options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { 42 Description = "在下框中输入请求头中需要添加Jwt授权Token:Bearer Token", 43 Name = "Authorization", 44 In = ParameterLocation.Header, 45 Scheme = "Bearer", 46 Type = SecuritySchemeType.ApiKey, 47 BearerFormat = "JWT" 48 }); 49 //添加安全要求 50 options.AddSecurityRequirement(new OpenApiSecurityRequirement { 51 new OpenApiSecurityScheme { 52 Reference = new OpenApiReference { 53 Type = ReferenceType.SecurityScheme, 54 Id = "Bearer" 55 } 56 }, 57 new List<string>() 58 }); 59 }); 60 } 61 return services; 62 }

1 /// <summary> 2 /// 使用自定义 Swagger 3 /// </summary> 4 /// <param name="app"></param> 5 /// <param name="apiInfo"></param> 6 /// <returns></returns> 7 public static IApplicationBuilder UseCustomSwagger(this IApplicationBuilder app, IApiInfo apiInfo) { 8 app.UseSwagger(c => { 9 c.RouteTemplate = "/{documentName}/{version}/swagger.json"; 10 }); 11 app.UseSwaggerUI(c => { 12 //遍历GroupVersion所有枚举值生成接口文档,Skip(1)是因为Enum第一个FieldInfo是内置的一个Int值 13 typeof(GroupVersion).GetFields().Skip(1).ToList().ForEach(f => { 14 //获取枚举值上的特性 15 var info = f.GetCustomAttributes(typeof(GroupInfoAttribute), false).OfType<GroupInfoAttribute>().FirstOrDefault(); 16 if (info != null) { 17 c.SwaggerEndpoint($"/{f.Name.ToLower()}/{info.Version}/swagger.json", $"{info.Title} {info.Version}"); 18 } 19 }); 20 c.DocumentTitle = apiInfo.ApiName + "接口文档"; 21 //c.SwaggerEndpoint($"/{apiInfo.ApiName}/{apiInfo.Version}/swagger.json", $"{apiInfo.Title} {apiInfo.Version}"); 22 //SWAGGER UI折叠 23 c.DocExpansion(DocExpansion.None); 24 //不显示model 25 c.DefaultModelExpandDepth(-1); 26 }); 27 return app; 28 }
}
}
查了一堆资料
好极了,要开始学后端咯(满脸写着开心