Gin框架分页的简洁实现
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
}
最后试试接口,解决。