224 lines
5.8 KiB
Go
224 lines
5.8 KiB
Go
|
|
package service
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"context"
|
|||
|
|
"fmt"
|
|||
|
|
"regexp"
|
|||
|
|
"strings"
|
|||
|
|
|
|||
|
|
"hm-server/app/main/model"
|
|||
|
|
|
|||
|
|
"github.com/pkg/errors"
|
|||
|
|
"github.com/zeromicro/go-zero/core/logx"
|
|||
|
|
"github.com/zeromicro/go-zero/rest"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
type ApiRegistryService struct {
|
|||
|
|
adminApiModel model.AdminApiModel
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func NewApiRegistryService(adminApiModel model.AdminApiModel) *ApiRegistryService {
|
|||
|
|
return &ApiRegistryService{
|
|||
|
|
adminApiModel: adminApiModel,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// RegisterAllApis 自动注册所有API到数据库
|
|||
|
|
func (s *ApiRegistryService) RegisterAllApis(ctx context.Context, routes []rest.Route) error {
|
|||
|
|
logx.Infof("开始注册API,共 %d 个路由", len(routes))
|
|||
|
|
|
|||
|
|
registeredCount := 0
|
|||
|
|
skippedCount := 0
|
|||
|
|
|
|||
|
|
for _, route := range routes {
|
|||
|
|
// 跳过不需要权限控制的API
|
|||
|
|
if s.shouldSkipApi(route.Path) {
|
|||
|
|
skippedCount++
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 解析API信息
|
|||
|
|
apiInfo := s.parseRouteToApi(route)
|
|||
|
|
|
|||
|
|
// 检查是否已存在
|
|||
|
|
existing, err := s.adminApiModel.FindOneByApiCode(ctx, apiInfo.ApiCode)
|
|||
|
|
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
|||
|
|
logx.Errorf("查询API失败: %v, apiCode: %s", err, apiInfo.ApiCode)
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果不存在则插入
|
|||
|
|
if existing == nil {
|
|||
|
|
_, err = s.adminApiModel.Insert(ctx, nil, apiInfo)
|
|||
|
|
if err != nil {
|
|||
|
|
logx.Errorf("插入API失败: %v, apiCode: %s", err, apiInfo.ApiCode)
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
registeredCount++
|
|||
|
|
logx.Infof("注册API成功: %s %s", apiInfo.Method, apiInfo.Url)
|
|||
|
|
} else {
|
|||
|
|
// 如果存在但信息有变化,则更新
|
|||
|
|
if s.shouldUpdateApi(existing, apiInfo) {
|
|||
|
|
existing.ApiName = apiInfo.ApiName
|
|||
|
|
existing.Method = apiInfo.Method
|
|||
|
|
existing.Url = apiInfo.Url
|
|||
|
|
existing.Description = apiInfo.Description
|
|||
|
|
|
|||
|
|
_, err = s.adminApiModel.Update(ctx, nil, existing)
|
|||
|
|
if err != nil {
|
|||
|
|
logx.Errorf("更新API失败: %v, apiCode: %s", err, apiInfo.ApiCode)
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
logx.Infof("更新API成功: %s %s", apiInfo.Method, apiInfo.Url)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
logx.Infof("API注册完成,新增: %d, 跳过: %d", registeredCount, skippedCount)
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// shouldSkipApi 判断是否应该跳过此API
|
|||
|
|
func (s *ApiRegistryService) shouldSkipApi(path string) bool {
|
|||
|
|
// 跳过公开API
|
|||
|
|
skipPaths := []string{
|
|||
|
|
"/api/v1/admin/auth/login", // 登录接口
|
|||
|
|
"/api/v1/app/", // 前端应用接口
|
|||
|
|
"/api/v1/agent/", // 代理接口
|
|||
|
|
"/api/v1/user/", // 用户接口
|
|||
|
|
"/api/v1/auth/", // 认证接口
|
|||
|
|
"/api/v1/notification/", // 通知接口
|
|||
|
|
"/api/v1/pay/", // 支付接口
|
|||
|
|
"/api/v1/query/", // 查询接口
|
|||
|
|
"/api/v1/product/", // 产品接口
|
|||
|
|
"/api/v1/authorization/", // 授权接口
|
|||
|
|
"/health", // 健康检查
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for _, skipPath := range skipPaths {
|
|||
|
|
if strings.HasPrefix(path, skipPath) {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// parseRouteToApi 将路由解析为API信息
|
|||
|
|
func (s *ApiRegistryService) parseRouteToApi(route rest.Route) *model.AdminApi {
|
|||
|
|
// 生成API编码
|
|||
|
|
apiCode := s.generateApiCode(route.Method, route.Path)
|
|||
|
|
|
|||
|
|
// 生成API名称
|
|||
|
|
apiName := s.generateApiName(route.Path)
|
|||
|
|
|
|||
|
|
// 生成描述
|
|||
|
|
description := s.generateDescription(route.Method, route.Path)
|
|||
|
|
|
|||
|
|
return &model.AdminApi{
|
|||
|
|
ApiName: apiName,
|
|||
|
|
ApiCode: apiCode,
|
|||
|
|
Method: route.Method,
|
|||
|
|
Url: route.Path,
|
|||
|
|
Status: 1, // 默认启用
|
|||
|
|
Description: description,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// generateApiCode 生成API编码
|
|||
|
|
func (s *ApiRegistryService) generateApiCode(method, path string) string {
|
|||
|
|
// 移除路径参数,如 :id
|
|||
|
|
cleanPath := regexp.MustCompile(`/:[\w]+`).ReplaceAllString(path, "")
|
|||
|
|
|
|||
|
|
// 转换为小写并替换特殊字符
|
|||
|
|
apiCode := strings.ToLower(method) + "_" + strings.ReplaceAll(cleanPath, "/", "_")
|
|||
|
|
apiCode = strings.TrimPrefix(apiCode, "_")
|
|||
|
|
apiCode = strings.TrimSuffix(apiCode, "_")
|
|||
|
|
|
|||
|
|
return apiCode
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// generateApiName 生成API名称
|
|||
|
|
func (s *ApiRegistryService) generateApiName(path string) string {
|
|||
|
|
// 从路径中提取模块和操作
|
|||
|
|
parts := strings.Split(strings.Trim(path, "/"), "/")
|
|||
|
|
if len(parts) < 3 {
|
|||
|
|
return path
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取模块名和操作名
|
|||
|
|
module := parts[len(parts)-2]
|
|||
|
|
action := parts[len(parts)-1]
|
|||
|
|
|
|||
|
|
// 转换为中文描述
|
|||
|
|
moduleMap := map[string]string{
|
|||
|
|
"agent": "代理管理",
|
|||
|
|
"auth": "认证管理",
|
|||
|
|
"feature": "功能管理",
|
|||
|
|
"menu": "菜单管理",
|
|||
|
|
"notification": "通知管理",
|
|||
|
|
"order": "订单管理",
|
|||
|
|
"platform_user": "平台用户",
|
|||
|
|
"product": "产品管理",
|
|||
|
|
"promotion": "推广管理",
|
|||
|
|
"query": "查询管理",
|
|||
|
|
"role": "角色管理",
|
|||
|
|
"user": "用户管理",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
actionMap := map[string]string{
|
|||
|
|
"list": "列表",
|
|||
|
|
"create": "创建",
|
|||
|
|
"update": "更新",
|
|||
|
|
"delete": "删除",
|
|||
|
|
"detail": "详情",
|
|||
|
|
"login": "登录",
|
|||
|
|
"config": "配置",
|
|||
|
|
"example": "示例",
|
|||
|
|
"refund": "退款",
|
|||
|
|
"link": "链接",
|
|||
|
|
"stats": "统计",
|
|||
|
|
"cleanup": "清理",
|
|||
|
|
"record": "记录",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
moduleName := moduleMap[module]
|
|||
|
|
if moduleName == "" {
|
|||
|
|
moduleName = module
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
actionName := actionMap[action]
|
|||
|
|
if actionName == "" {
|
|||
|
|
actionName = action
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return fmt.Sprintf("%s-%s", moduleName, actionName)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// generateDescription 生成API描述
|
|||
|
|
func (s *ApiRegistryService) generateDescription(method, path string) string {
|
|||
|
|
methodMap := map[string]string{
|
|||
|
|
"GET": "查询",
|
|||
|
|
"POST": "创建",
|
|||
|
|
"PUT": "更新",
|
|||
|
|
"DELETE": "删除",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
methodDesc := methodMap[method]
|
|||
|
|
if methodDesc == "" {
|
|||
|
|
methodDesc = method
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
apiName := s.generateApiName(path)
|
|||
|
|
|
|||
|
|
return fmt.Sprintf("%s%s", methodDesc, apiName)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// shouldUpdateApi 判断是否需要更新API
|
|||
|
|
func (s *ApiRegistryService) shouldUpdateApi(existing, new *model.AdminApi) bool {
|
|||
|
|
return existing.ApiName != new.ApiName ||
|
|||
|
|
existing.Method != new.Method ||
|
|||
|
|
existing.Url != new.Url ||
|
|||
|
|
existing.Description != new.Description
|
|||
|
|
}
|