♻️ feat(新增): 代码生成器

This commit is contained in:
bunny 2024-09-05 14:26:31 +08:00
parent 18e6c9adbf
commit 9a1024f0f7
31 changed files with 205 additions and 51 deletions

View File

@ -2,7 +2,19 @@
<project version="4">
<component name="GitCommitMessageStorage">
<option name="messageStorage">
<MessageStorage />
<MessageStorage>
<option name="commitTemplate">
<CommitTemplate>
<option name="body" value="" />
<option name="changes" value="" />
<option name="closes" value="" />
<option name="scope" value="" />
<option name="skipCi" value="" />
<option name="subject" value="" />
<option name="type" value="feat" />
</CommitTemplate>
</option>
</MessageStorage>
</option>
</component>
</project>

View File

@ -1,4 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise">
<file url="file://$PROJECT_DIR$/Bunny.Generate/ServerTemplate/Controller.cs" charset="GBK" />
</component>
</project>

Binary file not shown.

Binary file not shown.

View File

@ -1,12 +1,23 @@
{
"Version": 1,
"WorkspaceRootPath": "D:\\Project\\web\\Bunny-Cli\\template\\CSharp\\CSharp-Single-EFCore\\",
"WorkspaceRootPath": "D:\\MyFolder\\Bunny\\Bunny-cli\\CSharp\\CSharp-Single-EFCore\\",
"Documents": [],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": []
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": -1,
"Children": [
{
"$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
}
]
}
]
}
]
}

View File

@ -0,0 +1,6 @@
namespace Bunny.Common.Attribute;
[AttributeUsage(AttributeTargets.Method)]
public class TransactionAttribute : System.Attribute
{
}

View File

@ -37,7 +37,7 @@ public class EfCoreContext : DbContext
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
Log.Info("EfCoreContext 数据库连接...");
options.UseSqlServer(DbPath).AddInterceptors(new TransactionInterceptor());
options.UseSqlServer(DbPath);
}
/// <summary>

View File

@ -1,34 +0,0 @@
using Bunny.Common.Exception;
using Bunny.Dao.Common.Constant;
using Microsoft.EntityFrameworkCore.Diagnostics;
namespace Bunny.Common.Context.Database;
public class TransactionInterceptor : SaveChangesInterceptor
{
// 重写 SavingChanges 方法
public override InterceptionResult<int> SavingChanges(DbContextEventData eventData, InterceptionResult<int> result)
{
// 如果当前上下文存在事务,则直接返回结果
if (eventData.Context!.Database.CurrentTransaction != null) return result;
// 开始数据库事务
using var transaction = eventData.Context.Database.BeginTransaction();
try
{
// 调用基类方法继续保存更改
result = base.SavingChanges(eventData, result);
// 如果保存更改成功,则提交事务
transaction.Commit();
}
catch (System.Exception)
{
// 如果保存更改失败,则回滚事务并抛出自定义异常
transaction.Rollback();
throw new BunnyException(ExceptionConstant.DataBaseError);
}
return result;
}
}

View File

@ -0,0 +1,39 @@
using System.Transactions;
using Bunny.Common.Attribute;
using Bunny.Common.Context;
using log4net;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
namespace Bunny.Common.Filter;
public class TransactionIAsyncActionFilter : IAsyncActionFilter
{
private static readonly ILog Log = LogManager.GetLogger(typeof(TransactionIAsyncActionFilter));
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var actionDesc = context.ActionDescriptor as ControllerActionDescriptor;
var hasNotTransactionalAttribute =
actionDesc?.MethodInfo.IsDefined(typeof(TransactionAttribute), false) ?? false;
if (hasNotTransactionalAttribute)
{
await next();
return;
}
using var txScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);
var result = await next();
if (result.Exception == null)
{
txScope.Complete();
}
else
{
var errorMessage =
$"执行数据库出错 用户Id[{BaseContext.GetUserId()}] token [{BaseContext.GetToken()}]:{result.Exception}";
Log.Error(errorMessage);
}
}
}

View File

@ -0,0 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<None Update="Template\Controller.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Controller.cs</LastGenOutput>
</None>
<None Update="Template\IService.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>IService.cs</LastGenOutput>
</None>
<None Update="Template\Service.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Service.cs</LastGenOutput>
</None>
<None Update="ServerTemplate\Controller.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Controller.cs</LastGenOutput>
</None>
<None Update="ServerTemplate\IService.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>IService.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="WebTemplate\"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Bunny.WebApi\Bunny.WebApi.csproj"/>
</ItemGroup>
</Project>

View File

@ -0,0 +1,6 @@
<#
const string author = "Bunny";
const string controllerName = "控制器名称";
const string serviceName = "服务名称";
const string iServiceName = "实现服务名称";
#>

View File

@ -0,0 +1,26 @@
using Bunny.Dao.Common.Constant.Result;
using Bunny.Dao.Common.Result;
using Lazy.Captcha.Core;
using log4net;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Mvc;
<#@ include file="./BaseConstants.tt" #>
<#@ template hostspecific="true" language="C#" #>
<#@ output extension=".cs" encoding="utf-8" #>
<#@ assembly name="System.Core" #>
namespace Bunny.WebApi.Controllers;
/// <summary>
/// 控制器
/// By <#= author #>
/// <#= DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") #>
/// </summary>
[Microsoft.AspNetCore.Mvc.Route("/api/[controller]/[action]")]
public class <#= controllerName #>Controller : ControllerBase
{
private static readonly ILog Log = LogManager.GetLogger(typeof(CaptchaTestController));
}

View File

@ -0,0 +1,10 @@
<#@ template hostspecific="true" language="C#" #>
<#@ output extension=".cs" encoding="utf-8" #>
<#@ include file="./BaseConstants.tt" #>
namespace Bunny.Service.IService;
public interface I<#= serviceName #>Service
{
}

View File

@ -0,0 +1,10 @@
<#@ template hostspecific="true" language="C#" #>
<#@ output extension=".cs" encoding="utf-8" #>
<#@ include file="./BaseConstants.tt" #>
namespace Bunny.Service.IService.Service;
public class <#= serviceName #>Service : I<#= iServiceName #>Service
{
}

View File

@ -1,4 +1,6 @@
using Bunny.Common.Context.Database;
using Bunny.Common.Attribute;
using Bunny.Common.Context.Database;
using Bunny.Common.Exception;
using Bunny.Common.Utils.Net;
using Bunny.Dao.Common.Result;
using Bunny.Dao.Dto.System;
@ -59,9 +61,9 @@ public class BlogService : IBlogService
/// 批量添加数据
/// </summary>
/// <param name="url"></param>
[Transaction]
public void AddBatchBlogs(string url)
{
using var transaction = DbContext.Database.BeginTransaction();
var list = new List<Blog>();
for (var i = 0; i <= 100; i++)
@ -69,7 +71,7 @@ public class BlogService : IBlogService
DbContext.Blogs.AddRange(list);
DbContext.SaveChanges();
transaction.Commit();
throw new BunnyException("测试事务注解");
}
/// <summary>

View File

@ -0,0 +1,12 @@
using NUnit.Framework;
namespace Bunny.Test.Until.Test;
public class Test2
{
[Test]
public void Test1()
{
Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
}
}

View File

@ -5,13 +5,15 @@ VisualStudioVersion = 17.10.34928.147
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bunny.WebApi", "Bunny.WebApi\Bunny.WebApi.csproj", "{28753039-0C3B-4FE5-95F8-7EDC92DCBA26}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bunny.Common", "Bunny.Common\Bunny.Common.csproj", "{40D580AA-63CD-4912-835F-ECBB2C232F9E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bunny.Common", "Bunny.Common\Bunny.Common.csproj", "{40D580AA-63CD-4912-835F-ECBB2C232F9E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bunny.Test.Until", "Bunny.Test.Until\Bunny.Test.Until.csproj", "{945BE294-8057-40EE-9A98-5598D1A728B9}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bunny.Test.Until", "Bunny.Test.Until\Bunny.Test.Until.csproj", "{945BE294-8057-40EE-9A98-5598D1A728B9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bunny.Dao", "Bunny.Dao\Bunny.Dao.csproj", "{A0A986A6-A0A4-4627-B45A-94A882FC70ED}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bunny.Dao", "Bunny.Dao\Bunny.Dao.csproj", "{A0A986A6-A0A4-4627-B45A-94A882FC70ED}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bunny.Service", "Bunny.Service\Bunny.Service.csproj", "{7CEBC594-134C-48C1-96ED-263E047E7D96}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bunny.Service", "Bunny.Service\Bunny.Service.csproj", "{7CEBC594-134C-48C1-96ED-263E047E7D96}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bunny.Generate", "Bunny.Generate\Bunny.Generate.csproj", "{6594CE00-5781-4899-A4D9-D9E70CEFDF55}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -39,6 +41,10 @@ Global
{7CEBC594-134C-48C1-96ED-263E047E7D96}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7CEBC594-134C-48C1-96ED-263E047E7D96}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7CEBC594-134C-48C1-96ED-263E047E7D96}.Release|Any CPU.Build.0 = Release|Any CPU
{6594CE00-5781-4899-A4D9-D9E70CEFDF55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6594CE00-5781-4899-A4D9-D9E70CEFDF55}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6594CE00-5781-4899-A4D9-D9E70CEFDF55}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6594CE00-5781-4899-A4D9-D9E70CEFDF55}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -19,15 +19,16 @@
&lt;TestId&gt;NUnit3x::945BE294-8057-40EE-9A98-5598D1A728B9::net8.0::Bunny.Test.Until.JobTest.JobTest1.TestJob&lt;/TestId&gt;&#xD;
&lt;/TestAncestor&gt;&#xD;
&lt;/SessionState&gt;</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=83126680_002Dc767_002D40a2_002Dadfd_002Daa4542ab8b4b/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="TestJob #2" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=83126680_002Dc767_002D40a2_002Dadfd_002Daa4542ab8b4b/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="TestJob #2" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;TestAncestor&gt;&#xD;
&lt;TestId&gt;NUnit3x::945BE294-8057-40EE-9A98-5598D1A728B9::net8.0::Bunny.Test.Until.JobTest.JobTest1.TestJob&lt;/TestId&gt;&#xD;
&lt;TestId&gt;NUnit3x::945BE294-8057-40EE-9A98-5598D1A728B9::net8.0::Bunny.Test.Until.Test.Test1.Start&lt;/TestId&gt;&#xD;
&lt;TestId&gt;NUnit3x::945BE294-8057-40EE-9A98-5598D1A728B9::net8.0::Bunny.Test.Until.Test.Test1&lt;/TestId&gt;&#xD;
&lt;TestId&gt;NUnit3x::945BE294-8057-40EE-9A98-5598D1A728B9::net8.0::Bunny.Test.Until.NetUtilTest.NetTest2&lt;/TestId&gt;&#xD;
&lt;TestId&gt;NUnit3x::945BE294-8057-40EE-9A98-5598D1A728B9::net8.0::Bunny.Test.Until.Test.Test2.Test1&lt;/TestId&gt;&#xD;
&lt;/TestAncestor&gt;&#xD;
&lt;/SessionState&gt;</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=eb9da086_002D824a_002D4ac4_002Db755_002D94438e510122/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="Test1" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=eb9da086_002D824a_002D4ac4_002Db755_002D94438e510122/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="Test1" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;And&gt;&#xD;
&lt;TestAncestor&gt;&#xD;
@ -49,6 +50,7 @@
&lt;TestId&gt;NUnit3x::945BE294-8057-40EE-9A98-5598D1A728B9::net8.0::Bunny.Test.Until.Test.Test1.Start&lt;/TestId&gt;&#xD;
&lt;TestId&gt;NUnit3x::945BE294-8057-40EE-9A98-5598D1A728B9::net8.0::Bunny.Test.Until.NetUtilTest.NetTest2&lt;/TestId&gt;&#xD;
&lt;TestId&gt;NUnit3x::945BE294-8057-40EE-9A98-5598D1A728B9::net8.0::Bunny.Test.Until.Test.Test1.Method1&lt;/TestId&gt;&#xD;
&lt;TestId&gt;NUnit3x::945BE294-8057-40EE-9A98-5598D1A728B9::net8.0::Bunny.Test.Until.Test.Test2.Test1&lt;/TestId&gt;&#xD;
&lt;/TestAncestor&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/SessionState&gt;</s:String>

View File

@ -32,6 +32,7 @@ public static class ServiceRegistration
{
option.Filters.Add<GlobalExceptionFilter>();
option.Filters.Add<ValidateModelStateAttribute>();
option.Filters.Add<TransactionIAsyncActionFilter>();
option.Filters.Add<AuthorizationFilter>();
});
}

View File

@ -9,8 +9,9 @@ namespace Bunny.WebApi.Controllers;
/// <summary>
/// 验证码测试
/// 2024-9-11 09:02:18
/// </summary>
[Microsoft.AspNetCore.Mvc.Route("/api/[controller]/[action]")]
[Microsoft.AspNetCore.Components.Route("/api/[controller]/[action]")]
public class CaptchaTestController : ControllerBase
{
private static readonly ILog Log = LogManager.GetLogger(typeof(CaptchaTestController));

View File

@ -7,7 +7,7 @@ public class Program
{
public static void Main(string[] args)
{
Console.Title = "Bunny Template";
Console.Title = "Bunny ServerTemplate";
var builder = WebApplication.CreateBuilder(args);
// 基础配置

View File

@ -372,3 +372,5 @@ Exception Filter异常过滤器用于处理应用程序中发生的异
7. TypeFilterAttribute
类似于ServiceFilterAttribute但它是通过反射创建过滤器实例不需要过滤器在DI容器中注册。
可以接受参数,用于构造过滤器实例。
![](https://learn.microsoft.com/zh-cn/aspnet/core/mvc/controllers/filters/_static/filter-pipeline-2.png?view=aspnetcore-8.0)