平安校园
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 
 
 

274 行
9.5 KiB

  1. //
  2. namespace SafeCampus.System;
  3. /// <summary>
  4. /// <inheritdoc cref="IFileService"/>
  5. /// </summary>
  6. public class FileService : DbRepository<SysFile>, IFileService
  7. {
  8. private readonly IConfigService _configService;
  9. public FileService(IConfigService configService)
  10. {
  11. _configService = configService;
  12. }
  13. /// <inheritdoc/>
  14. public async Task<SqlSugarPagedList<SysFile>> Page(FilePageInput input)
  15. {
  16. var query = Context.Queryable<SysFile>().WhereIF(!string.IsNullOrEmpty(input.Engine), it => it.Engine == input.Engine)//根据关键字查询
  17. .WhereIF(!string.IsNullOrEmpty(input.SearchKey), it => it.Name.Contains(input.SearchKey))//根据关键字查询
  18. .OrderByIF(!string.IsNullOrEmpty(input.SortField), $"{input.SortField} {input.SortOrder}")//排序
  19. .OrderBy(it => it.Id);
  20. var pageInfo = await query.ToPagedListAsync(input.PageNum, input.PageSize);//分页
  21. return pageInfo;
  22. }
  23. /// <inheritdoc/>
  24. public async Task<long> UploadFile(string engine, IFormFile file)
  25. {
  26. return await StorageFile(engine, file);
  27. }
  28. /// <inheritdoc/>
  29. public async Task Delete(BaseIdListInput input)
  30. {
  31. var ids = input.Ids;//获取ID
  32. await DeleteByIdsAsync(ids.Cast<object>().ToArray());//根据ID删除数据库
  33. }
  34. /// <inheritdoc/>
  35. public FileStreamResult GetFileStreamResult(string path, string fileName, bool isPathFolder = false)
  36. {
  37. if (isPathFolder) path = path.CombinePath(fileName);
  38. fileName = HttpUtility.UrlEncode(fileName, Encoding.GetEncoding("UTF-8"));//文件名转utf8不然前端下载会乱码
  39. //文件转流
  40. var result = new FileStreamResult(new FileStream(path, FileMode.Open), "application/octet-stream")
  41. {
  42. FileDownloadName = fileName
  43. };
  44. return result;
  45. }
  46. public async Task<FileStreamResult> GetFileStreamResultFromMinio(string objectName, string fileName)
  47. {
  48. var minioService = App.GetService<MinioUtils>();
  49. var stream = await minioService.DownloadFileAsync(objectName);
  50. fileName = HttpUtility.UrlEncode(fileName, Encoding.GetEncoding("UTF-8"));//文件名转utf8不然前端下载会乱码
  51. //文件转流
  52. var result = new FileStreamResult(stream, "application/octet-stream")
  53. {
  54. FileDownloadName = fileName
  55. };
  56. return result;
  57. }
  58. /// <inheritdoc/>
  59. public FileStreamResult GetFileStreamResult(byte[] byteArray, string fileName)
  60. {
  61. fileName = HttpUtility.UrlEncode(fileName, Encoding.GetEncoding("UTF-8"));//文件名转utf8不然前端下载会乱码
  62. //文件转流
  63. var result = new FileStreamResult(new MemoryStream(byteArray), "application/octet-stream")
  64. {
  65. FileDownloadName = fileName
  66. };
  67. return result;
  68. }
  69. /// <inheritdoc/>
  70. public async Task<FileStreamResult> Download(BaseIdInput input)
  71. {
  72. var devFile = await GetByIdAsync(input.Id);
  73. if (devFile != null)
  74. {
  75. if (devFile.Engine == SysDictConst.FILE_ENGINE_LOCAL)
  76. return GetFileStreamResult(devFile.StoragePath, devFile.Name);
  77. if (devFile.Engine == SysDictConst.FILE_ENGINE_MINIO)
  78. return await GetFileStreamResultFromMinio(devFile.ObjName, devFile.Name);
  79. return null;
  80. }
  81. return null;
  82. }
  83. #region 方法
  84. /// <summary>
  85. /// 存储文件
  86. /// </summary>
  87. /// <param name="engine"></param>
  88. /// <param name="file"></param>
  89. private async Task<long> StorageFile(string engine, IFormFile file)
  90. {
  91. var bucketName = string.Empty;// 存储桶名称
  92. var storageUrl = string.Empty;// 定义存储的url,本地文件返回文件实际路径,其他引擎返回网络地址
  93. var objName = string.Empty;// 定义存储的url,本地文件返回文件实际路径,其他引擎返回网络地址
  94. var objectId = CommonUtils.GetSingleId();//生成id
  95. switch (engine)
  96. {
  97. //存储本地
  98. case SysDictConst.FILE_ENGINE_LOCAL:
  99. bucketName = "defaultBucketName";// 存储桶名称
  100. storageUrl = await StorageLocal(objectId, file);
  101. break;
  102. //存储本地
  103. case SysDictConst.FILE_ENGINE_MINIO:
  104. var config = await _configService.GetByConfigKey(CateGoryConst.CONFIG_FILE_MINIO, SysConfigConst.FILE_MINIO_DEFAULT_BUCKET_NAME);
  105. if (config != null)
  106. {
  107. bucketName = config.ConfigValue;// 存储桶名称
  108. (objName, storageUrl) = await StorageMinio(objectId, file);
  109. }
  110. break;
  111. default:
  112. throw Oops.Bah("不支持的文件引擎");
  113. }
  114. var fileSizeKb = (long)(file.Length / 1024.0);// 文件大小KB
  115. var fileSuffix = Path.GetExtension(file.FileName).ToLower();// 文件后缀
  116. var devFile = new SysFile
  117. {
  118. Id = objectId,
  119. Engine = engine,
  120. Bucket = bucketName,
  121. Name = file.FileName,
  122. Suffix = fileSuffix.Split(".")[1],
  123. ObjName = objName,
  124. SizeKb = fileSizeKb,
  125. SizeInfo = GetSizeInfo(fileSizeKb),
  126. StoragePath = storageUrl
  127. };
  128. if (engine != CateGoryConst.CONFIG_FILE_LOCAL)//如果不是本地,设置下载地址
  129. {
  130. devFile.DownloadPath = storageUrl;
  131. }
  132. //如果是图片,生成缩略图
  133. if (IsPic(fileSuffix))
  134. {
  135. //$"data:image/png;base64," + imgByte;
  136. await using var fileStream = file.OpenReadStream();//获取文件流
  137. var image = SKImage.FromEncodedData(fileStream);//获取图片
  138. var bmp = SKBitmap.FromImage(image);
  139. var thubnail = bmp.GetPicThumbnail(100, 100);//压缩图片
  140. var thubnailBase64 = ImageUtil.ImgToBase64String(thubnail);//转base64
  141. devFile.Thumbnail = "data:image/png;base64," + thubnailBase64;
  142. }
  143. await InsertAsync(devFile);
  144. return objectId;
  145. }
  146. /// <summary>
  147. /// 存储本地文件
  148. /// </summary>
  149. /// <param name="fileId"></param>
  150. /// <param name="file"></param>
  151. private async Task<string> StorageLocal(long fileId, IFormFile file)
  152. {
  153. string uploadFileFolder;
  154. var configKey = string.Empty;
  155. //判断是windows还是linux
  156. if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
  157. {
  158. configKey = SysConfigConst.FILE_LOCAL_FOLDER_FOR_UNIX;//Linux
  159. }
  160. else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
  161. {
  162. configKey = SysConfigConst.FILE_LOCAL_FOLDER_FOR_WINDOWS;//Windows
  163. }
  164. //获取路径配置
  165. var config = await _configService.GetByConfigKey(CateGoryConst.CONFIG_FILE_LOCAL, configKey);
  166. if (config != null)
  167. {
  168. uploadFileFolder = config.ConfigValue;//赋值路径
  169. var now = DateTime.Now.ToString("d");
  170. var filePath = Path.Combine(uploadFileFolder, now);
  171. if (!Directory.Exists(filePath))//如果不存在就创建文件夹
  172. Directory.CreateDirectory(filePath);
  173. var fileSuffix = Path.GetExtension(file.FileName).ToLower();// 文件后缀
  174. var fileObjectName = $"{fileId}{fileSuffix}";//存储后的文件名
  175. var fileName = Path.Combine(filePath, fileObjectName);//获取文件全路局
  176. fileName = fileName.Replace("\\", "/");//格式化一系
  177. //存储文件
  178. using (var stream = File.Create(Path.Combine(filePath, fileObjectName)))
  179. {
  180. await file.CopyToAsync(stream);
  181. }
  182. return fileName;
  183. }
  184. throw Oops.Oh("文件存储路径未配置");
  185. }
  186. /// <summary>
  187. /// 存储到minio
  188. /// </summary>
  189. /// <param name="fileId"></param>
  190. /// <param name="file"></param>
  191. /// <returns></returns>
  192. private async Task<(string objName, string downloadUrl)> StorageMinio(long fileId, IFormFile file)
  193. {
  194. var minioService = App.GetService<MinioUtils>();
  195. var now = DateTime.Now.ToString("d");
  196. var fileSuffix = Path.GetExtension(file.FileName).ToLower();// 文件后缀
  197. var fileObjectName = $"{now}/{fileId}{fileSuffix}";//存储后的文件名
  198. var downloadUrl = await minioService.PutObjectAsync(fileObjectName, file);
  199. return (fileObjectName, downloadUrl);
  200. }
  201. /// <summary>
  202. /// 获取文件大小
  203. /// </summary>
  204. /// <param name="fileSizeKb"></param>
  205. /// <returns></returns>
  206. private string GetSizeInfo(long fileSizeKb)
  207. {
  208. var b = fileSizeKb * 1024;
  209. const int mb = 1024 * 1024;
  210. const int kb = 1024;
  211. if (b / mb >= 1)
  212. {
  213. return Math.Round(b / (float)mb, 2) + "MB";
  214. }
  215. if (b / kb >= 1)
  216. {
  217. return Math.Round(b / (float)kb, 2) + "KB";
  218. }
  219. if (b == 0)
  220. {
  221. return "0B";
  222. }
  223. return null;
  224. }
  225. /// <summary>
  226. /// 判断是否是图片
  227. /// </summary>
  228. /// <param name="suffix">后缀名</param>
  229. /// <returns></returns>
  230. private bool IsPic(string suffix)
  231. {
  232. //图片后缀名列表
  233. var pics = new[]
  234. {
  235. ".png", ".bmp", ".gif", ".jpg", ".jpeg", ".psd"
  236. };
  237. if (pics.Contains(suffix))
  238. return true;
  239. return false;
  240. }
  241. #endregion 方法
  242. }