diff --git a/Infrastructure/Controllers/BaseController.cs b/Infrastructure/Controllers/BaseController.cs index 9a88f4e..d84a7d3 100644 --- a/Infrastructure/Controllers/BaseController.cs +++ b/Infrastructure/Controllers/BaseController.cs @@ -15,6 +15,7 @@ namespace Infrastructure.Controllers /// /// web层通用数据处理 /// + //[ApiController] public class BaseController : ControllerBase { public static string TIME_FORMAT_FULL = "yyyy-MM-dd HH:mm:ss"; diff --git a/Infrastructure/ModelBinder/CommaSeparatedArrayModelBinder.cs b/Infrastructure/ModelBinder/CommaSeparatedArrayModelBinder.cs new file mode 100644 index 0000000..735b054 --- /dev/null +++ b/Infrastructure/ModelBinder/CommaSeparatedArrayModelBinder.cs @@ -0,0 +1,51 @@ +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.ModelBinding.Binders; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace ZR.Infrastructure.ModelBinder +{ + public class CommaSeparatedArrayModelBinder : IModelBinder + { + public Task BindModelAsync(ModelBindingContext bindingContext) + { + var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); + if (valueProviderResult == ValueProviderResult.None) + { + return Task.CompletedTask; + } + + var value = valueProviderResult.FirstValue; + if (string.IsNullOrEmpty(value)) + { + return Task.CompletedTask; + } + + try + { + var array = value.Split(',').Select(x => (T)Convert.ChangeType(x, typeof(T))).ToArray(); + bindingContext.Result = ModelBindingResult.Success(array); + } + catch + { + bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, "Invalid value format"); + } + + return Task.CompletedTask; + } + } + + public class CommaSeparatedArrayModelBinderProvider : IModelBinderProvider + { + public IModelBinder? GetBinder(ModelBinderProviderContext context) + { + if (context.Metadata.ModelType == typeof(T[])) + { + return new BinderTypeModelBinder(typeof(CommaSeparatedArrayModelBinder)); + } + + return null; + } + } +} diff --git a/ZR.Admin.WebApi/GlobalUsing.cs b/ZR.Admin.WebApi/GlobalUsing.cs index 89190fa..8d76ef1 100644 --- a/ZR.Admin.WebApi/GlobalUsing.cs +++ b/ZR.Admin.WebApi/GlobalUsing.cs @@ -8,4 +8,5 @@ global using Mapster; global using Infrastructure.Extensions; global using Infrastructure.Controllers; global using ZR.ServiceCore.Middleware; -global using ZR.ServiceCore.Services; \ No newline at end of file +global using ZR.ServiceCore.Services; +global using ZR.Infrastructure.ModelBinder; \ No newline at end of file diff --git a/ZR.Admin.WebApi/Program.cs b/ZR.Admin.WebApi/Program.cs index 5df3ff0..9eca8fa 100644 --- a/ZR.Admin.WebApi/Program.cs +++ b/ZR.Admin.WebApi/Program.cs @@ -16,7 +16,12 @@ var builder = WebApplication.CreateBuilder(args); builder.Host.UseNLog(); // Add services to the container. -builder.Services.AddControllers(); +builder.Services.AddControllers(options => +{ + options.ModelBinderProviders.Insert(0, new CommaSeparatedArrayModelBinderProvider()); + options.ModelBinderProviders.Insert(0, new CommaSeparatedArrayModelBinderProvider()); + options.ModelBinderProviders.Insert(0, new CommaSeparatedArrayModelBinderProvider()); +}); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); @@ -37,7 +42,8 @@ builder.Services.AddIPRate(builder.Configuration); builder.Services.AddHttpContextAccessor(); //绑定整个对象到Model上 builder.Services.Configure(builder.Configuration); - +builder.Configuration.AddJsonFile("codeGen.json"); +builder.Configuration.AddJsonFile("iprate.json"); //jwt 认证 builder.Services.AddJwt(); //配置文件 diff --git a/ZR.Admin.WebApi/appsettings.json b/ZR.Admin.WebApi/appsettings.json index f91383c..2e52bf4 100644 --- a/ZR.Admin.WebApi/appsettings.json +++ b/ZR.Admin.WebApi/appsettings.json @@ -67,26 +67,6 @@ "AppID": "", "AppSecret": "" }, - //代码生成配置 - "gen": { - //是否显示移动端代码生成 - "showApp": false, - //自动去除表前缀 - "autoPre": true, - "author": "admin", - "tablePrefix": "sys_", //"表前缀(生成类名不会包含表前缀,多个用逗号分隔)", - "vuePath": "", //前端代码存储路径eg:D:\Work\ZRAdmin-Vue3 - "csharpTypeArr": { - "string": [ "varchar", "nvarchar", "text", "longtext" ], - "int": [ "int", "integer", "smallint", "int4", "int8", "int2" ], - "long": [ "bigint", "number" ], - "float": [ "numeric", "real", "float" ], - "decimal": [ "money", "decimal", "smallmoney" ], - "dateTime": [ "date", "datetime", "datetime2", "smalldatetime", "timestamp" ], - "byte": [ "tinyint" ], - "bool": [ "bit" ] - } - }, //邮箱配置信息 "MailOptions": { //发件人名称 @@ -107,36 +87,20 @@ "Cache": "127.0.0.1:6379,defaultDatabase=0,poolsize=50,ssl=false,writeBuffer=10240,prefix=cache:", "Session": "127.0.0.1:6379,defaultDatabase=0,poolsize=50,ssl=false,writeBuffer=10240,prefix=session:" }, - //接口请求限制 - "IpRateLimiting": { - "EnableEndpointRateLimiting": true, - "StackBlockedRequests": false, - "RealIpHeader": "X-Real-IP", - "ClientIdHeader": "X-ClientId", - "HttpStatusCode": 429, - "EndpointWhitelist": [ "post:/system/dict/data/types", "*:/msghub/negotiate", "*:/LogOut", "*:/common/uploadfile", "*:/VerifyScan" ], - "QuotaExceededResponse": { - "Content": "{{\"code\":429,\"msg\":\"访问过于频繁,请稍后重试\"}}", - "ContentType": "application/json", - "StatusCode": 429 - }, - //通用规则,api规则,结尾一定要带* - "GeneralRules": [ - { - "Endpoint": "*:/captchaImage", - //时间段,格式:{数字}{单位};可使用单位:s, m, h, d - "Period": "3s", - "Limit": 5 - }, - { - "Endpoint": "((post)|(put)):*", - "Period": "3s", - "Limit": 1 - } - ] - }, //验证码配置 "CaptchaOptions": { "IgnoreCase": true // 比较时是否忽略大小写 + }, + //代码生成配置 + "CodeGen": { + //是否显示移动端代码生成 + "showApp": false, + //自动去除表前缀 + "autoPre": true, + //默认生成业务模块名 + "moduleName": "business", + "author": "admin", + "tablePrefix": "sys_", //"表前缀(生成类名不会包含表前缀,多个用逗号分隔)", + "vuePath": "" //前端代码存储路径eg:D:\Work\ZRAdmin-Vue3 } } diff --git a/ZR.Admin.WebApi/iprate.json b/ZR.Admin.WebApi/iprate.json new file mode 100644 index 0000000..7269065 --- /dev/null +++ b/ZR.Admin.WebApi/iprate.json @@ -0,0 +1,30 @@ +{ + //接口请求限制 + "IpRateLimiting": { + "EnableEndpointRateLimiting": true, + "StackBlockedRequests": false, + "RealIpHeader": "X-Real-IP", + "ClientIdHeader": "X-ClientId", + "HttpStatusCode": 429, + "EndpointWhitelist": [ "post:/system/dict/data/types", "*:/msghub/negotiate", "*:/LogOut", "*:/common/uploadfile", "*:/VerifyScan" ], + "QuotaExceededResponse": { + "Content": "{{\"code\":429,\"msg\":\"访问过于频繁,请稍后重试\"}}", + "ContentType": "application/json", + "StatusCode": 429 + }, + //通用规则,api规则,结尾一定要带* + "GeneralRules": [ + { + "Endpoint": "*:/captchaImage", + //时间段,格式:{数字}{单位};可使用单位:s, m, h, d + "Period": "3s", + "Limit": 5 + }, + { + "Endpoint": "((post)|(put)):*", + "Period": "3s", + "Limit": 1 + } + ] + } +} diff --git a/ZR.Admin.WebApi/wwwroot/CodeGenTemplate/TplControllers.txt b/ZR.Admin.WebApi/wwwroot/CodeGenTemplate/TplControllers.txt index 2536570..496bf89 100644 --- a/ZR.Admin.WebApi/wwwroot/CodeGenTemplate/TplControllers.txt +++ b/ZR.Admin.WebApi/wwwroot/CodeGenTemplate/TplControllers.txt @@ -113,14 +113,11 @@ $if(replaceDto.ShowBtnDelete || replaceDto.ShowBtnMultiDel) [HttpDelete("{ids}")] [ActionPermissionFilter(Permission = "${replaceDto.PermissionPrefix}:delete")] [Log(Title = "${genTable.FunctionName}", BusinessType = BusinessType.DELETE)] - public IActionResult Delete${replaceDto.ModelTypeName}(string ids) + public IActionResult Delete${replaceDto.ModelTypeName}([ModelBinder(typeof(CommaSeparatedArrayModelBinder<${replaceDto.PKType}>))] ${replaceDto.PKType}[] ids) { - long[] idsArr = Tools.SpitLongArrary(ids); - if (idsArr.Length <= 0) { return ToResponse(ApiResult.Error($"删除失败Id 不能为空")); } + if (ids.Length <= 0) { return ToResponse(ApiResult.Error($"删除失败Id 不能为空")); } - var response = _${replaceDto.ModelTypeName}Service.Delete(idsArr$if(replaceDto.enableLog), "删除${genTable.FunctionName}"$end); - - return ToResponse(response); + return ToResponse(_${replaceDto.ModelTypeName}Service.Delete(ids$if(replaceDto.enableLog), "删除${genTable.FunctionName}"$end)); } $end diff --git a/ZR.CodeGenerator/Model/ImportCodeGenTableDto.cs b/ZR.CodeGenerator/Model/ImportCodeGenTableDto.cs new file mode 100644 index 0000000..ac395f3 --- /dev/null +++ b/ZR.CodeGenerator/Model/ImportCodeGenTableDto.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace ZR.CodeGenerator.Model +{ + public class ImportCodeGenTableDto + { + public string DbName { get; set; } + public List Tables { get; set; } + } + + public class CodeGenTables + { + public string Name { get; set; } + public string Description { get; set; } + } +} diff --git a/ZR.CodeGenerator/Model/InitTableDto.cs b/ZR.CodeGenerator/Model/InitTableDto.cs new file mode 100644 index 0000000..a1bf45a --- /dev/null +++ b/ZR.CodeGenerator/Model/InitTableDto.cs @@ -0,0 +1,13 @@ +using Infrastructure.Model; + +namespace ZR.CodeGenerator.Model +{ + public class InitTableDto + { + public string DbName { get; set; } + public string UserName { get; set; } + public string TableName { get; set; } + public string Desc { get; set; } + public CodeGen CodeGen { get; set; } + } +}