You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
199 lines
5.3 KiB
199 lines
5.3 KiB
package service |
|
|
|
import ( |
|
"bufio" |
|
"fmt" |
|
"os" |
|
"path/filepath" |
|
"regexp" |
|
"strings" |
|
) |
|
|
|
// SwaggerInfo Swagger注释信息 |
|
type SwaggerInfo struct { |
|
Summary string |
|
Description string |
|
Tags string |
|
Router string |
|
Method string |
|
} |
|
|
|
// SwaggerParser Swagger注释解析器 |
|
type SwaggerParser struct { |
|
swaggerMap map[string]SwaggerInfo |
|
} |
|
|
|
// NewSwaggerParser 创建Swagger解析器 |
|
func NewSwaggerParser() *SwaggerParser { |
|
parser := &SwaggerParser{ |
|
swaggerMap: make(map[string]SwaggerInfo), |
|
} |
|
fmt.Println("🔧 SwaggerParser创建成功") |
|
return parser |
|
} |
|
|
|
// ParseControllerDirectory 解析Controller目录下的所有文件 |
|
func (sp *SwaggerParser) ParseControllerDirectory(dir string) error { |
|
fmt.Printf("🔍 开始解析Controller目录: %s\n", dir) |
|
|
|
fileCount := 0 |
|
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { |
|
if err != nil { |
|
fmt.Printf("❌ 访问文件失败: %s, 错误: %v\n", path, err) |
|
return err |
|
} |
|
|
|
if !info.IsDir() && strings.HasSuffix(path, ".go") { |
|
fmt.Printf("📄 解析文件: %s\n", path) |
|
fileCount++ |
|
return sp.parseControllerFile(path) |
|
} |
|
|
|
return nil |
|
}) |
|
|
|
fmt.Printf("📊 解析完成,共处理 %d 个Go文件\n", fileCount) |
|
fmt.Printf("📋 解析到的Swagger信息数量: %d\n", len(sp.swaggerMap)) |
|
|
|
return err |
|
} |
|
|
|
// parseControllerFile 解析单个Controller文件 |
|
func (sp *SwaggerParser) parseControllerFile(filePath string) error { |
|
file, err := os.Open(filePath) |
|
if err != nil { |
|
return err |
|
} |
|
defer file.Close() |
|
|
|
scanner := bufio.NewScanner(file) |
|
var currentComment []string |
|
|
|
for scanner.Scan() { |
|
line := scanner.Text() |
|
|
|
// 检查是否是注释行 |
|
if strings.HasPrefix(strings.TrimSpace(line), "//") { |
|
currentComment = append(currentComment, line) |
|
} else { |
|
// 如果不是注释行,处理之前收集的注释 |
|
if len(currentComment) > 0 { |
|
swaggerInfo := sp.extractSwaggerInfo(currentComment) |
|
if swaggerInfo.Router != "" { |
|
// 使用Router路径作为key |
|
key := fmt.Sprintf("%s %s", swaggerInfo.Method, swaggerInfo.Router) |
|
sp.swaggerMap[key] = swaggerInfo |
|
} |
|
currentComment = nil |
|
} |
|
} |
|
} |
|
|
|
return scanner.Err() |
|
} |
|
|
|
// extractSwaggerInfo 从注释中提取Swagger信息 |
|
func (sp *SwaggerParser) extractSwaggerInfo(comments []string) SwaggerInfo { |
|
info := SwaggerInfo{} |
|
|
|
for _, comment := range comments { |
|
comment = strings.TrimSpace(comment) |
|
|
|
// 提取@Summary |
|
if strings.HasPrefix(comment, "// @Summary") { |
|
info.Summary = strings.TrimSpace(strings.TrimPrefix(comment, "// @Summary")) |
|
} |
|
|
|
// 提取@Description |
|
if strings.HasPrefix(comment, "// @Description") { |
|
info.Description = strings.TrimSpace(strings.TrimPrefix(comment, "// @Description")) |
|
} |
|
|
|
// 提取@Tags |
|
if strings.HasPrefix(comment, "// @Tags") { |
|
info.Tags = strings.TrimSpace(strings.TrimPrefix(comment, "// @Tags")) |
|
} |
|
|
|
// 提取@Router |
|
if strings.HasPrefix(comment, "// @Router") { |
|
routerLine := strings.TrimSpace(strings.TrimPrefix(comment, "// @Router")) |
|
// 解析格式:/path [method] |
|
parts := strings.Fields(routerLine) |
|
if len(parts) >= 2 { |
|
info.Router = parts[0] |
|
// 提取HTTP方法 |
|
if len(parts) > 1 { |
|
methodPart := parts[1] |
|
if strings.HasPrefix(methodPart, "[") && strings.HasSuffix(methodPart, "]") { |
|
info.Method = strings.ToUpper(strings.Trim(methodPart, "[]")) |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
return info |
|
} |
|
|
|
// GetSummary 根据路径和方法获取Summary |
|
func (sp *SwaggerParser) GetSummary(method, path string) string { |
|
// 尝试精确匹配 |
|
key := fmt.Sprintf("%s %s", strings.ToUpper(method), path) |
|
if info, exists := sp.swaggerMap[key]; exists { |
|
return info.Summary |
|
} |
|
|
|
// 尝试匹配不带/api前缀的路径 |
|
if strings.HasPrefix(path, "/api/") { |
|
pathWithoutAPI := strings.TrimPrefix(path, "/api") |
|
keyWithoutAPI := fmt.Sprintf("%s %s", strings.ToUpper(method), pathWithoutAPI) |
|
if info, exists := sp.swaggerMap[keyWithoutAPI]; exists { |
|
return info.Summary |
|
} |
|
} |
|
|
|
// 尝试模糊匹配(处理路径参数) |
|
for swaggerKey, info := range sp.swaggerMap { |
|
if sp.matchRoute(swaggerKey, fmt.Sprintf("%s %s", strings.ToUpper(method), path)) { |
|
return info.Summary |
|
} |
|
} |
|
|
|
// 尝试匹配转换后的路径(将:var转换为{var}) |
|
convertedPath := sp.convertPathFormat(path) |
|
if convertedPath != path { |
|
convertedKey := fmt.Sprintf("%s %s", strings.ToUpper(method), convertedPath) |
|
if info, exists := sp.swaggerMap[convertedKey]; exists { |
|
return info.Summary |
|
} |
|
} |
|
|
|
return "" |
|
} |
|
|
|
// convertPathFormat 转换路径格式:将:var格式改为{var}格式 |
|
func (sp *SwaggerParser) convertPathFormat(path string) string { |
|
re := regexp.MustCompile(`:([a-zA-Z0-9_]+)`) |
|
return re.ReplaceAllString(path, "{$1}") |
|
} |
|
|
|
// matchRoute 匹配路由(处理路径参数) |
|
func (sp *SwaggerParser) matchRoute(pattern, route string) bool { |
|
// 将路径参数转换为正则表达式 |
|
// 例如:/users/:id -> /users/[^/]+ |
|
patternRegex := regexp.MustCompile(`:[a-zA-Z0-9_]+`) |
|
regexPattern := patternRegex.ReplaceAllString(pattern, `[^/]+`) |
|
|
|
// 创建正则表达式 |
|
re, err := regexp.Compile("^" + regexPattern + "$") |
|
if err != nil { |
|
return false |
|
} |
|
|
|
return re.MatchString(route) |
|
} |
|
|
|
// GetAllSwaggerInfo 获取所有Swagger信息 |
|
func (sp *SwaggerParser) GetAllSwaggerInfo() map[string]SwaggerInfo { |
|
return sp.swaggerMap |
|
}
|
|
|