This commit is contained in:
徐蒙恩 2024-02-18 18:25:31 +08:00
commit d9e2b69d47
61 changed files with 2488 additions and 0 deletions

25
.dockerignore Normal file
View File

@ -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

188
.gitignore vendored Normal file
View File

@ -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

6
NuGet.Config Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
</packageSources>
</configuration>

60
SJZY.Track.Api.sln Normal file
View File

@ -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

View File

@ -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<GlobalExceptionFilter>();
options.Filters.AddService<RequestLogFilter>();
options.Filters.AddService<UnifyResultFilter>();
}).AddNewtonsoftJson();
context.Services.AddFluentValidationAutoValidation().AddFluentValidationClientsideAdapters();
//Json格式化全局处理
context.Services.Configure<MvcNewtonsoftJsonOptions>(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<AbpJsonOptions>(options => options.OutputDateTimeFormat = "yyyy-MM-dd HH:mm:ss");
Configure<AbpAuditingOptions>(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
}
}
}

View File

@ -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"]

View File

@ -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<ApiModule>();
var app = builder.Build();
await app.InitializeApplicationAsync();
await app.RunAsync();
}
catch (Exception ex)
{
Console.WriteLine($"项目启动失败,异常信息:{ex}");
}

View File

@ -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"
}

View File

@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>..\..</DockerfileContext>
</PropertyGroup>
<ItemGroup>
<Compile Remove="logs\**" />
<Content Remove="logs\**" />
<EmbeddedResource Remove="logs\**" />
<None Remove="logs\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="FluentValidation.AspNetCore" Version="11.2.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.2" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SJZY.Track.Application\SJZY.Track.Application.csproj" />
</ItemGroup>
</Project>

View File

@ -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/"
}
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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"
}
}
}
}

View File

@ -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": ""
}
}
}
}

View File

@ -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<AbpAutoMapperOptions>(options =>
{
options.AddMaps<ApplicationModule>(true);
});
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers.Create(typeof(ApplicationModule).Assembly);//创建动态api
});
//添加虚拟文件系统
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<ApplicationModule>("SJZY.Track.Application");
});
//添加多语言
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Add<TrackLocalizationResource>("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<AbpHttpClientBuilderOptions>(options =>
{
options.ProxyClientActions.Add(async (remoteName, serviceProvider, httpClient) =>
{
//如果设置Token,前端需要传入Token 否则引发异常
httpClient.SetTokenHeader();
httpClient.Timeout = TimeSpan.FromMinutes(3);
await Task.CompletedTask;
});
});
}
}
}

View File

@ -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<DemoEntity>, UnifyPageResultDto<GetDemoListByPageOutput>>(MemberList.None);
CreateMap<GetDemoListByPageInput, DemoValueObject>(MemberList.None).ReverseMap();
CreateMap<UnifyPageResultDto<GetDemoListByPageInput>, UnifyPageResultDto<DemoValueObject>>(MemberList.None).ReverseMap();
/*
代码说明:
MemberList.None的意思是,忽略源对象和目标对象的属性匹配检查,其他可选值:MemberList.Source(检查是否映射了所有源成员)、MemberList.Destination(检查是否映射了所有目标成员)
.ReverseMap()的意思是配置双向调用关系,既一行代码既支持从 GetDemoListByPageInput -> DemoValueObject 的映射,同时也支持从 DemoValueObject -> GetDemoListByPageInput 的映射
如果对一对模型多次配置规则,会以最后一次为准,配置了这样规则后,最终执行结果是 Name + 444
CreateMap<DemoInput, DemoEntity>().ForMember(dest => dest.Description, opt => opt.MapFrom(m => m.Name + "22"));
CreateMap<DemoInput, DemoEntity>().ForMember(dest => dest.Description, opt => opt.MapFrom(m => m.Name + "444"));
*/
CreateMap<DemoEntity, DemoInput>(MemberList.None).ReverseMap();
CreateMap<DemoEntity, GetDemoListByPageOutput>(MemberList.None);
CreateMap<DemoEntity, DemoDetailSaveInput>(MemberList.None).ReverseMap();
}
}
}

View File

@ -0,0 +1,43 @@
using AutoMapper;
using SJZY.Expand.ABP.Core.PublicMethords;
using SJZY.Track.Application.Dtos.Demo;
namespace SJZY.Track.Application.AutoMapper
{
/// <summary>
/// 稍复杂的配置类
/// </summary>
internal class DemoAutoMapperProfile : Profile
{
public DemoAutoMapperProfile()
{
CreateMap<ComplexAutomapperDemoInput, ComplexAutomapperDemoOutput>(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;
}
}
}

View File

@ -0,0 +1,89 @@
namespace SJZY.Track.Application.Dtos.Demo
{
/// <summary>
/// automapper 复杂转换样例
/// </summary>
public class ComplexAutomapperDemoInput
{
/// <summary>
/// 编号
/// </summary>
public int Id { get; set; }
/// <summary>
/// 操作类型
/// </summary>
public OptionType OptionType { get; set; }
/// <summary>
/// 描述
/// </summary>
public string Description { get; set; }
/// <summary>
/// 性别
/// </summary>
public Gender Gender { get; set; }
/// <summary>
/// 用户信息
/// </summary>
public UserInfoInput UserInfo { get; set; }
/// <summary>
/// 用户角色
/// </summary>
public List<UserRoleInput> UserRoleInputList { get; set; }
/// <summary>
/// 拓展演示,目前大家共同约定,暂时不使用充血模型
/// </summary>
/// <returns></returns>
public string GetAddress()
{
return "辽宁省沈阳市...";
}
}
public class ComplexAutomapperDemoOutput
{
/// <summary>
/// 编号
/// </summary>
public int Id { get; set; }
/// <summary>
/// 性别
/// </summary>
public string Gender { get; set; }
/// <summary>
/// 描述
/// </summary>
public string Description { get; set; }
/// <summary>
/// 年龄
/// </summary>
public int Age { get; set; }
/// <summary>
/// qq号码
/// </summary>
public string QQ { get; set; }
/// <summary>
/// 地址
/// </summary>
public string Address { get; set; }
/// <summary>
/// 角色编号
/// </summary>
public int[] RoleIds { get; set; }
}
}

View File

@ -0,0 +1,48 @@
namespace SJZY.Track.Application.Dtos.Demo
{
public class DemoDetailSaveInput
{
/// <summary>
///
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 年龄
/// </summary>
public int Age { get; set; }
/// <summary>
/// 描述
/// </summary>
public string Description { get; set; }
/// <summary>
/// 详情合集
/// </summary>
public List<DemoDetailInput> DemoDetailList { get; set; }
}
public class DemoDetailInput
{
/// <summary>
/// Id
/// </summary>
public int Id { get; set; }
/// <summary>
/// t_demo.id
/// </summary>
public int DemoId { get; set; }
/// <summary>
/// 一些说明..
/// </summary>
public string OtherInfo { get; set; }
}
}

View File

@ -0,0 +1,42 @@
namespace SJZY.Track.Application.Dtos.Demo
{
public class DemoInput
{
/// <summary>
/// 操作类型
/// </summary>
public OptionType Option { get; set; }
/// <summary>
///
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 年龄
/// </summary>
public int Age { get; set; }
/// <summary>
/// 描述
/// </summary>
public string Description { get; set; }
//以下两个属性用来说明类型转换
/// <summary>
/// 创建人id
/// </summary>
public string CreateUserId { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public string CreateTime { get; set; }
}
}

View File

@ -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; }
}
}

View File

@ -0,0 +1,10 @@
namespace SJZY.Track.Application.Dtos.Demo
{
public class GetDemoListByPageInput : PageInfoInput
{
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
}
}

View File

@ -0,0 +1,27 @@
namespace SJZY.Track.Application.Dtos.Demo
{
public class GetDemoListByPageOutput
{
/// <summary>
///
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 年龄
/// </summary>
public int Age { get; set; }
/// <summary>
/// 描述
/// </summary>
public string Description { get; set; }
public DateTime CreateTime { get; set; }
}
}

View File

@ -0,0 +1,9 @@
namespace SJZY.Track.Application.Dtos.Demo
{
public class MyCustomerResultOutput
{
public string Code { get; set; }
public string Message { get; set; }
}
}

View File

@ -0,0 +1,15 @@
namespace SJZY.Track.Application.Dtos.Demo
{
public class OssUploadOutput
{
/// <summary>
/// 文件key
/// </summary>
public string Key { get; set; }
/// <summary>
/// 文件路径
/// </summary>
public string Url { get; set; }
}
}

View File

@ -0,0 +1,42 @@
using System.ComponentModel;
using System.Text.Json.Serialization;
namespace SJZY.Track.Application.Dtos.Demo
{
public class SwaggerDemoInput
{
/// <summary>
/// 年龄
/// </summary>
/// <example>18</example> 这里可以写一些初始值
public int Age { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 性别(枚举的展示样例)
/// </summary>
public Gender Gender { get; set; }
/// <summary>
/// 隐藏属性
/// </summary>
[JsonIgnore]
public int MyProperty { get; set; }
}
public enum Gender
{
[Description("纯爷们")]
男 = 2,
[Description("大姑娘")]
女 = 5,
[Description("你憋问")]
未知 = 8
}
}

View File

@ -0,0 +1,98 @@
namespace SJZY.Track.Application.Dtos.Demo
{
public class ValidateExecuteInput
{
/// <summary>
/// 操作类型
/// </summary>
public OptionType Option { get; set; }
/// <summary>
/// 主键编号
/// </summary>
public int Id { get; set; }
/// <summary>
/// 雪花ID
/// </summary>
public long SnowId { get; set; }
/// <summary>
/// 登录账号
/// </summary>
public string LoginName { get; set; }
/// <summary>
/// 登录密码
/// </summary>
public string? PassWord { get; set; }
/// <summary>
/// 登录密码确认
/// </summary>
public string PassWordAgain { get; set; }
/// <summary>
/// 最大金额额度
/// </summary>
public decimal TotalQuota { get; set; }
/// <summary>
/// 最大数量
/// </summary>
public int MaxCount { get; set; }
/// <summary>
/// 最小数量
/// </summary>
public int MiniCount { get; set; }
/// <summary>
/// 用户信息
/// </summary>
public UserInfoInput UserInfoInput { get; set; }
/// <summary>
/// 用户角色
/// </summary>
public List<UserRoleInput> UserRoleInputList { get; set; }
}
public class UserInfoInput
{
/// <summary>
/// 生日
/// </summary>
public DateTime BirthDay { get; set; }
/// <summary>
/// qq号码
/// </summary>
public string QQ { get; set; }
/// <summary>
/// 电子邮箱
/// </summary>
public string Email { get; set; }
/// <summary>
/// 用户姓名
/// </summary>
public string UserName { get; set; }
}
public class UserRoleInput
{
/// <summary>
/// 角色编号
/// </summary>
public int Id { get; set; }
/// <summary>
/// 角色名称
/// </summary>
public string Name { get; set; }
}
}

View File

@ -0,0 +1,6 @@
namespace SJZY.Track.Application.Dtos.Demo
{
public class ValidateExecuteOutput
{
}
}

View File

@ -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;

View File

@ -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}"
}
}

View File

@ -0,0 +1,8 @@
{
"culture": "zh",
"texts": {
"NotFindData": "未找到指定编号下的任何数据!",
"ParameterDemo": "{0}在{1}地方做了{2}动作",
"ParameterDemo1": "{0}在{1}地方做了{2}动作"
}
}

View File

@ -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
{
}
}

View File

@ -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; }
}
}

View File

@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<!--<Nullable>enable</Nullable>-->
</PropertyGroup>
<ItemGroup>
<Compile Remove="Validations\Docuai\**" />
<EmbeddedResource Remove="Validations\Docuai\**" />
<None Remove="Validations\Docuai\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SJZY.Expand.AliyunOSS" Version="7.0.8" />
<PackageReference Include="SJZY.Expand.Excel" Version="7.0.4" />
<PackageReference Include="SJZY.UserCenter.HttpApi" Version="1.3.3" />
<PackageReference Include="SJZY.UserCenter.SharedModel" Version="2.3.3" />
<PackageReference Include="Volo.Abp.Http.Client" Version="7.0.2" />
<PackageReference Include="Volo.Abp.FluentValidation" Version="7.0.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SJZY.Track.HttpApi\SJZY.Track.HttpApi.csproj" />
<ProjectReference Include="..\SJZY.Track.Repository\SJZY.Track.Repository.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Interfaces\" />
</ItemGroup>
</Project>

View File

@ -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
{
/// <summary>
/// 接口请求完整样例
/// </summary>
[ApiExplorerSettings(GroupName = "Demo")]
public class InterFaceDemoService : ApplicationService
{
#region 构造函数
private readonly IDemoRepository _demoRepository;
public InterFaceDemoService(IDemoRepository demoRepository)
{
_demoRepository = demoRepository;
}
#endregion
#region 增删改
/// <summary>
/// 增删改
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("InterFace/Edit")]
public async Task<LongIdBaseDto> Edit(DemoInput input)
{
var res = new LongIdBaseDto();
if (input.Option == OptionType.新增)
{
var entity = ObjectMapper.Map<DemoInput, DemoEntity>(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 局部更新最佳实践
/// <summary>
/// 局部更新最佳实践
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
/// <exception cref="BusinessException"></exception>
[HttpPost("InterFace/UpdatePartColumns")]
public async Task<IdBaseDto> 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 分页查询接口
/// <summary>
/// 分页查询
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("InterFace/GetListByPage")]
public async Task<UnifyPageResultDto<GetDemoListByPageOutput>> GetListByPage(GetDemoListByPageInput input)
{
//分页时返回值统一用 PageResultDto<> 类型
var list = await _demoRepository.GetListByPage(input.PageSize, input.PageIndex, input.Name);
var res = ObjectMapper.Map<UnifyPageResultDto<DemoEntity>, UnifyPageResultDto<GetDemoListByPageOutput>>(list);
return res;
}
#endregion
#region 入参转换
/// <summary>
/// 入参转换
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("InterFace/InputToValueObject")]
public async Task<List<GetDemoListByPageOutput>> InputToValueObject(GetDemoListByPageInput input)
{
var obj = ObjectMapper.Map<GetDemoListByPageInput, DemoValueObject>(input);
var list = await _demoRepository.InputToValueObject(obj);
var res = ObjectMapper.Map<List<DemoEntity>, List<GetDemoListByPageOutput>>(list);
return res;
}
#endregion
#region 原生sql
/// <summary>
/// 原生sql
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
[HttpPost("InterFace/OriginalSql")]
public async Task<UnifyPageResultDto<DemoValueObject>> OriginalSql(DemoValueObject obj)
{
var list = await _demoRepository.OriginalSql(obj);
return list;
}
#endregion
#region 自定义返回结果格式
/// <summary>
/// 自定义返回结果格式
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("Demo/CustomerResult")]
[CustomerResult]
public async Task<MyCustomerResultOutput> GetListAsync()
{
/*
说明:
理论上我们有全公司级别的返回值约定,不管是前端调后端,还是后端微服务间的调用,都应完全遵循该规范。
但不排除有些特殊情况下,必须要返回自定义格式的场景。
*/
var res = new MyCustomerResultOutput();
res.Code = "200";
res.Message = "这是一个自定义返回结果";
return res;
}
#endregion
#region 约定类型下返回null
/// <summary>
/// 约定类型下返回null
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("Demo/ReturnNull")]
public async Task<MyCustomerResultOutput> ReturnNull()
{
MyCustomerResultOutput res = null;
return res;
}
#endregion
#region
/// <summary>
/// 没有返回值
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("Demo/WithoutReturnObject")]
public async Task<UnifyResultDto> WithoutReturnObject()
{
return null;
}
#endregion
#region 主从关系实体存储
/// <summary>
/// 主从关系实体存储
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
[HttpPost("InterFace/EntityRelationSave")]
public async Task<UnifyResultDto> EntityRelationSave(DemoDetailSaveInput input)
{
var obj = ObjectMapper.Map<DemoDetailSaveInput, DemoEntity>(input);
var res = await _demoRepository.EntityRelationSave(obj);
return new UnifyResultDto(res);
}
#endregion
#region 数据缓存
/// <summary>
/// 数据缓存
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("InterFace/GetDataCache")]
public async Task<DemoEntity> GetDataCache(IdBaseDto input)
{
var res = await _demoRepository.GetDataCache(input.Id);
return res;
}
#endregion
//[HttpPost("InterFace/AAAA")]
//public async Task<UnifyResultDto> AAAA()
//{
// var result = await _httpClientProxy.Service.GetSystemTokenAsync("Track");
// return result;
//}
}
}

View File

@ -0,0 +1,68 @@
using FluentValidation;
using SJZY.Track.Application.Dtos.Demo;
namespace SJZY.Track.Application.Validations.Demo
{
public class SimpleValidateInputValidation : AbstractValidator<ValidateExecuteInput>, 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());
}
}
}

View File

@ -0,0 +1,15 @@
using FluentValidation;
using SJZY.Track.Application.Dtos.Demo;
namespace SJZY.Track.Application.Validations.Demo
{
public class UserInfoInputValidation : AbstractValidator<UserInfoInput>, IValidationEnabled
{
public UserInfoInputValidation()
{
RuleFor(x => x.QQ).NotNull().WithMessage("QQ号码不能为空");
}
}
}

View File

@ -0,0 +1,13 @@
using FluentValidation;
using SJZY.Track.Application.Dtos.Demo;
namespace SJZY.Track.Application.Validations.Demo
{
public class UserRoleInputValidation : AbstractValidator<UserRoleInput>, IValidationEnabled
{
public UserRoleInputValidation()
{
RuleFor(m => m.Id).GreaterThan(0).WithMessage("角色ID必须大于0!");
}
}
}

View File

@ -0,0 +1,10 @@
namespace SJZY.Track.HttpApi.Dtos
{
public class RemoteDemoInput
{
/// <summary>
/// 当前时间
/// </summary>
public DateTime CurrentTime { get; set; }
}
}

View File

@ -0,0 +1,7 @@
namespace SJZY.Track.HttpApi.Dtos
{
public class RemoteDemoOutput
{
public string Context { get; set; }
}
}

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>0.0.2</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SJZY.Expand.ABP.Common" Version="7.0.11" />
<PackageReference Include="Volo.Abp.Core" Version="7.0.2" />
</ItemGroup>
</Project>

View File

@ -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
{
/// <summary>
/// 客户端连接测试接口
/// </summary>
public interface IRemoteDemoService : IRemoteService, IScopedDependency
{
Task<UnifyResultDto<RemoteDemoOutput>> ConnectionTest(RemoteDemoInput input);
}
}

View File

@ -0,0 +1,12 @@
using Volo.Abp.Modularity;
namespace SJZY.Track.HttpApi
{
public class TrackHttpApiModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
}
}
}

View File

@ -0,0 +1,15 @@
#pragma warning disable 1591
namespace SJZY.Track.Repository
{
/// <summary>
/// 仓储基类
/// </summary>
/// <typeparam name="T"></typeparam>
public class BasicRepository<T> : SimpleClient<T> where T : class, new()
{
public BasicRepository()
{
Context = SqlsugarScopeBasic.GetContextSafely("default");
}
}
}

View File

@ -0,0 +1,53 @@
#pragma warning disable 1591
namespace SJZY.Track.Repository
{
/// <summary>
/// Sqlsugar 上下文对象
/// </summary>
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 审计属性自动赋值
}
}

View File

@ -0,0 +1,24 @@
namespace SJZY.Track.Repository.Demo.Entitys
{
[SugarTable("t_demo_detail")]
public class DemoDetailEntity
{
/// <summary>
/// Id
/// </summary>
[SugarColumn(ColumnName = "id", IsPrimaryKey = true)]
public long Id { get; set; }
/// <summary>
/// t_demo.id
/// </summary>
[SugarColumn(ColumnName = "DemoId")]
public long DemoId { get; set; }
/// <summary>
/// 一些说明..
/// </summary>
[SugarColumn(ColumnName = "OtherInfo")]
public string OtherInfo { get; set; }
}
}

View File

@ -0,0 +1,40 @@
namespace SJZY.Track.Repository.Demo.Entitys
{
/// <summary>
/// 测试表
/// </summary>
[SugarTable("t_demo")]
public class DemoEntity : IFullAuditedBasicEntitys
{
/// <summary>
/// Id
/// </summary>
[SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsIdentity = true)]
public long Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
[SugarColumn(ColumnName = "Name")]
public string Name { get; set; }
/// <summary>
/// 年龄
/// </summary>
[SugarColumn(ColumnName = "Age")]
public int Age { get; set; }
/// <summary>
/// 描述
/// </summary>
[SugarColumn(ColumnName = "Description")]
public string Description { get; set; }
[Navigate(NavigateType.OneToMany, nameof(DemoDetailEntity.DemoId))]
public List<DemoDetailEntity> DemoDetailList { get; set; }
}
}

View File

@ -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<DemoEntity>, IDemoRepository, IScopedDependency
{
/*
一般情况下常规的增删改方法不需要自己实现,只需要按照 BasicRepository 中的格式原封不动的暴露出去即可,
比如这里接口 只声明了 UpdateAsync 和 InsertReturnIdentityAsync 接口的定义,但是这两个方法的实现我们不用写,直接交给父类实现即可
*/
#region 根据主键获取单条数据
/// <summary>
/// 根据主键获取单条数据
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public Task<DemoEntity> 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 分页获取
/// <summary>
/// 分页获取
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<UnifyPageResultDto<DemoEntity>> 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 参数为实体
/// <summary>
/// 参数很多的时候,定义模型接受参数
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public async Task<List<DemoEntity>> InputToValueObject(DemoValueObject obj)
{
var list = await AsQueryable().ToListAsync();
return list;
}
#endregion
#region 执行原生sql语句
/// <summary>
/// 执行原生sql语句
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public async Task<UnifyPageResultDto<DemoValueObject>> OriginalSql(DemoValueObject obj)
{
var parameters = new List<SugarParameter>();
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<DemoValueObject>(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 导航属性
/// <summary>
/// 导航属性
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<bool> EntityRelationSave(DemoEntity entity)
{
var res = await Context.InsertNav(entity).Include(m => m.DemoDetailList).ExecuteCommandAsync();
return res;
}
#endregion
#region 缓存
/// <summary>
/// 获取数据包含缓存
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public async Task<DemoEntity> GetDataCache(int id)
{
var redisKey = $"Demo:Endity:{id}";
var demo = await RedisHelper.Client.GetAsync<DemoEntity>(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
}
}

View File

@ -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<bool> EntityRelationSave(DemoEntity entity);
Task<int> InsertReturnIdentityAsync(DemoEntity entity);
Task<bool> UpdateAsync(DemoEntity entity);
Task<bool> DeleteAsync(DemoEntity entity);
Task<DemoEntity> GetById1(int id);
Task<UnifyPageResultDto<DemoEntity>> GetListByPage(int pageSize, int pageindex, string name);
Task<UnifyPageResultDto<DemoValueObject>> OriginalSql(DemoValueObject obj);
Task<List<DemoEntity>> InputToValueObject(DemoValueObject obj);
Task Transaction();
Task MultipleMethodTrans1();
Task MultipleMethodTrans2();
Task InternalTrans();
Task UpdatePartColumns(DemoEntity entity);
Task<DemoEntity> GetDataCache(int Id);
}
}

View File

@ -0,0 +1,18 @@
namespace SJZY.Track.Repository.Demo.ValueObjects
{
public class DemoValueObject
{
public string Name { get; set; }
/// <summary>
/// 当前页码
/// </summary>
public int PageIndex { get; set; }
/// <summary>
/// 每页大小
/// </summary>
public int PageSize { get; set; }
}
}

View File

@ -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;

View File

@ -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
{
/// <summary>
/// 仓储模块
/// </summary>
[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<SqlsugarOptions> {
new SqlsugarOptions()
{
ConnectionString = configuration["ConnectionStrings:DefaultConnection"],
DbType = DbType.MySql,
IsAutoCloseConnection = true,
ConfigId = "default"
}
}
);
}, DataBaseContext.OnExcutingAction, "SJZY.Track.Repository");
}
}
}

View File

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<Compile Remove="DataCenter\**" />
<EmbeddedResource Remove="DataCenter\**" />
<None Remove="DataCenter\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SJZY.Expand.ABP.Core" Version="7.5.6" />
<PackageReference Include="SJZY.LoggerCenter.HttpApi" Version="7.0.1" />
<PackageReference Include="Volo.Abp.Autofac" Version="7.0.2" />
</ItemGroup>
</Project>

View File

@ -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<InterFaceDemoService>();
}
#endregion
[Fact]
public async Task Test()
{
var data = new DemoInput();
var res = await _interFaceDemoService.Edit(data);
Assert.NotNull(res);
}
}
}

View File

@ -0,0 +1,7 @@
namespace SJZY.OpenApi.Test.ProblemTypeServiceTest
{
public class ProblemTypeServiceTest : TestModuleTestBase
{
}
}

View File

@ -0,0 +1,45 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<None Remove="appsettings.json" />
</ItemGroup>
<ItemGroup>
<Content Include="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AspNetCore.TestBase" Version="7.0.1" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\SJZY.OpenApi.Api\SJZY.OpenApi.Api.csproj" />
</ItemGroup>
</Project>

View File

@ -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<TestModule>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
app.InitializeApplication();
}
}
}

View File

@ -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)
{
//根据业务场景决定,是否需要删除测试数据
}
/// <summary>
/// 生成种子测试数据
/// </summary>
/// <param name="context"></param>
private static void SeedTestData(ApplicationInitializationContext context)
{
AsyncHelper.RunSync(async () =>
{
using (var scope = context.ServiceProvider.CreateScope())
{
await scope.ServiceProvider
.GetRequiredService<IDataSeeder>()
.SeedAsync();
}
});
}
}
}

View File

@ -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<Startup>
{
protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services)
{
base.ConfigureServices(context, services);
}
}
}

View File

@ -0,0 +1 @@
global using Xunit;

View File

@ -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
}
}