Skip to content

4. 项目结构优化

优化总结

  • 中间件处理(日志记录)
  • 统一的响应处理
  • API 文档
  • 单元测试
  • 更规范的错误处理

当前目录结构

当前项目采用了典型的 Go 项目分层架构,目录结构如下:

d:\works\RD\todo-list\
├── config\              # 配置相关
│   └── database.go     # 数据库配置和初始化
├── controllers\        # 控制器层,处理HTTP请求
│   └── todo_controller.go  # 待办事项的控制器
├── models\            # 数据模型层
│   └── todo.go       # 待办事项的数据模型定义
├── routes\           # 路由层
│   └── routes.go     # 路由配置和初始化
├── services\         # 服务层(当前为空,可以添加业务逻辑)
├── main.go          # 程序入口文件
├── go.mod           # Go模块定义
└── go.sum           # 依赖版本锁定文件

各层职责说明:

  1. config: 负责配置管理,目前包含数据库配置
  2. controllers: 处理 HTTP 请求,实现接口逻辑
  3. models: 定义数据结构和数据库模型
  4. routes: 配置 API 路由
  5. services: 可以添加复杂的业务逻辑处理(当前未使用)

这种分层架构的优点:

  • 职责分明,代码结构清晰
  • 便于维护和扩展
  • 符合单一职责原则
  • 有利于团队协作

建议后续可以添加:

  1. middleware 目录:用于存放中间件
  2. utils 目录:存放工具函数
  3. docs 目录:存放 API 文档
  4. tests 目录:存放测试文件

优化一波

给 AI 提问: 添加middleware 目录:用于存放中间件,utils 目录:存放工具函数,docs 目录:存放 API 文档,tests 目录:存放测试文件,如何优化目录结构?

我来帮你优化项目结构。首先创建新的目录:

bash
mkdir d:\works\RD\todo-list\middleware
mkdir d:\works\RD\todo-list\utils
mkdir d:\works\RD\todo-list\docs
mkdir d:\works\RD\todo-list\tests
  1. 首先创建一个日志中间件:
go
// :d:\works\RD\todo-list\middleware\logger.go
package middleware

import (
	"github.com/gin-gonic/gin"
	"time"
)

func Logger() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		path := c.Request.URL.Path

		c.Next()

		latency := time.Since(start)
		statusCode := c.Writer.Status()

		gin.DefaultWriter.Write([]byte(
			"[GIN] " + time.Now().Format("2006-01-02 15:04:05") +
				" | " + c.Request.Method +
				" | " + path +
				" | " + string(rune(statusCode)) +
				" | " + latency.String() + "\n",
		))
	}
}
  1. 添加一个工具函数文件:
go
// :d:\works\RD\todo-list\utils\response.go
package utils

import "github.com/gin-gonic/gin"

type Response struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data"`
}

func SuccessResponse(c *gin.Context, data interface{}) {
	c.JSON(200, Response{
		Code:    200,
		Message: "success",
		Data:    data,
	})
}

func ErrorResponse(c *gin.Context, code int, message string) {
	c.JSON(code, Response{
		Code:    code,
		Message: message,
		Data:    nil,
	})
}
  1. 添加测试文件示例:
go:d:\works\RD\todo-list\tests\todo_test.go
package tests

import (
	"testing"
	"net/http"
	"net/http/httptest"
	"todo-list/routes"
)

func TestGetTodos(t *testing.T) {
	router := routes.SetupRouter()

	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/api/v1/todos", nil)
	router.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("Expected status 200, got %v", w.Code)
	}
}
  1. 添加 API 文档:
markdown
<!-- :d:\works\RD\todo-list\docs\api.md -->

# Todo List API 文档

## 接口列表

### 1. 创建待办事项

- 请求方法:POST
- 路径:/api/v1/todos
- 请求体:
  ```json
  {
    "title": "任务标题",
    "description": "任务描述",
    "due_date": "2024-05-13T00:00:00Z",
    "completed": false
  }
  ```

### 2. 获取所有待办事项

- 请求方法:GET
- 路径:/api/v1/todos

### 3. 获取单个待办事项

- 请求方法:GET
- 路径:/api/v1/todos/:id

### 4. 更新待办事项

- 请求方法:PUT
- 路径:/api/v1/todos/:id

### 5. 删除待办事项

- 请求方法:DELETE
- 路径:/api/v1/todos/:id
  1. 更新路由文件以使用中间件:
go
// :d:\works\RD\todo-list\routes\routes.go
package routes

import (
	"github.com/gin-gonic/gin"
	"todo-list/controllers"
	"todo-list/config"
	"todo-list/middleware"
)

func SetupRouter() *gin.Engine {
	r := gin.Default()

	// 使用自定义中间件
	r.Use(middleware.Logger())

	// 获取数据库实例
	db, _ := config.InitDB()
	todoController := controllers.NewTodoController(db)

	// 设置路由
	v1 := r.Group("/api/v1")
	{
		todos := v1.Group("/todos")
		{
			todos.POST("/", todoController.Create)
			todos.GET("/", todoController.GetAll)
			todos.GET("/:id", todoController.GetOne)
			todos.PUT("/:id", todoController.Update)
			todos.DELETE("/:id", todoController.Delete)
		}
	}

	return r
}
  1. 更新控制器以使用统一响应格式:
go
// :d:\works\RD\todo-list\controllers\todo_controller.go
// 修改 Create 方法示例
func (tc *TodoController) Create(c *gin.Context) {
	var todo models.Todo
	if err := c.ShouldBindJSON(&todo); err != nil {
		utils.ErrorResponse(c, http.StatusBadRequest, err.Error())
		return
	}

	if err := tc.DB.Create(&todo).Error; err != nil {
		utils.ErrorResponse(c, http.StatusInternalServerError, "创建待办事项失败")
		return
	}

	utils.SuccessResponse(c, todo)
}

这样的目录结构更加完整,包含了:

  • 中间件处理(日志记录)
  • 统一的响应处理
  • API 文档
  • 单元测试
  • 更规范的错误处理

建议后续可以继续添加:

  1. 配置文件管理(如 config.yaml)
  2. 更多中间件(如认证、跨域处理等)
  3. 更完善的日志系统
  4. 更多单元测试用例