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


    系列文章

    前言

    上一篇文章介绍(水)了新建项目的操作,本文开始终于进入正题要开始写代码了!

    对了,上一篇文章有朋友留言问管理端的用户名和密码是多少,这个是我疏忽了,没有做一个便捷的项目初始化功能,目前登录管理端需要在数据库的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!


    __EOF__

  • 本文作者: 程序设计实验室
  • 本文链接: https://www.cnblogs.com/deali/p/16180920.html
  • 关于博主: 公众号:程序设计实验室,欢迎交流~
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    2022年潜江中级工程师职称查询方式有哪些呢?甘建二
    C++ Tutorials: C++ Language: Compound data types: Pointers
    嵌入式数据库sqlite3
    设计模式【5】——观察者模式
    top 修改进程的优先级
    软件工程开发和文档流程(及概要设计+详细设计)
    调试linux内核(1): 环境准备和原理介绍
    隐藏Zotero批注图标(便利贴)
    .net----泛型
    谷歌浏览器 ERR_MANDATORY_PROXY_CONFIGURATION_FAILED 报错的处理方式
  • 原文地址:https://www.cnblogs.com/deali/p/16180920.html