Gin框架分页的简洁实现

    1145

    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
    }
    

    最后试试接口,解决。

    测试图片