refactor: 重构后端架构为 go-zero 框架,优化项目结构

主要变更:
- 采用 go-zero 框架替代 Gin,提升开发效率
- 重构项目结构,API 文件模块化组织
- 将 model 移至 api/internal/model 目录
- 移除 common 包,改为标准 pkg 目录结构
- 实现统一的仓储模式,支持配置驱动数据库切换
- 简化测试策略,专注 API 集成测试
- 更新 CLAUDE.md 文档,提供详细的开发指导

技术栈更新:
- 框架: Gin → go-zero v1.6.0+
- 代码生成: 引入 goctl 工具
- 架构模式: 四层架构 → go-zero 三层架构 (Handler→Logic→Model)
- 项目布局: 遵循 Go 社区标准和 go-zero 最佳实践
This commit is contained in:
xujiang
2025-07-10 15:05:52 +08:00
parent a2f2f66f88
commit 39a42695d3
52 changed files with 6047 additions and 2349 deletions

View File

@ -14,6 +14,7 @@ import (
"go.uber.org/zap"
"photography-backend/internal/config"
"photography-backend/internal/database"
"photography-backend/internal/repository/postgres"
"photography-backend/internal/service"
"photography-backend/internal/service/auth"
@ -38,7 +39,7 @@ func main() {
defer zapLogger.Sync()
// 初始化数据库
db, err := postgres.NewDatabase(&cfg.Database)
db, err := database.New(cfg)
if err != nil {
zapLogger.Fatal("Failed to connect to database", zap.Error(err))
}
@ -49,11 +50,16 @@ func main() {
zapLogger.Fatal("Failed to migrate database", zap.Error(err))
}
// 填充种子数据
if err := db.Seed(); err != nil {
zapLogger.Warn("Failed to seed database", zap.Error(err))
}
// 初始化仓库
userRepo := postgres.NewUserRepository(db.DB)
photoRepo := postgres.NewPhotoRepository(db.DB)
categoryRepo := postgres.NewCategoryRepository(db.DB)
tagRepo := postgres.NewTagRepository(db.DB)
userRepo := postgres.NewUserRepository(db.GetDB())
photoRepo := postgres.NewPhotoRepository(db.GetDB())
categoryRepo := postgres.NewCategoryRepository(db.GetDB())
tagRepo := postgres.NewTagRepository(db.GetDB())
// 初始化服务
jwtService := auth.NewJWTService(&cfg.JWT)
@ -98,12 +104,12 @@ func main() {
// 设置路由
routes.SetupRoutes(r, &routes.Handlers{
Auth: authHandler,
Photo: photoHandler,
Category: categoryHandler,
Tag: tagHandler,
User: userHandler,
}, authMiddleware)
AuthHandler: authHandler,
PhotoHandler: photoHandler,
CategoryHandler: categoryHandler,
TagHandler: tagHandler,
UserHandler: userHandler,
}, authMiddleware, zapLogger)
// 创建HTTP服务器
server := &http.Server{

View File

@ -13,11 +13,12 @@ import (
"github.com/gin-gonic/gin"
"photography-backend/internal/config"
"photography-backend/internal/database"
"photography-backend/internal/models"
"photography-backend/internal/model/entity"
"photography-backend/internal/model/dto"
"photography-backend/internal/service/upload"
"photography-backend/internal/service/auth"
"photography-backend/internal/handlers"
"photography-backend/internal/middleware"
"photography-backend/internal/api/handlers"
"photography-backend/internal/api/middleware"
)
func main() {
@ -217,18 +218,18 @@ func main() {
// 认证相关处理函数
func login(c *gin.Context) {
var req models.LoginRequest
var req dto.LoginRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 查找用户
var user models.User
var user entity.User
db := database.GetDB()
// 可以使用用户名或邮箱登录
if err := db.Where("username = ? OR email = ?", req.Username, req.Username).First(&user).Error; err != nil {
if err := db.Where("username = ? OR email = ?", req.Email, req.Email).First(&user).Error; err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
return
}
@ -250,14 +251,14 @@ func login(c *gin.Context) {
}
func register(c *gin.Context) {
var req models.CreateUserRequest
var req dto.CreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 检查用户名是否已存在
var existingUser models.User
var existingUser entity.User
db := database.GetDB()
if err := db.Where("username = ? OR email = ?", req.Username, req.Email).First(&existingUser).Error; err == nil {
c.JSON(http.StatusConflict, gin.H{"error": "用户名或邮箱已存在"})
@ -265,12 +266,12 @@ func register(c *gin.Context) {
}
// 创建用户
user := models.User{
user := entity.User{
Username: req.Username,
Email: req.Email,
Password: req.Password, // 实际项目中应该加密
Name: req.Name,
Role: "user",
Role: entity.UserRoleUser,
IsActive: true,
}
@ -298,7 +299,7 @@ func refreshToken(c *gin.Context) {
// 用户 CRUD 操作
func getUsers(c *gin.Context) {
var users []models.User
var users []entity.User
db := database.GetDB()
if err := db.Find(&users).Error; err != nil {
@ -310,7 +311,7 @@ func getUsers(c *gin.Context) {
}
func createUser(c *gin.Context) {
var user models.User
var user entity.User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
@ -327,7 +328,7 @@ func createUser(c *gin.Context) {
func getUser(c *gin.Context) {
id := c.Param("id")
var user models.User
var user entity.User
db := database.GetDB()
if err := db.First(&user, id).Error; err != nil {
@ -340,7 +341,7 @@ func getUser(c *gin.Context) {
func updateUser(c *gin.Context) {
id := c.Param("id")
var user models.User
var user entity.User
db := database.GetDB()
if err := db.First(&user, id).Error; err != nil {
@ -365,7 +366,7 @@ func deleteUser(c *gin.Context) {
id := c.Param("id")
db := database.GetDB()
if err := db.Delete(&models.User{}, id).Error; err != nil {
if err := db.Delete(&entity.User{}, id).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
@ -375,7 +376,7 @@ func deleteUser(c *gin.Context) {
// 分类 CRUD 操作
func getCategories(c *gin.Context) {
var categories []models.Category
var categories []entity.Category
db := database.GetDB()
if err := db.Find(&categories).Error; err != nil {
@ -387,7 +388,7 @@ func getCategories(c *gin.Context) {
}
func createCategory(c *gin.Context) {
var category models.Category
var category entity.Category
if err := c.ShouldBindJSON(&category); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
@ -404,7 +405,7 @@ func createCategory(c *gin.Context) {
func getCategory(c *gin.Context) {
id := c.Param("id")
var category models.Category
var category entity.Category
db := database.GetDB()
if err := db.First(&category, id).Error; err != nil {
@ -417,7 +418,7 @@ func getCategory(c *gin.Context) {
func updateCategory(c *gin.Context) {
id := c.Param("id")
var category models.Category
var category entity.Category
db := database.GetDB()
if err := db.First(&category, id).Error; err != nil {
@ -442,7 +443,7 @@ func deleteCategory(c *gin.Context) {
id := c.Param("id")
db := database.GetDB()
if err := db.Delete(&models.Category{}, id).Error; err != nil {
if err := db.Delete(&entity.Category{}, id).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
@ -452,7 +453,7 @@ func deleteCategory(c *gin.Context) {
// 标签 CRUD 操作
func getTags(c *gin.Context) {
var tags []models.Tag
var tags []entity.Tag
db := database.GetDB()
if err := db.Find(&tags).Error; err != nil {
@ -464,7 +465,7 @@ func getTags(c *gin.Context) {
}
func createTag(c *gin.Context) {
var tag models.Tag
var tag entity.Tag
if err := c.ShouldBindJSON(&tag); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
@ -481,7 +482,7 @@ func createTag(c *gin.Context) {
func getTag(c *gin.Context) {
id := c.Param("id")
var tag models.Tag
var tag entity.Tag
db := database.GetDB()
if err := db.First(&tag, id).Error; err != nil {
@ -494,7 +495,7 @@ func getTag(c *gin.Context) {
func updateTag(c *gin.Context) {
id := c.Param("id")
var tag models.Tag
var tag entity.Tag
db := database.GetDB()
if err := db.First(&tag, id).Error; err != nil {
@ -519,7 +520,7 @@ func deleteTag(c *gin.Context) {
id := c.Param("id")
db := database.GetDB()
if err := db.Delete(&models.Tag{}, id).Error; err != nil {
if err := db.Delete(&entity.Tag{}, id).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
@ -529,7 +530,7 @@ func deleteTag(c *gin.Context) {
// 相册 CRUD 操作
func getAlbums(c *gin.Context) {
var albums []models.Album
var albums []entity.Album
db := database.GetDB()
if err := db.Find(&albums).Error; err != nil {
@ -541,7 +542,7 @@ func getAlbums(c *gin.Context) {
}
func createAlbum(c *gin.Context) {
var album models.Album
var album entity.Album
if err := c.ShouldBindJSON(&album); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
@ -558,7 +559,7 @@ func createAlbum(c *gin.Context) {
func getAlbum(c *gin.Context) {
id := c.Param("id")
var album models.Album
var album entity.Album
db := database.GetDB()
if err := db.First(&album, id).Error; err != nil {
@ -571,7 +572,7 @@ func getAlbum(c *gin.Context) {
func updateAlbum(c *gin.Context) {
id := c.Param("id")
var album models.Album
var album entity.Album
db := database.GetDB()
if err := db.First(&album, id).Error; err != nil {
@ -596,7 +597,7 @@ func deleteAlbum(c *gin.Context) {
id := c.Param("id")
db := database.GetDB()
if err := db.Delete(&models.Album{}, id).Error; err != nil {
if err := db.Delete(&entity.Album{}, id).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
@ -606,7 +607,7 @@ func deleteAlbum(c *gin.Context) {
// 照片 CRUD 操作
func getPhotos(c *gin.Context) {
var photos []models.Photo
var photos []entity.Photo
db := database.GetDB()
if err := db.Find(&photos).Error; err != nil {
@ -618,7 +619,7 @@ func getPhotos(c *gin.Context) {
}
func createPhoto(c *gin.Context) {
var photo models.Photo
var photo entity.Photo
if err := c.ShouldBindJSON(&photo); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
@ -635,7 +636,7 @@ func createPhoto(c *gin.Context) {
func getPhoto(c *gin.Context) {
id := c.Param("id")
var photo models.Photo
var photo entity.Photo
db := database.GetDB()
if err := db.First(&photo, id).Error; err != nil {
@ -648,7 +649,7 @@ func getPhoto(c *gin.Context) {
func updatePhoto(c *gin.Context) {
id := c.Param("id")
var photo models.Photo
var photo entity.Photo
db := database.GetDB()
if err := db.First(&photo, id).Error; err != nil {
@ -673,7 +674,7 @@ func deletePhoto(c *gin.Context) {
id := c.Param("id")
db := database.GetDB()
if err := db.Delete(&models.Photo{}, id).Error; err != nil {
if err := db.Delete(&entity.Photo{}, id).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}