using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Text; using System.Text.RegularExpressions; using System.Web; using Aliyun.OSS.Util; using Common.Enum; using Common.Util; using Entity.Base; using Entity.DbModel.System.SysBaseObject; using Entity.Dto.Req; using Furion.VirtualFileServer; using HybirdFrameworkCore.Autofac.Attribute; using HybirdFrameworkCore.Configuration; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using OnceMi.AspNetCore.OSS; using Repository.System; using Service.Mgr; using SqlSugar; using Yitter.IdGenerator; namespace Service.System { [Scope("SingleInstance")] public class SysFileServices : BaseServices { private readonly SysFileRepository _sysFileRep; private readonly SysUserRepository _sysUserRep; private readonly UploadOptions _uploadOptions; private readonly IOSSService _OSSService; private readonly string _imageType = ".jpg.png.bmp.gif.tif"; public SysFileServices( SysUserRepository sysUserRepository, SysFileRepository sysFileRep, IOSSServiceFactory ossServiceFactory) { _sysUserRep = sysUserRepository; _sysFileRep = sysFileRep; _uploadOptions = new UploadOptions { Path = AppSettingsHelper.GetContent("Upload", "Path"), MaxSize = Convert.ToInt64(AppSettingsHelper.GetContent("Upload", "MaxSize")), ContentType = new List { "image/jpg", "image/png", "image/jpeg", "image/gif", "image/bmp", "text/plain", "application/pdf", "application/msword", "application/vnd.ms-excel", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "video/mp4" }, EnableMd5 = false, }; } /// /// 上传头像 🔖 /// /// /// [DisplayName("上传头像")] public async Task UploadAvatar([Required] IFormFile file, string path) { var sysFile = await HandleUploadFile(file, path, _imageType); var user = _sysUserRep.QueryByClause(u => u.Id == UserManager.UserId); await _sysUserRep.UpdateAsync(u => new SysUser() { Avatar = sysFile.Url }, u => u.Id == user.Id); return sysFile; } /// /// 获取文件分页列表 🔖 /// /// /// [DisplayName("获取文件分页列表")] public async Task> Page(PageFileReq input) { RefAsync total = 0; var items = await _sysFileRep.QueryPageAsync( !string.IsNullOrWhiteSpace(input.FileName), u => u.FileName.Contains(input.FileName.Trim()), !string.IsNullOrWhiteSpace(input.StartTime.ToString()) && !string.IsNullOrWhiteSpace(input.EndTime.ToString()), u => u.CreateTime >= input.StartTime && u.CreateTime <= input.EndTime, u => u.CreateTime, input.Page, input.PageSize, total); return SqlSugarPagedExtensions.CreateSqlSugarPagedList(items, total, input.Page, input.PageSize); } /// /// 上传文件 🔖 /// /// /// /// [DisplayName("上传文件")] public async Task UploadFile([Required] IFormFile file, [FromQuery] string? path) { return await HandleUploadFile(file, path); } /// /// 上传文件Base64 /// /// /// /// /// /// private async Task UploadFileFromBase64(string strBase64, string fileName, string contentType, string? path) { byte[] fileData = Convert.FromBase64String(strBase64); var ms = new MemoryStream(); ms.Write(fileData); ms.Seek(0, SeekOrigin.Begin); if (string.IsNullOrEmpty(fileName)) fileName = $"{YitIdHelper.NextId()}.jpg"; if (string.IsNullOrEmpty(contentType)) contentType = "image/jpg"; IFormFile formFile = new FormFile(ms, 0, fileData.Length, "file", fileName) { Headers = new HeaderDictionary(), ContentType = contentType }; return await UploadFile(formFile, path); } /// /// 上传文件Base64 🔖 /// /// /// [DisplayName("上传文件Base64")] [HttpPost] public async Task UploadFileFromBase64(UploadFileFromBase64Req input) { return await UploadFileFromBase64(input.FileDataBase64, input.FileName, input.ContentType, input.Path); } /// /// 上传多文件 🔖 /// /// /// [DisplayName("上传多文件")] public async Task> UploadFiles([Required] List files) { var filelist = new List(); foreach (var file in files) { filelist.Add(await UploadFile(file, "")); } return filelist; } ///// ///// 根据文件Id或Url下载 🔖 ///// ///// ///// //[DisplayName("根据文件Id或Url下载")] //public async Task DownloadFile(FileReq input) //{ // var file = input.Id > 0 ? await GetFile(input) : await _sysFileRep.QueryByClauseAsync(u => u.Url == input.Url); // var fileName = HttpUtility.UrlEncode(file.FileName, Encoding.GetEncoding("UTF-8")); // if (_OSSProviderOptions.IsEnable) // { // var filePath = string.Concat(file.FilePath, "/", file.Id.ToString() + file.Suffix); // var stream = await (await _OSSService.PresignedGetObjectAsync(file.BucketName.ToString(), filePath, 5)).GetAsStreamAsync(); // return new FileStreamResult(stream.Stream, "application/octet-stream") { FileDownloadName = fileName + file.Suffix }; // } // else // { // var filePath = Path.Combine(file.FilePath, file.Id.ToString() + file.Suffix); // var path = Path.Combine(App.WebHostEnvironment.WebRootPath, filePath); // return new FileStreamResult(new FileStream(path, FileMode.Open), "application/octet-stream") { FileDownloadName = fileName + file.Suffix }; // } //} /// /// 更新文件 🔖 /// /// /// [ApiDescriptionSettings(Name = "Update"), HttpPost] [DisplayName("更新文件")] public async Task UpdateFile(FileReq input) { string result = ""; var isExist = await _sysFileRep.QueryByClauseAsync(u => u.Id == input.Id); if (isExist == null) result = "文件不存在"; bool updateResult = await _sysFileRep.UpdateAsync(u => new SysFile() { FileName = input.FileName }, u => u.Id == input.Id); if (updateResult) { result = "更新文件成功"; } return result; } /// /// 获取文件 /// /// /// private async Task GetFile([FromQuery] FileReq input) { var file = await _sysFileRep.QueryByClauseAsync(u => u.Id == input.Id); if (file==null) { //文件不存在 return new SysFile(); } return file; } /// /// 上传文件 /// /// 文件 /// 路径 /// 允许格式:.jpg.png.gif.tif.bmp /// private async Task HandleUploadFile(IFormFile file, string savePath, string allowSuffix = "") { if (file == null) throw new ArgumentException($"文件不存在");//文件不存在 // 判断是否重复上传的文件 var sizeKb = (long)(file.Length / 1024.0); // 大小KB var fileMd5 = string.Empty; if (_uploadOptions.EnableMd5) { using (var fileStream = file.OpenReadStream()) { fileMd5 = OssUtils.ComputeContentMd5(fileStream, fileStream.Length); } /* * Mysql8 中如果使用了 utf8mb4_general_ci 之外的编码会出错,尽量避免在条件里使用.ToString() * 因为 Squsugar 并不是把变量转换为字符串来构造SQL语句,而是构造了CAST(123 AS CHAR)这样的语句,这样这个返回值是utf8mb4_general_ci,所以容易出错。 */ var strSizeKb = sizeKb.ToString(); var sysFile = await _sysFileRep.QueryByClauseAsync(u => u.FileMd5 == fileMd5 && (u.SizeKb == null || u.SizeKb == strSizeKb)); if (sysFile != null) return sysFile; } var path = savePath; if (string.IsNullOrWhiteSpace(savePath)) { path = _uploadOptions.Path; var reg = new Regex(@"(\{.+?})"); var match = reg.Matches(path); match.ToList().ForEach(a => { var str = DateTime.Now.ToString(a.ToString().Substring(1, a.Length - 2)); // 每天一个目录 path = path.Replace(a.ToString(), str); }); } // 验证文件类型 if (!_uploadOptions.ContentType.Contains(file.ContentType)) throw new ArgumentException($"不允许的文件类型"); // 验证文件大小 if (sizeKb > _uploadOptions.MaxSize) throw new ArgumentException($"文件超过允许大小"); // 获取文件后缀 var suffix = Path.GetExtension(file.FileName).ToLower(); // 后缀 if (string.IsNullOrWhiteSpace(suffix)) { var contentTypeProvider = FS.GetFileExtensionContentTypeProvider(); suffix = contentTypeProvider.Mappings.FirstOrDefault(u => u.Value == file.ContentType).Key; // 修改 image/jpeg 类型返回的 .jpe 后缀 if (suffix == ".jpe") suffix = ".jpg"; } if (string.IsNullOrWhiteSpace(suffix)) throw new ArgumentException($"文件后缀错误"); var newFile = new SysFile { //Id = YitIdHelper.NextId(), FileName = Path.GetFileNameWithoutExtension(file.FileName), Suffix = suffix, SizeKb = sizeKb.ToString(), FileMd5 = fileMd5, }; var finalName = newFile.Id + suffix; // 文件最终名称 string time = DateTime.Now.ToString("yyyyMMdd"); var filePath = Path.Combine(savePath, time); if (!Directory.Exists(filePath)) Directory.CreateDirectory(filePath); filePath = Path.Combine(filePath, finalName); // 使用FileStream保存文件 using (var stream = new FileStream(filePath, FileMode.Create)) { await file.CopyToAsync(stream); } newFile.FilePath = filePath; newFile.Url = AppSettingsHelper.GetContent("HttpContextRequest", "Scheme") + "/" + time + "/" + finalName; await _sysFileRep.InsertAsync(newFile); SysFile newAddFile = await _sysFileRep.QueryByClauseAsync(u => u.FilePath == filePath); if (newAddFile != null) { newFile.Id = newAddFile.Id; return newFile; } else return null; } } }