基于.NetCore開發博客項目 StarBlog - (6) 頁面開發之博客文章列表

系列文章

  • 基于.NetCore開發博客項目 StarBlog - (1) 為什么需要自己寫一個博客?

  • 基于.NetCore開發博客項目 StarBlog - (2) 環境準備和創建項目

  • 基于.NetCore開發博客項目 StarBlog - (3) 模型設計

  • 基于.NetCore開發博客項目 StarBlog - (4) markdown博客批量導入

  • 基于.NetCore開發博客項目 StarBlog - (5) 開始搭建Web項目

  • 基于.NetCore開發博客項目 StarBlog - (6) 頁面開發之博客文章列表

  • ...

前言

前一篇文章把Web項目搭起來了,現在開始來寫頁面~

本文記錄博客文章列表的開發,包括參數、分類過濾、分頁、搜索、排序等內容。

ORM

本項目的ORM使用FreeSQL,前面「博客批量導入」的文章中有初步涉及到了,不過沒有介紹太多,這里再講一下幾個關鍵的地方。

不同于網上比較常見的EF Core,FreeSQL設計完模型之后不需要進行遷移操作,在開發模式下開啟自動結構同步(AutoSyncStructure)就能自動創建、修改數據表。

還有比較方便的一點是FreeSQL自帶了簡單的倉儲模式,不用再自己封裝一套,可以減少開發時的代碼量~

不過局限性也是有的,不封裝倉儲層的話,意味著service層代碼跟ORM綁定,以后如果切換ORM會帶來額外的重構成本。

打開StarBlog.Data項目,我們來寫一個擴展方法,新增Extensions目錄,在里面新增ConfigureFreeSql.cs

using?FreeSql;
using?Microsoft.Extensions.Configuration;
using?Microsoft.Extensions.DependencyInjection;namespace?StarBlog.Data.Extensions;public?static?class?ConfigureFreeSql?{public?static?void?AddFreeSql(this?IServiceCollection?services,?IConfiguration?configuration)?{var?freeSql?=?new?FreeSqlBuilder().UseConnectionString(DataType.Sqlite,?configuration.GetConnectionString("SQLite")).UseAutoSyncStructure(true).Build();services.AddSingleton(freeSql);//?倉儲模式支持services.AddFreeRepository();}
}

然后編輯StarBlog.Web項目下的Program.cs,注冊一下FreeSQL的服務,用我們剛才寫的擴展方法。

using?StarBlog.Data.Extensions;builder.Services.AddFreeSql(builder.Configuration);

在要用的地方注入就行了,比如

IBaseRepository<Post>?_postRepo;//?獲取全部文章
_postRepo.Select.ToList()

就很方便了,開箱即用~

Service

因為我們的后端既要渲染頁面,又要做RESTFul接口,所以要把業務邏輯抽象出來放在service層,避免在Controller里重復。

StarBlog.Web項目的Services目錄里新增PostService.cs,我們要在這封裝跟文章有關的邏輯~

首先依賴注入,把需要用到的服務注入進來

public?class?PostService?{private?readonly?IBaseRepository<Post>?_postRepo;private?readonly?IBaseRepository<Category>?_categoryRepo;public?PostService(IBaseRepository<Post>?postRepo,IBaseRepository<Category>?categoryRepo)?{_postRepo?=?postRepo;_categoryRepo?=?categoryRepo;}
}

寫一個獲取全部文章的方法

public?List<Post>?GetAll()?{return?_postRepo.Select.ToList();
}

這樣就初步搞定了,接下來要來寫Controller

Controller

StarBlog.Web項目的Controllers目錄下,新增BlogController.cs,用來實現跟博客有關的接口。

注入剛剛寫好的 PostService

public?class?BlogController?:?Controller?{private?readonly?PostService?_postService;public?BlogController(PostService?postService)?{_postService?=?postService;}
}

寫文章列表“接口”(MVC也算接口吧)

public?IActionResult?List()?{return?View(_postService.GetAll());
}

View

根據AspNetCore MVC項目的約定,要把網頁模板放在Views目錄下,按Controller分類

這個文章列表頁面,按照約定的路徑是:Views/Blog/List.cshtml,創建這個文件

@model?List<Post>
@{ViewData["Title"]?=?"博客列表";
}
<div?class="container?px-4?py-3">@foreach?(var?post?in?Model)?{<div?class="card?mb-3"><div?class="card-header">@Model.Category.Name</div><div?class="card-body"><h5?class="card-title">@Model.Title</h5><p?class="card-text">@Model.Summary</p><a?class="btn?btn-outline-secondary?stretched-link"asp-controller="Blog"?asp-action="Post"?asp-route-id="@Model.Id">查看全文</a></div></div>}
</div>

這樣簡單的文章列表就完成了

試試效果

運行項目,打開瀏覽器,輸入地址http://127.0.0.1:5038/Blog/List,可以看到文章列表如下,很簡單(簡陋),而且全部文章都顯示出來了,頁面很長,這很明顯并不是我們想要的最終效果。

58ef2fe8c6c6212992b523a819c5324c.png
image

不急,接下來慢慢來優化。

分頁

首先是頁面把全部文章都顯示出來的問題,我們需要引入分頁功能

分頁可以自己實現,也可以用第三方組件,我們用的FreeSQL也支持分頁的API,這里我直接掏出之前做項目用過的X.PagedList,它封裝了分頁取數據和前端的分頁部件,比較方便。

直接nuget里安裝這兩個包就行:

  • X.PagedList

  • X.PagedList.Mvc.Core

使用很簡單,X.PagedList組件定義了List類型的擴展方法,直接在ORM讀取出來的List上用就行

_postRepo.Select.ToList().ToPagedList(pageNumber,?pageSize);

返回類型是IPagedList<T>,除了當前頁面的數據,還包含有分頁的信息(當前頁面、總頁面數量、頁面大小、總數據量等),可以直接當List用。

然后X.PagedList組件還封裝了MVC模板上的HTML組件,使用也很簡單:

<nav?aria-label="Page?navigation?example">@Html.PagedListPager(Model.Posts,?page?=>?Url.Action(RazorHelper.GetCurrentActionName(ViewContext),?new?{page,?categoryId?=?Model.CurrentCategoryId}),new?PagedListRenderOptions?{LiElementClasses?=?new[]?{"page-item"},PageClasses?=?new[]?{"page-link"},UlElementClasses?=?new[]?{"pagination?justify-content-center"}})
</nav>

前端我要使用bootstrap的分頁組件,所以把bootstrap的class傳進去,如果是其他前端組件庫的話,只需要傳對應的class名稱就行。

渲染出來的頁面代碼是這樣的:

<div?class="pagination-container"><ul?class="pagination?justify-content-center"><li?class="active?page-item"><span?class="page-link">1</span></li><li?class="page-item"><a?class="page-link"?href="/Blog/List?page=2&amp;categoryId=0">2</a></li><li?class="page-item"><a?class="page-link"?href="/Blog/List?page=3&amp;categoryId=0">3</a></li><li?class="page-item"><a?class="page-link"?href="/Blog/List?page=4&amp;categoryId=0">4</a></li><li?class="page-item"><a?class="page-link"?href="/Blog/List?page=5&amp;categoryId=0">5</a></li><li?class="page-item"><a?class="page-link"?href="/Blog/List?page=6&amp;categoryId=0">6</a></li><li?class="page-item"><a?class="page-link"?href="/Blog/List?page=7&amp;categoryId=0">7</a></li><li?class="page-item"><a?class="page-link"?href="/Blog/List?page=8&amp;categoryId=0">8</a></li><li?class="page-item"><a?class="page-link"?href="/Blog/List?page=9&amp;categoryId=0">9</a></li><li?class="page-item"><a?class="page-link"?href="/Blog/List?page=10&amp;categoryId=0">10</a></li><li?class="PagedList-ellipses?page-item"><a?class="PagedList-skipToNext?page-link"?href="/Blog/List?page=11&amp;categoryId=0"?rel="next">…</a></li><li?class="PagedList-skipToNext?page-item"><a?class="page-link"?href="/Blog/List?page=2&amp;categoryId=0"?rel="next">&gt;</a></li><li?class="PagedList-skipToLast?page-item"><a?class="page-link"?href="/Blog/List?page=64&amp;categoryId=0">&gt;&gt;</a></li></ul>
</div>

顯示效果:

51babda73c16f3a2cb03e31f7fa21c7b.png
image

請求參數封裝

前面介紹的分頁需要在訪問頁面時傳入請求參數,這樣我們Controller的Action方法就需要加上pageNumberpageSize這兩個參數,后面還要加文章分類篩選和搜索排序什么的,這樣參數太多了,全都寫在Action方法的參數里不優雅,好在AspNetCore提供了class作為參數的寫法。

StarBlog.Web/ViewModels目錄下新建QueryFilters目錄,用來存不同接口的請求參數。

有些參數屬于不同接口都有的,合理利用面向對象,先寫個基類:QueryParameters.cs

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;?}
}

文章請求參數在此基礎上還增加了狀態、分類等,從上面這個基類派生一個新類就好:PostQueryParameters.cs

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";
}

service改造

我們的核心邏輯都是在service中實現的,請求參數肯定也要傳入給service來使用。

依然是先前的GetPagedList方法,給其加上各種篩選條件之后是這樣:

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);
}

根據傳入的參數,可以實現狀態過濾、分類過濾、關鍵詞過濾、排序和分頁功能。

ViewModel

一個MVC頁面只能指定一個Model,雖然可以用弱類型的ViewBag或者ViewData,但是弱類型不好維護,我們來定義一個ViewModel給頁面使用。

先確定要在文章列表頁面顯示哪些內容,例如顯示當前選擇的文章分類、所有分類列表。

StarBlog.WebViewModels目錄下,新建BlogListViewModel.cs,根據我們要展示的內容,定義模型如下

using?StarBlog.Data.Models;
using?X.PagedList;namespace?StarBlog.Web.ViewModels;?public?class?BlogListViewModel?{public?Category?CurrentCategory?{?get;?set;?}public?int?CurrentCategoryId?{?get;?set;?}public?IPagedList<Post>?Posts?{?get;?set;?}public?List<Category>?Categories?{?get;?set;?}
}

搞定。

controller改造

經過前面的鋪墊,controller這里就簡單了,不過還有要注意的地方,本項目是包含后端渲染和RESTFul接口兩部分的,因此controller要寫兩個,service只要一個就行。

RESTFul接口我后面再具體介紹,可以先看看改造后的RESTFul接口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()};
}

代碼很簡單,這個獲取文章列表的接口,就單純只需要給分頁和過濾后的列表數據就行。

而MVC的接口就沒這么簡單,要顯示在頁面上的東西,全都要在后端做渲染,包括我們在前面說的要顯示當前分類、所有分類列表。

代碼長這樣:

public?IActionResult?List(int?categoryId?=?0,?int?page?=?1,?int?pageSize?=?5)?{var?categories?=?_categoryRepo.Where(a?=>?a.Visible).IncludeMany(a?=>?a.Posts).ToList();categories.Insert(0,?new?Category?{?Id?=?0,?Name?=?"All",?Posts?=?_postRepo.Select.ToList()?});return?View(new?BlogListViewModel?{CurrentCategory?=?categoryId?==?0???categories[0]?:?categories.First(a?=>?a.Id?==?categoryId),CurrentCategoryId?=?categoryId,Categories?=?categories,Posts?=?_postService.GetPagedList(new?PostQueryParameters?{CategoryId?=?categoryId,Page?=?page,PageSize?=?pageSize,OnlyPublished?=?true})});
}

傳入參數只需要三個:

  • 分類ID

  • 當前頁面

  • 頁面大小

這個接口要做的事比較多

  • 獲取所有分類

  • 判斷當前分類

  • 獲取文章列表

最終返回我們前面定義的BlogListViewModel

然后在頁面模板里就可以用了。

View改造

第一件事把model換成BlogListViewModel

然后就是根據ViewModel里的數據進行頁面渲染,都是Bootstrap提供的頁面組件,代碼比較長我就不貼了,頁面模板的完整代碼可以在這看到:https://github.com/Deali-Axy/StarBlog/blob/master/StarBlog.Web/Views/Blog/List.cshtml

最終效果

截了個長圖,最終的頁面效果就是這樣了~

b5c004cc0ba7f4b5811682489e83269e.png
image

小結

如果你看到了這里,說明你是個有耐心的人 O(∩_∩)O哈哈~,同時對本項目是比較感興趣的,先感謝大家的支持~

本文一不小心就寫得比較長了,本來是想以那種每篇文章比較短的形式做一個連載,這樣讀起來不會有太大的壓力,沒想到稍微一展開講就涉及到很多內容,接下來的文章我得優化優化~

最近一段時間,公眾號后臺、微信都有收到朋友的催更,或者是抱怨我更新得太慢,實在是抱歉,最近被工作上的事情搞得有點暈頭轉向的,下班回家后晚上就只想看會書或者玩一下游戲放松,懈怠了,看到有這么多大佬在關注我的項目,頓時又充滿動力了!沖沖沖,接下來爭取每兩天更新一篇,歡迎繼續關注1ef1de0b2ce7d9449dfb20a1a9c10aa3.png~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/287331.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/287331.shtml
英文地址,請注明出處:http://en.pswp.cn/news/287331.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

時間序列matlab代碼,MATLAB在時間序列建模預測及程序代碼.pdf

第二十四章 時間序列模型時間序列是按時間順序排列的、隨時間變化且相互關聯的數據序列。分析時間序列的方法構成數據分析的一個重要領域&#xff0c;即時間序列分析。時間序列根據所研究的依據不同&#xff0c;可有不同的分類。1&#xff0e;按所研究的對象的多少分&#xff0…

Android之安卓8.0版本以上手機開啟熱點提示Caller already has an active LocalOnlyHotspot request

1 問題 在Android8.0手機開啟了熱點,關閉頁面再次打開熱點, /*** 開啟Android8.0版本手機以上的熱點,熱點名字和密碼都是隨機的。*/fun initWifiApGreaterThanEight(context: Context) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {var wifiManager:WifiMana…

JavaScript基礎和js概括

js內容概括&#xff1a; Html 結構化 CSS 樣式 JavaScript 行為交互 01.JavaScript基礎 02.JavaScript操作BOM對象 03.JavaScript操作DOM對象 ***** 04.JavaScript的面向對象 -------------------------------------- 05.jQuery (js) .css .js 06.jQuery選擇器 …

《看聊天記錄都學不會C語言?太菜了吧》(12)循環有多容易?你看一眼就懷...

若是大一學子或者是真心想學習剛入門的小伙伴可以私聊我&#xff0c;若你是真心學習可以送你書籍&#xff0c;指導你學習&#xff0c;給予你目標方向的學習路線&#xff0c;無套路&#xff0c;博客為證。 本系列文章將會以通俗易懂的對話方式進行教學&#xff0c;對話中將涵蓋…

***ECharts圖表入門和最佳實踐

ECharts數據圖表系統&#xff1f; 5分鐘上手&#xff01; 【ECharts簡介】 ECharts開源來自百度商業前端數據可視化團隊&#xff0c;基于html5 Canvas&#xff0c;是一個純Javascript圖表庫&#xff0c;提供直觀&#xff0c;生動&#xff0c;可交互&#xff0c;可個性化定制的數…

【經典回放】多種語言系列數據結構線性表之一:順序表

一、實驗任務描述 建立線性表的ADT后,編程完成: 1 用C語言完成一個順序表結構; 2 為順序表完成追加、刪除、插入、查找的功能; 3 建立一個鏈表的結點; 4 完成鏈表的追加、刪除、插入功能; 5* 用C#完成一個結點的類; 6* C#完成鏈表的追加、刪除、插入功能的類; 7* C#編寫…

原型繼承+原型鏈 + 對象繼承發展

一、原型繼承&#xff1a; &#xff11;、說起原型繼承&#xff0c;就要先由構造函數創造對象說起&#xff0c;首先了解構造函數內部基本原理&#xff1a; &#xff08;&#xff11;&#xff09;.在函數體最前面隱式的加上this {} &#xff08;&#xff12;&#xff09;.執行 …

Kotlin之?和!!最簡單的理解

一、? 1&#xff09;、?在聲明對象時&#xff0c;把它跟在類名后面&#xff0c;表示這個類允許為null var list: ArrayList<String>? null 2&#xff09;、調用對象時&#xff0c;把它跟在對象后面&#xff0c;表示如果為null程序就會視而不見&#xff0c;比如我們…

WPF|一個比較簡單帶點設計的登錄界面

閱讀目錄效果展示準備簡單說明 源碼結尾&#xff08;視頻及源碼倉庫&#xff09;1. 效果展示欣賞效果&#xff1a;2. 準備創建一個WPF工程&#xff0c;比如站長使用 .NET 7[1] 創建名為 Login5 的WPF項目。找一張圖片做為裝飾&#xff0c;放登錄表單左側&#xff1a;添加Nuget…

Android插件基礎之類加載器學習

記錄學習java 加載器學習所獲心得&#xff0c;逐步記錄了解java加載器的過程。為了知悉android 插件化的實現原理&#xff0c;從而需要從頭了解android加載apk&#xff0c;以及基礎的java類加載的加載過程情況&#xff0c;為方便記錄和記憶&#xff0c;故此將學習了解的過程記錄…

php多個文件上傳代碼,PHP單文件上傳類或多文件上傳類源碼

以下為引用的內容&#xff1a;php文件:代碼://如果收到表單傳來的參數&#xff0c;則進行上傳處理&#xff0c;否則顯示表單if(isset($_FILES[uploadinput])){//建目錄函數&#xff0c;其中參數$directoryName最后沒有"/"&#xff0c;//要是有的話&#xff0c;以/打散…

《看聊天記錄都學不會C語言?太菜了吧》(13)(9*9 乘法表)尋找電腦中的盲盒彩蛋

若是大一學子或者是真心想學習剛入門的小伙伴可以私聊我&#xff0c;若你是真心學習可以送你書籍&#xff0c;指導你學習&#xff0c;給予你目標方向的學習路線&#xff0c;無套路&#xff0c;博客為證。 本系列文章將會以通俗易懂的對話方式進行教學&#xff0c;對話中將涵蓋…

Fragment使用--文章集錦

android使用Fragment實現底部菜單使用show()和hide()來切換以保持Fragment狀態Android Fragment 真正的完全解析&#xff08;上&#xff09;Android Fragment實踐(一)糾正對Fragment Transaction BackStack的誤解多個Fragment 切換時不重新實例化Fragment詳解之四——管理Fragm…

Android之在在EditText的xml里面配置了相關屬性依然沒有顯示光標問題

1 問題 在EditText的xml里面配置了 android:cursorVisible"true" android:focusable"true" android:focusableInTouchMode"true" 依然沒有光標顯示 2 解決辦法 直接在代碼層控制&#xff0c;平且拉起鍵盤 fun showSoftInputFromWindow(activ…

【經典回放】多種語言系列數據結構線性表之二:鏈表

目錄 1 鏈表結構設計 2 簡單的鏈表測試 2 鏈表的組織和ADT設計 3 初始化有頭結點鏈表 4 有頭結點鏈表中追加一個結點(一行數據)

使用 Postman 實現 API 自動化測試

1背景介紹 相信大部分開發人員和測試人員對 postman 都十分熟悉&#xff0c;對于開發人員和測試人員而言&#xff0c;使用 postman 來編寫和保存測試用例會是一種比較方便和熟悉的方式。但 postman 本身是一個圖形化軟件&#xff0c;相對較難或較麻煩&#xff08;如使用 …

php json -gt;訪問,【轉】Php+ajax+jsonp解決ajax跨域問題

首先&#xff1a;jsonp是json用來跨域的一個東西。原理是通過script標簽的跨域特性來繞過同源策略。發送端&#xff1a;$.ajax({type : "post",url : "ajax.php",dataType : "jsonp",jsonp: "callback",//傳遞給請求處理程序或頁面的&…

《看聊天記錄都學不會Python到游戲實戰?太菜了吧》(1)加載Python神器!亮劍!

本系列文章將會以通俗易懂的對話方式進行教學&#xff0c;對話中將涵蓋了新手在學習中的一般問題。此系列將會持續更新&#xff0c;包括別的語言以及實戰都將使用對話的方式進行教學&#xff0c;基礎編程語言教學適用于零基礎小白&#xff0c;之后實戰課程也將會逐步更新。 若…

little tricks(持續更新)【python】

python中的list有reverse方法&#xff0c;但是字符串卻沒有&#xff0c;怎么辦呢&#xff1f; csdn博主有列了幾個方法&#xff0c;我覺得第一個最簡單直接&#xff0c;str[::-1]搞定。 當然也有一種怪異的方法&#xff0c;我把字符串轉為序列reverse一下&#xff0c;再轉回來不…

Codeigniter 3 拓展HMVC

2019獨角獸企業重金招聘Python工程師標準>>> 在Codeiniter&#xff08;以下統稱CI&#xff09; 2.X版本中&#xff0c;我們就通過拓展核心類庫實現了HMVC&#xff0c;但是同樣的代碼&#xff0c;拿到CI 3中&#xff0c;就很有可能不好用了。 ###拓展核心類庫方式 官…