gin + es 实践 06

发布于:2025-05-08 ⋅ 阅读:(23) ⋅ 点赞:(0)

开发指南

本文档为 Go-ES 项目的开发指南,介绍了如何设置开发环境、代码规范、测试方法以及如何贡献和扩展本项目。

开发环境设置

基础环境

  1. 安装 Go:使用 Go 1.21 或更高版本
  2. 安装 Git:版本控制工具
  3. 安装代码编辑器:推荐使用 VSCode 或 GoLand
  4. 安装 MySQL:用于数据存储
  5. 安装 Elasticsearch:用于搜索功能

推荐的 IDE 插件

若使用 VSCode,推荐安装以下插件:

  • Go: 官方 Go 语言支持插件
  • Go Test Explorer: Go 测试工具
  • REST Client: API 测试工具
  • YAML: YAML 文件支持
  • GitLens: Git 增强工具

初始化开发环境

# 克隆仓库
git clone https://github.com/saixiaoxi/go-es.git
cd go-es

# 安装依赖
go mod tidy

# 创建配置文件
cp config.example.yaml config.yaml

# 编辑配置文件,设置开发环境参数
vim config.yaml

启动开发服务器

# 运行应用
go run cmd/api/main.go

# 或构建并运行
go build -o bin/go-es cmd/api/main.go
./bin/go-es

项目扩展指南

添加新实体

  1. 创建领域实体:在 domain/entity/ 目录下创建新实体
// 例如,创建 category.go
package entity

import (
    "time"
    "github.com/google/uuid"
)

// Category 类别实体
type Category struct {
    ID          string    `json:"id" gorm:"type:varchar(36);primary_key"`
    Name        string    `json:"name" gorm:"type:varchar(100);not null;unique"`
    Description string    `json:"description" gorm:"type:text"`
    ParentID    string    `json:"parent_id" gorm:"type:varchar(36);index"`
    CreatedAt   time.Time `json:"created_at" gorm:"autoCreateTime"`
    UpdatedAt   time.Time `json:"updated_at" gorm:"autoUpdateTime"`
}

// NewCategory 创建新类别
func NewCategory(name, description, parentID string) *Category {
    return &Category{
        ID:          uuid.New().String(),
        Name:        name,
        Description: description,
        ParentID:    parentID,
        CreatedAt:   time.Now(),
        UpdatedAt:   time.Now(),
    }
}
  1. 定义仓储接口:在 domain/repository/ 目录下定义仓储接口
// 例如,创建 category_repository.go
package repository

import (
    "context"
    "github.com/saixiaoxi/go-es/domain/entity"
)

// CategoryRepository 类别仓储接口
type CategoryRepository interface {
    Create(ctx context.Context, category *entity.Category) error
    FindByID(ctx context.Context, id string) (*entity.Category, error)
    FindAll(ctx context.Context) ([]*entity.Category, error)
    Update(ctx context.Context, category *entity.Category) error
    Delete(ctx context.Context, id string) error
}
  1. 实现仓储:在 infrastructure/repository/ 目录下实现仓储接口
// 例如,创建 category_repository_impl.go
package repository

import (
    "context"
    "github.com/saixiaoxi/go-es/domain/entity"
    "github.com/saixiaoxi/go-es/domain/repository"
    "github.com/saixiaoxi/go-es/infrastructure/persistence"
)

// CategoryRepositoryImpl 类别仓储实现
type CategoryRepositoryImpl struct {
    db *persistence.Database
}

// NewCategoryRepository 创建类别仓储
func NewCategoryRepository(db *persistence.Database) repository.CategoryRepository {
    return &CategoryRepositoryImpl{
        db: db,
    }
}

// Create 创建类别
func (r *CategoryRepositoryImpl) Create(ctx context.Context, category *entity.Category) error {
    return r.db.GetDB().Create(category).Error
}

// 实现其他方法...
  1. 创建领域服务:在 domain/service/ 目录下创建领域服务

  2. 创建应用服务:在 application/service/ 目录下创建应用服务

  3. 创建 DTO:在 interfaces/dto/ 目录下定义 DTO

  4. 创建 API 处理器:在 interfaces/api/handler/ 目录下创建处理器

  5. 注册路由:在 interfaces/api/router/router.go 中注册新路由

添加新功能模块

例如,添加一个用户认证模块:

  1. 创建用户实体和相关仓储
  2. 实现认证服务:在 domain/service/ 目录下实现
  3. 创建中间件:在 interfaces/api/middleware/ 目录下创建认证中间件
  4. 添加认证路由和处理器

代码规范

命名约定

  • 包名:使用小写单词,不使用下划线或混合大小写
  • 文件名:使用下划线分隔的小写单词
  • 变量名:使用驼峰命名法(CamelCase)
  • 常量名:使用驼峰命名法,如果是包级常量,首字母大写
  • 接口名:通常以 “er” 结尾,如 Reader, Writer
  • 结构体名:使用大写开头的驼峰命名法

注释规范

  • 所有导出的类型、函数、变量和常量都应该有注释
  • 使用完整的句子,以被描述的对象名称开始
  • 使用 // 注释,而不是 /* */
  • 包注释应该位于 package 子句之前

错误处理

  • 错误应该被显式检查和处理
  • 避免使用 panic,除非在初始化阶段
  • 使用自定义错误类型增强错误信息
  • 考虑使用 errors.Wrap 来添加上下文

测试指南

单元测试

为关键组件编写单元测试:

// product_service_test.go
package service_test

import (
    "context"
    "testing"

    "github.com/saixiaoxi/go-es/domain/entity"
    "github.com/saixiaoxi/go-es/domain/service"
    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/mock"
)

// MockProductRepository 模拟产品仓储
type MockProductRepository struct {
    mock.Mock
}

// 实现ProductRepository接口的方法...

func TestCreateProduct(t *testing.T) {
    // 准备测试数据
    mockRepo := new(MockProductRepository)
    productService := service.NewProductService(mockRepo)
    
    product := entity.NewProduct("Test Product", "Description", 100.0, "Category", []string{"tag1"})
    
    // 设置Mock期望
    mockRepo.On("Create", mock.Anything, product).Return(nil)
    mockRepo.On("IndexProduct", mock.Anything, product).Return(nil)
    
    // 执行测试
    err := productService.CreateProduct(context.Background(), product)
    
    // 断言
    assert.NoError(t, err)
    mockRepo.AssertExpectations(t)
}

集成测试

编写集成测试验证系统各部分之间的交互:

// 在 tests/integration 目录下
func TestProductAPI(t *testing.T) {
    // 准备测试环境...
    
    // 发送HTTP请求
    resp, err := http.Post(
        "http://localhost:8080/api/v1/products",
        "application/json",
        strings.NewReader(`{"name":"Test Product","price":100,"category":"Test"}`),
    )
    
    // 断言
    assert.NoError(t, err)
    assert.Equal(t, http.StatusCreated, resp.StatusCode)
    
    // 解析响应...
}

运行测试

# 运行所有测试
go test ./...

# 运行指定包的测试
go test ./domain/service/...

# 运行带覆盖率的测试
go test -cover ./...

# 生成覆盖率报告
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out

文档生成

Swagger 文档

项目使用 Swagger 自动生成 API 文档:

# 安装 swag 工具
go install github.com/swaggo/swag/cmd/swag@latest

# 生成文档
swag init -g ./cmd/api/main.go

Go Doc

生成 Go 代码文档:

# 启动本地文档服务器
godoc -http=:6060

# 访问 http://localhost:6060/pkg/github.com/saixiaoxi/go-es/ 查看文档

常见开发任务

添加新的 API 端点

  1. 在 DTO 包中定义请求和响应结构
  2. 在处理器中添加新方法
  3. 添加 Swagger 注解
  4. 在路由器中注册路由

修改数据模型

  1. 更新实体定义
  2. 添加数据库迁移逻辑
  3. 更新 Elasticsearch 映射
  4. 更新相关 DTO

添加第三方服务集成

  1. infrastructure 层创建集成客户端
  2. 在领域服务中添加相关功能
  3. 更新配置文件

性能优化

数据库查询优化

  • 检查并优化数据库索引
  • 使用批量操作替代循环单个操作
  • 只查询必要字段

Elasticsearch 查询优化

  • 优化索引设计和映射
  • 使用过滤器缓存
  • 限制返回字段
  • 使用 _source_includes 替代返回完整文档

应用性能优化

  • 使用连接池管理数据库和 Elasticsearch 连接
  • 缓存重复的计算结果
  • 使用 goroutine 处理并行任务

故障排除

常见问题

  1. “no such file or directory”:路径问题,检查文件路径是否正确
  2. 导入循环依赖:重新设计包的层级结构,避免循环引用
  3. 连接超时:检查网络连接和服务状态

调试技巧

  1. 使用 log 包打印调试信息
  2. 使用 delve 调试器进行源码级调试
  3. 使用 curl 或 API 客户端(如 Postman)测试 API 端点

贡献指南

提交代码

  1. Fork 项目并创建功能分支
  2. 提交前运行测试确保通过
  3. 使用清晰的提交消息,格式如下:
    [模块] 简短描述
    
    详细描述,解释更改原因
    
  4. 提交 Pull Request

代码审查

提交 PR 后,代码审查将检查:

  1. 代码风格和质量
  2. 测试覆盖率
  3. 功能完整性
  4. 文档更新