refactor: Implement dependency injection for handlers and services

- Refactored AuthHandler, UserHandler, TextureHandler, ProfileHandler, CaptchaHandler, and YggdrasilHandler to use dependency injection.
- Removed direct instantiation of services and repositories within handlers, replacing them with constructor injection.
- Updated the container to initialize service instances and provide them to handlers.
- Enhanced code structure for better testability and adherence to Go best practices.
This commit is contained in:
lafay
2025-12-02 19:43:39 +08:00
parent 188a05caa7
commit 801f1b1397
33 changed files with 3628 additions and 4129 deletions

View File

@@ -1,30 +1,32 @@
package handler
import (
"carrotskin/internal/container"
"carrotskin/internal/model"
"carrotskin/internal/service"
"carrotskin/internal/types"
"carrotskin/pkg/database"
"carrotskin/pkg/logger"
"carrotskin/pkg/storage"
"strconv"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// GenerateTextureUploadURL 生成材质上传URL
// @Summary 生成材质上传URL
// @Description 生成预签名URL用于上传材质文件
// @Tags texture
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body types.GenerateTextureUploadURLRequest true "上传URL请求"
// @Success 200 {object} model.Response "生成成功"
// @Failure 400 {object} model.ErrorResponse "请求参数错误"
// @Router /api/v1/texture/upload-url [post]
func GenerateTextureUploadURL(c *gin.Context) {
// TextureHandler 材质处理器(依赖注入版本)
type TextureHandler struct {
container *container.Container
logger *zap.Logger
}
// NewTextureHandler 创建TextureHandler实例
func NewTextureHandler(c *container.Container) *TextureHandler {
return &TextureHandler{
container: c,
logger: c.Logger,
}
}
// GenerateUploadURL 生成材质上传URL
func (h *TextureHandler) GenerateUploadURL(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
@@ -36,16 +38,20 @@ func GenerateTextureUploadURL(c *gin.Context) {
return
}
storageClient := storage.MustGetClient()
if h.container.Storage == nil {
RespondServerError(c, "存储服务不可用", nil)
return
}
result, err := service.GenerateTextureUploadURL(
c.Request.Context(),
storageClient,
h.container.Storage,
userID,
req.FileName,
string(req.TextureType),
)
if err != nil {
logger.MustGetLogger().Error("生成材质上传URL失败",
h.logger.Error("生成材质上传URL失败",
zap.Int64("user_id", userID),
zap.String("file_name", req.FileName),
zap.String("texture_type", string(req.TextureType)),
@@ -63,18 +69,8 @@ func GenerateTextureUploadURL(c *gin.Context) {
})
}
// CreateTexture 创建材质记录
// @Summary 创建材质记录
// @Description 文件上传完成后,创建材质记录到数据库
// @Tags texture
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body types.CreateTextureRequest true "创建材质请求"
// @Success 200 {object} model.Response "创建成功"
// @Failure 400 {object} model.ErrorResponse "请求参数错误"
// @Router /api/v1/texture [post]
func CreateTexture(c *gin.Context) {
// Create 创建材质记录
func (h *TextureHandler) Create(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
@@ -86,13 +82,13 @@ func CreateTexture(c *gin.Context) {
return
}
maxTextures := service.GetMaxTexturesPerUser()
if err := service.CheckTextureUploadLimit(database.MustGetDB(), userID, maxTextures); err != nil {
maxTextures := h.container.UserService.GetMaxTexturesPerUser()
if err := h.container.TextureService.CheckUploadLimit(userID, maxTextures); err != nil {
RespondBadRequest(c, err.Error(), nil)
return
}
texture, err := service.CreateTexture(database.MustGetDB(),
texture, err := h.container.TextureService.Create(
userID,
req.Name,
req.Description,
@@ -104,7 +100,7 @@ func CreateTexture(c *gin.Context) {
req.IsSlim,
)
if err != nil {
logger.MustGetLogger().Error("创建材质失败",
h.logger.Error("创建材质失败",
zap.Int64("user_id", userID),
zap.String("name", req.Name),
zap.Error(err),
@@ -116,24 +112,15 @@ func CreateTexture(c *gin.Context) {
RespondSuccess(c, TextureToTextureInfo(texture))
}
// GetTexture 获取材质详情
// @Summary 获取材质详情
// @Description 根据ID获取材质详细信息
// @Tags texture
// @Accept json
// @Produce json
// @Param id path int true "材质ID"
// @Success 200 {object} model.Response "获取成功"
// @Failure 404 {object} model.ErrorResponse "材质不存在"
// @Router /api/v1/texture/{id} [get]
func GetTexture(c *gin.Context) {
// Get 获取材质详情
func (h *TextureHandler) Get(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
RespondBadRequest(c, "无效的材质ID", err)
return
}
texture, err := service.GetTextureByID(database.MustGetDB(), id)
texture, err := h.container.TextureService.GetByID(id)
if err != nil {
RespondNotFound(c, err.Error())
return
@@ -142,20 +129,8 @@ func GetTexture(c *gin.Context) {
RespondSuccess(c, TextureToTextureInfo(texture))
}
// SearchTextures 搜索材质
// @Summary 搜索材质
// @Description 根据关键词和类型搜索材质
// @Tags texture
// @Accept json
// @Produce json
// @Param keyword query string false "关键词"
// @Param type query string false "材质类型(SKIN/CAPE)"
// @Param public_only query bool false "只看公开材质"
// @Param page query int false "页码" default(1)
// @Param page_size query int false "每页数量" default(20)
// @Success 200 {object} model.PaginationResponse "搜索成功"
// @Router /api/v1/texture [get]
func SearchTextures(c *gin.Context) {
// Search 搜索材质
func (h *TextureHandler) Search(c *gin.Context) {
keyword := c.Query("keyword")
textureTypeStr := c.Query("type")
publicOnly := c.Query("public_only") == "true"
@@ -171,9 +146,9 @@ func SearchTextures(c *gin.Context) {
textureType = model.TextureTypeCape
}
textures, total, err := service.SearchTextures(database.MustGetDB(), keyword, textureType, publicOnly, page, pageSize)
textures, total, err := h.container.TextureService.Search(keyword, textureType, publicOnly, page, pageSize)
if err != nil {
logger.MustGetLogger().Error("搜索材质失败", zap.String("keyword", keyword), zap.Error(err))
h.logger.Error("搜索材质失败", zap.String("keyword", keyword), zap.Error(err))
RespondServerError(c, "搜索材质失败", err)
return
}
@@ -181,19 +156,8 @@ func SearchTextures(c *gin.Context) {
c.JSON(200, model.NewPaginationResponse(TexturesToTextureInfos(textures), total, page, pageSize))
}
// UpdateTexture 更新材质
// @Summary 更新材质
// @Description 更新材质信息(仅上传者可操作)
// @Tags texture
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "材质ID"
// @Param request body types.UpdateTextureRequest true "更新材质请求"
// @Success 200 {object} model.Response "更新成功"
// @Failure 403 {object} model.ErrorResponse "无权操作"
// @Router /api/v1/texture/{id} [put]
func UpdateTexture(c *gin.Context) {
// Update 更新材质
func (h *TextureHandler) Update(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
@@ -211,9 +175,9 @@ func UpdateTexture(c *gin.Context) {
return
}
texture, err := service.UpdateTexture(database.MustGetDB(), textureID, userID, req.Name, req.Description, req.IsPublic)
texture, err := h.container.TextureService.Update(textureID, userID, req.Name, req.Description, req.IsPublic)
if err != nil {
logger.MustGetLogger().Error("更新材质失败",
h.logger.Error("更新材质失败",
zap.Int64("user_id", userID),
zap.Int64("texture_id", textureID),
zap.Error(err),
@@ -225,18 +189,8 @@ func UpdateTexture(c *gin.Context) {
RespondSuccess(c, TextureToTextureInfo(texture))
}
// DeleteTexture 删除材质
// @Summary 删除材质
// @Description 删除材质(软删除,仅上传者可操作)
// @Tags texture
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "材质ID"
// @Success 200 {object} model.Response "删除成功"
// @Failure 403 {object} model.ErrorResponse "无权操作"
// @Router /api/v1/texture/{id} [delete]
func DeleteTexture(c *gin.Context) {
// Delete 删除材质
func (h *TextureHandler) Delete(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
@@ -248,8 +202,8 @@ func DeleteTexture(c *gin.Context) {
return
}
if err := service.DeleteTexture(database.MustGetDB(), textureID, userID); err != nil {
logger.MustGetLogger().Error("删除材质失败",
if err := h.container.TextureService.Delete(textureID, userID); err != nil {
h.logger.Error("删除材质失败",
zap.Int64("user_id", userID),
zap.Int64("texture_id", textureID),
zap.Error(err),
@@ -262,16 +216,7 @@ func DeleteTexture(c *gin.Context) {
}
// ToggleFavorite 切换收藏状态
// @Summary 切换收藏状态
// @Description 收藏或取消收藏材质
// @Tags texture
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "材质ID"
// @Success 200 {object} model.Response "切换成功"
// @Router /api/v1/texture/{id}/favorite [post]
func ToggleFavorite(c *gin.Context) {
func (h *TextureHandler) ToggleFavorite(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
@@ -283,9 +228,9 @@ func ToggleFavorite(c *gin.Context) {
return
}
isFavorited, err := service.ToggleTextureFavorite(database.MustGetDB(), userID, textureID)
isFavorited, err := h.container.TextureService.ToggleFavorite(userID, textureID)
if err != nil {
logger.MustGetLogger().Error("切换收藏状态失败",
h.logger.Error("切换收藏状态失败",
zap.Int64("user_id", userID),
zap.Int64("texture_id", textureID),
zap.Error(err),
@@ -298,17 +243,7 @@ func ToggleFavorite(c *gin.Context) {
}
// GetUserTextures 获取用户上传的材质列表
// @Summary 获取用户上传的材质列表
// @Description 获取当前用户上传的所有材质
// @Tags texture
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param page query int false "页码" default(1)
// @Param page_size query int false "每页数量" default(20)
// @Success 200 {object} model.PaginationResponse "获取成功"
// @Router /api/v1/texture/my [get]
func GetUserTextures(c *gin.Context) {
func (h *TextureHandler) GetUserTextures(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
@@ -317,9 +252,9 @@ func GetUserTextures(c *gin.Context) {
page := parseIntWithDefault(c.DefaultQuery("page", "1"), 1)
pageSize := parseIntWithDefault(c.DefaultQuery("page_size", "20"), 20)
textures, total, err := service.GetUserTextures(database.MustGetDB(), userID, page, pageSize)
textures, total, err := h.container.TextureService.GetByUserID(userID, page, pageSize)
if err != nil {
logger.MustGetLogger().Error("获取用户材质列表失败", zap.Int64("user_id", userID), zap.Error(err))
h.logger.Error("获取用户材质列表失败", zap.Int64("user_id", userID), zap.Error(err))
RespondServerError(c, "获取材质列表失败", err)
return
}
@@ -328,17 +263,7 @@ func GetUserTextures(c *gin.Context) {
}
// GetUserFavorites 获取用户收藏的材质列表
// @Summary 获取用户收藏的材质列表
// @Description 获取当前用户收藏的所有材质
// @Tags texture
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param page query int false "页码" default(1)
// @Param page_size query int false "每页数量" default(20)
// @Success 200 {object} model.PaginationResponse "获取成功"
// @Router /api/v1/texture/favorites [get]
func GetUserFavorites(c *gin.Context) {
func (h *TextureHandler) GetUserFavorites(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
@@ -347,9 +272,9 @@ func GetUserFavorites(c *gin.Context) {
page := parseIntWithDefault(c.DefaultQuery("page", "1"), 1)
pageSize := parseIntWithDefault(c.DefaultQuery("page_size", "20"), 20)
textures, total, err := service.GetUserTextureFavorites(database.MustGetDB(), userID, page, pageSize)
textures, total, err := h.container.TextureService.GetUserFavorites(userID, page, pageSize)
if err != nil {
logger.MustGetLogger().Error("获取用户收藏列表失败", zap.Int64("user_id", userID), zap.Error(err))
h.logger.Error("获取用户收藏列表失败", zap.Int64("user_id", userID), zap.Error(err))
RespondServerError(c, "获取收藏列表失败", err)
return
}