😎优化文件存储数据库相关代码

This commit is contained in:
zuohuaijun 2025-06-20 13:54:56 +08:00
parent e241ce5c3b
commit 7ae8e5e00f
8 changed files with 143 additions and 64 deletions

View File

@ -6,7 +6,7 @@
"MaxSize": 51200, // KB1024*50
"ContentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif", "image/bmp", "text/plain", "text/xml", "application/pdf", "application/msword", "application/vnd.ms-excel", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "video/mp4", "application/wps-office.docx", "application/wps-office.xlsx", "application/wps-office.pptx", "application/vnd.android.package-archive", "application/octet-stream" ],
"EnableMd5": false, // MDF5-
"EnableSaveFileToDb": false //便
"EnableSaveDb": false //
},
"OSSProvider": {
"Enabled": false,

View File

@ -27,10 +27,10 @@
<PackageReference Include="AspectCore.Extensions.Reflection" Version="2.4.0" />
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.1" Aliases="BouncyCastleV2" />
<PackageReference Include="Elastic.Clients.Elasticsearch" Version="9.0.6" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.88" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.88" />
<PackageReference Include="Furion.Pure" Version="4.9.7.88" />
<PackageReference Include="Elastic.Clients.Elasticsearch" Version="9.0.7" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.89" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.89" />
<PackageReference Include="Furion.Pure" Version="4.9.7.89" />
<PackageReference Include="Hardware.Info" Version="101.0.1.1" />
<PackageReference Include="Hashids.net" Version="1.7.0" />
<PackageReference Include="IPTools.China" Version="1.6.0" />

View File

@ -35,10 +35,9 @@ public sealed class UploadOptions : IConfigurableOptions
public bool EnableMd5 { get; set; }
/// <summary>
/// 把文件保存到数据库的表里
/// 启用文件存储到数据库
/// </summary>
public bool EnableSaveFileToDb { get; set; }
public bool EnableSaveDb { get; set; }
}
/// <summary>

View File

@ -4,8 +4,6 @@
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Furion.DependencyInjection;
namespace Admin.NET.Core.Service;
public class DbFileProvider : ICustomFileProvider, ITransient
@ -24,7 +22,8 @@ public class DbFileProvider : ICustomFileProvider, ITransient
}
public async Task<string> DownloadFileBase64Async(SysFile sysFile)
{// 考虑可能会曾经配置成保存到本地文件
{
// 若先前配置成保存到本地文件
if (string.IsNullOrEmpty(sysFile.Provider) || sysFile.Provider == "Local")
{
var provider = App.GetService<DefaultFileProvider>();
@ -45,7 +44,7 @@ public class DbFileProvider : ICustomFileProvider, ITransient
public async Task<FileStreamResult> GetFileStreamResultAsync(SysFile sysFile, string fileName)
{
// 考虑可能会曾经配置成保存到本地文件
// 若先前配置成保存到本地文件
if (string.IsNullOrEmpty(sysFile.Provider) || sysFile.Provider == "Local")
{
var provider = App.GetService<DefaultFileProvider>();

View File

@ -131,27 +131,19 @@ public class SysFileService : IDynamicApiController, ITransient
}
/// <summary>
/// 在upload路径下载文件 🔖
/// 根据文件Id和MD5下载与db存储模式路径对应 🔖
/// </summary>
/// <param name="id"></param>
/// <param name="fileMd5"></param>
/// <param name="fileName"></param>
/// <returns></returns>
/// <remarks>
/// 这个接口定义在 /upload/downloadfile与DbFileProvider返回的路径要对应得上
/// 之所以定义在这里有利于使用反向代理指入我们的upload文件夹时不用修改文件的下载路径。
/// 比如我们的前端就把他自己的upload转发到了我们后端的upload路径所以这种情况下我们用db来保存文件时就不用修改下载文件的方式
/// </remarks>
[Route("/upload/downloadfile")]
[AllowAnonymous]
[HttpGet]
[DisplayName("在upload路径")]
public async Task<IActionResult> DownloadFile2([FromQuery]long id, [FromQuery] string fileMd5, [FromQuery] string fileName)
[HttpGet("/upload/downloadfile")]
[DisplayName("根据文件Id和MD5下载")]
public async Task<IActionResult> DownloadFile2([FromQuery] long id, [FromQuery] string fileMd5)
{
var file = await GetFile(id);
if (file.FileMd5 != null && file.FileMd5 != fileMd5)
throw Oops.Bah("文件校验信息不符");
fileName = HttpUtility.UrlEncode(fileName, Encoding.GetEncoding("UTF-8"));
if (file.FileMd5 != null && file.FileMd5 != fileMd5) throw Oops.Oh("文件校验信息不符");
var fileName = HttpUtility.UrlEncode(file.FileName, Encoding.GetEncoding("UTF-8"));
return await GetFileStreamResult(file, fileName);
}

View File

@ -575,9 +575,7 @@ public class SysTenantService : IDynamicApiController, ITransient
if (tenantId < 1) tenantId = long.Parse(App.User?.FindFirst(ClaimConst.TenantId)?.Value ?? "0");
if (tenantId < 1) tenantId = SqlSugarConst.DefaultTenantId;
var tenant = await _sysTenantRep.GetFirstAsync(u => u.Id == tenantId);
if (tenant == null)
throw Oops.Bah($"租户信息不存在:{tenantId}");
var tenant = await _sysTenantRep.GetFirstAsync(u => u.Id == tenantId) ?? throw Oops.Oh($"租户信息不存在:{tenantId}");
// 若租户系统标题为空,则获取默认租户系统信息(兼容已有未配置的租户)
if (string.IsNullOrWhiteSpace(tenant.Title))

View File

@ -2,7 +2,7 @@
"name": "admin.net.pro",
"type": "module",
"version": "2.4.33",
"lastBuildTime": "2025.06.19",
"lastBuildTime": "2025.06.20",
"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
"author": "zuohuaijun",
"license": "MIT",
@ -24,7 +24,7 @@
"@vue-office/docx": "^1.6.2",
"@vue-office/excel": "^1.7.14",
"@vue-office/pdf": "^2.0.9",
"@vueuse/core": "^13.3.0",
"@vueuse/core": "^13.4.0",
"@vxe-ui/plugin-export-xlsx": "^4.2.2",
"@vxe-ui/plugin-render-element": "^4.0.11",
"@wangeditor/editor": "^5.1.23",
@ -83,8 +83,8 @@
"vue-router": "^4.5.1",
"vue-signature-pad": "^3.0.2",
"vue3-tree-org": "^4.2.2",
"vxe-pc-ui": "^4.6.26",
"vxe-table": "^4.13.43",
"vxe-pc-ui": "^4.6.27",
"vxe-table": "^4.13.44",
"xe-utils": "^3.7.5",
"xlsx-js-style": "^1.2.0"
},
@ -108,7 +108,7 @@
"prettier": "^3.5.3",
"rollup-plugin-visualizer": "^6.0.3",
"sass": "^1.89.2",
"terser": "^5.43.0",
"terser": "^5.43.1",
"typescript": "^5.8.3",
"vite": "^6.3.5",
"vite-plugin-cdn-import": "^1.0.1",

View File

@ -738,6 +738,59 @@ export const SysFileApiAxiosParamCreator = function (configuration?: Configurati
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = localVarFormParams;
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
/**
*
* @summary Id和MD5下载db存储模式路径对应 🔖
* @param {number} [id]
* @param {string} [fileMd5]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
uploadDownloadfileGet: async (id?: number, fileMd5?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/upload/downloadfile`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions :AxiosRequestConfig = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
if (id !== undefined) {
localVarQueryParameter['id'] = id;
}
if (fileMd5 !== undefined) {
localVarQueryParameter['fileMd5'] = fileMd5;
}
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
@ -952,6 +1005,21 @@ export const SysFileApiFp = function(configuration?: Configuration) {
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary Id和MD5下载db存储模式路径对应 🔖
* @param {number} [id]
* @param {string} [fileMd5]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async uploadDownloadfileGet(id?: number, fileMd5?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultIActionResult>>> {
const localVarAxiosArgs = await SysFileApiAxiosParamCreator(configuration).uploadDownloadfileGet(id, fileMd5, options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
};
},
}
};
@ -1105,6 +1173,17 @@ export const SysFileApiFactory = function (configuration?: Configuration, basePa
async apiSysFileUploadSignaturePostForm(file?: Blob, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultSysFile>> {
return SysFileApiFp(configuration).apiSysFileUploadSignaturePostForm(file, options).then((request) => request(axios, basePath));
},
/**
*
* @summary Id和MD5下载db存储模式路径对应 🔖
* @param {number} [id]
* @param {string} [fileMd5]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async uploadDownloadfileGet(id?: number, fileMd5?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultIActionResult>> {
return SysFileApiFp(configuration).uploadDownloadfileGet(id, fileMd5, options).then((request) => request(axios, basePath));
},
};
};
@ -1273,4 +1352,16 @@ export class SysFileApi extends BaseAPI {
public async apiSysFileUploadSignaturePostForm(file?: Blob, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultSysFile>> {
return SysFileApiFp(this.configuration).apiSysFileUploadSignaturePostForm(file, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary Id和MD5下载db存储模式路径对应 🔖
* @param {number} [id]
* @param {string} [fileMd5]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysFileApi
*/
public async uploadDownloadfileGet(id?: number, fileMd5?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultIActionResult>> {
return SysFileApiFp(this.configuration).uploadDownloadfileGet(id, fileMd5, options).then((request) => request(this.axios, this.basePath));
}
}