基于.NetCore開發博客項目 StarBlog - (25) 圖片接口與文件上傳
前言
上傳文件的接口設計有兩種風格,一種是整個項目只設置一個接口用來上傳,然后其他需要用到文件的地方,都只存一個引用ID;另一種是每個需要文件的地方單獨管理各自的文件。這倆各有優劣吧,本項目中選擇的是后者的風格,文章圖片和照片模塊又要能CRUD又要批量導入,還是各自管理文件比較好。
圖片接口
說會正題,先介紹一下圖片相關接口。
圖片列表
首先CRUD是肯定有的,圖片列表的分頁查看也是有的,不過因為篩選功能沒有做,所以就不定義一個ViewModel作為參數了。
控制器代碼 StarBlog.Web/Apis/Blog/PhotoController.cs
[HttpGet]
public ApiResponsePaged<Photo> GetList(int page = 1, int pageSize = 10) {
var paged = _photoService.GetPagedList(page, pageSize);
return new ApiResponsePaged<Photo> {
Pagination = paged.ToPaginationMetadata(),
Data = paged.ToList()
};
}
跟博客前臺公用一套圖片列表邏輯,所以這部分抽出來放在service,代碼如下
StarBlog.Web/Services/PhotoService.cs
public IPagedList<Photo> GetPagedList(int page = 1, int pageSize = 10) {
return _photoRepo.Select.OrderByDescending(a => a.CreateTime)
.ToList().ToPagedList(page, pageSize);
}
單個圖片
獲取單個圖片,跟獲取文章的差不多,傳入ID,找不到就返回404,找到就返回圖片對象
[HttpGet("{id}")]
public ApiResponse<Photo> Get(string id) {
var photo = _photoService.GetById(id);
return photo == null
? ApiResponse.NotFound($"圖片 {id} 不存在")
: new ApiResponse<Photo> {Data = photo};
}
圖片縮略圖
在本系列第20篇中,本項目已經實現了圖片顯示的優化,詳見:基于.NetCore開發博客項目 StarBlog - (20) 圖片顯示優化
除了 ImageSharp 組件提供的圖片縮略圖功能外,我這里還寫了另一個生成縮略圖的方法,這個方法有倆特點
- 直接在內存中生成返回,不會寫入緩存文件
- 生成的是Progressive JPEG格式,目前 ImageSharp 是不支持的,可以優化前端的加載速度
控制器代碼
[HttpGet("{id}/Thumb")]
public async Task<IActionResult> GetThumb(string id, [FromQuery] int width = 300) {
var data = await _photoService.GetThumb(id, width);
return new FileContentResult(data, "image/jpeg");
}
service代碼
/// <summary>
/// 生成Progressive JPEG縮略圖 (使用 MagickImage)
/// </summary>
/// <param name="width">設置為0則不調整大小</param>
public async Task<byte[]> GetThumb(string id, int width = 0) {
var photo = await _photoRepo.Where(a => a.Id == id).FirstAsync();
using (var image = new MagickImage(GetPhotoFilePath(photo))) {
image.Format = MagickFormat.Pjpeg;
if (width != 0) {
image.Resize(width, 0);
}
return image.ToByteArray();
}
}
這個 MagickImage 是用 C++ 寫的,在不同平臺上引用不同 native 庫,需要在 csproj 里面寫上配置,這樣發布的時候才會帶上對應的依賴庫,而且似乎在 CentOS 系統上會有坑…
<!-- 復制 Magick 庫 -->
<PropertyGroup>
<MagickCopyNativeWindows>true</MagickCopyNativeWindows>
<MagickCopyNativeLinux>true</MagickCopyNativeLinux>
<MagickCopyNativeMacOS>true</MagickCopyNativeMacOS>
</PropertyGroup>
其他接口
還有一些接口,跟之前介紹的大同小異,再重復一次也意義不大,讀者有需要的話可以自行查看源碼。
- 刪除圖片
- 設置和取消推薦
- 重建圖片庫數據(更新每個圖片的尺寸等數據,一般情況下不需要用到)
- 批量導入(本系列的第9篇已經介紹過)詳見:基于.NetCore開發博客項目 StarBlog - (9) 圖片批量導入
圖片文件上傳
這個同時也是圖片的添加接口
先定義DTO
public class PhotoCreationDto {
/// <summary>
/// 作品標題
/// </summary>
[Required(ErrorMessage = "作品標題不能為空")]
public string Title { get; set; }
/// <summary>
/// 拍攝地點
/// </summary>
[Required(ErrorMessage = "拍攝地點不能為空")]
public string Location { get; set; }
}
控制器代碼
[Authorize]
[HttpPost]
public ApiResponse<Photo> Add([FromForm] PhotoCreationDto dto, IFormFile file) {
var photo = _photoService.Add(dto, file);
return !ModelState.IsValid
? ApiResponse.BadRequest(ModelState)
: new ApiResponse<Photo>(photo);
}
因為上傳的同時還要附帶一些數據,需要使用 FormData 傳參,所以這里使用 [FromForm] 特性標記這個 dto 參數
IFormFile 類型的參數可以拿到上傳上來的文件
下面是service代碼
public Photo Add(PhotoCreationDto dto, IFormFile photoFile) {
var photoId = GuidUtils.GuidTo16String();
var photo = new Photo {
Id = photoId,
Title = dto.Title,
CreateTime = DateTime.Now,
Location = dto.Location,
FilePath = Path.Combine("photography", $"{photoId}.jpg")
};
var savePath = Path.Combine(_environment.WebRootPath, "media", photo.FilePath);
// 如果超出最大允許的大小,則按比例縮小
const int maxWidth = 2000;
const int maxHeight = 2000;
using (var image = Image.Load(photoFile.OpenReadStream())) {
if (image.Width > maxWidth)
image.Mutate(a => a.Resize(maxWidth, 0));
if (image.Height > maxHeight)
image.Mutate(a => a.Resize(0, maxHeight));
image.Save(savePath);
}
// 保存文件
using (var fs = new FileStream(savePath, FileMode.Create)) {
photoFile.CopyTo(fs);
}
// 讀取圖片的尺寸等數據
photo = BuildPhotoData(photo);
return _photoRepo.Insert(photo);
}
這里對圖片做了一些處理,拋開這些細節,其實對上傳的文件,最關鍵的只有幾行保存代碼
using (var fs = new FileStream("savePath", FileMode.Create)) {
photoFile.CopyTo(fs);
}
這樣就完成了文件上傳接口。
系列文章
- 基于.NetCore開發博客項目 StarBlog - (1) 為什么需要自己寫一個博客?
- 基于.NetCore開發博客項目 StarBlog - (2) 環境準備和創建項目
- 基于.NetCore開發博客項目 StarBlog - (3) 模型設計
- 基于.NetCore開發博客項目 StarBlog - (4) markdown博客批量導入
- 基于.NetCore開發博客項目 StarBlog - (5) 開始搭建Web項目
- 基于.NetCore開發博客項目 StarBlog - (6) 頁面開發之博客文章列表
- 基于.NetCore開發博客項目 StarBlog - (7) 頁面開發之文章詳情頁面
- 基于.NetCore開發博客項目 StarBlog - (8) 分類層級結構展示
- 基于.NetCore開發博客項目 StarBlog - (9) 圖片批量導入
- 基于.NetCore開發博客項目 StarBlog - (10) 圖片瀑布流
- 基于.NetCore開發博客項目 StarBlog - (11) 實現訪問統計
- 基于.NetCore開發博客項目 StarBlog - (12) Razor頁面動態編譯
- 基于.NetCore開發博客項目 StarBlog - (13) 加入友情鏈接功能
- 基于.NetCore開發博客項目 StarBlog - (14) 實現主題切換功能
- 基于.NetCore開發博客項目 StarBlog - (15) 生成隨機尺寸圖片
- 基于.NetCore開發博客項目 StarBlog - (16) 一些新功能 (監控/統計/配置/初始化)
- 基于.NetCore開發博客項目 StarBlog - (17) 自動下載文章里的外部圖片
- 基于.NetCore開發博客項目 StarBlog - (18) 實現本地Typora文章打包上傳
- 基于.NetCore開發博客項目 StarBlog - (19) Markdown渲染方案探索
- 基于.NetCore開發博客項目 StarBlog - (20) 圖片顯示優化
- 基于.NetCore開發博客項目 StarBlog - (21) 開始開發RESTFul接口
- 基于.NetCore開發博客項目 StarBlog - (22) 開發博客文章相關接口
- 基于.NetCore開發博客項目 StarBlog - (23) 文章列表接口分頁、過濾、搜索、排序
- 基于.NetCore開發博客項目 StarBlog - (24) 統一接口數據返回格式
- 基于.NetCore開發博客項目 StarBlog - (25) 圖片接口與文件上傳

浙公網安備 33010602011771號