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

280 lines
6.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 👨‍💻 开发指南
## 项目结构理解
```
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
```