feat: 完善依赖注入改造

完成所有Handler的依赖注入改造:
- AuthHandler: 认证相关功能
- UserHandler: 用户管理功能
- TextureHandler: 材质管理功能
- ProfileHandler: 档案管理功能
- CaptchaHandler: 验证码功能
- YggdrasilHandler: Yggdrasil API功能

新增错误类型定义:
- internal/errors/errors.go: 统一的错误类型和工厂函数

更新main.go:
- 使用container.NewContainer创建依赖容器
- 使用handler.RegisterRoutesWithDI注册路由

代码遵循Go最佳实践:
- 依赖通过构造函数注入
- Handler通过结构体方法实现
- 统一的错误处理模式
- 清晰的分层架构
This commit is contained in:
lan
2025-12-02 17:46:00 +08:00
parent f7589ebbb8
commit ffdc3e3e6b
13 changed files with 998 additions and 201 deletions

View File

@@ -0,0 +1,247 @@
package handler
import (
"carrotskin/internal/container"
"carrotskin/internal/service"
"carrotskin/internal/types"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// ProfileHandler 档案处理器
type ProfileHandler struct {
container *container.Container
logger *zap.Logger
}
// NewProfileHandler 创建ProfileHandler实例
func NewProfileHandler(c *container.Container) *ProfileHandler {
return &ProfileHandler{
container: c,
logger: c.Logger,
}
}
// Create 创建档案
// @Summary 创建Minecraft档案
// @Description 创建新的Minecraft角色档案UUID由后端自动生成
// @Tags profile
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body types.CreateProfileRequest true "档案信息(仅需提供角色名)"
// @Success 200 {object} model.Response{data=types.ProfileInfo} "创建成功"
// @Failure 400 {object} model.ErrorResponse "请求参数错误"
// @Router /api/v1/profile [post]
func (h *ProfileHandler) Create(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
var req types.CreateProfileRequest
if err := c.ShouldBindJSON(&req); err != nil {
RespondBadRequest(c, "请求参数错误: "+err.Error(), nil)
return
}
maxProfiles := service.GetMaxProfilesPerUser()
if err := service.CheckProfileLimit(h.container.DB, userID, maxProfiles); err != nil {
RespondBadRequest(c, err.Error(), nil)
return
}
profile, err := service.CreateProfile(h.container.DB, userID, req.Name)
if err != nil {
h.logger.Error("创建档案失败",
zap.Int64("user_id", userID),
zap.String("name", req.Name),
zap.Error(err),
)
RespondServerError(c, err.Error(), nil)
return
}
RespondSuccess(c, ProfileToProfileInfo(profile))
}
// List 获取档案列表
// @Summary 获取档案列表
// @Description 获取当前用户的所有档案
// @Tags profile
// @Accept json
// @Produce json
// @Security BearerAuth
// @Success 200 {object} model.Response "获取成功"
// @Router /api/v1/profile [get]
func (h *ProfileHandler) List(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
profiles, err := service.GetUserProfiles(h.container.DB, userID)
if err != nil {
h.logger.Error("获取档案列表失败",
zap.Int64("user_id", userID),
zap.Error(err),
)
RespondServerError(c, err.Error(), nil)
return
}
RespondSuccess(c, ProfilesToProfileInfos(profiles))
}
// Get 获取档案详情
// @Summary 获取档案详情
// @Description 根据UUID获取档案详细信息
// @Tags profile
// @Accept json
// @Produce json
// @Param uuid path string true "档案UUID"
// @Success 200 {object} model.Response "获取成功"
// @Failure 404 {object} model.ErrorResponse "档案不存在"
// @Router /api/v1/profile/{uuid} [get]
func (h *ProfileHandler) Get(c *gin.Context) {
uuid := c.Param("uuid")
if uuid == "" {
RespondBadRequest(c, "UUID不能为空", nil)
return
}
profile, err := service.GetProfileByUUID(h.container.DB, uuid)
if err != nil {
h.logger.Error("获取档案失败",
zap.String("uuid", uuid),
zap.Error(err),
)
RespondNotFound(c, err.Error())
return
}
RespondSuccess(c, ProfileToProfileInfo(profile))
}
// Update 更新档案
// @Summary 更新档案
// @Description 更新档案信息
// @Tags profile
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param uuid path string true "档案UUID"
// @Param request body types.UpdateProfileRequest true "更新信息"
// @Success 200 {object} model.Response "更新成功"
// @Failure 403 {object} model.ErrorResponse "无权操作"
// @Router /api/v1/profile/{uuid} [put]
func (h *ProfileHandler) Update(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
uuid := c.Param("uuid")
if uuid == "" {
RespondBadRequest(c, "UUID不能为空", nil)
return
}
var req types.UpdateProfileRequest
if err := c.ShouldBindJSON(&req); err != nil {
RespondBadRequest(c, "请求参数错误: "+err.Error(), nil)
return
}
var namePtr *string
if req.Name != "" {
namePtr = &req.Name
}
profile, err := service.UpdateProfile(h.container.DB, uuid, userID, namePtr, req.SkinID, req.CapeID)
if err != nil {
h.logger.Error("更新档案失败",
zap.String("uuid", uuid),
zap.Int64("user_id", userID),
zap.Error(err),
)
RespondWithError(c, err)
return
}
RespondSuccess(c, ProfileToProfileInfo(profile))
}
// Delete 删除档案
// @Summary 删除档案
// @Description 删除指定的Minecraft档案
// @Tags profile
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param uuid path string true "档案UUID"
// @Success 200 {object} model.Response "删除成功"
// @Failure 403 {object} model.ErrorResponse "无权操作"
// @Router /api/v1/profile/{uuid} [delete]
func (h *ProfileHandler) Delete(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
uuid := c.Param("uuid")
if uuid == "" {
RespondBadRequest(c, "UUID不能为空", nil)
return
}
if err := service.DeleteProfile(h.container.DB, uuid, userID); err != nil {
h.logger.Error("删除档案失败",
zap.String("uuid", uuid),
zap.Int64("user_id", userID),
zap.Error(err),
)
RespondWithError(c, err)
return
}
RespondSuccess(c, gin.H{"message": "删除成功"})
}
// SetActive 设置活跃档案
// @Summary 设置活跃档案
// @Description 将指定档案设置为活跃状态
// @Tags profile
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param uuid path string true "档案UUID"
// @Success 200 {object} model.Response "设置成功"
// @Failure 403 {object} model.ErrorResponse "无权操作"
// @Router /api/v1/profile/{uuid}/activate [post]
func (h *ProfileHandler) SetActive(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
uuid := c.Param("uuid")
if uuid == "" {
RespondBadRequest(c, "UUID不能为空", nil)
return
}
if err := service.SetActiveProfile(h.container.DB, uuid, userID); err != nil {
h.logger.Error("设置活跃档案失败",
zap.String("uuid", uuid),
zap.Int64("user_id", userID),
zap.Error(err),
)
RespondWithError(c, err)
return
}
RespondSuccess(c, gin.H{"message": "设置成功"})
}