commit d9e2b69d47e8ff56189056f7ce141d9c55c80c30 Author: 徐蒙恩 Date: Sun Feb 18 18:25:31 2024 +0800 first diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..3729ff0c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,25 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..72a52f27 --- /dev/null +++ b/.gitignore @@ -0,0 +1,188 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +*.pubxml + +# NuGet Packages +packages/* +*.nupkg +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +!packages/build/ + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ +logs/ +/.vs diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 00000000..3f0e0034 --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SJZY.Track.Api.sln b/SJZY.Track.Api.sln new file mode 100644 index 00000000..45fdba01 --- /dev/null +++ b/SJZY.Track.Api.sln @@ -0,0 +1,60 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32630.192 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SJZY.Track.Api", "src\SJZY.Track.Api\SJZY.Track.Api.csproj", "{5F1A9619-A5A3-4F5F-AEFF-880707A251E1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SJZY.Track.Application", "src\SJZY.Track.Application\SJZY.Track.Application.csproj", "{E052AEB3-A86F-431E-A685-769D3E59CB8A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DAC93270-5A25-40E5-B851-E7CA398DBC31}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0E2537C3-6EF3-4085-9BD2-CF923E53F82A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SJZY.Track.Repository", "src\SJZY.Track.Repository\SJZY.Track.Repository.csproj", "{D9CF5706-1972-414F-821E-AA32C13B8570}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SJZY.Track.HttpApi", "src\SJZY.Track.HttpApi\SJZY.Track.HttpApi.csproj", "{390A44FB-0DB5-4B66-86AB-7712DC3030F5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SJZY.Track.Test", "test\SJZY.Track.Test\SJZY.Track.Test.csproj", "{3A53539C-4A85-4E5D-A071-7B4B193AB0E0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5F1A9619-A5A3-4F5F-AEFF-880707A251E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5F1A9619-A5A3-4F5F-AEFF-880707A251E1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5F1A9619-A5A3-4F5F-AEFF-880707A251E1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5F1A9619-A5A3-4F5F-AEFF-880707A251E1}.Release|Any CPU.Build.0 = Release|Any CPU + {E052AEB3-A86F-431E-A685-769D3E59CB8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E052AEB3-A86F-431E-A685-769D3E59CB8A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E052AEB3-A86F-431E-A685-769D3E59CB8A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E052AEB3-A86F-431E-A685-769D3E59CB8A}.Release|Any CPU.Build.0 = Release|Any CPU + {D9CF5706-1972-414F-821E-AA32C13B8570}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D9CF5706-1972-414F-821E-AA32C13B8570}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D9CF5706-1972-414F-821E-AA32C13B8570}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D9CF5706-1972-414F-821E-AA32C13B8570}.Release|Any CPU.Build.0 = Release|Any CPU + {390A44FB-0DB5-4B66-86AB-7712DC3030F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {390A44FB-0DB5-4B66-86AB-7712DC3030F5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {390A44FB-0DB5-4B66-86AB-7712DC3030F5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {390A44FB-0DB5-4B66-86AB-7712DC3030F5}.Release|Any CPU.Build.0 = Release|Any CPU + {3A53539C-4A85-4E5D-A071-7B4B193AB0E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3A53539C-4A85-4E5D-A071-7B4B193AB0E0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3A53539C-4A85-4E5D-A071-7B4B193AB0E0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3A53539C-4A85-4E5D-A071-7B4B193AB0E0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {5F1A9619-A5A3-4F5F-AEFF-880707A251E1} = {DAC93270-5A25-40E5-B851-E7CA398DBC31} + {E052AEB3-A86F-431E-A685-769D3E59CB8A} = {DAC93270-5A25-40E5-B851-E7CA398DBC31} + {D9CF5706-1972-414F-821E-AA32C13B8570} = {DAC93270-5A25-40E5-B851-E7CA398DBC31} + {390A44FB-0DB5-4B66-86AB-7712DC3030F5} = {DAC93270-5A25-40E5-B851-E7CA398DBC31} + {3A53539C-4A85-4E5D-A071-7B4B193AB0E0} = {0E2537C3-6EF3-4085-9BD2-CF923E53F82A} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = { 8289A516 - 787C - 4D9D - B972 - E7047BDD206B} + SolutionGuid = {C8AD8123-683D-406E-A8FB-1D0184C19472} + EndGlobalSection +EndGlobal diff --git a/src/SJZY.Track.Api/ApiModule.cs b/src/SJZY.Track.Api/ApiModule.cs new file mode 100644 index 00000000..f679135d --- /dev/null +++ b/src/SJZY.Track.Api/ApiModule.cs @@ -0,0 +1,94 @@ +using FluentValidation.AspNetCore; +using Microsoft.AspNetCore.Mvc; +using SJZY.Expand.ABP.Core; +using SJZY.Expand.ABP.Core.Cors; +using SJZY.Expand.ABP.Core.Filter; +using SJZY.Expand.ABP.Core.JsonSerialization; +using SJZY.Expand.ABP.Core.Localization; +using SJZY.Expand.ABP.Core.Prometheus; +using SJZY.Expand.ABP.Core.Redis; +using SJZY.Expand.ABP.Core.Swagger; +using SJZY.Track.Application; +using Volo.Abp; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Serilog; +using Volo.Abp.Auditing; +using Volo.Abp.Autofac; +using Volo.Abp.Json; +using Volo.Abp.Modularity; + +[assembly: HostingStartup(typeof(SJZY.Expand.ABP.Core.HostingStartup))] +namespace SJZY.Track.Api +{ + [DependsOn( + typeof(AbpAutofacModule), + typeof(SjzyAbpCodeModule), + typeof(ApplicationModule), + typeof(AbpAspNetCoreMvcModule), + typeof(AbpAspNetCoreSerilogModule) + )] + public class ApiModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + var environment = context.Services.GetHostingEnvironment(); + var configuration = context.Services.GetConfiguration(); + context.Services.AddSwagger(); + //过滤器相关配置 + context.Services.AddMvc(options => + { + options.Filters.AddService(); + options.Filters.AddService(); + options.Filters.AddService(); + }).AddNewtonsoftJson(); + + context.Services.AddFluentValidationAutoValidation().AddFluentValidationClientsideAdapters(); + + //Json格式化全局处理 + context.Services.Configure(options => + { + options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();//.DefaultContractResolver(); + options.SerializerSettings.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss")); + options.SerializerSettings.Converters.Add(new LongJsonConverter()); + }); + + Configure(options => options.OutputDateTimeFormat = "yyyy-MM-dd HH:mm:ss"); + Configure(options => { options.IsEnabled = false; }); + + + context.Services.AddRedis(); + + } + + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + var app = context.GetApplicationBuilder(); + var env = context.GetEnvironment(); + + if (env.IsDevelopment()) + app.UseDeveloperExceptionPage(); + + app.UseRequestCulture(); + app.UseRouting(); + app.UseCorsPolicy(); + app.UseConfiguredEndpoints(); + app.UseAbpSwaggerUI(env); + app.UseAbpSerilogEnrichers(); + app.UsePrometheus(); + + #region 启动提示 + Console.WriteLine($@" + +-------------------------------------------------------+ + | | + | | + | 轨迹中心启动成功 | + | {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | + | | + | | + +-------------------------------------------------------+ + "); + #endregion + } + } + +} diff --git a/src/SJZY.Track.Api/Dockerfile b/src/SJZY.Track.Api/Dockerfile new file mode 100644 index 00000000..5b3298d2 --- /dev/null +++ b/src/SJZY.Track.Api/Dockerfile @@ -0,0 +1,9 @@ +FROM harbor.sjzy.local/images/dotnet:7.0 +COPY publish/ /app/ +COPY version.log /app/ +COPY --chown=appuser:appuser publish/ /app/ +COPY --chown=appuser:appuser version.log /app/ +ENV ASPNETCORE_HOSTINGSTARTUPASSEMBLIES SJZY.Expand.ABP.Core.HostingStartup;SkyAPM.Agent.AspNetCore +ENV SKYWALKING__SERVICENAME Package_Track_Dev +WORKDIR /app +CMD ["/usr/bin/dotnet","SJZY.Track.Api.dll"] \ No newline at end of file diff --git a/src/SJZY.Track.Api/Program.cs b/src/SJZY.Track.Api/Program.cs new file mode 100644 index 00000000..a9d373a7 --- /dev/null +++ b/src/SJZY.Track.Api/Program.cs @@ -0,0 +1,25 @@ +using SJZY.Expand.ABP.Core.Configuration; +using SJZY.Expand.ABP.Core.Configuration.AutoRegistOptions; +using SJZY.Expand.ABP.Core.Logger; +using SJZY.Track.Api; + +try +{ + var builder = WebApplication.CreateBuilder(args); + builder + .AddConfigurationContainer() + .AddOptionsFromConfiguration() + .UseSerilogDefault() + .Host.AddAppSettingsSecretsJson() + .UseAutofac(); + + await builder.AddApplicationAsync(); + + var app = builder.Build(); + await app.InitializeApplicationAsync(); + await app.RunAsync(); +} +catch (Exception ex) +{ + Console.WriteLine($"ÏîĿÆô¶¯ʧ°ܣ¬Ò쳣ÐÅϢ£º{ex}"); +} \ No newline at end of file diff --git a/src/SJZY.Track.Api/Properties/launchSettings.json b/src/SJZY.Track.Api/Properties/launchSettings.json new file mode 100644 index 00000000..cba7d693 --- /dev/null +++ b/src/SJZY.Track.Api/Properties/launchSettings.json @@ -0,0 +1,15 @@ +{ + "profiles": { + "SJZY.Track.Api": { + "commandName": "Project", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "SJZY.Expand.ABP.Core;SkyAPM.Agent.AspNetCore", + "SKYWALKING__SERVICENAME": "Track" + }, + "dotnetRunMessages": true, + "applicationUrl": "http://*:5054" + } + }, + "$schema": "https://json.schemastore.org/launchsettings.json" +} \ No newline at end of file diff --git a/src/SJZY.Track.Api/SJZY.Track.Api.csproj b/src/SJZY.Track.Api/SJZY.Track.Api.csproj new file mode 100644 index 00000000..0d485cec --- /dev/null +++ b/src/SJZY.Track.Api/SJZY.Track.Api.csproj @@ -0,0 +1,32 @@ + + + + net7.0 + enable + enable + True + Linux + ..\.. + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/SJZY.Track.Api/appsettings.Development.json b/src/SJZY.Track.Api/appsettings.Development.json new file mode 100644 index 00000000..0856dfd7 --- /dev/null +++ b/src/SJZY.Track.Api/appsettings.Development.json @@ -0,0 +1,68 @@ +{ + "Environment": "Dev", + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "ConnectionStrings": { + "DefaultConnection": "server=mysql-dev.default.svc.cluster.local;Database=sjzy_openapi;Uid=sjzy_dev_user;Pwd=818f83e5;AllowLoadLocalInfile=true;SslMode=None;Charset=utf8mb4;", + "BICenterConnection": "server=mysql-test.default.svc.cluster.local;Database=sjzy_bi_center;Uid=sjzy_test_user;Pwd=848c1c31;AllowLoadLocalInfile=true;SslMode=None;Charset=utf8mb4;" + }, + "Redis": { + "Host": "redis-dev.default.svc.cluster.local:6379", + "Password": "gaVEHR3V7qiY", + "MaxPoolSize": 1000, + "Database": 6, + "Prefix": "" + }, + "CorsPolicy": [ + "" + ], + "Swagger": { + "IsEnable": true, + "ServiceUrl": "", + "JsonUrlPrefix": "", //转发目录前缀,部署服务器时需要配置 /kingmall + "ScanPrefix": [ "SJZY" ] //全局扫描程序集或xml文件时只加载以 SJZY 开头的内容 + }, + "RabbitMQ": { + "UserName": "sjzy", + "Password": "jhUbkzDT7VVi", + "HostName": "rabbitmq-dev.default.svc.cluster.local", + "Port": 5672 + }, + "Serilog": { + "MinimumLevel": { + "Default": "Information", + "Override": { + "System": "Warning", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information", + "Microsoft.EntityFrameworkCore": "Information" + } + }, + "Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ], + "WriteTo": [ + { + "Name": "Console", + "Args": { + //"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, SystemConsoleTheme.Literate", + "outputTemplate": "{NewLine}[{Timestamp:yyyy-MM-dd HH:mm:ss fff} {Level:u3}] {Message:lj}" + } + } + ] + }, + "OSS": { + "AccessKeyId": "LTAI5t81UbwY8rkqLkURCEys", + "AccessKeySecret": "hFfNFTJSyVA1EqBSuXwBaSdm3RGoFL", + "Endpoint": "http://oss-cn-shenzhen.aliyuncs.com/", + "BucketName": "cams3", + "ReturnHttpsUrl": true + }, + "RemoteServices": { + "UserCenter": { + "BaseUrl": "http://192.168.80.55:5020/" + } + } +} diff --git a/src/SJZY.Track.Api/appsettings.Local.json b/src/SJZY.Track.Api/appsettings.Local.json new file mode 100644 index 00000000..6745bedd --- /dev/null +++ b/src/SJZY.Track.Api/appsettings.Local.json @@ -0,0 +1,96 @@ +{ + "Environment": "Dev", + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "ConnectionStrings": { + "DefaultConnection": "server=192.168.80.81;Database=sjzy_package_channel;Uid=root;Pwd=10c1fb814e7c1552;" + }, + "Redis": { + "ConnectionString": "192.168.80.57:6379,abortConnect=false", + "PassWord": "", + "DefaultDatabaseIndex": 6, + "Prefix": "" + }, + "Consul": { + "ServiceName": "PackageChannel", + "ServiceIP": "192.168.80.55", + "ServicePort": 5034, + "ServiceHealthCheck": "http://192.168.80.55:5034/HealthCheck", + "ConsulAddress": "http://192.168.80.56:8500" + }, + "CorsPolicy": [ + "http://172.16.216.101:18006" + ], + "Swagger": { + "IsEnable": true, + "ServiceUrl": "", + "JsonUrlPrefix": "", //转发目录前缀,部署服务器时需要配置 /kingmall + "ScanPrefix": [ "SJZY" ] //全局扫描程序集或xml文件时只加载以 SJZY 开头的内容 + }, + "OSS": { + "AccessKeyId": "LTAI5tJWyx1kgQfk221QFknu", + "AccessKeySecret": "0AvP3vyBdwT1pwvLXeqeJ448US8QL8", + "Endpoint": "http://oss-cn-shenzhen.aliyuncs.com/", + "BucketName": "cams3" + }, + "RabbitMQ": { + "UserName": "sjzy", + "Password": "sjzyadmin", + "HostName": "192.168.80.56", + "Port": 5672 + }, + "Custome": { + "Setting1": 12, + "Setting2": 22 + }, + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "System": "Warning", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information", + "Microsoft.EntityFrameworkCore": "Information" + } + }, + "Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ], + "WriteTo": [ + { + "Name": "Console", + "Args": { + //"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, SystemConsoleTheme.Literate", + "outputTemplate": "{NewLine}[{Timestamp:yyyy-MM-dd HH:mm:ss fff} {Level:u3}] {Message:lj}" + } + }, + { + "Name": "File", + "Args": { + "path": "logs/.log", + "rollingInterval": "Day", + "outputTemplate": "{NewLine}[{Timestamp:yyyy-MM-dd HH:mm:ss,fff} {Level:u3}] {Message:lj}" + } + }, + { + "Name": "Elasticsearch", + "Args": { + "nodeUris": "http://192.168.80.56:9200", + "indexFormat": "log_channel_{0:yyyy.MM.dd}", + "autoRegisterTemplate": true, + "autoRegisterTemplateVersion": "ESv7", + "connectionGlobalHeaders": "Authorization=Basic ZWxhc3RpYzpzanp5YWRtaW4=;" + } + } + ] + }, + "QiChaCha": { + "ApiUrl": "http://api.qichacha.com", + "Key": "3f07b46db1104426a7beec2a70b67334", + "SecretKey": "0DEDE94A0E14C5A060CF65F87A96FDDC", + "ValidDays": 180 + } + +} diff --git a/src/SJZY.Track.Api/appsettings.Test.json b/src/SJZY.Track.Api/appsettings.Test.json new file mode 100644 index 00000000..825693ce --- /dev/null +++ b/src/SJZY.Track.Api/appsettings.Test.json @@ -0,0 +1,91 @@ +{ + "Environment": "Dev", + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "ConnectionStrings": { + "DefaultConnection": "server=192.168.80.84;Database=sjzy_package_setting;Uid=sjzy_test_user;Pwd=848c1c31;AllowLoadLocalInfile=true;SslMode=None;Charset=utf8mb4;", + "canalView": "server=192.168.80.84;Database=sjzy_data_center;Uid=sjzy_test_user;Pwd=848c1c31;AllowLoadLocalInfile=true;SslMode=None;Charset=utf8mb4;" + }, + "Redis": { + "ConnectionString": "192.168.80.58:6379,abortConnect=false", + "PassWord": "", + "DefaultDatabaseIndex": 8, + "Prefix": "" + }, + "Consul": { + "ServiceName": "Package.Setting", + "ServiceIP": "192.168.80.57", + "ServicePort": 5047, + "ServiceHealthCheck": "http://192.168.80.57:5047/HealthCheck", + "ConsulAddress": "http://192.168.80.58:8500" + }, + "CorsPolicy": [ + "" + ], + "Swagger": { + "IsEnable": true, + "ServiceUrl": "", + "JsonUrlPrefix": "", //转发目录前缀,部署服务器时需要配置 /kingmall + "ScanPrefix": [ "SJZY" ] //全局扫描程序集或xml文件时只加载以 SJZY 开头的内容 + }, + "RabbitMQ": { + "UserName": "sjzy", + "Password": "sjzyadmin", + "HostName": "192.168.80.58", + "Port": 5672 + }, + "Custome": { + "Setting1": 12, + "Setting2": 22 + }, + "Serilog": { + "MinimumLevel": { + "Default": "Information", + "Override": { + "System": "Warning", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information", + "Microsoft.EntityFrameworkCore": "Information" + } + }, + "Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ], + "WriteTo": [ + { + "Name": "Console", + "Args": { + //"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, SystemConsoleTheme.Literate", + "outputTemplate": "{NewLine}[{Timestamp:yyyy-MM-dd HH:mm:ss fff} {Level:u3}] {Message:lj}" + } + }, + { + "Name": "File", + "Args": { + "path": "logs/.log", + "rollingInterval": "Day", + "outputTemplate": "{NewLine}[{Timestamp:yyyy-MM-dd HH:mm:ss,fff} {Level:u3}] {Message:lj}" + } + }, + { + "Name": "Elasticsearch", + "Args": { + "nodeUris": "http://192.168.80.97:9200", + "indexFormat": "log_package_setting_{0:yyyy.MM.dd}", + "autoRegisterTemplate": true, + "autoRegisterTemplateVersion": "ESv7", + "connectionGlobalHeaders": "Authorization=Basic ZWxhc3RpYzpzanp5YWRtaW4=;" + } + } + ] + }, + "OSS": { + "AccessKeyId": "LTAI5tJWyx1kgQfk221QFknu", + "AccessKeySecret": "0AvP3vyBdwT1pwvLXeqeJ448US8QL8", + "Endpoint": "http://oss-cn-shenzhen.aliyuncs.com/", + "BucketName": "cams3", + "ReturnHttpsUrl": true + } +} diff --git a/src/SJZY.Track.Api/appsettings.json b/src/SJZY.Track.Api/appsettings.json new file mode 100644 index 00000000..850809ba --- /dev/null +++ b/src/SJZY.Track.Api/appsettings.json @@ -0,0 +1,20 @@ +{ + "Configuration": { + "UseLocalConfiguration": true, // 是否使用本地配置文件 + "ConfiguraFileName": "appsettings.Development.json", //指定配置文件名称,开启 UseLocalConfiguration 时生效 + "Apollo": { + "AppId": "SJZY.Track.Configuration", + "Env": "DEV", + "Namespace": "Dev", + "MetaServer": "http://apollo-service-test-apollo-configservice.apollo.svc.cluster.local:8080", + "ConfigServer": [ "http://apollo-service-test-apollo-configservice.apollo.svc.cluster.local:8080" ] + } + }, + "Kestrel": { + "EndPoints": { + "Http": { + "Url": "http://*:5056" + } + } + } + } diff --git a/src/SJZY.Track.Api/skyapm.json b/src/SJZY.Track.Api/skyapm.json new file mode 100644 index 00000000..92023e4e --- /dev/null +++ b/src/SJZY.Track.Api/skyapm.json @@ -0,0 +1,30 @@ +{ + "SkyWalking": { + "ServiceName": "PackagePlatform", + "Namespace": "", + "HeaderVersions": [ + "sw8" + ], + "Sampling": { + "SamplePer3Secs": -1, + "Percentage": -1.0 + }, + "Logging": { + "Level": "Information", + "FilePath": "logs\\skyapm-{Date}.log" + }, + "Transport": { + "Interval": 3000, + "ProtocolVersion": "v8", + "QueueSize": 30000, + "BatchSize": 3000, + "gRPC": { + "Servers": "skywalking-skywalking-helm-oap.skywalking:11800", + "Timeout": 10000, + "ConnectTimeout": 10000, + "ReportTimeout": 600000, + "Authentication": "" + } + } + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/ApplicationModule.cs b/src/SJZY.Track.Application/ApplicationModule.cs new file mode 100644 index 00000000..0fa79af5 --- /dev/null +++ b/src/SJZY.Track.Application/ApplicationModule.cs @@ -0,0 +1,81 @@ +using SJZY.Expand.ABP.Core.Localization; +using SJZY.LoggerCenter.HttpApi; +using SJZY.Track.Application.Localization; +using SJZY.UserCenter.Contracts; +using SJZY.UserCenter.SharedModel; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.AutoMapper; +using Volo.Abp.FluentValidation; +using Volo.Abp.Http.Client; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; + +namespace SJZY.Track.Application +{ + [DependsOn( + typeof(AbpAutoMapperModule), + typeof(RepositoryModule), + typeof(AbpFluentValidationModule), + typeof(AbpLocalizationModule), + typeof(AbpVirtualFileSystemModule), + typeof(AbpHttpClientModule), + typeof(LoggerCenterHttpApiModule) + )] + public class ApplicationModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + Configure(options => + { + options.AddMaps(true); + }); + + Configure(options => + { + options.ConventionalControllers.Create(typeof(ApplicationModule).Assembly);//创建动态api + }); + + + + //添加虚拟文件系统 + Configure(options => + { + options.FileSets.AddEmbedded("SJZY.Track.Application"); + }); + + //添加多语言 + Configure(options => + { + options.Resources + .Add("zh") + .AddBaseTypes(typeof(SjzyBasicLocalization)) + .AddVirtualJson("/Localization/Resources"); + }); + + //日志中心 + context.Services.AddHttpClientProxies(typeof(LoggerCenterHttpApiModule).Assembly, "LoggerCenter", false); + + //用户中心 + context.Services.AddHttpClientProxies(typeof(SjzyUserCenterHttpApiModule).Assembly, "UserCenter", false); + } + + public override void PreConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + PreConfigure(options => + { + + options.ProxyClientActions.Add(async (remoteName, serviceProvider, httpClient) => + { + //如果设置Token,前端需要传入Token 否则引发异常 + httpClient.SetTokenHeader(); + httpClient.Timeout = TimeSpan.FromMinutes(3); + await Task.CompletedTask; + }); + }); + } + + } +} diff --git a/src/SJZY.Track.Application/AutoMapper/AutoMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/AutoMapperProfile.cs new file mode 100644 index 00000000..563fc396 --- /dev/null +++ b/src/SJZY.Track.Application/AutoMapper/AutoMapperProfile.cs @@ -0,0 +1,33 @@ +using AutoMapper; +using SJZY.Track.Application.Dtos.Demo; +using SJZY.Track.Repository.Demo.ValueObjects; + +namespace SJZY.Track.Application.AutoMapper +{ + internal class AutoMapperProfile : Profile + { + public AutoMapperProfile() + { + CreateMap, UnifyPageResultDto>(MemberList.None); + + CreateMap(MemberList.None).ReverseMap(); + CreateMap, UnifyPageResultDto>(MemberList.None).ReverseMap(); + /* + 代码说明: + MemberList.None的意思是,忽略源对象和目标对象的属性匹配检查,其他可选值:MemberList.Source(检查是否映射了所有源成员)、MemberList.Destination(检查是否映射了所有目标成员) + .ReverseMap()的意思是配置双向调用关系,既一行代码既支持从 GetDemoListByPageInput -> DemoValueObject 的映射,同时也支持从 DemoValueObject -> GetDemoListByPageInput 的映射 + + + 如果对一对模型多次配置规则,会以最后一次为准,配置了这样规则后,最终执行结果是 Name + 444 + CreateMap().ForMember(dest => dest.Description, opt => opt.MapFrom(m => m.Name + "22")); + CreateMap().ForMember(dest => dest.Description, opt => opt.MapFrom(m => m.Name + "444")); + + */ + + CreateMap(MemberList.None).ReverseMap(); + CreateMap(MemberList.None); + CreateMap(MemberList.None).ReverseMap(); + + } + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/AutoMapper/DemoAutoMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/DemoAutoMapperProfile.cs new file mode 100644 index 00000000..8e04d1ce --- /dev/null +++ b/src/SJZY.Track.Application/AutoMapper/DemoAutoMapperProfile.cs @@ -0,0 +1,43 @@ +using AutoMapper; +using SJZY.Expand.ABP.Core.PublicMethords; +using SJZY.Track.Application.Dtos.Demo; + + +namespace SJZY.Track.Application.AutoMapper +{ + /// + /// 稍复杂的配置类 + /// + internal class DemoAutoMapperProfile : Profile + { + public DemoAutoMapperProfile() + { + CreateMap(MemberList.None) + //层级不一致的场景 + .ForMember(dest => dest.QQ, opt => opt.MapFrom(source => source.UserInfo.QQ)) + //数据类型不一致的场景,这里如果不指定映射规则会直接取枚举的key值 + .ForMember(dest => dest.Gender, opt => opt.MapFrom(source => source.Gender.GetDescription())) + //一些简单计算的场景,酌情使用... + .ForMember(dest => dest.Age, opt => opt.MapFrom(source => GetAgeByBirthdate(source.UserInfo.BirthDay))) + //结构不一致的场景 + .ForMember(dest => dest.RoleIds, opt => opt.MapFrom(source => source.UserRoleInputList.Select(m => m.Id).ToArray())) + //条件映射(这里只是举例,日常开发时sqlsugar在新增时会避开自增主键) + .ForMember(dest => dest.Id, opt => + { + opt.Condition(src => src.OptionType == OptionType.删除 || src.OptionType == OptionType.修改); + }); + } + + public int GetAgeByBirthdate(DateTime birthdate) + { + DateTime now = DateTime.Now; + int age = now.Year - birthdate.Year; + if (now.Month < birthdate.Month || (now.Month == birthdate.Month && now.Day < birthdate.Day)) + { + age--; + } + return age < 0 ? 0 : age; + } + + } +} diff --git a/src/SJZY.Track.Application/Dtos/Demo/ComplexAutomapperDemoInput.cs b/src/SJZY.Track.Application/Dtos/Demo/ComplexAutomapperDemoInput.cs new file mode 100644 index 00000000..de4bc495 --- /dev/null +++ b/src/SJZY.Track.Application/Dtos/Demo/ComplexAutomapperDemoInput.cs @@ -0,0 +1,89 @@ +namespace SJZY.Track.Application.Dtos.Demo +{ + /// + /// automapper 复杂转换样例 + /// + public class ComplexAutomapperDemoInput + { + /// + /// 编号 + /// + public int Id { get; set; } + + /// + /// 操作类型 + /// + public OptionType OptionType { get; set; } + + /// + /// 描述 + /// + public string Description { get; set; } + + /// + /// 性别 + /// + public Gender Gender { get; set; } + + /// + /// 用户信息 + /// + public UserInfoInput UserInfo { get; set; } + + /// + /// 用户角色 + /// + public List UserRoleInputList { get; set; } + + /// + /// 拓展演示,目前大家共同约定,暂时不使用充血模型 + /// + /// + public string GetAddress() + { + return "辽宁省沈阳市..."; + } + + } + + public class ComplexAutomapperDemoOutput + { + /// + /// 编号 + /// + public int Id { get; set; } + + /// + /// 性别 + /// + public string Gender { get; set; } + + /// + /// 描述 + /// + public string Description { get; set; } + + /// + /// 年龄 + /// + public int Age { get; set; } + + /// + /// qq号码 + /// + public string QQ { get; set; } + + /// + /// 地址 + /// + public string Address { get; set; } + + /// + /// 角色编号 + /// + public int[] RoleIds { get; set; } + } + + + +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Dtos/Demo/DemoDetailInput.cs b/src/SJZY.Track.Application/Dtos/Demo/DemoDetailInput.cs new file mode 100644 index 00000000..30da5896 --- /dev/null +++ b/src/SJZY.Track.Application/Dtos/Demo/DemoDetailInput.cs @@ -0,0 +1,48 @@ +namespace SJZY.Track.Application.Dtos.Demo +{ + public class DemoDetailSaveInput + { + /// + /// + /// + public int Id { get; set; } + + /// + /// 姓名 + /// + public string Name { get; set; } + + /// + /// 年龄 + /// + public int Age { get; set; } + + /// + /// 描述 + /// + public string Description { get; set; } + + /// + /// 详情合集 + /// + public List DemoDetailList { get; set; } + } + + public class DemoDetailInput + { + /// + /// Id + /// + public int Id { get; set; } + + /// + /// t_demo.id + /// + public int DemoId { get; set; } + + /// + /// 一些说明.. + /// + public string OtherInfo { get; set; } + } +} diff --git a/src/SJZY.Track.Application/Dtos/Demo/DemoInput.cs b/src/SJZY.Track.Application/Dtos/Demo/DemoInput.cs new file mode 100644 index 00000000..13f63049 --- /dev/null +++ b/src/SJZY.Track.Application/Dtos/Demo/DemoInput.cs @@ -0,0 +1,42 @@ +namespace SJZY.Track.Application.Dtos.Demo +{ + public class DemoInput + { + /// + /// 操作类型 + /// + public OptionType Option { get; set; } + + /// + /// + /// + public int Id { get; set; } + + /// + /// 姓名 + /// + public string Name { get; set; } + + /// + /// 年龄 + /// + public int Age { get; set; } + + /// + /// 描述 + /// + public string Description { get; set; } + + //以下两个属性用来说明类型转换 + + /// + /// 创建人id + /// + public string CreateUserId { get; set; } + + /// + /// 创建时间 + /// + public string CreateTime { get; set; } + } +} diff --git a/src/SJZY.Track.Application/Dtos/Demo/ExcelImportOuput.cs b/src/SJZY.Track.Application/Dtos/Demo/ExcelImportOuput.cs new file mode 100644 index 00000000..46ef9d04 --- /dev/null +++ b/src/SJZY.Track.Application/Dtos/Demo/ExcelImportOuput.cs @@ -0,0 +1,11 @@ +namespace SJZY.Track.Application.Dtos.Demo +{ + public class ExcelImportOuput + { + [MiniExcelLibs.Attributes.ExcelColumnName("姓名")] + public string Name { get; set; } + + [MiniExcelLibs.Attributes.ExcelColumnName("年龄")] + public int Age { get; set; } + } +} diff --git a/src/SJZY.Track.Application/Dtos/Demo/GetDemoListByPageInput.cs b/src/SJZY.Track.Application/Dtos/Demo/GetDemoListByPageInput.cs new file mode 100644 index 00000000..55d86e2c --- /dev/null +++ b/src/SJZY.Track.Application/Dtos/Demo/GetDemoListByPageInput.cs @@ -0,0 +1,10 @@ +namespace SJZY.Track.Application.Dtos.Demo +{ + public class GetDemoListByPageInput : PageInfoInput + { + /// + /// 姓名 + /// + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Dtos/Demo/GetDemoListByPageOutput.cs b/src/SJZY.Track.Application/Dtos/Demo/GetDemoListByPageOutput.cs new file mode 100644 index 00000000..3c5bd96d --- /dev/null +++ b/src/SJZY.Track.Application/Dtos/Demo/GetDemoListByPageOutput.cs @@ -0,0 +1,27 @@ +namespace SJZY.Track.Application.Dtos.Demo +{ + public class GetDemoListByPageOutput + { + /// + /// + /// + public int Id { get; set; } + + /// + /// 姓名 + /// + public string Name { get; set; } + + /// + /// 年龄 + /// + public int Age { get; set; } + + /// + /// 描述 + /// + public string Description { get; set; } + + public DateTime CreateTime { get; set; } + } +} diff --git a/src/SJZY.Track.Application/Dtos/Demo/MyCustomerResultOutput.cs b/src/SJZY.Track.Application/Dtos/Demo/MyCustomerResultOutput.cs new file mode 100644 index 00000000..8d6896ac --- /dev/null +++ b/src/SJZY.Track.Application/Dtos/Demo/MyCustomerResultOutput.cs @@ -0,0 +1,9 @@ +namespace SJZY.Track.Application.Dtos.Demo +{ + public class MyCustomerResultOutput + { + public string Code { get; set; } + + public string Message { get; set; } + } +} diff --git a/src/SJZY.Track.Application/Dtos/Demo/OssUploadOutput.cs b/src/SJZY.Track.Application/Dtos/Demo/OssUploadOutput.cs new file mode 100644 index 00000000..367d2c54 --- /dev/null +++ b/src/SJZY.Track.Application/Dtos/Demo/OssUploadOutput.cs @@ -0,0 +1,15 @@ +namespace SJZY.Track.Application.Dtos.Demo +{ + public class OssUploadOutput + { + /// + /// 文件key + /// + public string Key { get; set; } + + /// + /// 文件路径 + /// + public string Url { get; set; } + } +} diff --git a/src/SJZY.Track.Application/Dtos/Demo/SwaggerDemoInput.cs b/src/SJZY.Track.Application/Dtos/Demo/SwaggerDemoInput.cs new file mode 100644 index 00000000..f521c50e --- /dev/null +++ b/src/SJZY.Track.Application/Dtos/Demo/SwaggerDemoInput.cs @@ -0,0 +1,42 @@ +using System.ComponentModel; +using System.Text.Json.Serialization; + +namespace SJZY.Track.Application.Dtos.Demo +{ + public class SwaggerDemoInput + { + /// + /// 年龄 + /// + /// 18 这里可以写一些初始值 + public int Age { get; set; } + + /// + /// 姓名 + /// + public string Name { get; set; } + + /// + /// 性别(枚举的展示样例) + /// + public Gender Gender { get; set; } + + /// + /// 隐藏属性 + /// + [JsonIgnore] + public int MyProperty { get; set; } + } + + public enum Gender + { + [Description("纯爷们")] + 男 = 2, + + [Description("大姑娘")] + 女 = 5, + + [Description("你憋问")] + 未知 = 8 + } +} diff --git a/src/SJZY.Track.Application/Dtos/Demo/ValidateExecuteInput.cs b/src/SJZY.Track.Application/Dtos/Demo/ValidateExecuteInput.cs new file mode 100644 index 00000000..f1c3fc45 --- /dev/null +++ b/src/SJZY.Track.Application/Dtos/Demo/ValidateExecuteInput.cs @@ -0,0 +1,98 @@ +namespace SJZY.Track.Application.Dtos.Demo +{ + public class ValidateExecuteInput + { + /// + /// 操作类型 + /// + public OptionType Option { get; set; } + + /// + /// 主键编号 + /// + public int Id { get; set; } + + /// + /// 雪花ID + /// + public long SnowId { get; set; } + + /// + /// 登录账号 + /// + public string LoginName { get; set; } + + /// + /// 登录密码 + /// + public string? PassWord { get; set; } + + /// + /// 登录密码确认 + /// + public string PassWordAgain { get; set; } + + /// + /// 最大金额额度 + /// + public decimal TotalQuota { get; set; } + + /// + /// 最大数量 + /// + public int MaxCount { get; set; } + + /// + /// 最小数量 + /// + public int MiniCount { get; set; } + + /// + /// 用户信息 + /// + public UserInfoInput UserInfoInput { get; set; } + + /// + /// 用户角色 + /// + public List UserRoleInputList { get; set; } + + } + + public class UserInfoInput + { + /// + /// 生日 + /// + public DateTime BirthDay { get; set; } + + /// + /// qq号码 + /// + public string QQ { get; set; } + + /// + /// 电子邮箱 + /// + public string Email { get; set; } + + /// + /// 用户姓名 + /// + public string UserName { get; set; } + } + + + public class UserRoleInput + { + /// + /// 角色编号 + /// + public int Id { get; set; } + + /// + /// 角色名称 + /// + public string Name { get; set; } + } +} diff --git a/src/SJZY.Track.Application/Dtos/Demo/ValidateExecuteOutput.cs b/src/SJZY.Track.Application/Dtos/Demo/ValidateExecuteOutput.cs new file mode 100644 index 00000000..13cede57 --- /dev/null +++ b/src/SJZY.Track.Application/Dtos/Demo/ValidateExecuteOutput.cs @@ -0,0 +1,6 @@ +namespace SJZY.Track.Application.Dtos.Demo +{ + public class ValidateExecuteOutput + { + } +} diff --git a/src/SJZY.Track.Application/GlobalUsing.cs b/src/SJZY.Track.Application/GlobalUsing.cs new file mode 100644 index 00000000..23e3b927 --- /dev/null +++ b/src/SJZY.Track.Application/GlobalUsing.cs @@ -0,0 +1,9 @@ +global using Microsoft.AspNetCore.Mvc; +global using Microsoft.Extensions.DependencyInjection; +global using SJZY.Expand.ABP.Common.Enums; +global using SJZY.Expand.ABP.Core.Common.Dto; +global using SJZY.Track.Repository; +global using SJZY.Track.Repository.Demo.Entitys; +global using Volo.Abp; +global using Volo.Abp.Application.Services; +global using Volo.Abp.Validation; diff --git a/src/SJZY.Track.Application/Localization/Resources/en.json b/src/SJZY.Track.Application/Localization/Resources/en.json new file mode 100644 index 00000000..5994b511 --- /dev/null +++ b/src/SJZY.Track.Application/Localization/Resources/en.json @@ -0,0 +1,8 @@ +{ + "culture": "en", + "texts": { + "NotNull1": "{0} is not null", + "NotFindData": "No data found under the specified number", + "ParameterDemo1": "{0} in {1} to do {2}" + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Localization/Resources/zh.json b/src/SJZY.Track.Application/Localization/Resources/zh.json new file mode 100644 index 00000000..48af2570 --- /dev/null +++ b/src/SJZY.Track.Application/Localization/Resources/zh.json @@ -0,0 +1,8 @@ +{ + "culture": "zh", + "texts": { + "NotFindData": "未找到指定编号下的任何数据!", + "ParameterDemo": "{0}在{1}地方做了{2}动作", + "ParameterDemo1": "{0}在{1}地方做了{2}动作" + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Localization/TrackLocalizationResource.cs b/src/SJZY.Track.Application/Localization/TrackLocalizationResource.cs new file mode 100644 index 00000000..70e2cea5 --- /dev/null +++ b/src/SJZY.Track.Application/Localization/TrackLocalizationResource.cs @@ -0,0 +1,10 @@ +using SJZY.Expand.ABP.Core.Localization; +using Volo.Abp.Localization; + +namespace SJZY.Track.Application.Localization +{ + [InheritResource(typeof(SjzyBasicLocalization))] + public class TrackLocalizationResource + { + } +} diff --git a/src/SJZY.Track.Application/Options/CustomeOptions.cs b/src/SJZY.Track.Application/Options/CustomeOptions.cs new file mode 100644 index 00000000..39f20d96 --- /dev/null +++ b/src/SJZY.Track.Application/Options/CustomeOptions.cs @@ -0,0 +1,10 @@ +using SJZY.Expand.ABP.Core; + +namespace SJZY.Track.Application.Options +{ + public class CustomeOptions : IOptionAutoInjection + { + public int Setting1 { get; set; } + public int Setting2 { get; set; } + } +} diff --git a/src/SJZY.Track.Application/SJZY.Track.Application.csproj b/src/SJZY.Track.Application/SJZY.Track.Application.csproj new file mode 100644 index 00000000..37c0357f --- /dev/null +++ b/src/SJZY.Track.Application/SJZY.Track.Application.csproj @@ -0,0 +1,33 @@ + + + + net7.0 + enable + True + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/SJZY.Track.Application/Services/Demo/InterFaceDemoService.cs b/src/SJZY.Track.Application/Services/Demo/InterFaceDemoService.cs new file mode 100644 index 00000000..145322ac --- /dev/null +++ b/src/SJZY.Track.Application/Services/Demo/InterFaceDemoService.cs @@ -0,0 +1,234 @@ +using SJZY.Expand.ABP.Core.Common; +using SJZY.Track.Application.Dtos.Demo; +using SJZY.Track.Repository.Demo.Services; +using SJZY.Track.Repository.Demo.ValueObjects; +using Volo.Abp.Http.Client.DynamicProxying; + +namespace SJZY.Track.Application.Services.Demo +{ + /// + /// 接口请求完整样例 + /// + [ApiExplorerSettings(GroupName = "Demo")] + public class InterFaceDemoService : ApplicationService + { + #region 构造函数 + private readonly IDemoRepository _demoRepository; + public InterFaceDemoService(IDemoRepository demoRepository) + { + _demoRepository = demoRepository; + } + #endregion + + #region 增删改 + /// + /// 增删改 + /// + /// + /// + [HttpPost("InterFace/Edit")] + public async Task Edit(DemoInput input) + { + var res = new LongIdBaseDto(); + + if (input.Option == OptionType.新增) + { + var entity = ObjectMapper.Map(input); + res.Id = await _demoRepository.InsertReturnIdentityAsync(entity); + } + else if (input.Option == OptionType.修改 || input.Option == OptionType.删除) + { + + var demoInfo = await _demoRepository.GetById1(input.Id); + if (demoInfo == null) + { + //校验数据是否存在... + throw new BusinessException(message: "未找到指定编号下的数据"); + } + + res.Id = demoInfo.Id; + if (input.Option == OptionType.删除) + { + //await _demoRepository.DeleteAsync(demoInfo); //真删除 + + //软删除 + demoInfo.IsDeleted = true; + await _demoRepository.UpdateAsync(demoInfo); + } + else + { + var entity = ObjectMapper.Map(input, demoInfo); + await _demoRepository.UpdateAsync(entity); + } + } + return res; + } + + #endregion + + #region 局部更新最佳实践 + /// + /// 局部更新最佳实践 + /// + /// + /// + /// + [HttpPost("InterFace/UpdatePartColumns")] + public async Task UpdatePartColumns(DemoInput input) + { + var demoInfo = await _demoRepository.GetById1(input.Id); + if (demoInfo == null) + { + //校验数据是否存在... + throw new BusinessException(message: "未找到指定编号下的数据"); + } + + //更新同时忽略某几项参数 + await _demoRepository.UpdatePartColumns(demoInfo); + + return new IdBaseDto() { Id = input.Id }; + } + #endregion + + #region 分页查询接口 + /// + /// 分页查询 + /// + /// + /// + [HttpPost("InterFace/GetListByPage")] + public async Task> GetListByPage(GetDemoListByPageInput input) + { + //分页时返回值统一用 PageResultDto<> 类型 + var list = await _demoRepository.GetListByPage(input.PageSize, input.PageIndex, input.Name); + + var res = ObjectMapper.Map, UnifyPageResultDto>(list); + + return res; + } + #endregion + + #region 入参转换 + /// + /// 入参转换 + /// + /// + /// + [HttpPost("InterFace/InputToValueObject")] + public async Task> InputToValueObject(GetDemoListByPageInput input) + { + var obj = ObjectMapper.Map(input); + var list = await _demoRepository.InputToValueObject(obj); + + var res = ObjectMapper.Map, List>(list); + return res; + } + #endregion + + #region 原生sql + + /// + /// 原生sql + /// + /// + /// + [HttpPost("InterFace/OriginalSql")] + public async Task> OriginalSql(DemoValueObject obj) + { + var list = await _demoRepository.OriginalSql(obj); + return list; + } + + #endregion + + #region 自定义返回结果格式 + /// + /// 自定义返回结果格式 + /// + /// + /// + [HttpPost("Demo/CustomerResult")] + [CustomerResult] + public async Task GetListAsync() + { + /* + 说明: + 理论上我们有全公司级别的返回值约定,不管是前端调后端,还是后端微服务间的调用,都应完全遵循该规范。 + 但不排除有些特殊情况下,必须要返回自定义格式的场景。 + */ + + var res = new MyCustomerResultOutput(); + res.Code = "200"; + res.Message = "这是一个自定义返回结果"; + + return res; + } + #endregion + + #region 约定类型下返回null + /// + /// 约定类型下返回null + /// + /// + /// + [HttpPost("Demo/ReturnNull")] + public async Task ReturnNull() + { + MyCustomerResultOutput res = null; + return res; + } + #endregion + + #region + /// + /// 没有返回值 + /// + /// + /// + [HttpPost("Demo/WithoutReturnObject")] + public async Task WithoutReturnObject() + { + return null; + } + #endregion + + #region 主从关系实体存储 + /// + /// 主从关系实体存储 + /// + /// + /// + [HttpPost("InterFace/EntityRelationSave")] + public async Task EntityRelationSave(DemoDetailSaveInput input) + { + var obj = ObjectMapper.Map(input); + var res = await _demoRepository.EntityRelationSave(obj); + + return new UnifyResultDto(res); + } + + #endregion + + #region 数据缓存 + /// + /// 数据缓存 + /// + /// + /// + [HttpPost("InterFace/GetDataCache")] + public async Task GetDataCache(IdBaseDto input) + { + var res = await _demoRepository.GetDataCache(input.Id); + return res; + } + #endregion + + //[HttpPost("InterFace/AAAA")] + //public async Task AAAA() + //{ + // var result = await _httpClientProxy.Service.GetSystemTokenAsync("Track"); + + // return result; + //} + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Application/Validations/Demo/SimpleValidateInputValidation.cs b/src/SJZY.Track.Application/Validations/Demo/SimpleValidateInputValidation.cs new file mode 100644 index 00000000..db26be85 --- /dev/null +++ b/src/SJZY.Track.Application/Validations/Demo/SimpleValidateInputValidation.cs @@ -0,0 +1,68 @@ +using FluentValidation; +using SJZY.Track.Application.Dtos.Demo; + +namespace SJZY.Track.Application.Validations.Demo +{ + + public class SimpleValidateInputValidation : AbstractValidator, IValidationEnabled + { + public SimpleValidateInputValidation() + { + /* + 非空校验 + NotNull 和 NotEmpty 的区别? + NotNull:请求中没找到指定参数 + NotEmpty:请求中没找到指定参数 或 参数值为初始值(0/"") + 关于字符串的最佳实践: + 参数定义成可空字符串 string?,校验规则只用isempty + + */ + RuleFor(x => x.PassWord).NotNull().WithMessage("操作密码为必填参数!").NotEmpty().WithMessage("操作密码不能为空!"); + + //雪花id + RuleFor(x => x.SnowId).NotNull().WithMessage("雪花ID为必填参数!").NotEmpty().WithMessage("雪花ID不能为空!"); + + //枚举校验 + RuleFor(x => x.Option).IsInEnum().WithMessage("操作类型不在可选范围!"); + + //字符串长度校验,长度不分中文、字符、数值 + RuleFor(x => x.LoginName).Length(6, 10).WithMessage("登录账号必须在6-10位之间!"); + RuleFor(x => x.LoginName).MaximumLength(10).WithMessage("登录账号不能超过10个字符!"); + RuleFor(x => x.LoginName).MinimumLength(6).WithMessage("登录账号不能小于6个字符!"); + + //正则表达式 + RuleFor(x => x.PassWord).Matches("^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[!@#$\\%\\^\\&\\*\\(\\)])[0-9a-zA-Z!@#$\\%\\^\\&\\*\\(\\)]{6,10}") + .WithMessage("密码必须同时包含数字、英文字母、特殊字符,且长度必须在6-10位之间"); + + //自定义校验规则,注意这里的校验仅限于模型参数级的校验,更复杂的业务校验应在业务层完成 + RuleFor(x => x.PassWordAgain).Must((data, context) => + { + return data.PassWord == data.PassWordAgain; + }).WithMessage("两次输入密码不一致!"); + + //数字类型校验 + RuleFor(x => x.MiniCount).LessThan(100).WithMessage("最小数量必须小于100"); + RuleFor(x => x.MiniCount).LessThanOrEqualTo(100).WithMessage("最小数量必须小于或等于100"); + RuleFor(x => x.MaxCount).GreaterThan(100).WithMessage("最大数量必须大于100"); + RuleFor(x => x.MaxCount).GreaterThanOrEqualTo(100).WithMessage("最大数量必须大于或等于100"); + + //小数类型校验,10.56 + RuleFor(x => x.TotalQuota).ScalePrecision(2, 4, true).WithMessage("最大额度金额【整数位+小数位】不能超过4位,且小数位不能超过2位"); + + //条件分支 + When(x => x.Option == OptionType.修改 || x.Option == OptionType.删除, () => + { + RuleFor(x => x.Id).NotNull().WithMessage("修改或删除时Id为必填参数!").GreaterThan(0).WithMessage("修改或删除时Id必须大于0!"); + }); + + //单个实体校验 + RuleFor(x => x.UserInfoInput).NotNull().WithMessage("用户信息为必填参数!").SetValidator(new UserInfoInputValidation()); + + //集合校验 + RuleForEach(x => x.UserRoleInputList).SetValidator(new UserRoleInputValidation()); + } + + } + + +} diff --git a/src/SJZY.Track.Application/Validations/Demo/UserInfoInputValidation.cs b/src/SJZY.Track.Application/Validations/Demo/UserInfoInputValidation.cs new file mode 100644 index 00000000..b8e5268f --- /dev/null +++ b/src/SJZY.Track.Application/Validations/Demo/UserInfoInputValidation.cs @@ -0,0 +1,15 @@ +using FluentValidation; +using SJZY.Track.Application.Dtos.Demo; + + +namespace SJZY.Track.Application.Validations.Demo +{ + public class UserInfoInputValidation : AbstractValidator, IValidationEnabled + { + public UserInfoInputValidation() + { + RuleFor(x => x.QQ).NotNull().WithMessage("QQ号码不能为空"); + } + + } +} diff --git a/src/SJZY.Track.Application/Validations/Demo/UserRoleInputValidation.cs b/src/SJZY.Track.Application/Validations/Demo/UserRoleInputValidation.cs new file mode 100644 index 00000000..fa0307a2 --- /dev/null +++ b/src/SJZY.Track.Application/Validations/Demo/UserRoleInputValidation.cs @@ -0,0 +1,13 @@ +using FluentValidation; +using SJZY.Track.Application.Dtos.Demo; + +namespace SJZY.Track.Application.Validations.Demo +{ + public class UserRoleInputValidation : AbstractValidator, IValidationEnabled + { + public UserRoleInputValidation() + { + RuleFor(m => m.Id).GreaterThan(0).WithMessage("角色ID必须大于0!"); + } + } +} diff --git a/src/SJZY.Track.HttpApi/Dtos/RemoteDemoInput.cs b/src/SJZY.Track.HttpApi/Dtos/RemoteDemoInput.cs new file mode 100644 index 00000000..b010b6bd --- /dev/null +++ b/src/SJZY.Track.HttpApi/Dtos/RemoteDemoInput.cs @@ -0,0 +1,10 @@ +namespace SJZY.Track.HttpApi.Dtos +{ + public class RemoteDemoInput + { + /// + /// 当前时间 + /// + public DateTime CurrentTime { get; set; } + } +} diff --git a/src/SJZY.Track.HttpApi/Dtos/RemoteDemoOutput.cs b/src/SJZY.Track.HttpApi/Dtos/RemoteDemoOutput.cs new file mode 100644 index 00000000..44cd1f41 --- /dev/null +++ b/src/SJZY.Track.HttpApi/Dtos/RemoteDemoOutput.cs @@ -0,0 +1,7 @@ +namespace SJZY.Track.HttpApi.Dtos +{ + public class RemoteDemoOutput + { + public string Context { get; set; } + } +} diff --git a/src/SJZY.Track.HttpApi/SJZY.Track.HttpApi.csproj b/src/SJZY.Track.HttpApi/SJZY.Track.HttpApi.csproj new file mode 100644 index 00000000..1d376964 --- /dev/null +++ b/src/SJZY.Track.HttpApi/SJZY.Track.HttpApi.csproj @@ -0,0 +1,14 @@ + + + + net7.0 + enable + enable + 0.0.2 + + + + + + + diff --git a/src/SJZY.Track.HttpApi/Services/IRemoteDemoService.cs b/src/SJZY.Track.HttpApi/Services/IRemoteDemoService.cs new file mode 100644 index 00000000..6ea693bf --- /dev/null +++ b/src/SJZY.Track.HttpApi/Services/IRemoteDemoService.cs @@ -0,0 +1,15 @@ +using SJZY.Expand.ABP.Core.Common.Dto; +using SJZY.Track.HttpApi.Dtos; +using Volo.Abp; +using Volo.Abp.DependencyInjection; + +namespace SJZY.Track.HttpApi.Services +{ + /// + /// 客户端连接测试接口 + /// + public interface IRemoteDemoService : IRemoteService, IScopedDependency + { + Task> ConnectionTest(RemoteDemoInput input); + } +} diff --git a/src/SJZY.Track.HttpApi/TrackHttpApiModule.cs b/src/SJZY.Track.HttpApi/TrackHttpApiModule.cs new file mode 100644 index 00000000..522c4cf8 --- /dev/null +++ b/src/SJZY.Track.HttpApi/TrackHttpApiModule.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Modularity; + +namespace SJZY.Track.HttpApi +{ + public class TrackHttpApiModule : AbpModule + { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + + } + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/BasicRepository.cs b/src/SJZY.Track.Repository/BasicRepository.cs new file mode 100644 index 00000000..380b3256 --- /dev/null +++ b/src/SJZY.Track.Repository/BasicRepository.cs @@ -0,0 +1,15 @@ +#pragma warning disable 1591 +namespace SJZY.Track.Repository +{ + /// + /// 仓储基类 + /// + /// + public class BasicRepository : SimpleClient where T : class, new() + { + public BasicRepository() + { + Context = SqlsugarScopeBasic.GetContextSafely("default"); + } + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/DataBaseContext.cs b/src/SJZY.Track.Repository/DataBaseContext.cs new file mode 100644 index 00000000..b9712ab1 --- /dev/null +++ b/src/SJZY.Track.Repository/DataBaseContext.cs @@ -0,0 +1,53 @@ +#pragma warning disable 1591 +namespace SJZY.Track.Repository +{ + /// + /// Sqlsugar 上下文对象 + /// + public class DataBaseContext + { + + #region 审计属性自动赋值 + + public static void OnExcutingAction(object oldValue, DataFilterModel entityInfo) + { + //过滤掉 "v_" 开头的表 + if (entityInfo.EntityColumnInfo.DbTableName.StartsWith("v_", StringComparison.OrdinalIgnoreCase)) + throw new Exception("非法的操作,不允许编辑映射表"); + + //新增 + if (entityInfo.OperationType == DataFilterType.InsertByObject) + { + if (entityInfo.PropertyName == nameof(ICreateBaicEntity.CreateTime)) + entityInfo.SetValue(DateTime.Now); + if (entityInfo.PropertyName == nameof(ICreateBaicEntity.CreateUserId)) + { + //entityInfo.SetValue(CurrentUserRequest.CurrentUser.UserId); + } + } + //修改 + else if (entityInfo.OperationType == DataFilterType.UpdateByObject) + { + if (entityInfo.PropertyName == nameof(IUpdateBasicEntity.UpdateTime)) + entityInfo.SetValue(DateTime.Now); + else if (entityInfo.PropertyName == nameof(IUpdateBasicEntity.UpdateUserId)) + { + //entityInfo.SetValue(CurrentUserRequest.CurrentUser.UserId); + } + //删除 + else if (entityInfo.PropertyName == nameof(IDeleteBasicEntity.IsDeleted)) + { + var currentType = entityInfo.EntityValue.GetType(); + bool.TryParse(currentType.GetProperty(entityInfo.PropertyName)?.GetValue(entityInfo.EntityValue)?.ToString(), out bool isdelete); + if (isdelete) + { + //currentType.GetProperty(nameof(IDeleteBasicEntity.DeleteUserId))?.SetValue(entityInfo.EntityValue, 5); + currentType.GetProperty(nameof(IDeleteBasicEntity.DeleteTime))?.SetValue(entityInfo.EntityValue, DateTime.Now); + } + } + } + } + + #endregion 审计属性自动赋值 + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Demo/Entitys/DemoDetailEntity.cs b/src/SJZY.Track.Repository/Demo/Entitys/DemoDetailEntity.cs new file mode 100644 index 00000000..a0f865f9 --- /dev/null +++ b/src/SJZY.Track.Repository/Demo/Entitys/DemoDetailEntity.cs @@ -0,0 +1,24 @@ +namespace SJZY.Track.Repository.Demo.Entitys +{ + [SugarTable("t_demo_detail")] + public class DemoDetailEntity + { + /// + /// Id + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true)] + public long Id { get; set; } + + /// + /// t_demo.id + /// + [SugarColumn(ColumnName = "DemoId")] + public long DemoId { get; set; } + + /// + /// 一些说明.. + /// + [SugarColumn(ColumnName = "OtherInfo")] + public string OtherInfo { get; set; } + } +} diff --git a/src/SJZY.Track.Repository/Demo/Entitys/DemoEntity.cs b/src/SJZY.Track.Repository/Demo/Entitys/DemoEntity.cs new file mode 100644 index 00000000..c82bd5cb --- /dev/null +++ b/src/SJZY.Track.Repository/Demo/Entitys/DemoEntity.cs @@ -0,0 +1,40 @@ +namespace SJZY.Track.Repository.Demo.Entitys +{ + + /// + /// 测试表 + /// + [SugarTable("t_demo")] + public class DemoEntity : IFullAuditedBasicEntitys + { + /// + /// Id + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsIdentity = true)] + public long Id { get; set; } + + /// + /// 姓名 + /// + [SugarColumn(ColumnName = "Name")] + public string Name { get; set; } + + /// + /// 年龄 + /// + [SugarColumn(ColumnName = "Age")] + public int Age { get; set; } + + /// + /// 描述 + /// + [SugarColumn(ColumnName = "Description")] + public string Description { get; set; } + + + [Navigate(NavigateType.OneToMany, nameof(DemoDetailEntity.DemoId))] + public List DemoDetailList { get; set; } + + } + +} diff --git a/src/SJZY.Track.Repository/Demo/Services/DemoRepository.cs b/src/SJZY.Track.Repository/Demo/Services/DemoRepository.cs new file mode 100644 index 00000000..4bb01002 --- /dev/null +++ b/src/SJZY.Track.Repository/Demo/Services/DemoRepository.cs @@ -0,0 +1,198 @@ +using SJZY.Track.Repository.Demo.Entitys; +using SJZY.Track.Repository.Demo.ValueObjects; +using System.Transactions; + +namespace SJZY.Track.Repository.Demo.Services +{ + public class DemoRepository : BasicRepository, IDemoRepository, IScopedDependency + { + /* + 一般情况下常规的增删改方法不需要自己实现,只需要按照 BasicRepository 中的格式原封不动的暴露出去即可, + 比如这里接口 只声明了 UpdateAsync 和 InsertReturnIdentityAsync 接口的定义,但是这两个方法的实现我们不用写,直接交给父类实现即可 + */ + + #region 根据主键获取单条数据 + + /// + /// 根据主键获取单条数据 + /// + /// + /// + public Task GetById1(int id) + { + /* + + //以下两种方法都不会因为没找到数据而抛异常 + var model1 = base.GetFirst(m => m.Id == 0); + var model = base.GetSingle(m => m.Id == 0); + + + + //同样的写法在linq下,如果不加 OrDefault 一定会报错 + var model = base.GetList().Single(m => m.Id == 0); + var model1 = base.GetList().First(m => m.Id == 0); + + */ + return base.GetSingleAsync(it => it.Id == id); + } + + #endregion + + #region 分页获取 + + /// + /// 分页获取 + /// + /// + /// + public async Task> GetListByPage(int pageSize, int pageindex, string name) + { + var list = await AsQueryable() + .WhereIF(!string.IsNullOrEmpty(name), a => a.Name.Contains(name)) + .ToPagedListAsync(pageindex, pageSize); + + return list; + } + #endregion + + #region 参数为实体 + + /// + /// 参数很多的时候,定义模型接受参数 + /// + /// + /// + public async Task> InputToValueObject(DemoValueObject obj) + { + var list = await AsQueryable().ToListAsync(); + return list; + } + #endregion + + #region 执行原生sql语句 + /// + /// 执行原生sql语句 + /// + /// + /// + public async Task> OriginalSql(DemoValueObject obj) + { + var parameters = new List(); + var sql = @$" + select + a.id, + a.Name, + a.Age, + a.Description + from t_demo a + where 1=1 + {" and a.Name like @Name ".WhereIF(!string.IsNullOrEmpty(obj.Name), obj.Name, ref parameters)} + order by a.id desc "; + + var list = await Context.SqlQueryable(sql) + .AddParameters(parameters) + .ToPagedListAsync(obj.PageIndex, obj.PageSize); + + return list; + } + + #endregion + + #region 简单事务 + public async Task Transaction() + { + + using (var ts = new TransactionScope()) + { + + await base.InsertAsync(new DemoEntity { Name = "1111" }); + await base.InsertAsync(new DemoEntity { Name = "222" }); + await base.InsertAsync(new DemoEntity { Name = "3333" }); + + //throw new BusinessException("E05632","手动抛异常"); + await base.InsertAsync(new DemoEntity { Name = "4444" }); + + ts.Complete(); + } + } + #endregion + + #region 夸方法事务 + public async Task MultipleMethodTrans1() + { + await base.InsertAsync(new DemoEntity { Name = "---" }); + await base.InsertAsync(new DemoEntity { Name = "+++" }); + } + + public async Task MultipleMethodTrans2() + { + + //throw new BusinessException(message: "手动抛出异常"); + await base.InsertAsync(new DemoEntity { Name = "xxx" }); + } + #endregion + + #region 事务嵌套 + public async Task InternalTrans() + { + using (var ts = new TransactionScope()) + { + await Transaction(); + await MultipleMethodTrans1(); + //throw new BusinessException(message: "手动抛出异常"); + await base.InsertAsync(new DemoEntity { Name = "xxx" }); + + ts.Complete(); + } + } + #endregion + + #region 局部更新 + public async Task UpdatePartColumns(DemoEntity entity) + { + Context.Updateable(entity).UpdateColumns(m => new { m.Description, m.Name }).ExecuteCommand(); + // UPDATE `test` SET `Name`= 'string',`Description`= 'string' WHERE `id`= 5 + + Context.Updateable(entity).IgnoreColumns(m => new { m.CreateUserId, m.Age }).ExecuteCommand(); + // UPDATE `test` SET`IsDeleted`= 0,`Name`= 'string',`Description`= 'string',`EnabledMark`= 0,`DeleteUserId`= 0,`DeleteTime`= '2022/8/13 23:42:36',`CreateTime`= '2015/5/12 0:00:00',`UpdateUserId`= 0,`UpdateTime`= '2022/8/13 23:55:27' WHERE `id`= 5 + } + #endregion + + #region 导航属性 + /// + /// 导航属性 + /// + /// + /// + /// + public async Task EntityRelationSave(DemoEntity entity) + { + var res = await Context.InsertNav(entity).Include(m => m.DemoDetailList).ExecuteCommandAsync(); + return res; + } + #endregion + + #region 缓存 + /// + /// 获取数据包含缓存 + /// + /// + /// + public async Task GetDataCache(int id) + { + var redisKey = $"Demo:Endity:{id}"; + var demo = await RedisHelper.Client.GetAsync(redisKey); + if (demo != null) + return demo; + + var aa = Context.Ado.Connection; + demo = await base.GetSingleAsync(m => m.Id == id); + + await RedisHelper.Client.SetAsync(redisKey, demo, 60 * 20); + + return demo; + } + #endregion + + } +} diff --git a/src/SJZY.Track.Repository/Demo/Services/IDemoRepository.cs b/src/SJZY.Track.Repository/Demo/Services/IDemoRepository.cs new file mode 100644 index 00000000..bf3a2083 --- /dev/null +++ b/src/SJZY.Track.Repository/Demo/Services/IDemoRepository.cs @@ -0,0 +1,24 @@ +using SJZY.Track.Repository.Demo.Entitys; +using SJZY.Track.Repository.Demo.ValueObjects; + +namespace SJZY.Track.Repository.Demo.Services +{ + public interface IDemoRepository + { + Task EntityRelationSave(DemoEntity entity); + Task InsertReturnIdentityAsync(DemoEntity entity); + Task UpdateAsync(DemoEntity entity); + Task DeleteAsync(DemoEntity entity); + Task GetById1(int id); + Task> GetListByPage(int pageSize, int pageindex, string name); + Task> OriginalSql(DemoValueObject obj); + Task> InputToValueObject(DemoValueObject obj); + Task Transaction(); + Task MultipleMethodTrans1(); + Task MultipleMethodTrans2(); + Task InternalTrans(); + Task UpdatePartColumns(DemoEntity entity); + + Task GetDataCache(int Id); + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/Demo/ValueObjects/DemoValueObject.cs b/src/SJZY.Track.Repository/Demo/ValueObjects/DemoValueObject.cs new file mode 100644 index 00000000..782554e1 --- /dev/null +++ b/src/SJZY.Track.Repository/Demo/ValueObjects/DemoValueObject.cs @@ -0,0 +1,18 @@ +namespace SJZY.Track.Repository.Demo.ValueObjects +{ + public class DemoValueObject + { + + public string Name { get; set; } + + /// + /// 当前页码 + /// + public int PageIndex { get; set; } + + /// + /// 每页大小 + /// + public int PageSize { get; set; } + } +} diff --git a/src/SJZY.Track.Repository/GlobalUsing.cs b/src/SJZY.Track.Repository/GlobalUsing.cs new file mode 100644 index 00000000..dc581267 --- /dev/null +++ b/src/SJZY.Track.Repository/GlobalUsing.cs @@ -0,0 +1,7 @@ +global using SJZY.Expand.ABP.Core; +global using SJZY.Expand.ABP.Core.Common.Dto; +global using SJZY.Expand.ABP.Core.SqlSugar; +global using SJZY.Expand.ABP.Core.SqlSugar.Entitys; +global using SJZY.Expand.ABP.Core.SqlSugar.Tools; +global using SqlSugar; +global using Volo.Abp.DependencyInjection; diff --git a/src/SJZY.Track.Repository/RepositoryModule.cs b/src/SJZY.Track.Repository/RepositoryModule.cs new file mode 100644 index 00000000..e4a336b9 --- /dev/null +++ b/src/SJZY.Track.Repository/RepositoryModule.cs @@ -0,0 +1,33 @@ +using Microsoft.Extensions.DependencyInjection; +using SJZY.Expand.ABP.Core.SqlSugar.Options; +using Volo.Abp.Autofac; +using Volo.Abp.Modularity; + +namespace SJZY.Track.Repository +{ + /// + /// 仓储模块 + /// + [DependsOn(typeof(AbpAutofacModule))] + public class RepositoryModule : AbpModule + { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + context.Services.AddSqlsugar(options => + { + options.AddRange(new List { + new SqlsugarOptions() + { + ConnectionString = configuration["ConnectionStrings:DefaultConnection"], + DbType = DbType.MySql, + IsAutoCloseConnection = true, + ConfigId = "default" + } + } + ); + }, DataBaseContext.OnExcutingAction, "SJZY.Track.Repository"); + } + } +} \ No newline at end of file diff --git a/src/SJZY.Track.Repository/SJZY.Track.Repository.csproj b/src/SJZY.Track.Repository/SJZY.Track.Repository.csproj new file mode 100644 index 00000000..d4c60ce9 --- /dev/null +++ b/src/SJZY.Track.Repository/SJZY.Track.Repository.csproj @@ -0,0 +1,23 @@ + + + + net7.0 + enable + enable + True + + + + + + + + + + + + + + + + diff --git a/test/SJZY.OpenApi.Test/Demo/DemoTest.cs b/test/SJZY.OpenApi.Test/Demo/DemoTest.cs new file mode 100644 index 00000000..c8479c89 --- /dev/null +++ b/test/SJZY.OpenApi.Test/Demo/DemoTest.cs @@ -0,0 +1,27 @@ +using SJZY.OpenApi.Application.Dtos.Demo; +using SJZY.OpenApi.Application.Services.Demo; + +namespace SJZY.OpenApi.Test.Demo +{ + public class DemoTest : TestModuleTestBase + { + #region 构造函数 + private InterFaceDemoService _interFaceDemoService; + public DemoTest() + { + _interFaceDemoService = GetRequiredService(); + } + #endregion + + [Fact] + public async Task Test() + { + var data = new DemoInput(); + + var res = await _interFaceDemoService.Edit(data); + + Assert.NotNull(res); + } + + } +} diff --git a/test/SJZY.OpenApi.Test/ProblemTypeService/ProblemTypeServiceTest.cs b/test/SJZY.OpenApi.Test/ProblemTypeService/ProblemTypeServiceTest.cs new file mode 100644 index 00000000..ce783b3f --- /dev/null +++ b/test/SJZY.OpenApi.Test/ProblemTypeService/ProblemTypeServiceTest.cs @@ -0,0 +1,7 @@ +namespace SJZY.OpenApi.Test.ProblemTypeServiceTest +{ + public class ProblemTypeServiceTest : TestModuleTestBase + { + + } +} \ No newline at end of file diff --git a/test/SJZY.OpenApi.Test/SJZY.OpenApi.Test.csproj b/test/SJZY.OpenApi.Test/SJZY.OpenApi.Test.csproj new file mode 100644 index 00000000..1969e8f8 --- /dev/null +++ b/test/SJZY.OpenApi.Test/SJZY.OpenApi.Test.csproj @@ -0,0 +1,45 @@ + + + + net7.0 + enable + enable + + false + + + + + + + + + PreserveNewest + true + PreserveNewest + + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/test/SJZY.OpenApi.Test/Startup.cs b/test/SJZY.OpenApi.Test/Startup.cs new file mode 100644 index 00000000..eee65d21 --- /dev/null +++ b/test/SJZY.OpenApi.Test/Startup.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace SJZY.OpenApi.Test +{ + public class Startup + { + public void ConfigureServices(IServiceCollection services) + { + services.AddApplication(); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) + { + app.InitializeApplication(); + } + } +} diff --git a/test/SJZY.OpenApi.Test/TestModule.cs b/test/SJZY.OpenApi.Test/TestModule.cs new file mode 100644 index 00000000..f0567c60 --- /dev/null +++ b/test/SJZY.OpenApi.Test/TestModule.cs @@ -0,0 +1,67 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using SJZY.OpenApi.Api; +using SJZY.OpenApi.Application; +using SJZY.OpenApi.Repository; +using Volo.Abp; +using Volo.Abp.AspNetCore.TestBase; +using Volo.Abp.Authorization; +using Volo.Abp.Autofac; +using Volo.Abp.Data; +using Volo.Abp.Http.Client; +using Volo.Abp.Modularity; +using Volo.Abp.Threading; + +[assembly: HostingStartup(typeof(SJZY.Expand.ABP.Core.HostingStartup))] +namespace SJZY.OpenApi.Test +{ + [DependsOn( + typeof(AbpAspNetCoreTestBaseModule), + typeof(AbpAutofacModule), + typeof(AbpAuthorizationModule), + typeof(RepositoryModule), + typeof(ApplicationModule), + typeof(ApiModule), + typeof(AbpHttpClientModule) //添加abp的http代理模块 + )] + + [assembly: HostingStartup(typeof(Expand.ABP.Core.HostingStartup))] + public class TestModule : AbpModule + { + + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAlwaysAllowAuthorization(); + //添加内网服务 + //context.Services.AddHttpClientProxies(typeof(LoggerCenterHttpApiModule).Assembly, "LoggerCenter", false); + } + + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + SeedTestData(context); + } + + public override void OnApplicationShutdown(ApplicationShutdownContext context) + { + //根据业务场景决定,是否需要删除测试数据 + } + + /// + /// 生成种子测试数据 + /// + /// + private static void SeedTestData(ApplicationInitializationContext context) + { + AsyncHelper.RunSync(async () => + { + using (var scope = context.ServiceProvider.CreateScope()) + { + await scope.ServiceProvider + .GetRequiredService() + .SeedAsync(); + } + }); + } + } + +} diff --git a/test/SJZY.OpenApi.Test/TestModuleTestBase.cs b/test/SJZY.OpenApi.Test/TestModuleTestBase.cs new file mode 100644 index 00000000..c05bf867 --- /dev/null +++ b/test/SJZY.OpenApi.Test/TestModuleTestBase.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Volo.Abp.AspNetCore.TestBase; + +namespace SJZY.OpenApi.Test +{ + public class TestModuleTestBase : AbpAspNetCoreIntegratedTestBase + { + protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + base.ConfigureServices(context, services); + } + + + } +} diff --git a/test/SJZY.OpenApi.Test/Usings.cs b/test/SJZY.OpenApi.Test/Usings.cs new file mode 100644 index 00000000..8c927eb7 --- /dev/null +++ b/test/SJZY.OpenApi.Test/Usings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file diff --git a/test/SJZY.OpenApi.Test/appsettings.json b/test/SJZY.OpenApi.Test/appsettings.json new file mode 100644 index 00000000..3a46aee6 --- /dev/null +++ b/test/SJZY.OpenApi.Test/appsettings.json @@ -0,0 +1,91 @@ +{ + "Environment": "Dev", + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "ConnectionStrings": { + "DefaultConnection": "server=192.168.80.81;Database=sjzy_package_setting;Uid=root;Pwd=10c1fb814e7c1552;SslMode=None;Charset=utf8mb4;", + "DataCenter": "server=192.168.80.81;Database=sjzy_data_center;Uid=root;Pwd=10c1fb814e7c1552;SslMode=None;Charset=utf8mb4;" + }, + "Redis": { + "ConnectionString": "192.168.80.56:6379,abortConnect=false", + "PassWord": "sjzyadmin", + "DefaultDatabaseIndex": 8, + "Prefix": "" + }, + "Consul": { + "ServiceName": "Package.Setting", + "ServiceIP": "192.168.80.55", + "ServicePort": 5047, + "ServiceHealthCheck": "http://192.168.80.55:5047/HealthCheck", + "ConsulAddress": "http://192.168.80.56:8500" + }, + "CorsPolicy": [ + "" + ], + "Swagger": { + "IsEnable": true, + "ServiceUrl": "", + "JsonUrlPrefix": "", //转发目录前缀,部署服务器时需要配置 /kingmall + "ScanPrefix": [ "SJZY" ] //全局扫描程序集或xml文件时只加载以 SJZY 开头的内容 + }, + "RabbitMQ": { + "UserName": "sjzy", + "Password": "sjzyadmin", + "HostName": "192.168.80.56", + "Port": 5672 + }, + "Custome": { + "Setting1": 12, + "Setting2": 22 + }, + "Serilog": { + "MinimumLevel": { + "Default": "Information", + "Override": { + "System": "Warning", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information", + "Microsoft.EntityFrameworkCore": "Information" + } + }, + "Enrich": [ "FromLogContext", "WithMachineName", "WithProcessId", "WithThreadId" ], + "WriteTo": [ + { + "Name": "Console", + "Args": { + //"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, SystemConsoleTheme.Literate", + "outputTemplate": "{NewLine}[{Timestamp:yyyy-MM-dd HH:mm:ss fff} {Level:u3}] {Message:lj}" + } + }, + { + "Name": "File", + "Args": { + "path": "logs/.log", + "rollingInterval": "Day", + "outputTemplate": "{NewLine}[{Timestamp:yyyy-MM-dd HH:mm:ss,fff} {Level:u3}] {Message:lj}" + } + }, + { + "Name": "Elasticsearch", + "Args": { + "nodeUris": "http://192.168.80.97:9200", + "indexFormat": "log_package_setting_{0:yyyy.MM.dd}", + "autoRegisterTemplate": true, + "autoRegisterTemplateVersion": "ESv7", + "connectionGlobalHeaders": "Authorization=Basic ZWxhc3RpYzpzanp5YWRtaW4=;" + } + } + ] + }, + "OSS": { + "AccessKeyId": "LTAI5tJWyx1kgQfk221QFknu", + "AccessKeySecret": "0AvP3vyBdwT1pwvLXeqeJ448US8QL8", + "Endpoint": "http://oss-cn-shenzhen.aliyuncs.com/", + "BucketName": "cams3", + "ReturnHttpsUrl": true + } +}