package service import ( "fmt" "gofaster/internal/auth/model" "gofaster/internal/auth/repository" "reflect" "strings" "github.com/gin-gonic/gin" "go.uber.org/zap" "gorm.io/gorm" ) // RouteInfo 路由信息结构 type RouteInfo struct { Path string `json:"path"` Method string `json:"method"` Module string `json:"module"` Description string `json:"description"` } // RouteSyncService 路由同步服务 type RouteSyncService struct { routeMappingRepo *repository.RouteMappingRepository resourceRepo repository.ResourceRepository log *zap.Logger } // NewRouteSyncService 创建路由同步服务实例 func NewRouteSyncService( routeMappingRepo *repository.RouteMappingRepository, resourceRepo repository.ResourceRepository, log *zap.Logger, ) *RouteSyncService { return &RouteSyncService{ routeMappingRepo: routeMappingRepo, resourceRepo: resourceRepo, log: log, } } // SyncRoutes 同步路由信息到数据库 func (s *RouteSyncService) SyncRoutes(router *gin.Engine) error { s.log.Info("开始同步后台路由信息...") // 收集所有路由信息 routes := s.collectRoutes(router) // 同步到数据库 createdCount, updatedCount, err := s.syncToDatabase(routes) if err != nil { s.log.Error("路由同步失败", zap.Error(err)) return err } s.log.Info("路由同步完成", zap.Int("总路由数", len(routes)), zap.Int("新增数", createdCount), zap.Int("更新数", updatedCount), ) return nil } // collectRoutes 收集路由信息 func (s *RouteSyncService) collectRoutes(router *gin.Engine) []RouteInfo { var routes []RouteInfo // 遍历所有注册的路由 for _, route := range router.Routes() { if route.Method != "" && route.Path != "" { module := s.extractModuleFromPath(route.Path) description := s.generateDescription(route.Method, route.Path) routes = append(routes, RouteInfo{ Path: route.Path, Method: route.Method, Module: module, Description: description, }) } } return routes } // collectRoutesFromGroup 从路由组收集路由信息 func (s *RouteSyncService) collectRoutesFromGroup(group interface{}, routes *[]RouteInfo) { // 使用反射获取路由组信息 val := reflect.ValueOf(group) if val.Kind() == reflect.Ptr { val = val.Elem() } // 尝试获取路由组的方法 if val.Kind() == reflect.Struct { // 这里需要根据实际的gin路由组结构来提取路由信息 // 由于gin的路由组结构比较复杂,我们主要依赖Routes()方法 } } // extractModuleFromPath 从路径中提取模块名 func (s *RouteSyncService) extractModuleFromPath(path string) string { // 移除开头的斜杠 path = strings.TrimPrefix(path, "/") // 分割路径 parts := strings.Split(path, "/") if len(parts) == 0 { return "unknown" } // 第一个部分通常是模块名 module := parts[0] // 映射常见的模块名 switch module { case "api": if len(parts) > 1 { return parts[1] // 如 /api/auth -> auth } return "api" case "auth": return "auth" case "workflow": return "workflow" case "user": return "user" case "role": return "role" case "permission": return "permission" case "resource": return "resource" default: return module } } // generateDescription 生成路由描述 func (s *RouteSyncService) generateDescription(method, path string) string { module := s.extractModuleFromPath(path) switch method { case "GET": if strings.Contains(path, "/:id") { return fmt.Sprintf("获取%s详情", module) } return fmt.Sprintf("获取%s列表", module) case "POST": return fmt.Sprintf("创建%s", module) case "PUT": return fmt.Sprintf("更新%s", module) case "DELETE": return fmt.Sprintf("删除%s", module) case "PATCH": return fmt.Sprintf("部分更新%s", module) default: return fmt.Sprintf("%s操作", method) } } // syncToDatabase 同步路由信息到数据库 func (s *RouteSyncService) syncToDatabase(routes []RouteInfo) (int, int, error) { createdCount := 0 updatedCount := 0 for _, route := range routes { // 检查是否已存在 existing, err := s.routeMappingRepo.FindByBackendRoute(route.Path, route.Method) if err != nil && err != gorm.ErrRecordNotFound { s.log.Error("查询路由映射失败", zap.String("path", route.Path), zap.String("method", route.Method), zap.Error(err), ) continue } // 创建或更新路由映射 mapping := &model.RouteMapping{ BackendRoute: route.Path, HTTPMethod: route.Method, AuthGroup: s.getAuthGroupByMethod(route.Method), Module: route.Module, Description: route.Description, Status: 1, } if existing == nil { // 创建新的路由映射 if err := s.routeMappingRepo.Create(mapping); err != nil { s.log.Error("创建路由映射失败", zap.String("path", route.Path), zap.String("method", route.Method), zap.Error(err), ) continue } createdCount++ s.log.Debug("创建路由映射", zap.String("path", route.Path), zap.String("method", route.Method), ) } else { // 更新现有路由映射 mapping.ID = existing.ID if err := s.routeMappingRepo.Update(mapping); err != nil { s.log.Error("更新路由映射失败", zap.String("path", route.Path), zap.String("method", route.Method), zap.Error(err), ) continue } updatedCount++ s.log.Debug("更新路由映射", zap.String("path", route.Path), zap.String("method", route.Method), ) } } return createdCount, updatedCount, nil } // getAuthGroupByMethod 根据HTTP方法获取权限分组 func (s *RouteSyncService) getAuthGroupByMethod(method string) string { // 修改型操作 editMethods := []string{"POST", "PUT", "PATCH", "DELETE"} for _, editMethod := range editMethods { if method == editMethod { return "Edit" } } // 读取型操作 return "Read" } // GetSyncStatus 获取同步状态 func (s *RouteSyncService) GetSyncStatus() (map[string]interface{}, error) { // 获取数据库中的路由映射总数 totalMappings, err := s.routeMappingRepo.FindAll() if err != nil { return nil, err } // 按模块统计 moduleStats := make(map[string]int) for _, mapping := range totalMappings { moduleStats[mapping.Module]++ } return map[string]interface{}{ "total_mappings": len(totalMappings), "module_stats": moduleStats, "last_sync": "应用启动时自动同步", }, nil } // SyncFrontendRoute 同步前端路由映射 func (s *RouteSyncService) SyncFrontendRoute(routeMapping *model.RouteMapping) error { s.log.Info("同步前端路由映射", zap.String("frontendRoute", routeMapping.FrontendRoute), zap.String("backendRoute", routeMapping.BackendRoute), zap.String("module", routeMapping.Module)) // 检查是否已存在相同的前端路由 existing, err := s.routeMappingRepo.FindByFrontendRoute(routeMapping.FrontendRoute) if err != nil && err != gorm.ErrRecordNotFound { return err } if len(existing) > 0 { // 更新现有记录 for _, existingMapping := range existing { if existingMapping.HTTPMethod == routeMapping.HTTPMethod { // 更新匹配的记录 routeMapping.ID = existingMapping.ID return s.routeMappingRepo.Update(routeMapping) } } } // 创建新记录 return s.routeMappingRepo.Create(routeMapping) } // BatchSyncFrontendRoutes 批量同步前端路由 func (s *RouteSyncService) BatchSyncFrontendRoutes(routeMappings []model.RouteMapping) (int, int, []string) { successCount := 0 errorCount := 0 var errors []string for _, mapping := range routeMappings { if err := s.SyncFrontendRoute(&mapping); err != nil { errorCount++ errorMsg := fmt.Sprintf("同步路由失败 %s -> %s: %s", mapping.FrontendRoute, mapping.BackendRoute, err.Error()) errors = append(errors, errorMsg) s.log.Error("批量同步路由失败", zap.Error(err)) } else { successCount++ } } return successCount, errorCount, errors } // GetFrontendRoutes 获取前端路由列表 func (s *RouteSyncService) GetFrontendRoutes(module, authGroup string) ([]model.RouteMapping, error) { if module != "" && authGroup != "" { return s.routeMappingRepo.FindByModuleAndAuthGroup(module, authGroup) } else if module != "" { return s.routeMappingRepo.FindByModule(module) } else if authGroup != "" { return s.routeMappingRepo.FindByAuthGroup(authGroup) } else { return s.routeMappingRepo.FindAll() } }