» Go:使用Gin构建REST API » 2. 开发 » 2.10 分页

分页

如果你的数据库中有数百万的记录,你肯定不希望将其一骨碌地给到同一个页面中。那样的话,客户端和服务端都无法承受。所以,你需要分页。

添加分页逻辑

调整方法参数,domain/gateway/book_manager.go

@@ -12,5 +12,5 @@ type BookManager interface {
        UpdateBook(ctx context.Context, id uint, b *model.Book) error
        DeleteBook(ctx context.Context, id uint) error
        GetBook(ctx context.Context, id uint) (*model.Book, error)
-       GetBooks(ctx context.Context) ([]*model.Book, error)
+       GetBooks(ctx context.Context, offset int) ([]*model.Book, error)
 }

GetBooks 方法添加名为 offset 的参数。

infrastructure/config/config.go 中添加 pageSize 配置项:

@@ -21,7 +21,8 @@ type DBConfig struct {
 }
 
 type ApplicationConfig struct {
-       Port int `json:"port" yaml:"port"`
+       Port     int `json:"port" yaml:"port"`
+       PageSize int `json:"page_size" yaml:"page_size"`
 }
 
 type CacheConfig struct {

设置 page_size 配置值,config.yml

@@ -1,5 +1,6 @@
 app:
   port: 8080
+  page_size: 5
 db:
   file_name: "test.db"

合入 PageSizeapplication/wire_helper.go

@@ -15,7 +15,7 @@ type WireHelper struct {
 }
 
 func NewWireHelper(c *config.Config) (*WireHelper, error) {
-       db, err := database.NewMySQLPersistence(c.DB.DSN)
+       db, err := database.NewMySQLPersistence(c.DB.DSN, c.App.PageSize)
        if err != nil {
                return nil, err
        }

更新查询逻辑,将 offsetpageSize 考虑进去,infrastructure/database/mysql.go

@@ -13,10 +13,11 @@ import (
 )
 
 type MySQLPersistence struct {
-       db *gorm.DB
+       db       *gorm.DB
+       pageSize int
 }
 
-func NewMySQLPersistence(dsn string) (*MySQLPersistence, error) {
+func NewMySQLPersistence(dsn string, pageSize int) (*MySQLPersistence, error) {
        db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
        if err != nil {
                return nil, err
@@ -24,7 +25,7 @@ func NewMySQLPersistence(dsn string) (*MySQLPersistence, error) {
        // Auto Migrate the data structs
        db.AutoMigrate(&model.Book{})
 
-       return &MySQLPersistence{db}, nil
+       return &MySQLPersistence{db, pageSize}, nil
 }
 
 func (s *MySQLPersistence) CreateBook(ctx context.Context, b *model.Book) (uint, error) {
@@ -54,9 +55,9 @@ func (s *MySQLPersistence) GetBook(ctx context.Context, id uint) (*model.Book, e
        return &book, nil
 }
 
-func (s *MySQLPersistence) GetBooks(ctx context.Context) ([]*model.Book, error) {
+func (s *MySQLPersistence) GetBooks(ctx context.Context, offset int) ([]*model.Book, error) {
        books := make([]*model.Book, 0)
-       if err := s.db.WithContext(ctx).Find(&books).Error; err != nil {
+       if err := s.db.WithContext(ctx).Offset(offset).Limit(s.pageSize).Find(&books).Error; err != nil {
                return nil, err
        }
        return books, nil

调整缓存键,application/executor/book_operator.go

@@ -3,6 +3,7 @@ package executor
 import (
        "context"
        "encoding/json"
+       "fmt"
 
        "literank.com/rest-books/domain/gateway"
        "literank.com/rest-books/domain/model"
@@ -33,8 +34,9 @@ func (o *BookOperator) GetBook(ctx context.Context, id uint) (*model.Book, error
        return o.bookManager.GetBook(ctx, id)
 }
 
-func (o *BookOperator) GetBooks(ctx context.Context) ([]*model.Book, error) {
-       rawValue, err := o.cacheHelper.Load(ctx, booksKey)
+func (o *BookOperator) GetBooks(ctx context.Context, offset int) ([]*model.Book, error) {
+       k := fmt.Sprintf("%s-%d", booksKey, offset)
+       rawValue, err := o.cacheHelper.Load(ctx, k)
        if err != nil {
                return nil, err
        }
@@ -47,7 +49,7 @@ func (o *BookOperator) GetBooks(ctx context.Context) ([]*model.Book, error) {
                }
        } else {
                // Cache key does not exist
-               books, err = o.bookManager.GetBooks(ctx)
+               books, err = o.bookManager.GetBooks(ctx, offset)
                if err != nil {
                        return nil, err
                }
@@ -55,7 +57,7 @@ func (o *BookOperator) GetBooks(ctx context.Context) ([]*model.Book, error) {
                if err != nil {
                        return nil, err
                }
-               if err := o.cacheHelper.Save(ctx, booksKey, string(value)); err != nil {
+               if err := o.cacheHelper.Save(ctx, k, string(value)); err != nil {
                        return nil, err
                }
        }

最后一步,在 adaptor/router.go 中传递 query 参数:

@@ -12,7 +12,10 @@ import (
        "literank.com/rest-books/domain/model"
 )
 
-const fieldID = "id"
+const (
+       fieldID     = "id"
+       fieldOffset = "o"
+)
 
 // RestHandler handles all restful requests
 type RestHandler struct {
@@ -50,7 +53,17 @@ func MakeRouter(wireHelper *application.WireHelper) (*gin.Engine, error) {
 
 // Get all books
 func (r *RestHandler) getBooks(c *gin.Context) {
-       books, err := r.bookOperator.GetBooks(c)
+       offset := 0
+       offsetParam := c.Query(fieldOffset)
+       if offsetParam != "" {
+               value, err := strconv.Atoi(offsetParam)
+               if err != nil {
+                       c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid offset"})
+                       return
+               }
+               offset = value
+       }
+       books, err := r.bookOperator.GetBooks(c, offset)
        if err != nil {
                fmt.Printf("Failed to get books: %v\n", err)
                c.JSON(http.StatusNotFound, gin.H{"error": "failed to get books"})

好啦!改完啦!让我们试下。

使用 curl 测试

放入待测试数据

curl -X POST -H "Content-Type: application/json" -d '{"title": "The Great Gatsby", "author": "F. Scott Fitzgerald", "published_at": "1925-04-10", "description": "A novel depicting the opulent lives of wealthy Long Island residents during the Jazz Age.", "isbn": "9780743273565", "total_pages": 218}' http://localhost:8080/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "To Kill a Mockingbird", "author": "Harper Lee", "published_at": "1960-07-11", "description": "A novel set in the American South during the 1930s, dealing with themes of racial injustice and moral growth.", "isbn": "9780061120084", "total_pages": 281}' http://localhost:8080/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "1984", "author": "George Orwell", "published_at": "1949-06-08", "description": "A dystopian novel depicting a totalitarian regime, surveillance, and propaganda.", "isbn": "9780451524935", "total_pages": 328}' http://localhost:8080/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "Pride and Prejudice", "author": "Jane Austen", "published_at": "1813-01-28", "description": "A classic novel exploring the themes of love, reputation, and social class in Georgian England.", "isbn": "9780486284736", "total_pages": 279}' http://localhost:8080/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "The Catcher in the Rye", "author": "J.D. Salinger", "published_at": "1951-07-16", "description": "A novel narrated by a disaffected teenager, exploring themes of alienation and identity.", "isbn": "9780316769488", "total_pages": 277}' http://localhost:8080/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "The Lord of the Rings", "author": "J.R.R. Tolkien", "published_at": "1954-07-29", "description": "A high fantasy epic following the quest to destroy the One Ring and defeat the Dark Lord Sauron.", "isbn": "9780544003415", "total_pages": 1178}' http://localhost:8080/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "Moby-Dick", "author": "Herman Melville", "published_at": "1851-10-18", "description": "A novel exploring themes of obsession, revenge, and the nature of good and evil.", "isbn": "9780142000083", "total_pages": 624}' http://localhost:8080/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "The Hobbit", "author": "J.R.R. Tolkien", "published_at": "1937-09-21", "description": "A fantasy novel set in Middle-earth, following the adventure of Bilbo Baggins and the quest for treasure.", "isbn": "9780345339683", "total_pages": 310}' http://localhost:8080/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "The Adventures of Huckleberry Finn", "author": "Mark Twain", "published_at": "1884-12-10", "description": "A novel depicting the journey of a young boy and an escaped slave along the Mississippi River.", "isbn": "9780486280615", "total_pages": 366}' http://localhost:8080/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "War and Peace", "author": "Leo Tolstoy", "published_at": "1869-01-01", "description": "A novel depicting the Napoleonic era in Russia, exploring themes of love, war, and historical determinism.", "isbn": "9781400079988", "total_pages": 1392}' http://localhost:8080/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "Alice’s Adventures in Wonderland", "author": "Lewis Carroll", "published_at": "1865-11-26", "description": "A children’s novel featuring a young girl named Alice who falls into a fantastical world populated by peculiar creatures.", "isbn": "9780141439761", "total_pages": 192}' http://localhost:8080/books
curl -X POST -H "Content-Type: application/json" -d '{"title": "The Odyssey", "author": "Homer", "published_at": "8th Century BC", "description": "An ancient Greek epic poem attributed to Homer, detailing the journey of Odysseus after the Trojan War.", "isbn": "9780140268867", "total_pages": 541}' http://localhost:8080/books

列出第一页的图书

curl -X GET http://localhost:8080/books

结果:

[
  {
    "id": 1,
    "title": "Great Book II",
    "author": "Carl Smith",
    "published_at": "2022-01-01 08:00:00.000",
    "description": "Another sample book description",
    "isbn": "8334567890",
    "total_pages": 3880,
    "created_at": "2024-02-25T16:29:31.353+08:00",
    "updated_at": "2024-02-25T16:29:31.353+08:00"
  },
  {
    "id": 2,
    "title": "The Great Gatsby",
    "author": "F. Scott Fitzgerald",
    "published_at": "1925-04-10",
    "description": "A novel depicting the opulent lives of wealthy Long Island residents during the Jazz Age.",
    "isbn": "9780743273565",
    "total_pages": 218,
    "created_at": "2024-02-26T17:28:26.542+08:00",
    "updated_at": "2024-02-26T17:28:26.542+08:00"
  },
  {
    "id": 3,
    "title": "To Kill a Mockingbird",
    "author": "Harper Lee",
    "published_at": "1960-07-11",
    "description": "A novel set in the American South during the 1930s, dealing with themes of racial injustice and moral growth.",
    "isbn": "9780061120084",
    "total_pages": 281,
    "created_at": "2024-02-26T17:28:54.178+08:00",
    "updated_at": "2024-02-26T17:28:54.178+08:00"
  },
  {
    "id": 4,
    "title": "1984",
    "author": "George Orwell",
    "published_at": "1949-06-08",
    "description": "A dystopian novel depicting a totalitarian regime, surveillance, and propaganda.",
    "isbn": "9780451524935",
    "total_pages": 328,
    "created_at": "2024-02-26T17:28:54.197+08:00",
    "updated_at": "2024-02-26T17:28:54.197+08:00"
  },
  {
    "id": 5,
    "title": "Pride and Prejudice",
    "author": "Jane Austen",
    "published_at": "1813-01-28",
    "description": "A classic novel exploring the themes of love, reputation, and social class in Georgian England.",
    "isbn": "9780486284736",
    "total_pages": 279,
    "created_at": "2024-02-26T17:28:54.213+08:00",
    "updated_at": "2024-02-26T17:28:54.213+08:00"
  }
]

列出偏移之后的图书:

curl -X GET http://localhost:8080/books?o=5

结果:

[
  {
    "id": 6,
    "title": "The Catcher in the Rye",
    "author": "J.D. Salinger",
    "published_at": "1951-07-16",
    "description": "A novel narrated by a disaffected teenager, exploring themes of alienation and identity.",
    "isbn": "9780316769488",
    "total_pages": 277,
    "created_at": "2024-02-26T17:28:54.23+08:00",
    "updated_at": "2024-02-26T17:28:54.23+08:00"
  },
  {
    "id": 7,
    "title": "The Lord of the Rings",
    "author": "J.R.R. Tolkien",
    "published_at": "1954-07-29",
    "description": "A high fantasy epic following the quest to destroy the One Ring and defeat the Dark Lord Sauron.",
    "isbn": "9780544003415",
    "total_pages": 1178,
    "created_at": "2024-02-26T17:28:54.246+08:00",
    "updated_at": "2024-02-26T17:28:54.246+08:00"
  },
  {
    "id": 8,
    "title": "Moby-Dick",
    "author": "Herman Melville",
    "published_at": "1851-10-18",
    "description": "A novel exploring themes of obsession, revenge, and the nature of good and evil.",
    "isbn": "9780142000083",
    "total_pages": 624,
    "created_at": "2024-02-26T17:28:54.262+08:00",
    "updated_at": "2024-02-26T17:28:54.262+08:00"
  },
  {
    "id": 9,
    "title": "The Hobbit",
    "author": "J.R.R. Tolkien",
    "published_at": "1937-09-21",
    "description": "A fantasy novel set in Middle-earth, following the adventure of Bilbo Baggins and the quest for treasure.",
    "isbn": "9780345339683",
    "total_pages": 310,
    "created_at": "2024-02-26T17:28:54.278+08:00",
    "updated_at": "2024-02-26T17:28:54.278+08:00"
  },
  {
    "id": 10,
    "title": "The Adventures of Huckleberry Finn",
    "author": "Mark Twain",
    "published_at": "1884-12-10",
    "description": "A novel depicting the journey of a young boy and an escaped slave along the Mississippi River.",
    "isbn": "9780486280615",
    "total_pages": 366,
    "created_at": "2024-02-26T17:28:54.293+08:00",
    "updated_at": "2024-02-26T17:28:54.293+08:00"
  }
]

列出另一个偏移后的图书:

curl -X GET http://localhost:8080/books?o=10

结果:

[
  {
    "id": 11,
    "title": "War and Peace",
    "author": "Leo Tolstoy",
    "published_at": "1869-01-01",
    "description": "A novel depicting the Napoleonic era in Russia, exploring themes of love, war, and historical determinism.",
    "isbn": "9781400079988",
    "total_pages": 1392,
    "created_at": "2024-02-26T17:28:54.309+08:00",
    "updated_at": "2024-02-26T17:28:54.309+08:00"
  },
  {
    "id": 12,
    "title": "The Odyssey",
    "author": "Homer",
    "published_at": "8th Century BC",
    "description": "An ancient Greek epic poem attributed to Homer, detailing the journey of Odysseus after the Trojan War.",
    "isbn": "9780140268867",
    "total_pages": 541,
    "created_at": "2024-02-26T17:29:22.386+08:00",
    "updated_at": "2024-02-26T17:29:22.386+08:00"
  },
  {
    "id": 13,
    "title": "Alice’s Adventures in Wonderland",
    "author": "Lewis Carroll",
    "published_at": "1865-11-26",
    "description": "A children’s novel featuring a young girl named Alice who falls into a fantastical world populated by peculiar creatures.",
    "isbn": "9780141439761",
    "total_pages": 192,
    "created_at": "2024-02-26T17:31:55.903+08:00",
    "updated_at": "2024-02-26T17:31:55.903+08:00"
  }
]

看来分页功能一切正常!进展不错!