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.
 
 
 
 
 
 

323 lines
8.3 KiB

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()
}
}