项目结构 #
一、项目结构概述 #
1.1 为什么需要良好的项目结构 #
良好的项目结构带来以下好处:
| 好处 | 说明 |
|---|---|
| 可维护性 | 代码组织清晰,易于维护 |
| 可扩展性 | 方便添加新功能 |
| 可测试性 | 便于编写单元测试 |
| 团队协作 | 统一的代码组织方式 |
| 代码复用 | 避免重复代码 |
1.2 Fiber项目结构原则 #
text
1. 按功能模块组织
2. 分层架构设计
3. 依赖注入
4. 配置与代码分离
5. 统一的错误处理
二、基础项目结构 #
2.1 简单项目结构 #
适合小型项目或学习:
text
my-fiber-app/
├── main.go
├── handlers/
│ └── user.go
├── models/
│ └── user.go
├── go.mod
└── go.sum
2.2 标准项目结构 #
适合中型项目:
text
my-fiber-app/
├── cmd/
│ └── main.go
├── internal/
│ ├── handlers/
│ │ ├── user.go
│ │ └── auth.go
│ ├── models/
│ │ └── user.go
│ ├── services/
│ │ └── user.go
│ └── repositories/
│ └── user.go
├── pkg/
│ ├── config/
│ │ └── config.go
│ ├── middleware/
│ │ └── auth.go
│ └── utils/
│ └── response.go
├── config/
│ └── config.yaml
├── go.mod
├── go.sum
├── Makefile
└── README.md
三、企业级项目结构 #
3.1 完整项目结构 #
适合大型企业项目:
text
my-fiber-app/
├── cmd/
│ ├── api/
│ │ └── main.go
│ └── worker/
│ └── main.go
├── internal/
│ ├── domain/
│ │ ├── user/
│ │ │ ├── entity.go
│ │ │ ├── repository.go
│ │ │ └── service.go
│ │ └── product/
│ │ ├── entity.go
│ │ ├── repository.go
│ │ └── service.go
│ ├── handlers/
│ │ ├── user.go
│ │ ├── product.go
│ │ └── health.go
│ ├── middleware/
│ │ ├── auth.go
│ │ ├── logger.go
│ │ └── cors.go
│ └── infrastructure/
│ ├── database/
│ │ ├── postgres.go
│ │ └── redis.go
│ └── queue/
│ └── rabbitmq.go
├── pkg/
│ ├── config/
│ │ └── config.go
│ ├── logger/
│ │ └── logger.go
│ ├── validator/
│ │ └── validator.go
│ └── utils/
│ ├── response.go
│ └── jwt.go
├── api/
│ ├── openapi.yaml
│ └── docs/
├── configs/
│ ├── config.yaml
│ └── config.example.yaml
├── scripts/
│ ├── build.sh
│ └── deploy.sh
├── deployments/
│ ├── docker/
│ │ ├── Dockerfile
│ │ └── docker-compose.yaml
│ └── k8s/
│ └── deployment.yaml
├── test/
│ ├── integration/
│ └── e2e/
├── go.mod
├── go.sum
├── Makefile
└── README.md
3.2 目录说明 #
| 目录 | 说明 |
|---|---|
| cmd | 应用入口,可以有多个入口 |
| internal | 私有代码,不可被外部导入 |
| pkg | 公共代码,可被外部导入 |
| api | API文档 |
| configs | 配置文件 |
| scripts | 脚本文件 |
| deployments | 部署配置 |
| test | 测试文件 |
四、代码分层 #
4.1 分层架构 #
text
┌─────────────────────────────────────┐
│ Handlers (路由处理) │
├─────────────────────────────────────┤
│ Services (业务逻辑) │
├─────────────────────────────────────┤
│ Repositories (数据访问) │
├─────────────────────────────────────┤
│ Models (数据模型) │
└─────────────────────────────────────┘
4.2 Handler层 #
负责处理HTTP请求和响应:
go
// internal/handlers/user.go
package handlers
import (
"github.com/gofiber/fiber/v2"
"my-fiber-app/internal/services"
)
type UserHandler struct {
service *services.UserService
}
func NewUserHandler(service *services.UserService) *UserHandler {
return &UserHandler{service: service}
}
func (h *UserHandler) GetUsers(c *fiber.Ctx) error {
users, err := h.service.GetAll()
if err != nil {
return c.Status(500).JSON(fiber.Map{
"error": err.Error(),
})
}
return c.JSON(users)
}
func (h *UserHandler) GetUser(c *fiber.Ctx) error {
id := c.Params("id")
user, err := h.service.GetByID(id)
if err != nil {
return c.Status(404).JSON(fiber.Map{
"error": "User not found",
})
}
return c.JSON(user)
}
func (h *UserHandler) CreateUser(c *fiber.Ctx) error {
var req CreateUserRequest
if err := c.BodyParser(&req); err != nil {
return c.Status(400).JSON(fiber.Map{
"error": err.Error(),
})
}
user, err := h.service.Create(&req)
if err != nil {
return c.Status(500).JSON(fiber.Map{
"error": err.Error(),
})
}
return c.Status(201).JSON(user)
}
4.3 Service层 #
负责业务逻辑处理:
go
// internal/services/user.go
package services
import (
"my-fiber-app/internal/models"
"my-fiber-app/internal/repositories"
)
type UserService struct {
repo *repositories.UserRepository
}
func NewUserService(repo *repositories.UserRepository) *UserService {
return &UserService{repo: repo}
}
func (s *UserService) GetAll() ([]*models.User, error) {
return s.repo.FindAll()
}
func (s *UserService) GetByID(id string) (*models.User, error) {
return s.repo.FindByID(id)
}
func (s *UserService) Create(req *CreateUserRequest) (*models.User, error) {
user := &models.User{
Name: req.Name,
Email: req.Email,
}
if err := s.repo.Create(user); err != nil {
return nil, err
}
return user, nil
}
4.4 Repository层 #
负责数据访问:
go
// internal/repositories/user.go
package repositories
import (
"gorm.io/gorm"
"my-fiber-app/internal/models"
)
type UserRepository struct {
db *gorm.DB
}
func NewUserRepository(db *gorm.DB) *UserRepository {
return &UserRepository{db: db}
}
func (r *UserRepository) FindAll() ([]*models.User, error) {
var users []*models.User
if err := r.db.Find(&users).Error; err != nil {
return nil, err
}
return users, nil
}
func (r *UserRepository) FindByID(id string) (*models.User, error) {
var user models.User
if err := r.db.First(&user, "id = ?", id).Error; err != nil {
return nil, err
}
return &user, nil
}
func (r *UserRepository) Create(user *models.User) error {
return r.db.Create(user).Error
}
4.5 Model层 #
定义数据模型:
go
// internal/models/user.go
package models
import (
"time"
"github.com/google/uuid"
)
type User struct {
ID string `json:"id" gorm:"primaryKey"`
Name string `json:"name" gorm:"not null"`
Email string `json:"email" gorm:"unique;not null"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (u *User) BeforeCreate(tx *gorm.DB) error {
u.ID = uuid.New().String()
return nil
}
五、路由组织 #
5.1 路由注册 #
go
// internal/routes/routes.go
package routes
import (
"github.com/gofiber/fiber/v2"
"my-fiber-app/internal/handlers"
"my-fiber-app/internal/middleware"
)
func SetupRoutes(app *fiber.App, userHandler *handlers.UserHandler) {
// 健康检查
app.Get("/health", func(c *fiber.Ctx) error {
return c.JSON(fiber.Map{"status": "ok"})
})
// API v1
v1 := app.Group("/api/v1")
// 用户路由
users := v1.Group("/users")
users.Get("/", userHandler.GetUsers)
users.Get("/:id", userHandler.GetUser)
users.Post("/", userHandler.CreateUser)
users.Put("/:id", middleware.Auth(), userHandler.UpdateUser)
users.Delete("/:id", middleware.Auth(), userHandler.DeleteUser)
}
5.2 主入口 #
go
// cmd/api/main.go
package main
import (
"log"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/recover"
"my-fiber-app/internal/handlers"
"my-fiber-app/internal/repositories"
"my-fiber-app/internal/services"
"my-fiber-app/internal/routes"
"my-fiber-app/pkg/config"
"my-fiber-app/pkg/database"
)
func main() {
// 加载配置
cfg, err := config.Load()
if err != nil {
log.Fatal(err)
}
// 连接数据库
db, err := database.Connect(cfg.Database)
if err != nil {
log.Fatal(err)
}
// 初始化依赖
userRepo := repositories.NewUserRepository(db)
userService := services.NewUserService(userRepo)
userHandler := handlers.NewUserHandler(userService)
// 创建应用
app := fiber.New(fiber.Config{
AppName: cfg.AppName,
})
// 全局中间件
app.Use(logger.New())
app.Use(recover.New())
// 注册路由
routes.SetupRoutes(app, userHandler)
// 启动服务
log.Fatal(app.Listen(":" + cfg.Port))
}
六、配置管理 #
6.1 配置文件 #
yaml
# configs/config.yaml
app:
name: My Fiber App
port: 3000
env: development
database:
host: localhost
port: 5432
name: myapp
user: postgres
password: secret
redis:
host: localhost
port: 6379
db: 0
6.2 配置加载 #
go
// pkg/config/config.go
package config
import (
"os"
"github.com/spf13/viper"
)
type Config struct {
App AppConfig
Database DatabaseConfig
Redis RedisConfig
}
type AppConfig struct {
Name string
Port string
Env string
}
type DatabaseConfig struct {
Host string
Port int
Name string
User string
Password string
}
type RedisConfig struct {
Host string
Port int
DB int
}
func Load() (*Config, error) {
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath("./configs")
viper.AddConfigPath(".")
// 环境变量覆盖
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err != nil {
return nil, err
}
var cfg Config
if err := viper.Unmarshal(&cfg); err != nil {
return nil, err
}
// 环境变量优先
if port := os.Getenv("PORT"); port != "" {
cfg.App.Port = port
}
return &cfg, nil
}
七、最佳实践 #
7.1 依赖注入 #
go
// 使用构造函数注入依赖
type UserHandler struct {
service *services.UserService
}
func NewUserHandler(service *services.UserService) *UserHandler {
return &UserHandler{service: service}
}
7.2 统一响应格式 #
go
// pkg/utils/response.go
package utils
import "github.com/gofiber/fiber/v2"
type Response struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
func Success(c *fiber.Ctx, data interface{}) error {
return c.JSON(Response{
Code: 0,
Message: "success",
Data: data,
})
}
func Error(c *fiber.Ctx, code int, message string) error {
return c.JSON(Response{
Code: code,
Message: message,
})
}
7.3 错误处理 #
go
// pkg/errors/errors.go
package errors
import "github.com/gofiber/fiber/v2"
type AppError struct {
Code int
Message string
}
func (e *AppError) Error() string {
return e.Message
}
func NewNotFoundError(message string) *AppError {
return &AppError{Code: 404, Message: message}
}
func NewBadRequestError(message string) *AppError {
return &AppError{Code: 400, Message: message}
}
// 全局错误处理
func ErrorHandler(c *fiber.Ctx, err error) error {
if e, ok := err.(*AppError); ok {
return c.Status(e.Code).JSON(fiber.Map{
"error": e.Message,
})
}
return c.Status(500).JSON(fiber.Map{
"error": "Internal Server Error",
})
}
八、总结 #
8.1 项目结构要点 #
| 要点 | 说明 |
|---|---|
| 分层架构 | Handler → Service → Repository → Model |
| 依赖注入 | 使用构造函数注入依赖 |
| 配置管理 | 配置与代码分离 |
| 错误处理 | 统一的错误处理机制 |
| 路由组织 | 按模块组织路由 |
8.2 下一步 #
现在你已经了解了项目结构,接下来让我们学习 路由基础,深入了解Fiber的路由系统!
最后更新:2026-03-28