refactor(main): 重构主应用结构以提高模块化
- 将main.go中的初始化逻辑提取到新的app包中 - 创建bootstrap包来处理配置加载和数据库初始化 - 添加middleware包来管理CORS中间件 - 创建router包来处理路由配置 - 简化main函数,只保留应用启动逻辑 - 使用依赖注入模式组织服务和处理器
This commit is contained in:
50
memora-api/internal/app/app.go
Normal file
50
memora-api/internal/app/app.go
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"memora-api/internal/bootstrap"
|
||||||
|
"memora-api/internal/handler"
|
||||||
|
"memora-api/internal/router"
|
||||||
|
"memora-api/internal/service"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type App struct {
|
||||||
|
engine *gin.Engine
|
||||||
|
addr string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(configPath string) (*App, error) {
|
||||||
|
cfg, err := bootstrap.LoadConfig(configPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("加载配置失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := bootstrap.InitDB(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("连接数据库失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := bootstrap.AutoMigrate(db); err != nil {
|
||||||
|
return nil, fmt.Errorf("数据库迁移失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wordService := service.NewWordService(db)
|
||||||
|
wordHandler := handler.NewWordHandler(wordService)
|
||||||
|
engine := router.New(wordHandler)
|
||||||
|
|
||||||
|
return &App{
|
||||||
|
engine: engine,
|
||||||
|
addr: fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) Run() error {
|
||||||
|
return a.engine.Run(a.addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) Addr() string {
|
||||||
|
return a.addr
|
||||||
|
}
|
||||||
7
memora-api/internal/bootstrap/config.go
Normal file
7
memora-api/internal/bootstrap/config.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package bootstrap
|
||||||
|
|
||||||
|
import "memora-api/internal/config"
|
||||||
|
|
||||||
|
func LoadConfig(path string) (*config.Config, error) {
|
||||||
|
return config.LoadConfig(path)
|
||||||
|
}
|
||||||
17
memora-api/internal/bootstrap/database.go
Normal file
17
memora-api/internal/bootstrap/database.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package bootstrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"memora-api/internal/config"
|
||||||
|
"memora-api/internal/model"
|
||||||
|
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func InitDB(cfg *config.Config) (*gorm.DB, error) {
|
||||||
|
return gorm.Open(mysql.Open(cfg.Database.DSN()), &gorm.Config{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func AutoMigrate(db *gorm.DB) error {
|
||||||
|
return db.AutoMigrate(&model.Word{}, &model.MemoryRecord{})
|
||||||
|
}
|
||||||
17
memora-api/internal/middleware/cors.go
Normal file
17
memora-api/internal/middleware/cors.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
func CORS() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
||||||
|
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
||||||
|
|
||||||
|
if c.Request.Method == "OPTIONS" {
|
||||||
|
c.AbortWithStatus(204)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
25
memora-api/internal/router/router.go
Normal file
25
memora-api/internal/router/router.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"memora-api/internal/handler"
|
||||||
|
"memora-api/internal/middleware"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func New(wordHandler *handler.WordHandler) *gin.Engine {
|
||||||
|
r := gin.Default()
|
||||||
|
r.Use(middleware.CORS())
|
||||||
|
|
||||||
|
api := r.Group("/api")
|
||||||
|
{
|
||||||
|
api.POST("/words", wordHandler.AddWord)
|
||||||
|
api.GET("/words", wordHandler.GetWords)
|
||||||
|
api.GET("/review", wordHandler.GetReviewWords)
|
||||||
|
api.POST("/review", wordHandler.SubmitReview)
|
||||||
|
api.GET("/stats", wordHandler.GetStatistics)
|
||||||
|
api.GET("/audio", wordHandler.GetAudio)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
@@ -1,78 +1,19 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"memora-api/internal/config"
|
"memora-api/internal/app"
|
||||||
"memora-api/internal/handler"
|
|
||||||
"memora-api/internal/model"
|
|
||||||
"memora-api/internal/service"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"gorm.io/driver/mysql"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// 加载配置
|
application, err := app.New("config.yaml")
|
||||||
cfg, err := config.LoadConfig("config.yaml")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("加载配置失败: %v", err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 连接数据库
|
log.Printf("服务器启动在: %s", application.Addr())
|
||||||
db, err := gorm.Open(mysql.Open(cfg.Database.DSN()), &gorm.Config{})
|
if err := application.Run(); err != nil {
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("连接数据库失败: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 自动迁移表
|
|
||||||
if err := db.AutoMigrate(&model.Word{}, &model.MemoryRecord{}); err != nil {
|
|
||||||
log.Fatalf("数据库迁移失败: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 初始化服务
|
|
||||||
wordService := service.NewWordService(db)
|
|
||||||
wordHandler := handler.NewWordHandler(wordService)
|
|
||||||
|
|
||||||
// 启动 Gin
|
|
||||||
r := gin.Default()
|
|
||||||
|
|
||||||
// CORS 中间件
|
|
||||||
r.Use(func(c *gin.Context) {
|
|
||||||
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
|
||||||
c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
|
||||||
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
|
||||||
if c.Request.Method == "OPTIONS" {
|
|
||||||
c.AbortWithStatus(204)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.Next()
|
|
||||||
})
|
|
||||||
|
|
||||||
// 路由
|
|
||||||
api := r.Group("/api")
|
|
||||||
{
|
|
||||||
// 记忆模式
|
|
||||||
api.POST("/words", wordHandler.AddWord)
|
|
||||||
api.GET("/words", wordHandler.GetWords)
|
|
||||||
|
|
||||||
// 复习模式
|
|
||||||
api.GET("/review", wordHandler.GetReviewWords)
|
|
||||||
api.POST("/review", wordHandler.SubmitReview)
|
|
||||||
|
|
||||||
// 统计
|
|
||||||
api.GET("/stats", wordHandler.GetStatistics)
|
|
||||||
|
|
||||||
// 音频
|
|
||||||
api.GET("/audio", wordHandler.GetAudio)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 启动服务器
|
|
||||||
addr := fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port)
|
|
||||||
log.Printf("服务器启动在: %s", addr)
|
|
||||||
if err := r.Run(addr); err != nil {
|
|
||||||
log.Fatalf("启动服务器失败: %v", err)
|
log.Fatalf("启动服务器失败: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user