Explorar o código

新增oss上传文件,支持md5秒传

zhontai %!s(int64=2) %!d(string=hai) anos
pai
achega
1ce9f6e662

+ 10 - 5
src/hosts/ZhonTai.Host/Configs/ossconfig.json

@@ -13,7 +13,8 @@
       "IsEnableCache": true,
       "BucketName": "admin",
       "Url": "", //文件外链
-      "Enable": false
+      "Enable": true,
+      "Md5":  false
     },
     //阿里云
     {
@@ -26,7 +27,8 @@
       "IsEnableCache": true,
       "BucketName": "admin",
       "Url": "",
-      "Enable": false
+      "Enable": false,
+      "Md5": false
     },
     //腾讯云
     {
@@ -39,7 +41,8 @@
       "IsEnableCache": true,
       "BucketName": "admin",
       "Url": "",
-      "Enable": false
+      "Enable": false,
+      "Md5": false
     },
     //七牛
     {
@@ -52,7 +55,8 @@
       "IsEnableCache": true,
       "BucketName": "admin",
       "Url": "",
-      "Enable": false
+      "Enable": false,
+      "Md5": false
     },
     //华为云
     {
@@ -65,7 +69,8 @@
       "IsEnableCache": true,
       "BucketName": "admin",
       "Url": "",
-      "Enable": false
+      "Enable": false,
+      "Md5": false
     }
   ]
 }

+ 1 - 0
src/platform/ZhonTai.Admin/Core/Configs/OSSConfig.cs

@@ -16,6 +16,7 @@ public class OSSOptions
     public string BucketName { get; set; } = "admin";
     public string Url { get; set; }
     public bool Enable { get; set; } = false;
+    public bool Md5 { get; set; } = false;
 }
 
 /// <summary>

+ 0 - 9
src/platform/ZhonTai.Admin/Services/File/Dto/FileAddInput.cs

@@ -1,9 +0,0 @@
-namespace ZhonTai.Admin.Services.File.Dto;
-
-/// <summary>
-/// 添加
-/// </summary>
-public class FileAddInput
-{
-   
-}

+ 1 - 1
src/platform/ZhonTai.Admin/Services/File/Dto/FileGetOutput.cs

@@ -1,6 +1,6 @@
 
 namespace ZhonTai.Admin.Services.File.Dto;
 
-public class FileGetOutput : FileUpdateInput
+public class FileGetOutput
 {
 }

+ 2 - 3
src/platform/ZhonTai.Admin/Services/File/Dto/FileGetPageOutput.cs

@@ -1,5 +1,4 @@
-using OnceMi.AspNetCore.OSS;
-using System;
+using System;
 
 namespace ZhonTai.Admin.Services.File.Dto;
 
@@ -8,7 +7,7 @@ public class FileGetPageOutput
     /// <summary>
     /// OSS供应商
     /// </summary>
-    public OSSProvider? Provider { get; set; }
+    public string ProviderName { get; set; }
 
     /// <summary>
     /// 存储桶名称

+ 0 - 15
src/platform/ZhonTai.Admin/Services/File/Dto/FileUpdateInput.cs

@@ -1,15 +0,0 @@
-using System.ComponentModel.DataAnnotations;
-
-namespace ZhonTai.Admin.Services.File.Dto;
-
-/// <summary>
-/// 修改
-/// </summary>
-public partial class FileUpdateInput : FileAddInput
-{
-    /// <summary>
-    /// 文件Id
-    /// </summary>
-    [Required(ErrorMessage = "请选择文件")]
-    public string Id { get; set; }
-}

+ 113 - 1
src/platform/ZhonTai.Admin/Services/File/FileService.cs

@@ -7,6 +7,17 @@ using Microsoft.AspNetCore.Mvc;
 using ZhonTai.Admin.Core.Consts;
 using ZhonTai.Admin.Domain.File.Dto;
 using ZhonTai.Admin.Domain.File;
+using Microsoft.AspNetCore.Http;
+using System.IO;
+using System;
+using ZhonTai.Admin.Core.Configs;
+using OnceMi.AspNetCore.OSS;
+using Microsoft.Extensions.Options;
+using System.Linq;
+using ZhonTai.Common.Files;
+using ZhonTai.Common.Helpers;
+using System.ComponentModel.DataAnnotations;
+using System.Collections.Generic;
 
 namespace ZhonTai.Admin.Services.File;
 
@@ -17,6 +28,9 @@ namespace ZhonTai.Admin.Services.File;
 public class FileService : BaseService, IFileService, IDynamicApi
 {
     private IFileRepository _fileRepository => LazyGetRequiredService<IFileRepository>();
+    private IOSSServiceFactory _oSSServiceFactory => LazyGetRequiredService<IOSSServiceFactory>();
+
+    private OSSConfig _oSSConfig => LazyGetRequiredService<IOptions<OSSConfig>>().Value;
 
     public FileService()
     {
@@ -39,7 +53,7 @@ public class FileService : BaseService, IFileService, IDynamicApi
         .Count(out var total)
         .OrderByDescending(true, c => c.Id)
         .Page(input.CurrentPage, input.PageSize)
-        .ToListAsync<FileGetPageOutput>();
+        .ToListAsync(a => new FileGetPageOutput { ProviderName = a.Provider.ToString() });
 
         var data = new PageOutput<FileGetPageOutput>()
         {
@@ -49,4 +63,102 @@ public class FileService : BaseService, IFileService, IDynamicApi
 
         return data;
     }
+
+    /// <summary>
+    /// 上传文件
+    /// </summary>
+    /// <param name="file"></param>
+    /// <param name="fileDirectory"></param>
+    /// <returns></returns>
+    public async Task<FileEntity> UploadFileAsync([Required] IFormFile file, string fileDirectory = "")
+    {
+        var oSSService = _oSSServiceFactory.Create(_oSSConfig.Provider.ToString());
+        var oSSOptions = _oSSConfig.OSSConfigs.Where(a => a.Enable && a.Provider == _oSSConfig.Provider).FirstOrDefault();
+
+        var md5 = string.Empty;
+        if (oSSOptions.Md5)
+        {
+            md5 = MD5Encrypt.GetHash(file.OpenReadStream());
+            var md5FileEntity = await _fileRepository.Where(a => a.Md5 == md5 && a.Provider == oSSOptions.Provider).FirstAsync();
+            if (md5FileEntity != null)
+            {
+                var sameFileEntity = new FileEntity
+                {
+                    Provider = oSSOptions.Provider,
+                    BucketName = oSSOptions.BucketName,
+                    FileGuid = FreeUtil.NewMongodbId(),
+                    FileName = Path.GetFileNameWithoutExtension(file.FileName),
+                    Extension = Path.GetExtension(file.FileName).ToLower(),
+                    FileDirectory = md5FileEntity.FileDirectory,
+                    Size = md5FileEntity.Size,
+                    SizeFormat = md5FileEntity.SizeFormat,
+                    Md5 = md5,
+                    LinkUrl = md5FileEntity.LinkUrl
+                };
+                sameFileEntity = await _fileRepository.InsertAsync(sameFileEntity);
+                return sameFileEntity;
+            }
+        }
+
+        if (fileDirectory.IsNull())
+        {
+            fileDirectory = DateTime.Now.ToString("yyyy/MM/dd");
+        }
+
+        var fileSize = new FileSize(file.Length);
+        var fileEntity = new FileEntity
+        {
+            Provider = oSSOptions.Provider,
+            BucketName = oSSOptions.BucketName,
+            FileGuid = FreeUtil.NewMongodbId(),
+            FileName = Path.GetFileNameWithoutExtension(file.FileName),
+            Extension = Path.GetExtension(file.FileName).ToLower(),
+            FileDirectory = fileDirectory,
+            Size = fileSize.Size,
+            SizeFormat = fileSize.ToString(),
+            Md5 = md5
+        };
+
+        var filePath = Path.Combine(fileDirectory, fileEntity.FileGuid + fileEntity.Extension).ToPath();
+        var url = oSSOptions.Url;
+        if (url.IsNull())
+        {
+            url = oSSOptions.Provider switch
+            {
+                OSSProvider.Minio => $"{oSSOptions.Endpoint}/{oSSOptions.BucketName}",
+                OSSProvider.Aliyun => $"{oSSOptions.BucketName}.{oSSOptions.Endpoint}",
+                OSSProvider.QCloud => $"{oSSOptions.BucketName}-{oSSOptions.Endpoint}.cos.{oSSOptions.Region}.myqcloud.com",
+                OSSProvider.Qiniu => $"{oSSOptions.BucketName}.{oSSOptions.Region}.qiniucs.com",
+                OSSProvider.HuaweiCloud => $"{oSSOptions.BucketName}.{oSSOptions.Endpoint}",
+                _ => ""
+            };
+        }
+        if (url.IsNull())
+        {
+            throw ResultOutput.Exception($"请配置{oSSOptions.Provider}的Url参数");
+        }
+
+        var urlProtocol = (oSSOptions.IsEnableHttps ? "https" : "http");
+        fileEntity.LinkUrl = $"{urlProtocol}://{url}/{filePath}";
+        await oSSService.PutObjectAsync(oSSOptions.BucketName, filePath, file.OpenReadStream());
+        fileEntity = await _fileRepository.InsertAsync(fileEntity);
+
+        return fileEntity;
+    }
+
+    /// <summary>
+    /// 上传多文件
+    /// </summary>
+    /// <param name="files"></param>
+    /// <param name="fileDirectory"></param>
+    /// <returns></returns>
+    public async Task<List<FileEntity>> UploadFilesAsync([Required] IFormFileCollection files, string fileDirectory = "")
+    {
+        var fileList = new List<FileEntity>();
+        foreach (var file in files)
+        {
+            fileList.Add(await UploadFileAsync(file, fileDirectory));
+        }
+        return fileList;
+    }
 }

+ 9 - 1
src/platform/ZhonTai.Admin/Services/File/IFileService.cs

@@ -1,5 +1,9 @@
-using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Threading.Tasks;
 using ZhonTai.Admin.Core.Dto;
+using ZhonTai.Admin.Domain.File;
 using ZhonTai.Admin.Domain.File.Dto;
 using ZhonTai.Admin.Services.File.Dto;
 
@@ -11,4 +15,8 @@ namespace ZhonTai.Admin.Services.File;
 public interface IFileService
 {
     Task<PageOutput<FileGetPageOutput>> GetPageAsync(PageInput<FileGetPageDto> input);
+
+    Task<FileEntity> UploadFileAsync(IFormFile file, string fileDirectory = "");
+
+    Task<List<FileEntity>> UploadFilesAsync([Required] IFormFileCollection files, string fileDirectory = "");
 }

+ 16 - 15
src/platform/ZhonTai.Admin/ZhonTai.Admin.xml

@@ -4269,12 +4269,7 @@
             文档接口
             </summary>
         </member>
-        <member name="T:ZhonTai.Admin.Services.File.Dto.FileAddInput">
-            <summary>
-            添加
-            </summary>
-        </member>
-        <member name="P:ZhonTai.Admin.Services.File.Dto.FileGetPageOutput.Provider">
+        <member name="P:ZhonTai.Admin.Services.File.Dto.FileGetPageOutput.ProviderName">
             <summary>
             OSS供应商
             </summary>
@@ -4329,26 +4324,32 @@
             修改时间
             </summary>
         </member>
-        <member name="T:ZhonTai.Admin.Services.File.Dto.FileUpdateInput">
+        <member name="T:ZhonTai.Admin.Services.File.FileService">
             <summary>
-            修改
+            文件服务
             </summary>
         </member>
-        <member name="P:ZhonTai.Admin.Services.File.Dto.FileUpdateInput.Id">
+        <member name="M:ZhonTai.Admin.Services.File.FileService.GetPageAsync(ZhonTai.Admin.Core.Dto.PageInput{ZhonTai.Admin.Domain.File.Dto.FileGetPageDto})">
             <summary>
-            文件Id
+            查询文件列表
             </summary>
+            <param name="input"></param>
+            <returns></returns>
         </member>
-        <member name="T:ZhonTai.Admin.Services.File.FileService">
+        <member name="M:ZhonTai.Admin.Services.File.FileService.UploadFileAsync(Microsoft.AspNetCore.Http.IFormFile,System.String)">
             <summary>
-            文件服务
+            上传文件
             </summary>
+            <param name="file"></param>
+            <param name="fileDirectory"></param>
+            <returns></returns>
         </member>
-        <member name="M:ZhonTai.Admin.Services.File.FileService.GetPageAsync(ZhonTai.Admin.Core.Dto.PageInput{ZhonTai.Admin.Domain.File.Dto.FileGetPageDto})">
+        <member name="M:ZhonTai.Admin.Services.File.FileService.UploadFilesAsync(Microsoft.AspNetCore.Http.IFormFileCollection,System.String)">
             <summary>
-            查询文件列表
+            上传多文件
             </summary>
-            <param name="input"></param>
+            <param name="files"></param>
+            <param name="fileDirectory"></param>
             <returns></returns>
         </member>
         <member name="T:ZhonTai.Admin.Services.File.IFileService">

+ 15 - 1
src/platform/ZhonTai.Common/Helpers/MD5Encrypt.cs

@@ -1,4 +1,5 @@
-using System.Security.Cryptography;
+using System.IO;
+using System.Security.Cryptography;
 using System.Text;
 using ZhonTai.Common.Extensions;
 
@@ -60,4 +61,17 @@ public class MD5Encrypt
         byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(password));
         return s.ToBase64();
     }
+
+    public static string GetHash(Stream stream)
+    {
+        StringBuilder sb = new();
+        using var md5 = MD5.Create();
+        byte[] hashBytes = md5.ComputeHash(stream);
+        foreach (byte bt in hashBytes)
+        {
+            sb.Append(bt.ToString("x2"));
+        }
+
+        return sb.ToString();
+    }
 }