前言

上一篇留的坑,火速补上。

在之前的第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 - (23) 文章列表接口分页、过滤、搜索、排序的更多相关文章

  1. 基于.NetCore开发博客项目 StarBlog - (16) 一些新功能 (监控/统计/配置/初始化)

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  2. 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 ... 基于. ...

  3. 基于.NetCore开发博客项目 StarBlog - (3) 模型设计

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  4. 基于.NetCore开发博客项目 StarBlog - (4) markdown博客批量导入

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  5. 基于.NetCore开发博客项目 StarBlog - (5) 开始搭建Web项目

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  6. 基于.NetCore开发博客项目 StarBlog - (6) 页面开发之博客文章列表

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  7. 基于.NetCore开发博客项目 StarBlog - (7) 页面开发之文章详情页面

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  8. 基于.NetCore开发博客项目 StarBlog - (8) 分类层级结构展示

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  9. 基于.NetCore开发博客项目 StarBlog - (9) 图片批量导入

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  10. 基于.NetCore开发博客项目 StarBlog - (10) 图片瀑布流

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

随机推荐

  1. 18-基于CentOS7搭建RabbitMQ3.10.7集群镜像队列+HaProxy+Keepalived高可用架构

    集群架构 虚拟机规划 IP hostname 节点说明 端口 控制台地址 192.168.247.150 rabbitmq.master rabbitmq master 5672 http://192 ...

  2. python之流程控制上-if、while

    流程控制 编写程序,是将自己的逻辑思想记录下来,使得计算机能够执行的过程. 而流程控制,则是逻辑结构中十分重要的一环. 在程序中,基础的流程结构分为顺序结构.分支结构.顺序结构 顺序结构自不必多说,上 ...

  3. 追求性能极致:Redis6.0的多线程模型

    Redis系列1:深刻理解高性能Redis的本质 Redis系列2:数据持久化提高可用性 Redis系列3:高可用之主从架构 Redis系列4:高可用之Sentinel(哨兵模式) Redis系列5: ...

  4. 重写 hashcode()真有那么简单嘛?

    万万没想到一个 hashcode() 方法,既然会引出一堆的知识盲区,简直了. 起因: 老八股:为什么重写Equals方法要重写HashCode方法. 大声告诉我为什么,闭着眼睛先把答案背出来,啥?这 ...

  5. 微软出品自动化神器【Playwright+Java】系列(五) 之 常见点击事件操作

    写在前面 明天就是周五了,这周有那么一两天心情特别不好,真的是做什么都没兴致,所以导致整个人都很丧,什么都不想做. 本打算周一就更新这篇文章的,但由于公司一直加班,每天到家很晚,都是挤时间去学,理解后 ...

  6. Oracle注入

    Oracle 查询出所有的表 select * from all_tables 查询出当前用户的表 select * from user_tables 查询出所有的字段 select*from all ...

  7. 驱动开发:内核枚举LoadImage映像回调

    在笔者之前的文章<驱动开发:内核特征码搜索函数封装>中我们封装实现了特征码定位功能,本章将继续使用该功能,本次我们需要枚举内核LoadImage映像回调,在Win64环境下我们可以设置一个 ...

  8. 关于引用JS和CSS文件刷新浏览器缓存问题,部署服务器后客户端样式不刷新

    问题描述 对样式的css文件进行了修改,部署到服务器后访问发现页面展示不正常,但是刷新之后就会展示正常. 问题分析 研究之后发现可能的原因有 css文件过大,加载缓慢 本地缓存问题,虽然服务器修改了c ...

  9. nginx.conf指令注释

    nginx.conf指令注释 ######Nginx配置文件nginx.conf中文详解##### #定义Nginx运行的用户和用户组 user www www; #nginx进程数,建议设置为等于C ...

  10. 2流高手速成记(之八):基于Sentinel实现微服务体系下的限流与熔断

    我们接上回 上一篇中,我们进行了简要的微服务实现,也体会到了SpringCloudAlibaba的强大和神奇之处 我们仅改动了两个注释,其他全篇代码不变,原来的独立服务就被我们分为了provider和 ...