Gin框架分页的简洁实现

991

Gin的框架实在是太简洁了,连分页都没有。
还好我们有GORM,GORM提供了一种scope方法,可以把一部分数据库请求封装起来。

新建utils/pagination文件
简单封装一下分页实现。

package utils

import (
	"errors"
	"gorm.io/gorm"
)

type Paginator struct {
	Total  int `json:"total" form:"total"`   //总页数
	Limit  int `json:"limit" form:"limit" `  //每页多少条
	Offset int `json:"offset" form:"offset"` //偏移量
	Page   int `json:"page" form:"page"`     //当前页数
}

// ? 通过计算OFFSET和LIMIT来进行分页请求

func PaginatorHandler(paginator *Paginator) error {
	if paginator == nil {
		return errors.New("输入错误")
	}
	//设置默认页面大小
	if paginator.Limit == 0 {
		paginator.Limit = 10
	}
	if paginator.Page == 0 {
		paginator.Offset = 0
	} else if paginator.Page > 0 {
		paginator.Offset = (paginator.Page - 1) * paginator.Limit
	}
	return nil
}

// GORM分页数据库查询

func (p *Paginator) GormPagenation() func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		return db.Offset(p.Offset).Limit(p.Limit)
	}
}

看不懂?
接下来是GORM官网的示例

func Paginate(r *http.Request) func(db *gorm.DB) *gorm.DB {
  return func (db *gorm.DB) *gorm.DB {
    q := r.URL.Query()
    page, _ := strconv.Atoi(q.Get("page"))
    if page == 0 {
      page = 1
    }

    pageSize, _ := strconv.Atoi(q.Get("page_size"))
    switch {
    case pageSize > 100:
      pageSize = 100
    case pageSize <= 0:
      pageSize = 10
    }

    offset := (page - 1) * pageSize
    return db.Offset(offset).Limit(pageSize)
  }
}

db.Scopes(Paginate(r)).Find(&users)
db.Scopes(Paginate(r)).Find(&articles)

我们将Web处理部分抽了出来,集中在controller层处理。
controller层用法:

func GetAllArt(c *gin.Context) {
	//申请内存
	p := &utils.Paginator{}
	err := c.ShouldBindQuery(p)
	if err != nil {
		c.JSON(http.StatusInternalServerError, e.ErrorHandler(err, e.INTERNAL_ERROR))
		return
	}
	//解析出offset
	err = utils.PaginatorHandler(p)
	if err != nil {
		c.JSON(http.StatusInternalServerError, e.ErrorHandler(err, e.INTERNAL_ERROR))
		return
	}
	a, err := model.GetAllArt(p)
	if err != nil {
		c.JSON(http.StatusInternalServerError, e.ErrorHandler(err, e.INTERNAL_ERROR))
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"code":      http.StatusOK,
		"paginator": p,
		"data":      a,
	})
}

然后是model层用法,前端还需要total,这里用GORM的count来获取并返回给上层。c层验证并不多,考虑在中间件上加上表单验证

func GetAllArt(paginator *utils.Paginator) ([]Article, error) {
	var articles []Article
	//分页查询
	err := db.Model(&Article{}).Scopes(paginator.GormPagenation()).Find(&articles).Error
	if err != nil {
		return nil, err
	}
	var total int64
	err = db.Model(&Article{}).Count(&total).Error
	if err != nil {
		return nil, err
	}
	paginator.Total = int(total)
	return articles, nil
}

最后试试接口,解决。

测试图片