基于.NetCore開發博客項目 StarBlog - (23) 文章列表接口分頁、過濾、搜索、排序
前言
上一篇留的坑,火速補上。
在之前的第6篇中,已經有初步介紹,本文做一些補充,已經搞定這部分的同學可以快速跳過,基于.NetCore開發博客項目 StarBlog - (6) 頁面開發之博客文章列表
對標準的WebApi來說,分頁、過濾、搜索、排序是很常見的功能,既可以方便用戶查看數據,又可以提升程序性能。
通用請求參數
定義一個類來作為通用的請求參數
列表接口通用的參數是這幾個:PageSize
, Page
, Search
, SortBy
反映到URL上,就是 Blog/?pageSize=10&page=1&search=關鍵詞
這樣的形式
public class QueryParameters {
/// <summary>
/// 最大頁面條目
/// </summary>
public const int MaxPageSize = 50;
private int _pageSize = 10;
/// <summary>
/// 頁面大小
/// </summary>
public int PageSize {
get => _pageSize;
set => _pageSize = (value > MaxPageSize) ? MaxPageSize : value;
}
/// <summary>
/// 當前頁碼
/// </summary>
public int Page { get; set; } = 1;
/// <summary>
/// 搜索關鍵詞
/// </summary>
public string? Search { get; set; }
/// <summary>
/// 排序字段
/// </summary>
public string? SortBy { get; set; }
}
文章列表請求參數
在通用請求參數 QueryParameters
的基礎上,派生出文章列表的請求參數類 PostQueryParameters
public class PostQueryParameters : QueryParameters {
/// <summary>
/// 僅請求已發布文章
/// </summary>
public bool OnlyPublished { get; set; } = false;
/// <summary>
/// 文章狀態
/// </summary>
public string? Status { get; set; }
/// <summary>
/// 分類ID
/// </summary>
public int CategoryId { get; set; } = 0;
/// <summary>
/// 排序字段
/// </summary>
public new string? SortBy { get; set; } = "-LastUpdateTime";
}
在通用請求參數的基礎上,增加文章相關的篩選字段。
SortBy
字段使用 new
關鍵詞覆蓋基類屬性,設置為默認排序是最后更新時間,前面加個減號表示倒序。
service
在 StarBlog.Web/Services/PostService.cs
中封裝獲取分頁列表的方法
代碼里有注釋,比較容易,根據 PostQueryParameters
中的各種參數來做過濾篩選
public IPagedList<Post> GetPagedList(PostQueryParameters param) {
var querySet = _postRepo.Select;
// 是否發布
if (param.OnlyPublished) {
querySet = _postRepo.Select.Where(a => a.IsPublish);
}
// 狀態過濾
if (!string.IsNullOrEmpty(param.Status)) {
querySet = querySet.Where(a => a.Status == param.Status);
}
// 分類過濾
if (param.CategoryId != 0) {
querySet = querySet.Where(a => a.CategoryId == param.CategoryId);
}
// 關鍵詞過濾
if (!string.IsNullOrEmpty(param.Search)) {
querySet = querySet.Where(a => a.Title.Contains(param.Search));
}
// 排序
if (!string.IsNullOrEmpty(param.SortBy)) {
// 是否升序
var isAscending = !param.SortBy.StartsWith("-");
var orderByProperty = param.SortBy.Trim('-');
querySet = querySet.OrderByPropertyName(orderByProperty, isAscending);
}
return querySet.Include(a => a.Category).ToList()
.ToPagedList(param.Page, param.PageSize);
}
搜索的實現
在上面 service 的代碼中
可以看到搜索只是簡單的“關鍵詞過濾”
使用 Title.Contains(param.Search)
,轉換成SQL就是
select * from post where title like '%關鍵詞%'
單純判斷標題字符串中是否包含有關鍵詞的子串。
這對于簡單搜索一下文章是夠用的,如果要像谷歌、百度這類搜索引擎一樣能搜到文章的內容,需要用上全文檢索。
現在主流的就是 ElasticSearch 和 Solr,后續可以考慮把這個功能加入本項目~
PS:關于全文檢索,我之前寫過一篇文章:全文檢索引擎原理以及Lucene簡單介紹
同時開源了一個玩具級的全文檢索引擎,https://github.com/Deali-Axy/CloverSearch
分頁的實現
本項目使用 X.PagedList
來實現分頁功能
這個組件在結合MVC使用很方便,如果純WebApi的話,用數據庫自帶的分頁是更好的選擇,性能更好。
這個分頁組件是在
IEnumerable<T>
上添加了擴展方法ToPagedList
,所以在用的時候要先把數據都讀取出來,再執行分頁,性能不如在數據庫里做好分頁再讀出來,很多ORM都支持這個功能,FreeSQL也不例外。用法例子:
var list = fsql.Select<Topic>() .Where(a => a.Id > 10) .Count(out var total) //總記錄數量 .Page(1, 20) .Tolist();
詳情請查看FreeSQL官方文檔:https://freesql.net/guide/paging.html
用上 X.PagedList
這個組件后,在任意 IEnumerable<T>
對象上執行 ToPagedList
方法,可以得到 IPagedList<T>
對象
這個對象處理當前頁面的列表數據,還有分頁信息。
為了讓前端可以方便的使用這部分信息,我又寫了個擴展方法。
StarBlog.Web/Extensions/PagedListExt.cs
public static class PagedListExt {
public static PaginationMetadata ToPaginationMetadata(this IPagedList page) {
return new PaginationMetadata {
PageCount = page.PageCount,
TotalItemCount = page.TotalItemCount,
PageNumber = page.PageNumber,
PageSize = page.PageSize,
HasNextPage = page.HasNextPage,
HasPreviousPage = page.HasPreviousPage,
IsFirstPage = page.IsFirstPage,
IsLastPage = page.IsLastPage,
FirstItemOnPage = page.FirstItemOnPage,
LastItemOnPage = page.LastItemOnPage
};
}
public static string ToPaginationMetadataJson(this IPagedList page) {
return JsonSerializer.Serialize(ToPaginationMetadata(page));
}
}
這樣就可以在分頁后得到的 IPagedList
對象上執行 ToPaginationMetadata
得到分頁元數據了。
這個 PaginationMetadata
也是本項目里定義的 ViewModel,StarBlog.Web/ViewModels/PaginationMetadata.cs
代碼如下
public class PaginationMetadata {
public int PageCount { get; set; }
public int TotalItemCount { get; set; }
public int PageNumber { get; set; }
public int PageSize { get; set; }
public bool HasPreviousPage { get; set; }
public bool HasNextPage { get; set; }
public bool IsFirstPage { get; set; }
public bool IsLastPage { get; set; }
public int FirstItemOnPage { get; set; }
public int LastItemOnPage { get; set; }
}
搞定
controller與最終效果
代碼如下
[AllowAnonymous]
[HttpGet]
public ApiResponsePaged<Post> GetList([FromQuery] PostQueryParameters param) {
var pagedList = _postService.GetPagedList(param);
return new ApiResponsePaged<Post> {
Message = "Get posts list",
Data = pagedList.ToList(),
Pagination = pagedList.ToPaginationMetadata()
};
}
獲取到分頁數據之后,輸出 ApiResponsePaged<T>
類型的返回值
這個也是我封裝的接口返回值類型,下一篇文章會詳細介紹
Data
屬性就是列表數據,Pagination
屬性是分頁的信息。
請求這個接口返回的效果如下
{
"pagination": {
"pageCount": 40,
"totalItemCount": 394,
"pageNumber": 1,
"pageSize": 10,
"hasPreviousPage": false,
"hasNextPage": true,
"isFirstPage": true,
"isLastPage": false,
"firstItemOnPage": 1,
"lastItemOnPage": 10
},
"statusCode": 200,
"successful": true,
"message": "Get posts list",
"data": [{...},{...},{...},{...},{...}]
}
系列文章
- 基于.NetCore開發博客項目 StarBlog - (1) 為什么需要自己寫一個博客?
- 基于.NetCore開發博客項目 StarBlog - (2) 環境準備和創建項目
- 基于.NetCore開發博客項目 StarBlog - (3) 模型設計
- 基于.NetCore開發博客項目 StarBlog - (4) markdown博客批量導入
- 基于.NetCore開發博客項目 StarBlog - (5) 開始搭建Web項目
- 基于.NetCore開發博客項目 StarBlog - (6) 頁面開發之博客文章列表
- 基于.NetCore開發博客項目 StarBlog - (7) 頁面開發之文章詳情頁面
- 基于.NetCore開發博客項目 StarBlog - (8) 分類層級結構展示
- 基于.NetCore開發博客項目 StarBlog - (9) 圖片批量導入
- 基于.NetCore開發博客項目 StarBlog - (10) 圖片瀑布流
- 基于.NetCore開發博客項目 StarBlog - (11) 實現訪問統計
- 基于.NetCore開發博客項目 StarBlog - (12) Razor頁面動態編譯
- 基于.NetCore開發博客項目 StarBlog - (13) 加入友情鏈接功能
- 基于.NetCore開發博客項目 StarBlog - (14) 實現主題切換功能
- 基于.NetCore開發博客項目 StarBlog - (15) 生成隨機尺寸圖片
- 基于.NetCore開發博客項目 StarBlog - (16) 一些新功能 (監控/統計/配置/初始化)
- 基于.NetCore開發博客項目 StarBlog - (17) 自動下載文章里的外部圖片
- 基于.NetCore開發博客項目 StarBlog - (18) 實現本地Typora文章打包上傳
- 基于.NetCore開發博客項目 StarBlog - (19) Markdown渲染方案探索
- 基于.NetCore開發博客項目 StarBlog - (20) 圖片顯示優化
- 基于.NetCore開發博客項目 StarBlog - (21) 開始開發RESTFul接口
- 基于.NetCore開發博客項目 StarBlog - (22) 開發博客文章相關接口
- 基于.NetCore開發博客項目 StarBlog - (23) 文章列表接口分頁、過濾、搜索、排序