前言
上一篇留的坑,火速补上。
在之前的第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) 文章列表接口分页、过滤、搜索、排序