跳转至

实战项目

📚 章节概述

本章将通过一个完整的实战项目,综合运用前面所学的 Go 知识。我们将构建一个 RESTful API 服务。

任务管理API架构图

上图给出了任务管理 API 的核心分层与模块关系,便于把握项目组织方式。

🎯 项目目标

  • 构建功能完整的 RESTful API
  • 综合运用 Go 的核心特性
  • 学习项目组织和模块化
  • 掌握测试和文档编写
  • 了解部署和运行

🛠️ 项目概述

1.1 项目简介

我们将构建一个 任务管理 API,具有以下功能:

  • 用户认证
  • 任务 CRUD 操作
  • 数据库集成
  • 并发处理
  • 测试覆盖

1.2 技术栈

  • Gin:Web 框架
  • GORM:ORM 框架
  • SQLite:数据库
  • JWT:认证

📦 项目结构

Text Only
task-api/
├── go.mod
├── go.sum
├── main.go
├── models/
│   └── user.go
├── handlers/
│   └── task.go
├── middleware/
│   └── auth.go
├── config/
│   └── config.go
├── tests/
│   └── integration_test.go
└── README.md

🚀 项目实现

2.1 go.mod

Go
module task-api

go 1.22

require (
    github.com/gin-gonic/gin v1.9.1
    gorm.io/gorm v1.25.4
    gorm.io/driver/sqlite v1.5.2
    github.com/golang-jwt/jwt/v5 v5.0.0
)

2.2 模型定义

models/task.go

Go
package models

import (
    "gorm.io/gorm"
    "time"
)

type Task struct {
    gorm.Model
    Title       string    `json:"title"`
    Description string    `json:"description"`
    Status      string    `json:"status"`
    DueDate     time.Time `json:"due_date"`
    UserID      uint      `json:"user_id"`
}

type User struct {
    gorm.Model
    Username string `json:"username" gorm:"unique"`
    Password string `json:"password"`
    Tasks   []Task `json:"tasks" gorm:"foreignKey:UserID"`
}

2.3 数据库初始化

config/database.go

Go
package config

import (
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
    "task-api/models"
)

var DB *gorm.DB

func InitDB() error {
    var err error
    DB, err = gorm.Open(sqlite.Open("tasks.db"), &gorm.Config{})
    if err != nil {
        return err
    }

    DB.AutoMigrate(&models.User{}, &models.Task{})
    return nil
}

2.4 处理器

handlers/task.go

Go
package handlers

import (
    "net/http"
    "task-api/config"
    "task-api/models"
    "github.com/gin-gonic/gin"
)

func CreateTask(c *gin.Context) {
    var task models.Task
    if err := c.ShouldBindJSON(&task); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    config.DB.Create(&task)
    c.JSON(http.StatusCreated, task)
}

func GetTasks(c *gin.Context) {
    var tasks []models.Task
    config.DB.Find(&tasks)
    c.JSON(http.StatusOK, tasks)
}

func GetTask(c *gin.Context) {
    id := c.Param("id")
    var task models.Task
    if err := config.DB.First(&task, id).Error; err != nil {
        c.JSON(http.StatusNotFound, gin.H{"error": "Task not found"})
        return
    }
    c.JSON(http.StatusOK, task)
}

func UpdateTask(c *gin.Context) {
    id := c.Param("id")
    var task models.Task
    if err := config.DB.First(&task, id).Error; err != nil {
        c.JSON(http.StatusNotFound, gin.H{"error": "Task not found"})
        return
    }

    if err := c.ShouldBindJSON(&task); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    config.DB.Save(&task)
    c.JSON(http.StatusOK, task)
}

func DeleteTask(c *gin.Context) {
    id := c.Param("id")
    config.DB.Delete(&models.Task{}, id)
    c.Status(http.StatusNoContent)
}

2.5 中间件

middleware/auth.go

Go
package middleware

import (
    "net/http"
    "strings"
    "github.com/gin-gonic/gin"
)

func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        if token == "" {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header required"})
            c.Abort()
            return
        }

        if !strings.HasPrefix(token, "Bearer ") {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid authorization format"})
            c.Abort()
            return
        }

        // 验证 JWT token
        // ...

        c.Next()
    }
}

2.6 主程序

main.go

Go
package main

import (
    "task-api/config"
    "task-api/handlers"
    "task-api/middleware"
    "github.com/gin-gonic/gin"
)

func main() {
    // 初始化数据库
    if err := config.InitDB(); err != nil {
        panic("Failed to connect to database")
    }

    // 创建路由
    r := gin.Default()

    // 公开路由(需要实现 handlers.Register 和 handlers.Login)
    // r.POST("/register", handlers.Register)
    // r.POST("/login", handlers.Login)

    // 认证路由
    authorized := r.Group("/api")
    authorized.Use(middleware.AuthMiddleware())

    authorized.GET("/tasks", handlers.GetTasks)
    authorized.POST("/tasks", handlers.CreateTask)
    authorized.GET("/tasks/:id", handlers.GetTask)
    authorized.PUT("/tasks/:id", handlers.UpdateTask)
    authorized.DELETE("/tasks/:id", handlers.DeleteTask)

    // 启动服务器
    r.Run(":8080")
}

🧪 测试

3.1 集成测试

tests/integration_test.go

Go
package tests

import (
    "bytes"
    "encoding/json"
    "net/http"
    "net/http/httptest"
    "testing"
    "task-api/handlers"
    "github.com/gin-gonic/gin"
    "github.com/stretchr/testify/assert"
)

func TestCreateTask(t *testing.T) {
    router := gin.Default()
    router.POST("/tasks", handlers.CreateTask)

    task := map[string]string{
        "title":       "Test Task",
        "description": "Test Description",
        "status":      "pending",
    }

    jsonData, _ := json.Marshal(task)
    req, _ := http.NewRequest("POST", "/tasks", bytes.NewBuffer(jsonData))
    req.Header.Set("Content-Type", "application/json")

    w := httptest.NewRecorder()
    router.ServeHTTP(w, req)

    assert.Equal(t, http.StatusCreated, w.Code)
}

📚 文档

4.1 README.md

Markdown
# Task API

一个简单的任务管理 RESTful API。

## 功能

- 用户注册和登录
- 任务的 CRUD 操作
- JWT 认证
- 数据库持久化

## 安装

```bash
go mod download
go run main.go
```

## API 端点

### 认证
- `POST /register` - 用户注册
- `POST /login` - 用户登录

### 任务
- `GET /api/tasks` - 获取所有任务
- `POST /api/tasks` - 创建任务
- `GET /api/tasks/:id` - 获取单个任务
- `PUT /api/tasks/:id` - 更新任务
- `DELETE /api/tasks/:id` - 删除任务

## 示例

```bash
# 创建任务
curl -X POST http://localhost:8080/api/tasks \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"title":"New Task","description":"Task description","status":"pending"}'
```

## 🚀 构建和部署

### 5.1 构建

```bash
# 构建可执行文件
go build -o task-api

# 交叉编译
GOOS=linux GOARCH=amd64 go build -o task-api-linux
```

### 5.2 运行

```bash
# 运行
./task-api

# 或使用 go run
go run main.go
```

📝 练习题

练习 1:添加新功能

Go
// TODO: 添加以下功能
// - 任务标签
// - 任务优先级
// - 任务搜索
// - 任务统计

练习 2:性能优化

Go
// TODO: 优化以下方面
// - 数据库查询
// - 并发处理
// - 缓存机制

💡 最佳实践

1. 错误处理

Go
// 好:统一的错误处理
func handleError(c *gin.Context, err error) {
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{
            "error": err.Error(),
        })
        return
    }
}

// 避免:分散的错误处理

2. 配置管理

Go
// 好:使用配置文件
type Config struct {
    DatabaseURL string
    JWTSecret   string
    Port        string
}

// 避免:硬编码配置

🎯 项目总结

通过这个实战项目,我们学习了:

  • ✅ 项目组织和模块化
  • ✅ RESTful API 设计
  • ✅ 数据库集成
  • ✅ 中间件使用
  • ✅ 测试编写
  • ✅ 文档编写
  • ✅ 构建和部署

📚 扩展阅读

🎯 本章小结

本章通过一个完整的实战项目,综合运用了前面所学的 Go 知识:

  • ✅ 构建了功能完整的 RESTful API
  • ✅ 综合运用了 Go 的核心特性
  • ✅ 学习了项目组织和模块化
  • ✅ 掌握了测试和文档编写
  • ✅ 了解了部署和运行

上一章: Web开发 | 下一章: gRPC与微服务

恭喜! 基础教程到此完成!继续学习进阶章节(gRPC、数据库、新特性)提升实战能力 🐹