GoLand 项目从 0 到 1:第一天 —— 搭建项目基础架构与核心雏形

开篇:第一天的核心任务

在《GoLand 项目从 0 到 1》专栏的第一天,我们聚焦于项目的基础搭建工作。核心任务是确定技术栈、搭建项目架构雏形,并完成理解go的调用模式,为后续开发奠定基础。经过一天的推进,项目已初步具备可扩展的架构框架,明确了各模块的职责划分,为后续功能开发铺平了道路。
注:领导比较好,其实用什么语言开发都可以,我本是Java开发工程师,从没有碰过go,领导愿意让我们尝试新东西,因为领导之前是写go的,所以项目的架构是有他来搭建的,由于也有过五年多的开发经验所以理解起来也不是特别困难。

项目需求总结(组内一起评审需求文档得出的结论)

根据项目需求文档,本项目旨在构建一个具备完整业务链路的 Golang 服务器系统,核心需求包括:

  1. 实现用户认证与管理功能(登录、注册、信息维护)
  2. 支持多数据库交互(MySQL、Redis、Neo4j 等)
  3. 提供标准化 API 接口及自动生成的文档
  4. 具备完善的中间件支持(认证、日志、跨域等)
  5. 支持开发 / 生产环境隔离部署,提供容器化配置
  6. 实现基础业务模块的 CRUD 操作示例(demo)

第一天完成的核心工作

1. 技术栈确定

采用 Go 语言 结合 Gin 框架 进行开发。Gin 作为高性能的 Web 框架,其轻量特性与路由效率能够满足项目对并发处理及响应速度的要求,同时便于后续功能扩展

2. 项目架构雏形搭建(之前有开发一个java项目,所以项目架构上差不多,业务模块,中间件模块,项目统一协议等)

基于领域驱动设计思想,完成了项目的分层架构设计,明确了各模块的职责边界:

  • 区分私有业务逻辑(internal)与公共组件(pkg)
  • 实现配置、日志、响应格式等基础工具的封装
  • 规划多数据库与中间件的集成方案

3. 基础 Demo 开发(领导写的,便于我们熟悉)

完成了核心模块的 demo 验证,包括:

  • 实现示例接口的 CRUD 操作(对应 internal/handlers/demo.go)
  • 验证路由配置与中间件绑定逻辑
  • 测试数据库连接与数据模型映射

4. 项目结构详解(个人理解-基于java项目理解用箭头表示)

当前项目已形成清晰的目录结构,各模块功能如下(按层级划分):


golang-server/

├── main.go // 程序入口文件,负责初始化资源和启动服务 →→→ springboot启动类

├── go.mod // 项目依赖管理文件,声明模块和依赖版本 →→→ pom.xml

├── go.sum // 依赖包校验和文件,确保依赖完整性 →→→ Maven统一管理

├── Dockerfile // 开发环境Docker构建配置

├── Dockerfile.prod // 生产环境Docker构建配置

├── docker-compose.yml // 多容器编排配置,定义服务依赖关系

├── Makefile // 自动化脚本,包含编译、运行、测试等命令 →→→ Maven 的pom.xml中的<build>配置

├── .gitignore // Git版本控制忽略规则

├── README.md // 项目说明文档,包含启动指南和功能介绍

├── config/ // 配置管理模块 →→→ src/main/resources/ 目录  application.yml

│ ├── config.go // 配置结构体定义及加载逻辑

│ ├── config.development.yaml // 开发环境配置参数(数据库、端口等)

│ └── config.production.yaml // 生产环境配置参数

├── docs/ // API文档模块

│ ├── docs.go // Swagger文档配置元数据

│ ├── swagger.json // 自动生成的API文档JSON

│ └── swagger.yaml // 自动生成的API文档YAML

├── internal/ // 项目私有业务逻辑(仅内部可访问) →→→ controller

│ ├── handlers/ // HTTP请求处理器

│ │ ├── auth.go // 认证相关接口处理(登录、注册)

│ │ ├── user.go // 用户管理接口处理

│ │ └── demo.go // 示例接口CRUD实现

│ ├── models/ // 数据模型定义  →→→ 实体类

│ │ ├── user.go // 用户实体结构及数据库映射

│ │ ├── demo.go // 示例实体结构及验证规则

│ │ └── article.go // MongoDB文档模型示例

│ └── routes/ // 路由配置  →→→  控制器类的 @RequestMapping 注解(定义 API 路由) + 路由配置类

│ └── routes.go // 定义API路由规则及中间件绑定

├── pkg/ // 公共可复用组件(可外部引用)

│ ├── auth/ // 认证工具

│ │ └── jwt.go // JWT令牌生成与验证  →→→ JwtTokenProvider.java

│ ├── database/ // 数据库连接管理

│ │ ├── mysql.go // MySQL连接池配置

│ │ ├── redis.go // Redis客户端封装

│ │ └── neo4j.go // Neo4j图数据库连接

│ ├── logger/ // 日志工具 →→→ logback-spring.xml

│ │ └── logger.go // 基于logrus的日志封装(分级、文件输出)

│ ├── middleware/ // HTTP中间件

│ │ ├── auth.go // 认证验证中间件

│ │ ├── cors.go // 跨域处理中间件

│ │ ├── logger.go // 请求日志记录中间件

│ │ └── recovery.go // 程序异常恢复中间件

│ ├── mq/ // 消息队列工具

│ │ └── rabbitmq.go // RabbitMQ生产者/消费者封装

│ └── response/ // 响应处理工具

│ └── response.go // 统一API响应格式(成功/错误/分页)

└── scripts/ // 辅助脚本

└── start.sh // 项目启动脚本(环境变量设置、依赖检查)

5. 完整流程拆解(以Demo中的查询列表为例)

1. 前端发送请求

前端通过 HTTP 客户端(如 Axios)发送请求:

// 前端示例代码
axios.get("/api/v1/demos", {
   page: 1,    // 页码
   size: 10,   // 每页条数
   name: '',    // 名称模糊查询
   status: '',// 状态筛选
   sort: '',     // 排序字段
   order: ''  // 排序方向
})
2. 请求到达服务器,经过中间件处理(顺序执行),再经过路由匹配

核心文件:internal/routes/routes.go
项目启动时,main.go 会加载路由配置,routes.go 中定义了所有接口的路由规则,找到对应的路径:

// SetupRoutes 初始化应用路由配置
func SetupRoutes(r *gin.Engine) {
	// 注册全局中间件(按顺序执行)
	r.Use(middleware.CORS())          // 跨域处理
	r.Use(middleware.TraceID())       // 请求追踪ID
	r.Use(middleware.RequestLogger())  // 请求日志记录
	r.Use(middleware.Recovery())       // 异常恢复

	// Swagger文档路由
	// 访问路径: /swagger/index.html
	r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

	// 健康检查端点
	// 用于服务健康监测和负载均衡检查
	r.GET("/health", func(c *gin.Context) {
		c.JSON(200, gin.H{"status": "ok"}) // 返回简单健康状态
	})

	api := r.Group("/api/v1")
	{
	    // Demo管理路由组
		demoHandler := handlers.NewDemoHandler() // 初始化Demo处理器
		demos := api.Group("/demos")
		{
			demos.GET("", demoHandler.ListDemos)                     // 获取Demo列表
			demos.GET("/:id", demoHandler.GetDemo)                   // 获取单个Demo
			demos.POST("", middleware.Auth(), demoHandler.CreateDemo) // 创建Demo(需认证)
			demos.PUT("/:id", middleware.Auth(), demoHandler.UpdateDemo) // 更新Demo(需认证)
			demos.DELETE("/:id", middleware.Auth(), demoHandler.DeleteDemo) // 删除Demo(需认证)
			demos.POST("/batch-delete", middleware.Auth(), demoHandler.BatchDeleteDemos) // 批量删除Demo(需认证)
			demos.PUT("/:id/status", middleware.Auth(), demoHandler.UpdateDemoStatus) // 更新Demo状态(需认证)
			demos.GET("/status/:status", demoHandler.GetDemosByStatus) // 根据状态获取Demo列表
		}

		// 预留扩展区域
		// 可在此添加其他业务模块的路由组
		// 例如产品管理、订单管理等
	}
}

此时请求会根据 URL 路径 /api/v1/demos 匹配到 demoHandler.ListDemos 函数,并触发绑定的中间件。

3. 进入处理器处理业务逻辑

核心文件:internal/handlers/demo.go

// ListDemos 处理获取Demo列表的GET请求
// 支持分页、筛选和排序功能
func (h *DemoHandler) ListDemos(c *gin.Context) {
	// 1. 绑定查询参数到DemoQuery结构体
	var query models.DemoQuery
	if err := c.ShouldBindQuery(&query); err != nil {
		response.BadRequest(c, "Invalid query parameters")
		return
	}

	// 2. 调用服务层获取数据
	result, err := h.service.List(&query)
	if err != nil {
		response.InternalServerError(c, "Failed to get demo list")
		return
	}

	// 3. 返回标准化响应
	response.Success(c, result)
}
// DemoQuery 查询条件
type DemoQuery struct {
	Name   string `form:"name"`   // 名称模糊查询
	Status int    `form:"status"` // 状态筛选
	Page   int    `form:"page"`   // 页码
	Size   int    `form:"size"`   // 每页数量
	Sort   string `form:"sort"`   // 排序字段
	Order  string `form:"order"`  // 排序方向
}
4. 数据模型与数据库交互
// List 实现Demo列表的分页查询功能
// 参数: query - 包含分页、筛选和排序条件的查询对象
// 返回值: 分页结果数据和可能的错误
func (s *DemoService) List(query *models.DemoQuery) (*models.DemoListResponse, error) {
    // 获取数据库连接
    db := database.GetDB()

    // 初始化查询条件
    where := make([]string, 0)       // WHERE条件语句
    args := make([]interface{}, 0)   // WHERE条件参数

    // 构建名称模糊查询条件
    if query.Name != "" {
        where = append(where, "name LIKE ?")
        args = append(args, "%"+query.Name+"%") // 添加通配符实现模糊查询
    }

    // 构建状态筛选条件
    if query.Status > 0 {
        where = append(where, "status = ?")
        args = append(args, query.Status)
    }

    // 1. 创建一个针对Demo模型的新查询构建器
// db: 已初始化的*gorm.DB数据库连接
// Model(): 指定要操作的数据模型,这里使用models.Demo结构体
// &models.Demo{}: 创建一个空的Demo结构体实例作为模型引用
// 
// 实际效果:创建一个准备查询demos表的SQL构建器,后续所有操作都将基于这个模型
    queryBuilder := db.Model(&models.Demo{})
    
    // 应用WHERE条件(如果有)
    if len(where) > 0 {
        queryBuilder = queryBuilder.Where(strings.Join(where, " AND "), args...)
    }

    // 获取符合条件的总记录数
    var total int64
    if err := queryBuilder.Count(&total).Error; err != nil {
        return nil, fmt.Errorf("failed to count demos: %w", err)
    }

    // 处理分页参数
    page := query.Page    // 当前页码
    size := query.Size    // 每页数量
    
    // 页码校验和默认值
    if page < 1 {
        page = 1  // 页码最小为1
    }
    if size < 1 || size > 100 {
        size = 10 // 每页数量限制在1-100之间,默认10
    }

    // 计算分页偏移量
    offset := (page - 1) * size

    // 处理排序参数
    sortField := query.Sort   // 排序字段
    order := query.Order      // 排序方向
    
    // 设置默认排序字段和方向
    if sortField == "" {
        sortField = "created_at"  // 默认按创建时间排序
    }
    if order == "" {
        order = "desc"           // 默认降序
    }
    if order != "asc" && order != "desc" {
        order = "desc"           // 非法值处理为降序
    }

    // 执行分页查询
    var demos []models.Demo
// 对应生成的SQL示例:
// SELECT * FROM demos 
// WHERE [conditions...] 
// ORDER BY [sortField] [order] 
// LIMIT [size] OFFSET [offset]
    if err := queryBuilder.Offset(offset).Limit(size).Order(sortField + " " + order).Find(&demos).Error; err != nil {
        return nil, fmt.Errorf("failed to get demos: %w", err)
    }

    // 返回分页结果
    return &models.DemoListResponse{
        Items: demos,  // 当前页数据
        Total: total,  // 总记录数
        Page:  page,   // 当前页码
        Size:  size,   // 每页数量
    }, nil
}
type Demo struct {
	ID          uint           `json:"id" gorm:"primarykey"`
	Name        string         `json:"name" gorm:"size:100;not null;comment:名称"`
	Description string         `json:"description" gorm:"size:500;comment:描述"`
	Status      int            `json:"status" gorm:"default:1;comment:状态 1:启用 0:禁用"`
	Sort        int            `json:"sort" gorm:"default:0;comment:排序"`
	Extra       string         `json:"extra" gorm:"type:text;comment:扩展字段"`
	CreatedAt   time.Time      `json:"created_at"`
	UpdatedAt   time.Time      `json:"updated_at"`
	DeletedAt   gorm.DeletedAt `json:"-" gorm:"index"`
}

// TableName 指定表名
func (Demo) TableName() string {
	return "demos"
}

// DemoListResponse 列表响应
type DemoListResponse struct {
	Items []Demo `json:"items"`
	Total int64  `json:"total"`
	Page  int    `json:"page"`
	Size  int    `json:"size"`
}
6. 生成响应返回前端
func Success(c *gin.Context, data interface{}) {
	c.JSON(http.StatusOK, Response{
		Code:    200,
		Message: "success",
		Data:    data,
		TraceID: c.GetString("trace_id"),
	})
}

以上流程都是个人理解,注释也是个人理解

总结与后续计划

第一天的工作聚焦于项目基础建设,已完成技术栈确认、架构设计与核心目录搭建,并通过 demo 验证了基础功能的可行性。后续将基于当前架构,逐步完善各模块的具体实现,包括数据库交互逻辑开发、API 接口完善及前端联调准备等。

专栏将持续记录项目开发全过程
 

最后推荐两个go的学习网址:

Context · Go语言中文文档https://www.topgoer.com/%E5%B8%B8%E7%94%A8%E6%A0%87%E5%87%86%E5%BA%93/Context.htmlGo 继承 | 菜鸟教程https://www.runoob.com/go/go-inheritance.html视频的话b站的大地

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java坤坤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值