项目介绍

使用gin + gorm实现分页,按一般的mvc架构思想去划分目录,良好的编码习惯是用Dao层去查询数据库,Server层去实现业务逻辑(此案例业务逻辑简单所以没有封装)。

第三方库

  • gin
  • gorm以及对应的mysql驱动包

目录结构

├── README.md
├── config
│ └── config.go
├── controller
│ └── user.go    
├── dao
│ └── user.go
├── data.sql
├── go.mod
├── go.sum
├── main.go
├── model
│ ├── page.go
│ └── user.go
├── routes
│ └── routes.go
└── utils
    └── pagination.go

config目录

var DB *gorm.DB

func init() {
    var err error
    DB, err = gorm.Open(mysql.Open("帐号:密码@tcp(数据库连接地址:3306)/数据库名?charset=utf8mb4&parseTime=True&loc=Local"))
    if err != nil {
        panic(err)
    }

    var db *sql.DB
    db, err = DB.DB()
    if err != nil {
        panic(err)
    }

    // 设置打开数据库连接最大数量
    db.SetMaxOpenConns(100)

    // 设置空闲连接池连接的最大数量
    db.SetMaxIdleConns(10)

    // 设置连接最大可复用时间
    db.SetConnMaxLifetime(time.Hour)

    db.SetConnMaxIdleTime(time.Hour)

    // 自动迁移
    if err := DB.AutoMigrate(&model.User{}); err != nil {
        log.Panicf("自动迁移失败: %s", err)
    }
}

该目录主要存放配置信息,这里主要是设置gorm的连接配置,定义好模型后还可以自动迁移,相比较Laravel框架的迁移方便多了。

controller目录

定义用户控制器,与路由直接绑定:

func GetAllUser(c *gin.Context) {
    pagination := utils.GeneratePaginationFromRequest(c)
    // 这里可以组装查询条件
    var user model.User
    users, err := dao.GetAllUsers(&user, &pagination)
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": err,
        })
        return
    }
    c.JSON(http.StatusOK, gin.H{
        "data": users,
    })
}

dao目录

直接查询数据库,这样可以保证Model层的简洁,一般在Laravel框架我只在Model层定义关联关系,查询都是放在Dao层,Spring Boot框架也是如此设计。

func GetAllUsers(user *model.User, pagination *model.Pagination) (users []model.User, err error) {
    // 分页查询
    offset := (pagination.Page - 1) * pagination.Limit
    err = config.DB.Where(user).Limit(pagination.Limit).Offset(offset).Order(pagination.Sort).Find(&users).Error
    return
}

model目录

page文件

定义分页的结构体:

type Pagination struct {
    Limit int    `json:"limit" form:"limit" uri:"limit"`
    Page  int    `json:"page" form:"page" uri:"page"`
    Sort  string `json:"sort" form:"sort" uri:"sort"`
}

user文件

定义用户模型:

type User struct {
    ID        uint      `gorm:"primaryKey" json:"id"`
    Name      string    `gorm:"varchar(20);comment:'用户名称'" json:"name"`
    Email     string    `gorm:"comment:'邮箱'" json:"email"`
    CreatedAt time.Time `gorm:"autoCreateTime;comment:'创建时间'" json:"created_at"`
    UpdatedAt time.Time `gorm:"autoUpdateTime;comment:'操作事件'" json:"updated_at]"`
}

routes目录

定义路由规则:

func SetUpRouter() *gin.Engine {
    r := gin.Default()
    user := r.Group("/user")
    {
        user.GET("all", controller.GetAllUser)
    }
    return r
}

utils目录

辅助函数,类似Laravel框架的helper:

func GeneratePaginationFromRequest(c *gin.Context) (pagination model.Pagination) {
    if err := c.ShouldBind(&pagination); err != nil {
        fmt.Printf("参数绑定错误:%s\n", err)
    }

    // 校验参数
    if pagination.Limit < 0 {
        pagination.Limit = 2
    }
    if pagination.Page < 1 {
        pagination.Page = 1
    }

    if len(pagination.Sort) == 0 {
        pagination.Sort = "created_at desc"
    }

    return
}

测试sql

insert into users (`name`, `email`, `created_at`, `updated_at`) values ("chris", "aaaa@chris.com", "2022-07-13 18:00:00", "2022-07-13 18:00:00");
insert into users (`name`, `email`, `created_at`, `updated_at`) values ("张三", "zhangsan@chris.com", "2022-07-13 18:00:00", "2022-07-13 18:00:00");
insert into users (`name`, `email`, `created_at`, `updated_at`) values ("李四", "lisi@chris.com", "2022-07-13 18:00:00", "2022-07-13 18:00:00");
insert into users (`name`, `email`, `created_at`, `updated_at`) values ("王五", "wangwu@chris.com", "2022-07-13 18:00:00", "2022-07-13 18:00:00");

main函数

上述代码都完成后,就可以运行测试:

func main() {
    router := routes.SetUpRouter()
    err := router.Run(":8080")
    if err != nil {
        panic(err)
    }
}

运行结果

img.png