🌐 项目目标#
使用 Gin
框架搭建一个简单web服务.
🛠️ 项目结构#
1todo-api/
2├── main.go # 入口文件
3├── routes/
4│ └── todo_routes.go # 路由定义
5├── models/
6│ └── todo.go # 数据结构
7├── middleware/
8│ └── logging.go # 自定义中间件
9├── config/
10│ └── config.go # 配置管理
11└── go.mod # Go 模块
📦 安装依赖#
1go mod init todo-api
2go get -u github.com/gin-gonic/gin
3go get -u github.com/jackc/pgx/v4
🧪 代码示例#
1. 配置管理(config/config.go
)#
1package configimport "github.com/joho/godotenv"func LoadEnv() {
2err := godotenv.Load()
3if err != nil {
4panic("Error loading .env file")
5 }
6}
2. 数据库连接(main.go
)#
1package mainimport (
2"context"
3"fmt"
4"log"
5"github.com/gin-gonic/gin"
6"github.com/jackc/pgx/v4"
7"todo-api/config"
8"todo-api/routes"
9)type Todo struct {
10ID int `json:"id"`
11Title string `json:"title"`
12}func main() {
13// 1. 加载环境变量
14config.LoadEnv()// 2. 连接 PostgreSQL
15connStr := fmt.Sprintf(
16"postgres://%s:%s@%s:%s/%s?sslmode=disable",
17os.Getenv("DB_USER"),
18os.Getenv("DB_PASSWORD"),
19os.Getenv("DB_HOST"),
20os.Getenv("DB_PORT"),
21os.Getenv("DB_NAME"),
22)conn, err := pgx.Connect(context.Background(), connStr)
23if err != nil {
24log.Fatal("无法连接数据库:", err)
25}
26defer conn.Close(context.Background())// 3. 创建 Gin 应用
27r := gin.Default()// 4. 注册路由
28todoRoutes := routes.TodoRoutes{DB: conn}
29r.POST("/todos", todoRoutes.CreateTodo)
30r.GET("/todos", todoRoutes.GetAllTodos)// 5. 启动服务
31r.Run(":8080")
32}
3. 路由实现(routes/todo_routes.go
)#
1package routesimport (
2"github.com/gin-gonic/gin"
3"todo-api/models"
4)type TodoRoutes struct {
5DB *pgx.Conn
6}func (tr *TodoRoutes) CreateTodo(c *gin.Context) {
7var todo models.Todo
8if err := c.ShouldBindJSON(&todo); err != nil {
9c.JSON(400, gin.H{"error": err.Error()})
10return
11}_, err := tr.DB.Exec(context.Background(), "INSERT INTO todos (title) VALUES ($1)", todo.Title)
12if err != nil {
13 c.JSON(500, gin.H{"error": "数据库操作失败"})
14 return
15}
16
17c.JSON(201, gin.H{"message": "成功创建任务"})
18_, err := tr.DB.Exec(context.Background(), "INSERT INTO todos (title) VALUES ($1)", todo.Title)
19if err != nil {
20 c.JSON(500, gin.H{"error": "数据库操作失败"})
21 return
22}
23
24c.JSON(201, gin.H{"message": "成功创建任务"})
25}func (tr *TodoRoutes) GetAllTodos(c *gin.Context) {
26rows, err := tr.DB.Query(context.Background(), "SELECT id, title FROM todos")
27if err != nil {
28c.JSON(500, gin.H{"error": "查询失败"})
29return
30}var todos []models.Todo
31for rows.Next() {
32 var t models.Todo
33 if err := rows.Scan(&t.ID, &t.Title); err != nil {
34 c.JSON(500, gin.H{"error": "解析结果失败"})
35 return
36 }
37 todos = append(todos, t)
38}
39
40c.JSON(200, todos)
41var todos []models.Todo
42for rows.Next() {
43 var t models.Todo
44 if err := rows.Scan(&t.ID, &t.Title); err != nil {
45 c.JSON(500, gin.H{"error": "解析结果失败"})
46 return
47 }
48 todos = append(todos, t)
49}
50
51c.JSON(200, todos)
52}