前言九月太忙 , 只更新了三篇文章,本来这个功能是从九月初就开始做的 , 结果一直拖到现在国庆假期才有时间完善并且写文章~
之前我更新了几篇关于 Python 的文章 , 有朋友留言问是不是不更新 .Net 了 , 那肯定不能?。抑荒芩怠肝?全 都 要」 , 所以我反手就更新了一篇Asp-Net-Core开发笔记 。
然后顺便立个Flag:今年底前完成StarBlog系列文章的主体部分(即API开发+后台前端开发,目前只完成博客前后端部分),加油吧~
【18 基于.NetCore开发博客项目 StarBlog -实现本地Typora文章打包上传】OK,说回本文,程序员都喜欢用Markdown来写文章 , 但由于markdown是纯文本格式,在其中插入的图片要如何保存,就成了一大烦恼,有人选择图床,但不一定永久有效;有人选择本地存储,图片永久有效,但如何分享文章又成了一个难题…
我选的就是第二种 , 本地存储 。使用Typora写文章 , 图片保存在和Markdown文件同名的目录(markdown.assets)下,这样可以获得很好的写作体验,然后分享的问题就交给StarBlog吧,这个项目开发的初衷就是为了把本地的文章发表成博客 。
不过之前只有批量导入文章的功能,现在我要做的就是单独实现一个单篇文章打包导入的功能 。
随着文章越来越多,系列文章的目录放前面有点影响阅读了,所以从这篇开始我把它放到最后面~实现思路假设我用Typora写了一篇Markdown文章,文件名为:
StarBlog.md
,并且在里面插入了若干图片,根据配置 , Typora会自动生成一个目录(StarBlog.assets
)来存放这些图片 。为了实现导入,我要把这个markdown文件和这个存图片的目录一起打包成zip压缩文件上传,后端将zip压缩包解压到临时目录 , 读取Markdown文件,解析其中的内容,进行导入操作 。
代码实现OK,开始写代码吧
同时所有项目代码已经上传GitHub,欢迎各位大佬Star/Fork!
- 博客后端+前台项目地址:https://github.com/Deali-Axy/StarBlog
- 管理后台前端项目地址:https://github.com/Deali-Axy/StarBlog-Admin
ZipFile
这个库用于操作zip压缩包,在 System.IO.Compression
里,直接用就完事了 。解压前得先把文件复制到临时目录,并创建一个新的临时目录来放解压后的文件 。
在
Services/BlogServices.cs
里新增代码public async Task<Post> Upload(PostCreationDto dto, IFormFile file) {// 先复制到临时文件var tempFile = Path.GetTempFileName();await using (var fs = new FileStream(tempFile, FileMode.Create)) {await file.CopyToAsync(fs);}// 设定解压用的临时目录var extractPath = Path.Combine(Path.GetTempPath(), "StarBlog", Guid.NewGuid().ToString());// 使用 GBK 编码解压,防止中文文件名乱码Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);ZipFile.ExtractToDirectory(tempFile, extractPath, Encoding.GetEncoding("GBK"));}
本来直接 ZipFile.ExtractToDirectory()
就能解压了,但如果压缩包里的文件用了中文名,就得先设置编码 。解析Markdown关于 C# 解析 Markdown ,在本系列一开始就写过,所以这里就不再当复读机了,可以直接看这两篇文章:
- 基于.NetCore开发博客项目 StarBlog - (4) markdown博客批量导入
- C#解析Markdown文档,实现替换图片链接操作
因为是做单篇文章导入,所以我这里获取临时目录写的所有
*.md
文件之后只取第一个文件来处理(理论上也不应该有多个~)var dir = new DirectoryInfo(extractPath);var files = dir.GetFiles("*.md");var mdFile = files.First();using var reader = mdFile.OpenText();var content = await reader.ReadToEndAsync();var post = new Post {Id = GuidUtils.GuidTo16String(),Status = "已发布",Title = dto.Title ?? $"{DateTime.Now.ToLongDateString()} 文章",IsPublish = true,Content = content,Path = "",CreationTime = DateTime.Now,LastUpdateTime = DateTime.Now,CategoryId = dto.CategoryId,};var assetsPath = Path.Combine(_environment.WebRootPath, "media", "blog");var processor = new PostProcessor(extractPath, assetsPath, post);// 处理文章标题和状态processor.InflateStatusTitle();// 处理文章正文内容// 导入文章的时候一并导入文章里的图片 , 并对图片相对路径做替换操作post.Content = processor.MarkdownParse();post.Summary = processor.GetSummary(200);
Markdown相关的处理,我封装了 PostProcessor
这个对象,在 StarBlog.Share
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 一 CPS攻击案例——基于脉冲宽度调制PWM的无人机攻击
- Vue3 Vite3 多环境配置 - 基于 vite 创建 vue3 全家桶项目(续篇)
- 2 Libgdx游戏开发——接水滴游戏实现
- 五 Qt+ECharts开发笔记:ECharts的动态排序柱状图介绍、基础使用和Qt封装Demo
- 18-基于CentOS7搭建RabbitMQ3.10.7集群镜像队列+HaProxy+Keepalived高可用架构
- Asp-Net-Core开发笔记:集成Hangfire实现异步任务队列和定时任务
- 【疫情动态条形图】用Python开发全球疫情排名动态条形图bar_chart_race
- 驱动开发:通过Async反向与内核通信
- 云原生下基于K8S声明式GitOps持续部署工具ArgoCD实战-上
- gRPC+Protocol Buffer Go微服务实战 - 用户服务开发