gormt中分页查询的使用

Posted jiangxiaoju

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了gormt中分页查询的使用相关的知识,希望对你有一定的参考价值。

原创不易,未经允许,请勿转载。

文章目录

gormt的Github链接

最近因为项目需要,所以使用了gormt这个项目,用来自动生成struct等代码。但是美中不足的是它里面生成的一些函数不支持分页查询,所以我就参考之前Java使用的Mybatis-Plus中的分页插件,在gormt中实现了对分页查询的支持。当需要进行分页查询的操作时,我们只需要传入每个分页的大小、当前的页数(从1开始计算),以及排序条件、筛选条件即可,不需要再去关心偏移量等一些复杂的操作。
接下来我简单介绍一下增加的内容以及如何使用

如何使用?

分页查询的功能默认是开启的,IPagePage的内容在生成的gen.page.go文件中,SelectPage函数则是在dbname.gen.tablename.go文件中
可以通过配置文件中的这个选项选择是否开启

is_out_page: true # 是否输出分页函数 

IPage接口的介绍

这里提供了一个IPage接口,定义了以下方法,作用如注释所示

type IPage interface 
	GetRecords() interface      // 获取查询的记录
	SetRecords(interface)       // 设置查询的记录
	GetTotal() int64              // 获取总记录数
	SetTotal(int64)               // 设置总记录数
	GetCurrent() int64            // 获取当前页
	SetCurrent(int64)             // 设置当前页
	GetSize() int64               // 获取每页显示大小
	SetSize(int64)                // 设置每页显示大小
	AddOrderItem(OrderItem)       // 设置排序条件
	AddOrderItems([]OrderItem)    // 批量设置排序条件
	GetOrederItemsString() string // 将排序条件拼接成字符串
	Offset() int64                // 获取偏移量
	GetPages() int64              // 获取总的分页数

IPage的基础上,提供了一个默认实现Page,它实现了IPage中的所有方法。

type Page struct 
	total   int64       // 总的记录数
	size    int64       // 每页显示的大小
	current int64       // 当前页
	orders  []OrderItem // 排序条件
	Records interface // 查询数据列表



func (page *Page) GetRecords() interface 
	return page.Records


func (page *Page) SetRecords(records interface) 
	page.Records = records


func (page *Page) GetTotal() int64 
	return page.total


func (page *Page) SetTotal(total int64) 
	page.total = total



func (page *Page) GetCurrent() int64 
	return page.current


func (page *Page) SetCurrent(current int64) 
	page.current = current


func (page *Page) GetSize() int64 
	return page.size

func (page *Page) SetSize(size int64) 
	page.size = size



func (page *Page) AddOrderItem(orderItem OrderItem) 
	page.orders = append(page.orders, orderItem)


func (page *Page) AddOrderItems(orderItems []OrderItem) 
	page.orders = append(page.orders, orderItems...)


func (page *Page) GetOrederItemsString() string 
	arr := make([]string, 0)
	var order string

	for _, val := range page.orders 
		if val.asc 
			order = ""
		 else 
			order = "desc"
		
		arr = append(arr, fmt.Sprintf("%s %s", val.column, order))
	
	return strings.Join(arr, ",")


func (page *Page) Offset() int64 
	if page.GetCurrent() > 0 
		return (page.GetCurrent() - 1) * page.GetSize()
	 else 
		return 0
	


func (page *Page) GetPages() int64 
	if page.GetSize() == 0 
		return 0
	
	pages := page.GetTotal() / page.GetSize()
	if page.GetTotal()%page.size != 0 
		pages++
	

	return pages



// 提供了一个构造方法,需要传入每个分页的大小,以及当前所处的页
func NewPage(size, current int64, orderItems ...OrderItem) *Page 
	return &Pagesize: size, current: current, orders: orderItems


IPageOrderItem是用作于排序的,定义如下,并且提供了两种构造方法

type OrderItem struct 
	column string // 需要排序的字段
	asc    bool   // 是否正序排列,默认true


func BuildAsc(column string) OrderItem 
	return OrderItemcolumn: column, asc: true


func BuildDesc(column string) OrderItem 
	return OrderItemcolumn: column, asc: false


func BuildAscs(columns ...string) []OrderItem 
	items := make([]OrderItem, 0)
	for _, val := range columns 
		items = append(items, BuildAsc(val))
	
	return items


func BuildDescs(columns ...string) []OrderItem 
	items := make([]OrderItem, 0)
	for _, val := range columns 
		items = append(items, BuildDesc(val))
	
	return items

SelectPage函数的介绍

假设查询的表结构如下所示

type BlogAdmin struct 
	ID        uint       `gorm:"primaryKey;column:id;type:int unsigned;not null" json:"-"`                            // 用户ID
	CreatedAt time.Time  `gorm:"column:created_at;type:datetime;not null;default:CURRENT_TIMESTAMP" json:"createdAt"` // 创建时间
	UpdatedAt time.Time  `gorm:"column:updated_at;type:datetime;not null;default:CURRENT_TIMESTAMP" json:"updatedAt"` // 修改时间
	DeletedAt *time.Time `gorm:"index:idx_deleted;column:deleted_at;type:datetime" json:"deletedAt"`                  // 删除时间
	Username  string     `gorm:"unique;unique;column:username;type:varchar(255);not null" json:"username"`            // 用户名
	Password  string     `gorm:"column:password;type:varchar(255);not null" json:"password"`                          // 密码


下面是生成的对BlogAdmin这个表的分页查询函数。一共需要传入两个参数

  • page:实现了IPage接口的类都可以,默认可以使用Page
  • opts: 查询条件

返回值:

  • resultPage:实现了IPage接口,默认为Page。查询的记录将保存将通过SetRecords保存。
  • err:错误

首先先获取出查询条件,根据查询条件,先查询出满足条件的记录,然后统计记录数,接着看是否需要排序,如果需要排序的话,则先进行排序操作。最后获取页面大小和偏移量,把查询结果保存到results里面。
因为BlogAdmin的表并未设置外键,所以下列代码中并未生成预加载部分的代码。

// SelectPage 分页查询
func (obj *_BlogAdminMgr) SelectPage(page IPage, opts ...Option) (resultPage IPage, err error) 
	options := options
		query: make(map[string]interface, len(opts)),
	
	for _, o := range opts 
		o.apply(&options)
	
	resultPage = page
	results := make([]BlogAdmin, 0)
	var count int64 // 统计总的记录数
	query := obj.DB.WithContext(obj.ctx).Model(BlogAdmin).Where(options.query)
	query.Count(&count)
	resultPage.SetTotal(count)
	if len(page.GetOrederItemsString()) > 0 
		query = query.Order(page.GetOrederItemsString())
	
	err = query.Limit(int(page.GetSize())).Offset(int(page.Offset())).Find(&results).Error

	resultPage.SetRecords(results)
	return

自定义IPage

如果说Page不能满足您的使用需要的话,可以自定义一个IPage的实现类。最简单的做法是继承Page,然后定制您所需要的方法即可。

type MyPage struct 
    Page
    ...//一些拓展的字段


// 可以是新增的方法,也可以是重写Page实现好的方法,主要要使用指针类型
func (page *MyPage) someFunc(...) 
 	...   


假设现在有这么个需求,在前端分页展示的时候,我们不希望展示出所有的按钮,假设页面数量很多,但我们只需要固定展示10个分页按钮的话,效果如下。那单纯使用Page就很难满足这个需求,还需要额外的一些处理。所以可以自定义IPage的实现类,代码如下。


type MyPage struct 
    Page
	begin int64  // 第一个分页按钮的页码
    end   int64  // 最后一个分页按钮的页码
    showPages int // 展示的页面数


func (page *MyPage) setShowBtnNum() 
    if(page.GetPages() < page.showPages) 
    	page.begin = 1
        if page.GetPages() > 1 
            page.end = page.GetPages()
         else 
            page.end = 1  
        
     else 
        page.begin = page.GetCurrent() - (page.showPages/2)
        if page.showPages %2 == 0 
   			page.end = page.GetCurrent() + (page.showPages/2 - 1)
         else 
            page.end = page.GetCurrent() + page.showPages/2
        
     	
        if page.begin < 1 
        
        	page.begin = 1
            page.end = page.begin + page.showPages - 1;
        
        if page.end > page.showPages 
            page.end = page.GetCurrent()
            page.begin = page.end - (page.showPages - 1)
        
    

简单的使用案例

下面使用的结构体由下表生成的
https://github.com/xxjwxc/gormt/blob/master/data/view/genfunc/model/matrix.sql


func GetGorm(dataSourceName string) *gorm.DB 
	db, err := gorm.Open(mysql.Open(dataSourceName), &gorm.ConfigPrepareStmt: false)
	if err != nil 
		panic(err)
	
	sqlDB, err := db.DB()
	if err != nil 
		panic(err)
	
	// SetMaxIdleConns 设置空闲连接池中连接的最大数量
	sqlDB.SetMaxIdleConns(10)

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

	// SetConnMaxLifetime 设置了连接可复用的最大时间。
	sqlDB.SetConnMaxLifetime(time.Hour)

	return db.Debug()


// TestSelectPage 测试分页查询功能
func TestSelectPage(t *testing.T) 
	model.OpenRelated() // 打开全局预加载 (外键)

	db := GetGorm("root:123456@tcp(192.168.253.100:3306)/gormt?charset=utf8&parseTime=True&loc=Local&interpolateParams=True")
	defer func() 
		sqldb, _ := db.DB()
		sqldb.Close()
	()

	accountMgr := model.AccountMgr(db)
	// 构造分页条件
	page := model.NewPage(1, 1)
	// 不带条件的查询
	result, err := accountMgr.SelectPage(page)
	fmt.Println("不带条件查询")
	fmt.Println(err)
	fmt.Println(result.GetPages())
	fmt.Println(result.GetTotal())
	for _, val := range result.GetRecords().([]model.Account) 
		fmt.Println(val)
	

	//带条件查询
	page = model.NewPage(1, 2)
	result, err = accountMgr.SelectPage(page, accountMgr.WithName("bbbb"))
	fmt.Println("带条件查询")
	fmt.Println(err)
	fmt.Println(result.GetPages())
	fmt.Println(result.GetTotal())
	for _, val := range result.GetRecords().([]model.Account) 
		fmt.Println(val)
	

	// 进行排序,按name字段降序
	page = model.NewPage(1, 1, model.BuildDesc("name"))
	result, err = accountMgr.SelectPage(page)
	fmt.Println("进行排序,按name字段降序")
	fmt.Println(err)
	fmt.Println(result.GetPages())
	fmt.Println(result.GetTotal())
	for _, val := range result.GetRecords().([]model.Account) 
		fmt.Println(val)
	


gormt的Github链接
最近因为项目需要,所以使用了gormt这个项目,用来自动生成struct等代码。但是美中不足的是它里面生成的一些函数不支持分页查询,所以我就参考之前Java使用的Mybatis-Plus中的分页插件,在gormt中实现了对分页查询的支持。当需要进行分页查询的操作时,我们只需要传入每个分页的大小、当前的页数(从1开始计算),以及排序条件、筛选条件即可,不需要再去关心偏移量等一些复杂的操作。
接下来我简单介绍一下增加的内容以及如何使用

IPage和Page的内容在生成的gen.page.go文件中,SelectPage函数则是在dbname.gen.tablename.go文件中

IPage接口的介绍

这里提供了一个IPage接口,定义了以下方法,作用如注释所示

type IPage interface 
	GetRecords() interface      // 获取查询的记录
	SetRecords(interface)       // 设置查询的记录
	GetTotal() int64              // 获取总记录数
	SetTotal(int64)               // 设置总记录数
	GetCurrent() int64            // 获取当前页
	SetCurrent(int64)             // 设置当前页
	GetSize() int64               // 获取每页显示大小
	SetSize(int64)                // 设置每页显示大小
	AddOrderItem(OrderItem)       // 设置排序条件
	AddOrderItems([]OrderItem)    // 批量设置排序条件
	GetOrederItemsString() string // 将排序条件拼接成字符串
	Offset() int64                // 获取偏移量
	GetPages() int64              // 获取总的分页数

IPage的基础上,提供了一个默认实现Page,它实现了IPage中的所有方法。

type Page struct 
	total   int64       // 总的记录数
	size    int64       // 每页显示的大小
	current int64       // 当前页
	orders  []OrderItem // 排序条件
	Records interface // 查询数据列表



func (page *Page) GetRecords() interface 
	return page.Records


func (page *Page) SetRecords(records interface) 
	page.Records = records


func (page *Page) GetTotal() int64 
	return page.total


func (page *Page) SetTotal(total int64) 
	page.total = total



func (page *Page) GetCurrent() int64 
	return page.current


func (page *Page) SetCurrent(current int64) 
	page.current = current


func (page *Page) GetSize() int64 gormt中分页查询的使用

新人 记录VUE中分页实现

jsp分页计算总页数公式

jsp 如何将查询结果实现分页,最好简单易懂

JavaWeb中分页的实现

ABAP中如何实现强制分页/如何设置打印机和打印格式?