Go Web 编程实战Go Web 编程实战
首页
课程导读
首页
课程导读
  • 课程导读
  • 课程目录

    • Go基础语法精要
    • Web基础与HTTP处理
    • Gin框架入门
    • 路由与中间件
    • 数据库操作
    • 模板渲染
    • 错误处理与日志
    • 测试与部署
    • 高级中间件模式
    • 微服务架构
    • 性能优化
    • 安全最佳实践
    • 项目结构与代码组织

项目结构与代码组织

1. 标准Go项目布局

参考Golang标准项目布局:

myproject/
├── api/                  # API协议定义(Swagger, protobuf)
├── assets/               # 静态资源文件
├── build/               # 构建脚本和Dockerfile
├── cmd/                 # 主应用程序入口
│   └── myapp/           # 主程序包
│       └── main.go      # 主程序入口
├── configs/             # 配置文件模板或默认配置
├── deployments/         # 部署配置(k8s, nomad)
├── docs/                # 设计文档
├── examples/            # 示例代码
├── githooks/            # Git钩子
├── init/                # 系统初始化脚本
├── internal/            # 私有应用程序代码
│   ├── app/             # 应用层
│   ├── domain/          # 领域层
│   └── infrastructure/  # 基础设施层
├── pkg/                 # 可复用的公共库
├── scripts/             # 各种脚本
├── test/                # 测试工具和测试数据
├── third_party/         # 第三方工具和代码
├── web/                 # Web应用特定组件
├── go.mod               # Go模块定义
├── go.sum               # Go模块校验
├── Makefile             # 构建管理
└── README.md            # 项目说明

2. 分层架构设计

清晰的分层架构

internal/
├── app/                 # 应用层(用例)
│   ├── handlers/       # HTTP处理器
│   ├── services/       # 业务服务
│   └── workers/        # 后台任务
├── domain/             # 领域层
│   ├── models/         # 领域模型
│   ├── repositories/   # 仓储接口
│   └── services/       # 领域服务
└── infrastructure/     # 基础设施层
    ├── db/             # 数据库访问
    ├── cache/          # 缓存实现
    ├── queue/          # 消息队列
    └── config/         # 配置加载

依赖关系

HTTP Handler → Application Service → Domain Service → Repository → DB

3. 模块化组织

按功能模块组织

internal/
├── user/               # 用户模块
│   ├── handler.go      # HTTP处理器
│   ├── service.go      # 业务逻辑
│   ├── repository.go   # 数据访问
│   └── model.go        # 数据模型
├── order/              # 订单模块
│   ├── handler.go
│   ├── service.go
│   ├── repository.go
│   └── model.go
└── product/            # 产品模块
    ├── handler.go
    ├── service.go
    ├── repository.go
    └── model.go

模块间通信

// 通过接口定义模块边界
type UserRepository interface {
    FindByID(id string) (*User, error)
    Save(user *User) error
}

// 实现可以独立替换
type MySQLUserRepository struct {
    db *sql.DB
}

func (r *MySQLUserRepository) FindByID(id string) (*User, error) {
    // 数据库查询实现
}

4. 配置管理

使用Viper管理配置

import "github.com/spf13/viper"

type Config struct {
    Database struct {
        Host     string
        Port     int
        Username string
        Password string
    }
    Server struct {
        Port int
    }
}

func LoadConfig(path string) (Config, error) {
    viper.SetConfigName("config")
    viper.SetConfigType("yaml")
    viper.AddConfigPath(path)
    
    if err := viper.ReadInConfig(); err != nil {
        return Config{}, err
    }
    
    var config Config
    if err := viper.Unmarshal(&config); err != nil {
        return Config{}, err
    }
    
    return config, nil
}

环境变量覆盖

# config.yaml
database:
  host: localhost
  port: 3306

# 通过环境变量覆盖
export APP_DATABASE_HOST=mysql.prod
export APP_DATABASE_PORT=3307
// 自动绑定环境变量
viper.AutomaticEnv()
viper.SetEnvPrefix("app")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

5. 文档与代码生成

Swagger文档生成

// main.go
// @title My API
// @version 1.0
// @description This is a sample server.
// @host localhost:8080
// @BasePath /api/v1
func main() {
    r := gin.Default()
    
    // 路由定义
    r.GET("/users/:id", getUser)
    
    // Swagger
    r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
    
    r.Run(":8080")
}

// @Summary 获取用户
// @Description 通过ID获取用户详情
// @ID get-user-by-id
// @Produce json
// @Param id path string true "用户ID"
// @Success 200 {object} User
// @Router /users/{id} [get]
func getUser(c *gin.Context) {
    // 实现...
}

Wire依赖注入生成

// provider.go
var UserSet = wire.NewSet(
    ProvideUserRepository,
    ProvideUserService,
    ProvideUserHandler,
)

func ProvideUserRepository(db *sql.DB) *MySQLUserRepository {
    return &MySQLUserRepository{db: db}
}

func ProvideUserService(repo UserRepository) *UserService {
    return &UserService{repo: repo}
}

func ProvideUserHandler(service *UserService) *UserHandler {
    return &UserHandler{service: service}
}

// wire.go
func InitializeUserHandler(db *sql.DB) (*UserHandler, error) {
    wire.Build(
        UserSet,
    )
    return &UserHandler{}, nil
}

提示:良好的项目结构应该随着项目规模的增长而演进。从简单开始,在需要时逐步引入更复杂的结构。

Prev
安全最佳实践