增强插件系统:添加参数验证功能
- 在插件助手中新增 ValidateParams 函数,用于验证传入参数是否符合定义,确保参数的完整性和正确性。 - 更新 ExecuteAction 方法,集成参数验证逻辑,提升插件执行的安全性和可靠性。 - 示例程序中添加新的选项,展示如何生成插件API文档和OpenAPI/Swagger文档,增强用户体验。 此更新提升了插件系统的健壮性,便于开发者更好地管理和使用插件功能。
This commit is contained in:
767
examples/plugin/openapi_generator.go
Normal file
767
examples/plugin/openapi_generator.go
Normal file
@@ -0,0 +1,767 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// OpenAPIGenerator 用于生成符合OpenAPI 3.0规范的API文档
|
||||
type OpenAPIGenerator struct {
|
||||
pm *PluginManager // 插件管理器
|
||||
outputPath string // 输出路径
|
||||
info map[string]interface{}
|
||||
}
|
||||
|
||||
// NewOpenAPIGenerator 创建一个新的OpenAPI生成器
|
||||
func NewOpenAPIGenerator(pm *PluginManager, outputPath string) *OpenAPIGenerator {
|
||||
return &OpenAPIGenerator{
|
||||
pm: pm,
|
||||
outputPath: outputPath,
|
||||
info: map[string]interface{}{
|
||||
"title": "插件系统API",
|
||||
"description": "插件系统提供的API接口文档",
|
||||
"version": "1.0.0",
|
||||
"contact": map[string]interface{}{
|
||||
"name": "开发团队",
|
||||
"email": "dev@example.com",
|
||||
"url": "https://example.com",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// SetInfo 设置API文档的基本信息
|
||||
func (g *OpenAPIGenerator) SetInfo(title, description, version string) {
|
||||
g.info["title"] = title
|
||||
g.info["description"] = description
|
||||
g.info["version"] = version
|
||||
}
|
||||
|
||||
// SetContact 设置联系人信息
|
||||
func (g *OpenAPIGenerator) SetContact(name, email, url string) {
|
||||
g.info["contact"] = map[string]interface{}{
|
||||
"name": name,
|
||||
"email": email,
|
||||
"url": url,
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateOpenAPI 生成OpenAPI文档
|
||||
func (g *OpenAPIGenerator) GenerateOpenAPI() error {
|
||||
// 确保输出目录存在
|
||||
if err := os.MkdirAll(g.outputPath, 0755); err != nil {
|
||||
return fmt.Errorf("创建输出目录失败: %v", err)
|
||||
}
|
||||
|
||||
// 创建OpenAPI规范文档
|
||||
openapiSpec := g.createOpenAPISpec()
|
||||
|
||||
// 将文档保存为JSON文件
|
||||
jsonPath := filepath.Join(g.outputPath, "openapi.json")
|
||||
jsonData, err := json.MarshalIndent(openapiSpec, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("JSON序列化失败: %v", err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(jsonPath, jsonData, 0644); err != nil {
|
||||
return fmt.Errorf("写入JSON文件失败: %v", err)
|
||||
}
|
||||
|
||||
// 创建HTML查看器
|
||||
htmlPath := filepath.Join(g.outputPath, "index.html")
|
||||
htmlContent := g.createSwaggerUIHTML()
|
||||
if err := os.WriteFile(htmlPath, []byte(htmlContent), 0644); err != nil {
|
||||
return fmt.Errorf("写入HTML文件失败: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// createOpenAPISpec 创建完整的OpenAPI规范文档
|
||||
func (g *OpenAPIGenerator) createOpenAPISpec() map[string]interface{} {
|
||||
// 基本结构
|
||||
spec := map[string]interface{}{
|
||||
"openapi": "3.0.0",
|
||||
"info": g.info,
|
||||
"servers": []map[string]interface{}{
|
||||
{
|
||||
"url": "/api",
|
||||
"description": "API服务器",
|
||||
},
|
||||
},
|
||||
"tags": []map[string]interface{}{},
|
||||
"paths": map[string]interface{}{},
|
||||
"components": map[string]interface{}{
|
||||
"schemas": map[string]interface{}{},
|
||||
"parameters": map[string]interface{}{},
|
||||
},
|
||||
}
|
||||
|
||||
// 获取所有插件
|
||||
plugins := g.pm.GetAllPlugins()
|
||||
|
||||
// 生成标签(按插件类型分组)
|
||||
pluginTypeMap := make(map[PluginType]bool)
|
||||
for _, p := range plugins {
|
||||
pluginTypeMap[p.Type()] = true
|
||||
}
|
||||
|
||||
tags := make([]map[string]interface{}, 0)
|
||||
for pType := range pluginTypeMap {
|
||||
tags = append(tags, map[string]interface{}{
|
||||
"name": string(pType),
|
||||
"description": fmt.Sprintf("%s 类型的插件", pType),
|
||||
})
|
||||
}
|
||||
spec["tags"] = tags
|
||||
|
||||
// 为每个插件生成路径
|
||||
paths := make(map[string]interface{})
|
||||
schemas := make(map[string]interface{})
|
||||
|
||||
for _, p := range plugins {
|
||||
pluginName := p.Name()
|
||||
pluginType := string(p.Type())
|
||||
|
||||
// 插件基本信息路径
|
||||
pluginInfoPath := fmt.Sprintf("/plugins/{name}/info")
|
||||
if _, exists := paths[pluginInfoPath]; !exists {
|
||||
paths[pluginInfoPath] = map[string]interface{}{
|
||||
"get": map[string]interface{}{
|
||||
"summary": "获取插件信息",
|
||||
"description": "获取指定插件的详细信息",
|
||||
"operationId": "getPluginInfo",
|
||||
"tags": []string{"Plugin"},
|
||||
"parameters": []map[string]interface{}{
|
||||
{
|
||||
"name": "name",
|
||||
"in": "path",
|
||||
"description": "插件名称",
|
||||
"required": true,
|
||||
"schema": map[string]interface{}{
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
"responses": map[string]interface{}{
|
||||
"200": map[string]interface{}{
|
||||
"description": "成功",
|
||||
"content": map[string]interface{}{
|
||||
"application/json": map[string]interface{}{
|
||||
"schema": map[string]interface{}{
|
||||
"$ref": "#/components/schemas/PluginInfo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"404": map[string]interface{}{
|
||||
"description": "插件不存在",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 定义插件操作的路径
|
||||
operations := p.GetAllOperations()
|
||||
for opName, opInfo := range operations {
|
||||
pathTemplate := fmt.Sprintf("/plugins/{name}/execute/{action}")
|
||||
|
||||
// 如果路径不存在,创建路径
|
||||
if _, exists := paths[pathTemplate]; !exists {
|
||||
paths[pathTemplate] = map[string]interface{}{
|
||||
"post": map[string]interface{}{
|
||||
"summary": "执行插件操作",
|
||||
"description": "对指定插件执行特定操作",
|
||||
"operationId": "executePluginAction",
|
||||
"tags": []string{"Plugin"},
|
||||
"parameters": []map[string]interface{}{
|
||||
{
|
||||
"name": "name",
|
||||
"in": "path",
|
||||
"description": "插件名称",
|
||||
"required": true,
|
||||
"schema": map[string]interface{}{
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "action",
|
||||
"in": "path",
|
||||
"description": "操作名称",
|
||||
"required": true,
|
||||
"schema": map[string]interface{}{
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
"requestBody": map[string]interface{}{
|
||||
"description": "操作参数",
|
||||
"content": map[string]interface{}{
|
||||
"application/json": map[string]interface{}{
|
||||
"schema": map[string]interface{}{
|
||||
"type": "object",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"responses": map[string]interface{}{
|
||||
"200": map[string]interface{}{
|
||||
"description": "操作成功",
|
||||
"content": map[string]interface{}{
|
||||
"application/json": map[string]interface{}{
|
||||
"schema": map[string]interface{}{
|
||||
"type": "object",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"400": map[string]interface{}{
|
||||
"description": "参数错误",
|
||||
},
|
||||
"404": map[string]interface{}{
|
||||
"description": "插件或操作不存在",
|
||||
},
|
||||
"500": map[string]interface{}{
|
||||
"description": "服务器错误",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 为每个操作创建特定的路径
|
||||
opPath := fmt.Sprintf("/plugins/%s/actions/%s", pluginName, opName)
|
||||
opRequestSchema := g.createRequestSchema(opName, opInfo, schemas)
|
||||
opResponseSchema := g.createResponseSchema(opName, opInfo, schemas)
|
||||
|
||||
paths[opPath] = map[string]interface{}{
|
||||
"post": map[string]interface{}{
|
||||
"summary": getMapString(opInfo, "description", fmt.Sprintf("执行 %s", opName)),
|
||||
"description": getMapString(opInfo, "description", fmt.Sprintf("在 %s 插件上执行 %s 操作", pluginName, opName)),
|
||||
"operationId": fmt.Sprintf("%s_%s", pluginName, opName),
|
||||
"tags": []string{pluginType},
|
||||
"requestBody": map[string]interface{}{
|
||||
"description": "操作参数",
|
||||
"content": map[string]interface{}{
|
||||
"application/json": map[string]interface{}{
|
||||
"schema": opRequestSchema,
|
||||
},
|
||||
},
|
||||
"required": true,
|
||||
},
|
||||
"responses": map[string]interface{}{
|
||||
"200": map[string]interface{}{
|
||||
"description": "操作成功",
|
||||
"content": map[string]interface{}{
|
||||
"application/json": map[string]interface{}{
|
||||
"schema": opResponseSchema,
|
||||
},
|
||||
},
|
||||
},
|
||||
"400": map[string]interface{}{
|
||||
"description": "参数错误",
|
||||
},
|
||||
"500": map[string]interface{}{
|
||||
"description": "服务器错误",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 添加通用路径
|
||||
// 获取所有插件
|
||||
paths["/plugins"] = map[string]interface{}{
|
||||
"get": map[string]interface{}{
|
||||
"summary": "获取所有插件",
|
||||
"description": "获取系统中所有可用插件的列表",
|
||||
"operationId": "getAllPlugins",
|
||||
"tags": []string{"PluginSystem"},
|
||||
"responses": map[string]interface{}{
|
||||
"200": map[string]interface{}{
|
||||
"description": "成功",
|
||||
"content": map[string]interface{}{
|
||||
"application/json": map[string]interface{}{
|
||||
"schema": map[string]interface{}{
|
||||
"type": "array",
|
||||
"items": map[string]interface{}{
|
||||
"$ref": "#/components/schemas/PluginInfo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// 按类型获取插件
|
||||
paths["/plugins/type/{type}"] = map[string]interface{}{
|
||||
"get": map[string]interface{}{
|
||||
"summary": "按类型获取插件",
|
||||
"description": "获取指定类型的所有插件",
|
||||
"operationId": "getPluginsByType",
|
||||
"tags": []string{"PluginSystem"},
|
||||
"parameters": []map[string]interface{}{
|
||||
{
|
||||
"name": "type",
|
||||
"in": "path",
|
||||
"description": "插件类型",
|
||||
"required": true,
|
||||
"schema": map[string]interface{}{
|
||||
"type": "string",
|
||||
"enum": []string{
|
||||
string(PluginTypeGeneral),
|
||||
string(PluginTypeStorage),
|
||||
string(PluginTypeUtils),
|
||||
string(PluginTypeNetwork),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"responses": map[string]interface{}{
|
||||
"200": map[string]interface{}{
|
||||
"description": "成功",
|
||||
"content": map[string]interface{}{
|
||||
"application/json": map[string]interface{}{
|
||||
"schema": map[string]interface{}{
|
||||
"type": "array",
|
||||
"items": map[string]interface{}{
|
||||
"$ref": "#/components/schemas/PluginInfo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// 获取插件所有操作
|
||||
paths["/plugins/{name}/actions"] = map[string]interface{}{
|
||||
"get": map[string]interface{}{
|
||||
"summary": "获取插件所有操作",
|
||||
"description": "获取指定插件支持的所有操作",
|
||||
"operationId": "getPluginActions",
|
||||
"tags": []string{"PluginSystem"},
|
||||
"parameters": []map[string]interface{}{
|
||||
{
|
||||
"name": "name",
|
||||
"in": "path",
|
||||
"description": "插件名称",
|
||||
"required": true,
|
||||
"schema": map[string]interface{}{
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
"responses": map[string]interface{}{
|
||||
"200": map[string]interface{}{
|
||||
"description": "成功",
|
||||
"content": map[string]interface{}{
|
||||
"application/json": map[string]interface{}{
|
||||
"schema": map[string]interface{}{
|
||||
"type": "object",
|
||||
"additionalProperties": map[string]interface{}{
|
||||
"type": "object",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"404": map[string]interface{}{
|
||||
"description": "插件不存在",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// 设置路径和组件
|
||||
spec["paths"] = paths
|
||||
|
||||
// 添加基本模式
|
||||
schemas["PluginInfo"] = map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"name": map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": "插件名称",
|
||||
},
|
||||
"version": map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": "插件版本",
|
||||
},
|
||||
"description": map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": "插件描述",
|
||||
},
|
||||
"author": map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": "插件作者",
|
||||
},
|
||||
"type": map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": "插件类型",
|
||||
"enum": []string{
|
||||
string(PluginTypeGeneral),
|
||||
string(PluginTypeStorage),
|
||||
string(PluginTypeUtils),
|
||||
string(PluginTypeNetwork),
|
||||
},
|
||||
},
|
||||
"enabled": map[string]interface{}{
|
||||
"type": "boolean",
|
||||
"description": "插件是否启用",
|
||||
},
|
||||
},
|
||||
"required": []string{"name", "version", "type", "enabled"},
|
||||
}
|
||||
|
||||
// 更新组件模式
|
||||
spec["components"].(map[string]interface{})["schemas"] = schemas
|
||||
|
||||
return spec
|
||||
}
|
||||
|
||||
// createRequestSchema 创建操作请求的JSON Schema
|
||||
func (g *OpenAPIGenerator) createRequestSchema(opName string, opInfo map[string]interface{}, schemas map[string]interface{}) map[string]interface{} {
|
||||
schemaName := fmt.Sprintf("%sRequest", opName)
|
||||
|
||||
// 如果没有参数,返回空对象模式
|
||||
params, ok := opInfo["parameters"].(map[string]interface{})
|
||||
if !ok || len(params) == 0 {
|
||||
return map[string]interface{}{
|
||||
"type": "object",
|
||||
}
|
||||
}
|
||||
|
||||
// 创建请求模式
|
||||
schema := map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{},
|
||||
"required": []string{},
|
||||
}
|
||||
properties := schema["properties"].(map[string]interface{})
|
||||
required := schema["required"].([]string)
|
||||
|
||||
// 添加参数
|
||||
for paramName, paramInfo := range params {
|
||||
if info, ok := paramInfo.(map[string]interface{}); ok {
|
||||
paramType := getMapString(info, "type", "string")
|
||||
paramDesc := getMapString(info, "description", "")
|
||||
paramRequired := getMapBool(info, "required", false)
|
||||
|
||||
// 为不同类型创建不同的模式
|
||||
var propSchema map[string]interface{}
|
||||
|
||||
switch paramType {
|
||||
case "string":
|
||||
propSchema = map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": paramDesc,
|
||||
}
|
||||
case "integer":
|
||||
propSchema = map[string]interface{}{
|
||||
"type": "integer",
|
||||
"description": paramDesc,
|
||||
}
|
||||
case "float":
|
||||
propSchema = map[string]interface{}{
|
||||
"type": "number",
|
||||
"description": paramDesc,
|
||||
}
|
||||
case "boolean":
|
||||
propSchema = map[string]interface{}{
|
||||
"type": "boolean",
|
||||
"description": paramDesc,
|
||||
}
|
||||
case "array":
|
||||
propSchema = map[string]interface{}{
|
||||
"type": "array",
|
||||
"description": paramDesc,
|
||||
"items": map[string]interface{}{
|
||||
"type": "object",
|
||||
},
|
||||
}
|
||||
|
||||
// 如果有元素类型信息,使用它
|
||||
if elemType, ok := info["elemType"].(map[string]interface{}); ok {
|
||||
elemTypeStr := getMapString(elemType, "type", "string")
|
||||
propSchema["items"] = map[string]interface{}{
|
||||
"type": g.mapTypeToOpenAPI(elemTypeStr),
|
||||
}
|
||||
}
|
||||
case "object", "struct":
|
||||
// 对于结构体和对象,创建一个引用
|
||||
structName := fmt.Sprintf("%s_%s", schemaName, paramName)
|
||||
propSchema = map[string]interface{}{
|
||||
"$ref": fmt.Sprintf("#/components/schemas/%s", structName),
|
||||
"description": paramDesc,
|
||||
}
|
||||
|
||||
// 创建结构体模式
|
||||
structSchema := map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{},
|
||||
"required": []string{},
|
||||
}
|
||||
|
||||
// 添加结构体字段
|
||||
if fields, ok := info["fields"].(map[string]interface{}); ok {
|
||||
structProps := structSchema["properties"].(map[string]interface{})
|
||||
structReq := structSchema["required"].([]string)
|
||||
|
||||
for fieldName, fieldInfo := range fields {
|
||||
if fi, ok := fieldInfo.(map[string]interface{}); ok {
|
||||
fieldType := getMapString(fi, "type", "string")
|
||||
fieldDesc := getMapString(fi, "description", "")
|
||||
fieldRequired := getMapBool(fi, "required", false)
|
||||
|
||||
structProps[fieldName] = map[string]interface{}{
|
||||
"type": g.mapTypeToOpenAPI(fieldType),
|
||||
"description": fieldDesc,
|
||||
}
|
||||
|
||||
if fieldRequired {
|
||||
structReq = append(structReq, fieldName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
structSchema["required"] = structReq
|
||||
}
|
||||
|
||||
// 添加到模式
|
||||
schemas[structName] = structSchema
|
||||
default:
|
||||
propSchema = map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": paramDesc,
|
||||
}
|
||||
}
|
||||
|
||||
properties[paramName] = propSchema
|
||||
|
||||
if paramRequired {
|
||||
required = append(required, paramName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有必填参数,删除required数组
|
||||
if len(required) == 0 {
|
||||
delete(schema, "required")
|
||||
} else {
|
||||
schema["required"] = required
|
||||
}
|
||||
|
||||
// 添加到模式
|
||||
schemas[schemaName] = schema
|
||||
|
||||
return map[string]interface{}{
|
||||
"$ref": fmt.Sprintf("#/components/schemas/%s", schemaName),
|
||||
}
|
||||
}
|
||||
|
||||
// createResponseSchema 创建操作响应的JSON Schema
|
||||
func (g *OpenAPIGenerator) createResponseSchema(opName string, opInfo map[string]interface{}, schemas map[string]interface{}) map[string]interface{} {
|
||||
schemaName := fmt.Sprintf("%sResponse", opName)
|
||||
|
||||
// 如果没有返回值,返回空对象模式
|
||||
returns, ok := opInfo["returns"].(map[string]interface{})
|
||||
if !ok || len(returns) == 0 {
|
||||
return map[string]interface{}{
|
||||
"type": "object",
|
||||
}
|
||||
}
|
||||
|
||||
// 如果只有一个错误返回,使用简单响应
|
||||
if len(returns) == 1 && returns["error"] != nil {
|
||||
return map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"success": map[string]interface{}{
|
||||
"type": "boolean",
|
||||
"description": "操作是否成功",
|
||||
},
|
||||
"error": map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": "错误信息",
|
||||
"nullable": true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 创建响应模式
|
||||
schema := map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"success": map[string]interface{}{
|
||||
"type": "boolean",
|
||||
"description": "操作是否成功",
|
||||
},
|
||||
},
|
||||
}
|
||||
properties := schema["properties"].(map[string]interface{})
|
||||
|
||||
// 遍历所有返回值
|
||||
for retName, retInfo := range returns {
|
||||
if retName == "error" {
|
||||
properties["error"] = map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": "错误信息",
|
||||
"nullable": true,
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if info, ok := retInfo.(map[string]interface{}); ok {
|
||||
retType := getMapString(info, "type", "string")
|
||||
retDesc := getMapString(info, "description", "")
|
||||
|
||||
// 为不同类型创建不同的模式
|
||||
var propSchema map[string]interface{}
|
||||
|
||||
switch retType {
|
||||
case "string":
|
||||
propSchema = map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": retDesc,
|
||||
}
|
||||
case "integer":
|
||||
propSchema = map[string]interface{}{
|
||||
"type": "integer",
|
||||
"description": retDesc,
|
||||
}
|
||||
case "float":
|
||||
propSchema = map[string]interface{}{
|
||||
"type": "number",
|
||||
"description": retDesc,
|
||||
}
|
||||
case "boolean":
|
||||
propSchema = map[string]interface{}{
|
||||
"type": "boolean",
|
||||
"description": retDesc,
|
||||
}
|
||||
case "array":
|
||||
propSchema = map[string]interface{}{
|
||||
"type": "array",
|
||||
"description": retDesc,
|
||||
"items": map[string]interface{}{
|
||||
"type": "object",
|
||||
},
|
||||
}
|
||||
|
||||
// 如果有元素类型信息,使用它
|
||||
if elemType, ok := info["elemType"].(map[string]interface{}); ok {
|
||||
elemTypeStr := getMapString(elemType, "type", "string")
|
||||
propSchema["items"] = map[string]interface{}{
|
||||
"type": g.mapTypeToOpenAPI(elemTypeStr),
|
||||
}
|
||||
}
|
||||
case "object":
|
||||
// 对于对象,创建嵌套模式
|
||||
propSchema = map[string]interface{}{
|
||||
"type": "object",
|
||||
"description": retDesc,
|
||||
"properties": map[string]interface{}{},
|
||||
}
|
||||
|
||||
// 如果有属性信息,添加它们
|
||||
if props, ok := info["properties"].(map[string]interface{}); ok {
|
||||
propsMap := propSchema["properties"].(map[string]interface{})
|
||||
|
||||
for propName, propInfo := range props {
|
||||
if pi, ok := propInfo.(map[string]interface{}); ok {
|
||||
propType := getMapString(pi, "type", "string")
|
||||
propDesc := getMapString(pi, "description", "")
|
||||
|
||||
propsMap[propName] = map[string]interface{}{
|
||||
"type": g.mapTypeToOpenAPI(propType),
|
||||
"description": propDesc,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
propSchema = map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": retDesc,
|
||||
}
|
||||
}
|
||||
|
||||
properties[retName] = propSchema
|
||||
}
|
||||
}
|
||||
|
||||
// 添加到模式
|
||||
schemas[schemaName] = schema
|
||||
|
||||
return map[string]interface{}{
|
||||
"$ref": fmt.Sprintf("#/components/schemas/%s", schemaName),
|
||||
}
|
||||
}
|
||||
|
||||
// createSwaggerUIHTML 创建包含Swagger UI的HTML文件
|
||||
func (g *OpenAPIGenerator) createSwaggerUIHTML() string {
|
||||
return `<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>插件系统API文档</title>
|
||||
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4.5.0/swagger-ui.css" >
|
||||
<style>
|
||||
html { box-sizing: border-box; overflow: -moz-scrollbars-vertical; overflow-y: scroll; }
|
||||
*, *:before, *:after { box-sizing: inherit; }
|
||||
body { margin: 0; background: #fafafa; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4.5.0/swagger-ui-bundle.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@4.5.0/swagger-ui-standalone-preset.js"></script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
const ui = SwaggerUIBundle({
|
||||
url: "openapi.json",
|
||||
dom_id: '#swagger-ui',
|
||||
deepLinking: true,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout"
|
||||
});
|
||||
window.ui = ui;
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>`
|
||||
}
|
||||
|
||||
// mapTypeToOpenAPI 将内部类型映射到OpenAPI类型
|
||||
func (g *OpenAPIGenerator) mapTypeToOpenAPI(internalType string) string {
|
||||
switch internalType {
|
||||
case "integer":
|
||||
return "integer"
|
||||
case "float":
|
||||
return "number"
|
||||
case "boolean":
|
||||
return "boolean"
|
||||
case "array":
|
||||
return "array"
|
||||
case "object", "struct":
|
||||
return "object"
|
||||
default:
|
||||
return "string"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user