基於.NetCore開發部落格專案 StarBlog - (3) 模型設計

程式設計實驗室發表於2022-04-22

系列文章

  • 基於.NetCore開發部落格專案 StarBlog - (1) 為什麼需要自己寫一個部落格?
  • 基於.NetCore開發部落格專案 StarBlog - (2) 環境準備和建立專案
  • 基於.NetCore開發部落格專案 StarBlog - (3) 模型設計
  • ...
  • 基於.NetCore開發部落格專案 StarBlog - 介面返回值包裝
  • 基於.NetCore開發部落格專案 StarBlog - 上傳圖片功能
  • 基於.NetCore開發部落格專案 StarBlog - 身份認證功能
  • 基於.NetCore開發部落格專案 StarBlog - 前端相關
  • 基於.NetCore開發部落格專案 StarBlog - 前端開發 (1) 準備篇
  • 基於.NetCore開發部落格專案 StarBlog - 前端開發 (2) 頁面路由
  • 基於.NetCore開發部落格專案 StarBlog - 前端開發 (3) SASS與SCSS
  • 基於.NetCore開發部落格專案 StarBlog - 前端開發 (4) FontAwesome圖示
  • 基於.NetCore開發部落格專案 StarBlog - 前端開發 (5) Axios網路請求封裝
  • 基於.NetCore開發部落格專案 StarBlog - 前端開發 (6) 登入頁面
  • 基於.NetCore開發部落格專案 StarBlog - 前端開發 (7) 主頁面
  • 基於.NetCore開發部落格專案 StarBlog - 前端開發 (8) Vuex與狀態管理
  • 基於.NetCore開發部落格專案 StarBlog - 前端開發之檔案上傳
  • 基於.NetCore開發部落格專案 StarBlog - 前端開發之瀑布流圖片列表
  • 基於.NetCore開發部落格專案 StarBlog - 前端開發之導航守衛
  • ...

前言

上一篇文章介紹(水)了新建專案的操作,本文開始終於進入正題要開始寫程式碼了!

對了,上一篇文章有朋友留言問管理端的使用者名稱和密碼是多少,這個是我疏忽了,沒有做一個便捷的專案初始化功能,目前登入管理端需要在資料庫的User表建立一個使用者,後續我會完善角色和許可權控制部分,然後給專案加一些命令列工具,就像django-admin那樣。

OK,本文介紹StarBlog部落格專案的模型設計。

模型設計

根據部落格的功能需求,資料分成三類:

  • 文章相關(文章、文章分類)
  • 攝影/相簿相關
  • 推薦內容配置(推薦文章、分類、圖片;置頂文章、分類)

程式碼

由於我還沒學DDD,(後續學了Abp vNext框架的話可能會用新技術進行重構),所以先用傳統的MVC架構來規劃專案~

回顧上一篇文章,我們新建了幾個專案,現在,我們要把資料模型寫在StarBlog.Data專案中。

開啟IDE,在StarBlog.Data專案中新建一個目錄,名為 Models,接下來的資料模型全都要放到這個目錄/名稱空間下。

由於專案程式碼已經在GitHub開源了,資料模型程式碼我就不全部貼上來了,先看看建立完成之後的目錄結構。

程式碼可以這裡看到:https://github.com/Deali-Axy/StarBlog/tree/master/StarBlog.Data/Models

Models
├── Category.cs			 # 文章分類
├── FeaturedCategory.cs  # 推薦分類
├── FeaturedPhoto.cs     # 推薦圖片
├── FeaturedPost.cs      # 推薦文章
├── Photo.cs             # 攝影圖片
├── Post.cs              # 文章
├── TopPost.cs           # 置頂文章
└── User.cs              # 使用者

為了便於讀者理解專案設計和模型間的關係,我們挑幾個關鍵的說一下。

Category.cs

文章分類。完整程式碼見:https://github.com/Deali-Axy/StarBlog/blob/master/StarBlog.Data/Models/Category.cs

StarBlog部落格支援markdown批量匯入,然後以目錄結構作為文章的分類,目錄名就是分類名,且支援多級分類。

部分程式碼如下:

public class Category {
    public int Id { get; set; }
    public string Name { get; set; }
    public int ParentId { get; set; }
    public bool Visible { get; set; } = true;
}

Post.cs

完整程式碼見:https://github.com/Deali-Axy/StarBlog/blob/master/StarBlog.Data/Models/Post.cs

部落格網站,最重要的就是文章,文章的模型部分程式碼如下

namespace StarBlog.Data.Models;

public class Post {
    // 省略部分欄位...
    public string? Status { get; set; }
    public bool IsPublish { get; set; }
    public string? Path { get; set; }
    public DateTime CreationTime { get; set; }
    public DateTime LastUpdateTime { get; set; }
    public string? Categories { get; set; }
}

首先看StatusIsPublish欄位,一個是文章狀態(未完成、未修改、未釋出),一個是否釋出。最終決定文章是否在網站上展示是IsPublish欄位,那Status欄位存在的意義是啥?

答案:為了保留匯入前的文章狀態。

本專案的部落格支援匯入整個目錄markdown檔案作為文章,我的習慣是會在markdown檔案的檔名最前面寫上這個文章的狀態,比如一篇未完成的文章,它的檔名是:(未完成)StarBlog部落格開發筆記(3):模型設計,所以這個Status欄位就是要把(未完成)中的這個狀態識別提取出來,(具體用到的是正規表示式,這是後面要介紹的內容)。

然後是Path欄位,這個欄位表示文章作為markdown檔案匯入前存放的相對位置,比如匯入了D:\blog這個目錄裡的所有文章,而這個目錄的結構是這樣的:

blog
├── Asp-Net-Core學習筆記
│   ├── Asp-Net-Core學習筆記:1.MVC入門篇.md
│   ├── Asp-Net-Core學習筆記:2.MVC檢視、模型、持久化、檔案、錯誤處理、日誌.md
│   ├── Asp-Net-Core學習筆記:3.使用SignalR實時通訊框架開發聊天室.md
│   ├── Asp-Net-Core學習筆記:4.Blazor-WebAssembly入門.md
│   ├── Asp-Net-Core學習筆記:5.構建和部署.md
│   ├── Asp-Net-Core學習筆記:WebApi開發實踐.md
│   ├── Asp-Net-Core學習筆記:身份認證入門.md
│   ├── Asp-Net-Core學習筆記:部署,早知道,還是docker,以及一點碎碎念.md
├── Asp-Net-Core開發筆記
│   ├── Asp-Net-Core開發筆記:使用NPM和gulp管理前端靜態檔案.md
│   ├── Asp-Net-Core開發筆記:在docker部署時遇到一個小坑.md
│   └── Asp-Net-Core開發筆記:介面返回json物件出現套娃遞迴問題.md
├── 不吹不黑,跨平臺框架AspNetCore開發實踐雜談.md
├── 夢想裝潢平臺開發記錄,Asp-Net-Core上手實踐.md
├── (未修改)How-to-Connect-to-MySQL-from--NET-Core.md
├── (未修改)使用Ocelot實現Api閘道器.md
├── (未釋出)跨域配置.md
├── (未完成)ASP-NET-Core-使用-Hangfire-定時任務.md
├── (未完成)Core-定時任務之HangFire.md
├── (未完成)使用-ASP-NET-Core-和-Hangfire-實現-HTTP-非同步化方案.md
├── (未完成)使用Sentry.md
└── (未完成)在xunit裡使用依賴注入.md

那對於在blog/AspNetCore目錄下的文章(未釋出)跨域配置.md 來說,它的Path欄位就是AspNetCore

對於在blog/AspNetCore/Asp-Net-Core學習筆記目錄下的文章來說,Path欄位就是AspNetCore/Asp-Net-Core學習筆記

這個Path欄位的意義,就在於實現前面說的多級分類,同時最下面的Categories欄位,也是為了實現多級分類準備的。

在文章匯入的過程中,目錄名稱作為文章分類名建立了文章的分類,同時記錄分類ID到文章的CategoryId欄位中,如果是多級分類的話,文章的CategoryId欄位記錄的是最後一個分類,父分類是不在這個CategoryId裡的,雖然Category有個ParentId欄位可以找到父分類,但是在實際使用的時候比較麻煩,所以我又加了這個 Categories 欄位,把文章的分類層級記錄起來,其內容類似這樣 1,2,3 ,用逗號分隔開分類ID

這樣前臺展示的時候只需要用 servicesCategories 欄位處理成 List<Category> 就可以了。

Photo.cs

對了,還有圖片模型,因為平時有空會拍照,所以做個攝影分享的功能,這個模型就存上傳的圖片。

部分程式碼如下

public class Photo {
    // 省略部分欄位...
    public string Location { get; set; }
    public string FilePath { get; set; }
    public long Height { get; set; }
    public long Width { get; set; }
}

圖片的高度和寬度欄位我一開始是沒考慮的,不過在做瀑布流展示的時候發現沒有寬高度不行,於是找到了 SixLabors.ImageSharp 這個庫讀取圖片資訊,這個庫功能還挺強的,推薦一波~

Location拍攝地點現在只能手動輸入,我之前用Python做過一個相簿的專案,可以根據圖片的Exif資訊讀取拍攝的GPS資訊,然後用逆地址解析的方法解析出拍攝的地址,這個先記個todo,後面來實現~

其他的

三個Featured開頭的是推薦相關的,可以在後臺配置;

然後置頂文章和置頂分類只能分別設定一個,展示在網站主頁。

大概就這些了,下篇文章見~

同時所有專案程式碼已經上傳GitHub,歡迎各位大佬Star/Fork!

相關文章