Skip to content

hezq168/gin_base

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gin_base

一个基于 Gin 的分层项目模板,采用 Handler -> Service -> Repo 架构,适合中小型 Go Web 项目快速起步。

一、为什么要分层?

在小项目里:

func main() {
    // 查询数据库
    // 写业务逻辑
    // 返回HTTP
}

这样写问题不大。

但项目越来越大后,会出现:

  • 代码耦合
  • 不方便维护
  • 不方便测试
  • 不方便扩展
  • 一个文件几千行

因此企业开发中通常会采用:

Handler -> Service -> Repo

分层架构。

二、标准目录结构


gin_base/
├── cmd/
│   └── main.go           # 程序入口,启动服务
├── internal/
│   ├── handler/          # HTTP Handler 层,处理请求和响应
│   │   ├── user_handler.go
│   │   └── order_handler.go
│   ├── model/            # 数据模型定义
│   │   ├── user.go
│   │   └── order.go
│   ├── repo/             # 数据访问层,操作数据库或模拟数据
│   │   ├── user_repo.go
│   │   └── order_repo.go
│   ├── router/           # 路由注册
│   │   └── router.go
│   └── service/          # 业务逻辑层
│       ├── user_service.go
│       └── order_service.go
├── go.mod
└── README.md

分层说明

  • Handler:负责接收 HTTP 请求、参数校验、调用 Service 层。
  • Service:编写业务逻辑,处理具体业务场景,调用 Repo 层。
  • Repo:数据访问层,负责与数据库或其他存储交互(本例为模拟数据)。
  • Model:定义数据结构。

运行方式

  1. 安装依赖:

    go mod tidy
  2. 启动服务:

    go run cmd/main.go
  3. 访问接口:

     - 获取用户信息
         ```
         GET http://localhost:8081/user/1
         ```
         返回示例:
         ```json
         {
             "id": 1,
             "name": "zhangsan"
         }
         ```
    
     - 获取订单信息
         ```
         GET http://localhost:8081/order/1
         ```
         返回示例:
         ```json
         {
             "id": 1,
             "title": "order title"
         }
         ```
    

依赖

  • gin-gonic/gin
  • 其他依赖见 go.mod

适用场景

  • 适合需要清晰分层、便于维护和扩展的 Go Web 项目。
  • 可作为企业级项目的基础模板。

如需扩展业务,只需在对应层级增加文件和逻辑即可。例如:

## 目录结构

project/
├── cmd/
│   └── main.go
├── handler/
│   ├── user_handler.go
│   └── order_handler.go
├── service/
│   ├── user_service.go
│   └── order_service.go
├── repo/
│   ├── user_repo.go
│   └── order_repo.go
├── model/
│   ├── user.go
│   └── order.go
└── router/
    └── router.go

依赖注入说明

main.go 通过依赖注入方式组装 handler/service/repo,便于解耦和单元测试。例如:

userRepo := repo.NewUserRepo()
userService := service.NewUserService(userRepo)
userHandler := handler.NewUserHandler(userService)

orderRepo := repo.NewOrderRepo()
orderService := service.NewOrderService(orderRepo)
orderHandler := handler.NewOrderHandler(orderService)

三、各层职责


1、Handler 层

作用:

  • 接收 HTTP 请求
  • 参数校验
  • 返回 JSON
  • 调用 service

不要写:

  • 数据库逻辑
  • 核心业务逻辑

例如:

func (h *UserHandler) GetUser(c *gin.Context) {
    id := c.Param("id")

    user, err := h.userService.GetUser(id)

    c.JSON(200, user)
}

2、Service 层

作用:

  • 业务逻辑
  • 权限判断
  • 数据组合
  • 状态控制
  • 调用多个 repo

例如:

func (s *userService) GetUser(id int) (*model.User, error) {

    // 业务逻辑

    return s.userRepo.GetUser(id)
}

Service 是整个系统核心。


3、Repo 层

作用:

  • 数据访问
  • MySQL
  • Redis
  • K8S
  • Prometheus
  • Elasticsearch

Repo 不负责业务逻辑。

例如:

func (r *userRepo) GetUser(id int) (*model.User, error) {
    return db.Query(...)
}

四、为什么要“面向接口”?

核心思想:

依赖抽象
而不是
依赖实现

例如:

type UserRepo interface {
    GetUser(id int) (*model.User, error)
}

Service 依赖:

repo.UserRepo

而不是:

*userRepo

这样以后:

  • 可以换 MySQL
  • 可以换 Redis
  • 可以 mock 测试
  • 可以扩展

而不用修改 service。


五、Repo 示例

repo/user_repo.go

package repo

import "gin_base/internal/model"

type UserRepo interface {
    GetUser(id int) (*model.User, error)
}

type userRepo struct {
}

func NewUserRepo() UserRepo {
    return &userRepo{}
}

func (r *userRepo) GetUser(id int) (*model.User, error) {

    // 模拟数据库

    return &model.User{
        ID:   id,
        Name: "zhangsan",
    }, nil
}

六、Service 示例

service/user_service.go

package service

import (
    "gin_base/internal/model"
    "gin_base/internal/repo"
)

type UserService interface {
    GetUser(id int) (*model.User, error)
}

type userService struct {
    userRepo repo.UserRepo
}

func NewUserService(userRepo repo.UserRepo) UserService {
    return &userService{
        userRepo: userRepo,
    }
}

func (s *userService) GetUser(id int) (*model.User, error) {
    return s.userRepo.GetUser(id)
}

七、Handler 示例

handler/user_handler.go

package handler

import (
    "net/http"
    "strconv"

    "github.com/gin-gonic/gin"

    "gin_base/internal/service"
)

type UserHandler struct {
    userService service.UserService
}

func NewUserHandler(userService service.UserService) *UserHandler {
    return &UserHandler{
        userService: userService,
    }
}

func (h *UserHandler) GetUser(c *gin.Context) {
    idStr := c.Param("id")
    id, err := strconv.Atoi(idStr)
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"msg": "id错误"})
        return
    }
    user, err := h.userService.GetUser(id)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
        return
    }
    c.JSON(http.StatusOK, user)
}

八、依赖注入

main.go:

import (
    "gin_base/internal/handler"
    "gin_base/internal/repo"
    "gin_base/internal/router"
    "gin_base/internal/service"
)

func main() {
    userRepo := repo.NewUserRepo()
    userService := service.NewUserService(userRepo)
    userHandler := handler.NewUserHandler(userService)
    r := router.SetupRouter(userHandler)
    r.Run(":8081")
}

这叫:

依赖注入(Dependency Injection)

九、为什么不建议 main.go 写所有逻辑?

错误方式:

main.go
    查询数据库
    写业务逻辑
    返回HTTP

问题:

  • 无法维护
  • 无法测试
  • 无法扩展

十、这种架构适合什么项目?

适合:

  • DevOps平台
  • 自动化运维平台
  • K8S管理平台
  • 发布平台
  • 工单系统
  • SaaS系统
  • 微服务系统

十一、为什么 Go 不建议过度拆分?

Go 强调:

简单
清晰
低复杂度

因此:

下面这种:

repo/
├── interface.go
├── user_repo.go

不是必须。

下面这种也完全可以:

repo/
└── user_repo.go

接口和实现写一起。

只要:

  • 结构清晰
  • 职责明确

即可。


十二、真正重要的是什么?

不是:

有没有 interface.go

而是:

是否做到了解耦
是否依赖接口
是否职责清晰

十三、后期还能扩展什么?

后面还会增加:

middleware/
config/
pkg/
utils/
dto/
vo/

以及:

  • JWT
  • RBAC
  • Casbin
  • GORM
  • Redis
  • K8S client-go
  • Prometheus

十四、总结

标准调用链:

HTTP请求
   ↓
Handler
   ↓
Service
   ↓
Repo
   ↓
MySQL / Redis / K8S

核心思想:

高内聚
低耦合
面向接口
职责分离

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages