» Rust:使用Rocket构建REST API » 2. 开发 » 2.10 分页

分页

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

添加分页逻辑

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

@@ -7,5 +7,5 @@ pub trait BookManager: Send + Sync {
     fn update_book(&self, id: u32, b: &model::Book) -> Result<(), Box<dyn Error>>;
     fn delete_book(&self, id: u32) -> Result<(), Box<dyn Error>>;
     fn get_book(&self, id: u32) -> Result<Option<model::Book>, Box<dyn Error>>;
-    fn get_books(&self) -> Result<Vec<model::Book>, Box<dyn Error>>;
+    fn get_books(&self, offset: u32) -> Result<Vec<model::Book>, Box<dyn Error>>;
 }

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

添加 page_size 配置项,infrastructure/config/mod.rs:

@@ -25,6 +25,7 @@ pub struct CacheConfig {
 #[derive(Debug, Deserialize, Serialize)]
 pub struct ApplicationConfig {
     pub port: i32,
+    pub page_size: u32,
 }
 
 pub fn parse_config(file_name: &str) -> Config {

设置 page_size 配置值,config.toml:

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

合入 page_sizeapplication/wire_helper.rs:

@@ -13,7 +13,8 @@ pub struct WireHelper {
 
 impl WireHelper {
     pub fn new(c: &Config) -> Result<Self, Box<dyn std::error::Error>> {
-        let sql_persistence = Arc::new(database::MySQLPersistence::new(&c.db.dsn)?);
+        let sql_persistence =
+            Arc::new(database::MySQLPersistence::new(&c.db.dsn, c.app.page_size)?);
         let no_sql_persistence = Arc::new(database::MongoPersistence::new(
             &c.db.mongo_uri,
             &c.db.mongo_db_name,

更新查询逻辑,将 offsetpage_size 考虑进去,infrastructure/database/mysql.rs:

@@ -9,12 +9,13 @@ use crate::domain::model;
 
 pub struct MySQLPersistence {
     pool: Pool,
+    page_size: u32,
 }
 
 impl MySQLPersistence {
-    pub fn new(dsn: &str) -> Result<Self, MySQLError> {
+    pub fn new(dsn: &str, page_size: u32) -> Result<Self, MySQLError> {
         let pool = Pool::new(dsn)?;
-        Ok(MySQLPersistence { pool })
+        Ok(MySQLPersistence { pool, page_size })
     }
 }
 
@@ -93,10 +94,10 @@ impl BookManager for MySQLPersistence {
         Ok(books.first().cloned())
     }
 
-    fn get_books(&self) -> Result<Vec<model::Book>, Box<dyn Error>> {
+    fn get_books(&self, offset: u32) -> Result<Vec<model::Book>, Box<dyn Error>> {
         let mut conn = self.pool.get_conn()?;
         let books = conn.query_map(
-            "SELECT * FROM books",
+            format!("SELECT * FROM books LIMIT {}, {}", offset, self.page_size),
             |(
                 id,
                 title,

调整缓存键,application/executor/book_operator.rs:

@@ -30,15 +30,16 @@ impl BookOperator {
         self.book_manager.get_book(id)
     }
 
-    pub fn get_books(&self) -> Result<Vec<model::Book>, Box<dyn std::error::Error>> {
-        let raw_value = self.cache_helper.load(BOOKS_KEY)?;
+    pub fn get_books(&self, offset: u32) -> Result<Vec<model::Book>, Box<dyn std::error::Error>> {
+        let k = format!("{}-{}", BOOKS_KEY, offset);
+        let raw_value = self.cache_helper.load(&k)?;
         if let Some(v) = raw_value {
             let cached_books = serde_json::from_str(&v)?;
             Ok(cached_books)
         } else {
-            let fetched_books = self.book_manager.get_books()?;
+            let fetched_books = self.book_manager.get_books(offset)?;
             let v = serde_json::to_string(&fetched_books)?;
-            self.cache_helper.save(BOOKS_KEY, &v)?;
+            self.cache_helper.save(&k, &v)?;
             Ok(fetched_books)
         }
     }

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

@@ -24,11 +24,12 @@ pub fn health_check() -> content::RawJson<&'static str> {
     content::RawJson("{\"status\":\"ok\"}")
 }
 
-#[get("/books")]
+#[get("/books?<o>")]
 pub fn get_books(
     rest_handler: &rocket::State<RestHandler>,
+    o: Option<u32>,
 ) -> Result<Json<Vec<model::Book>>, status::Custom<Json<ErrorResponse>>> {
-    match rest_handler.book_operator.get_books() {
+    match rest_handler.book_operator.get_books(o.unwrap_or(0)) {
         Ok(books) => Ok(Json(books)),
         Err(err) => Err(status::Custom(
             Status::InternalServerError,

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

使用 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:8000/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:8000/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:8000/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:8000/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:8000/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:8000/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:8000/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:8000/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:8000/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:8000/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:8000/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:8000/books

列出第一页的图书

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

结果:

[
  {
    "id": 3,
    "title": "Sample Book",
    "author": "John Doe",
    "published_at": "2023-01-01",
    "description": "A sample book description",
    "isbn": "1234567890",
    "total_pages": 200,
    "created_at": "2024-03-01 12:40:16",
    "updated_at": "2024-03-01 12:40:16"
  },
  {
    "id": 4,
    "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-03-02 05:48:25",
    "updated_at": "2024-03-02 05:48:25"
  },
  {
    "id": 5,
    "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-03-02 05:48:25",
    "updated_at": "2024-03-02 05:48:25"
  },
  {
    "id": 6,
    "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-03-02 05:48:25",
    "updated_at": "2024-03-02 05:48:25"
  },
  {
    "id": 7,
    "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-03-02 05:48:25",
    "updated_at": "2024-03-02 05:48:25"
  }
]

列出偏移之后的图书:

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

结果:

[
  {
    "id": 8,
    "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-03-02 05:48:25",
    "updated_at": "2024-03-02 05:48:25"
  },
  {
    "id": 9,
    "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-03-02 05:48:25",
    "updated_at": "2024-03-02 05:48:25"
  },
  {
    "id": 10,
    "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-03-02 05:48:25",
    "updated_at": "2024-03-02 05:48:25"
  },
  {
    "id": 11,
    "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-03-02 05:48:25",
    "updated_at": "2024-03-02 05:48:25"
  },
  {
    "id": 12,
    "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-03-02 05:48:25",
    "updated_at": "2024-03-02 05:48:25"
  }
]

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

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

结果:

[
  {
    "id": 13,
    "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-03-02 05:48:25",
    "updated_at": "2024-03-02 05:48:25"
  },
  {
    "id": 14,
    "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-03-02 05:48:25",
    "updated_at": "2024-03-02 05:48:25"
  },
  {
    "id": 15,
    "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-03-02 05:48:25",
    "updated_at": "2024-03-02 05:48:25"
  },
  {
    "id": 16,
    "title": "Sample Book",
    "author": "John Doe",
    "published_at": "2023-01-01",
    "description": "A sample book description",
    "isbn": "1234567890",
    "total_pages": 200,
    "created_at": "2024-03-07 10:17:59",
    "updated_at": "2024-03-07 10:17:59"
  },
  {
    "id": 17,
    "title": "Sample Book",
    "author": "John Doe",
    "published_at": "2023-01-01",
    "description": "A sample book description",
    "isbn": "1234567890",
    "total_pages": 200,
    "created_at": "2024-03-07 10:18:20",
    "updated_at": "2024-03-07 10:18:20"
  }
]

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