280 lines
6.4 KiB
Markdown
280 lines
6.4 KiB
Markdown
# 👨💻 开发指南
|
||
|
||
## 项目结构理解
|
||
|
||
```
|
||
tyapi-server-gin/
|
||
├── cmd/api/ # 应用入口
|
||
├── internal/ # 内部代码
|
||
│ ├── app/ # 应用层
|
||
│ ├── config/ # 配置管理
|
||
│ ├── container/ # 依赖注入
|
||
│ ├── domains/ # 业务域
|
||
│ │ └── user/ # 用户域示例
|
||
│ └── shared/ # 共享基础设施
|
||
├── pkg/ # 外部包
|
||
├── scripts/ # 脚本文件
|
||
├── test/ # 测试文件
|
||
└── docs/ # 文档目录
|
||
```
|
||
|
||
## 开发流程
|
||
|
||
### 1. 创建新的业务域
|
||
|
||
```bash
|
||
# 使用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`:
|
||
|
||
```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`:
|
||
|
||
```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`:
|
||
|
||
```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`:
|
||
|
||
```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`:
|
||
|
||
```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)
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 常用开发命令
|
||
|
||
```bash
|
||
# 代码格式化
|
||
make fmt
|
||
|
||
# 代码检查
|
||
make lint
|
||
|
||
# 运行测试
|
||
make test
|
||
|
||
# 测试覆盖率
|
||
make test-coverage
|
||
|
||
# 生成API文档
|
||
make docs
|
||
|
||
# 热重载开发
|
||
make dev
|
||
|
||
# 构建二进制文件
|
||
make build
|
||
|
||
# 清理临时文件
|
||
make clean
|
||
```
|
||
|
||
## 测试编写
|
||
|
||
### 单元测试示例
|
||
|
||
```go
|
||
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)
|
||
}
|
||
```
|
||
|
||
### 集成测试示例
|
||
|
||
```go
|
||
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 提交规范
|
||
|
||
```bash
|
||
# 功能开发
|
||
git commit -m "feat: 添加用户注册功能"
|
||
|
||
# 问题修复
|
||
git commit -m "fix: 修复登录验证问题"
|
||
|
||
# 文档更新
|
||
git commit -m "docs: 更新API文档"
|
||
|
||
# 重构代码
|
||
git commit -m "refactor: 重构用户服务层"
|
||
```
|
||
|
||
### 分支管理
|
||
|
||
- `main`: 主分支,用于生产发布
|
||
- `develop`: 开发分支,用于集成测试
|
||
- `feature/xxx`: 功能分支,用于新功能开发
|
||
- `hotfix/xxx`: 热修复分支,用于紧急修复
|
||
|
||
## 调试技巧
|
||
|
||
### 使用 Delve 调试器
|
||
|
||
```bash
|
||
# 安装 Delve
|
||
go install github.com/go-delve/delve/cmd/dlv@latest
|
||
|
||
# 启动调试
|
||
dlv debug ./cmd/api/main.go
|
||
|
||
# 设置断点
|
||
(dlv) break main.main
|
||
(dlv) continue
|
||
```
|
||
|
||
### 日志调试
|
||
|
||
```go
|
||
// 添加调试日志
|
||
logger.Debug("Processing user request",
|
||
zap.String("user_id", userID),
|
||
zap.String("action", "create_product"))
|
||
|
||
// 临时调试信息
|
||
fmt.Printf("Debug: %+v\n", debugData)
|
||
```
|
||
|
||
### 性能分析
|
||
|
||
```bash
|
||
# 启用 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
|
||
```
|