Files
tyapi-server/docs/开始指南/开发指南.md

6.4 KiB
Raw Blame History

👨‍💻 开发指南

项目结构理解

tyapi-server-gin/
├── cmd/api/                 # 应用入口
├── internal/                # 内部代码
│   ├── app/                 # 应用层
│   ├── config/              # 配置管理
│   ├── container/           # 依赖注入
│   ├── domains/             # 业务域
│   │   └── user/            # 用户域示例
│   └── shared/              # 共享基础设施
├── pkg/                     # 外部包
├── scripts/                 # 脚本文件
├── test/                    # 测试文件
└── docs/                    # 文档目录

开发流程

1. 创建新的业务域

# 使用Makefile创建新域
make new-domain DOMAIN=product

# 手动创建目录结构
mkdir -p internal/domains/product/{entities,dto,services,repositories,handlers,routes,events}

2. 实现业务实体

创建 internal/domains/product/entities/product.go

type Product struct {
    BaseEntity
    Name        string `gorm:"not null;size:100"`
    Description string `gorm:"size:500"`
    Price       float64 `gorm:"not null"`
    CategoryID  uint    `gorm:"not null"`
}

func (p *Product) Validate() error {
    if p.Name == "" {
        return errors.New("产品名称不能为空")
    }
    if p.Price <= 0 {
        return errors.New("产品价格必须大于0")
    }
    return nil
}

3. 定义仓储接口

创建 internal/domains/product/repositories/product_repository.go

type ProductRepository interface {
    shared.BaseRepository[entities.Product]
    FindByCategory(ctx context.Context, categoryID uint) ([]*entities.Product, error)
    FindByPriceRange(ctx context.Context, min, max float64) ([]*entities.Product, error)
}

4. 实现业务服务

创建 internal/domains/product/services/product_service.go

type ProductService interface {
    CreateProduct(ctx context.Context, req *dto.CreateProductRequest) (*dto.ProductResponse, error)
    GetProduct(ctx context.Context, id uint) (*dto.ProductResponse, error)
    UpdateProduct(ctx context.Context, id uint, req *dto.UpdateProductRequest) (*dto.ProductResponse, error)
    DeleteProduct(ctx context.Context, id uint) error
}

5. 实现 HTTP 处理器

创建 internal/domains/product/handlers/product_handler.go

func (h *ProductHandler) CreateProduct(c *gin.Context) {
    var req dto.CreateProductRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        response.Error(c, http.StatusBadRequest, "请求参数无效", err)
        return
    }

    product, err := h.productService.CreateProduct(c.Request.Context(), &req)
    if err != nil {
        response.Error(c, http.StatusInternalServerError, "创建产品失败", err)
        return
    }

    response.Success(c, product)
}

6. 配置路由

创建 internal/domains/product/routes/product_routes.go

func RegisterProductRoutes(router shared.Router, handler *handlers.ProductHandler) {
    v1 := router.Group("/api/v1")
    {
        products := v1.Group("/products")
        {
            products.POST("", handler.CreateProduct)
            products.GET("/:id", handler.GetProduct)
            products.PUT("/:id", handler.UpdateProduct)
            products.DELETE("/:id", handler.DeleteProduct)
        }
    }
}

常用开发命令

# 代码格式化
make fmt

# 代码检查
make lint

# 运行测试
make test

# 测试覆盖率
make test-coverage

# 生成API文档
make docs

# 热重载开发
make dev

# 构建二进制文件
make build

# 清理临时文件
make clean

测试编写

单元测试示例

func TestProductService_CreateProduct(t *testing.T) {
    // 设置测试数据
    mockRepo := mocks.NewProductRepository(t)
    service := services.NewProductService(mockRepo, nil)

    req := &dto.CreateProductRequest{
        Name:        "测试产品",
        Description: "测试描述",
        Price:       99.99,
        CategoryID:  1,
    }

    // 设置Mock期望
    mockRepo.On("Create", mock.Anything, mock.AnythingOfType("*entities.Product")).
        Return(&entities.Product{}, nil)

    // 执行测试
    result, err := service.CreateProduct(context.Background(), req)

    // 断言结果
    assert.NoError(t, err)
    assert.NotNil(t, result)
    assert.Equal(t, req.Name, result.Name)
}

集成测试示例

func TestProductAPI_Integration(t *testing.T) {
    // 启动测试服务器
    testApp := setupTestApp(t)
    defer testApp.Cleanup()

    // 创建测试请求
    reqBody := `{"name":"测试产品","price":99.99,"category_id":1}`
    req := httptest.NewRequest("POST", "/api/v1/products", strings.NewReader(reqBody))
    req.Header.Set("Content-Type", "application/json")

    // 执行请求
    w := httptest.NewRecorder()
    testApp.ServeHTTP(w, req)

    // 验证响应
    assert.Equal(t, http.StatusCreated, w.Code)

    var response map[string]interface{}
    json.Unmarshal(w.Body.Bytes(), &response)
    assert.Equal(t, "success", response["status"])
}

开发规范

代码风格

  • 使用 gofmt 格式化代码
  • 遵循 Go 命名规范
  • 添加必要的注释和文档
  • 函数长度不超过 50 行

Git 提交规范

# 功能开发
git commit -m "feat: 添加用户注册功能"

# 问题修复
git commit -m "fix: 修复登录验证问题"

# 文档更新
git commit -m "docs: 更新API文档"

# 重构代码
git commit -m "refactor: 重构用户服务层"

分支管理

  • main: 主分支,用于生产发布
  • develop: 开发分支,用于集成测试
  • feature/xxx: 功能分支,用于新功能开发
  • hotfix/xxx: 热修复分支,用于紧急修复

调试技巧

使用 Delve 调试器

# 安装 Delve
go install github.com/go-delve/delve/cmd/dlv@latest

# 启动调试
dlv debug ./cmd/api/main.go

# 设置断点
(dlv) break main.main
(dlv) continue

日志调试

// 添加调试日志
logger.Debug("Processing user request",
    zap.String("user_id", userID),
    zap.String("action", "create_product"))

// 临时调试信息
fmt.Printf("Debug: %+v\n", debugData)

性能分析

# 启用 pprof
go tool pprof http://localhost:8080/debug/pprof/profile

# 内存分析
go tool pprof http://localhost:8080/debug/pprof/heap

# 协程分析
go tool pprof http://localhost:8080/debug/pprof/goroutine