♻️ feat(修改): 返回方式;表单验证字段;数据库自动填充字段

This commit is contained in:
bunny 2024-08-30 16:08:08 +08:00
parent 2165c49419
commit 04f0c79c2e
35 changed files with 225 additions and 195 deletions

View File

@ -5,7 +5,7 @@
<driver-ref>sqlite.xerial</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
<jdbc-url>jdbc:sqlite:D:\Project\web\Bunny-Cli\template\CSharp\CSharp-Single-EFCore\Bunny.WebApi\bunny.db</jdbc-url>
<jdbc-url>jdbc:sqlite:D:\MyFolder\Bunny\Bunny-cli\CSharp\CSharp-Single-EFCore\Bunny.WebApi\bunny.db</jdbc-url>
<jdbc-additional-properties>
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
</jdbc-additional-properties>

View File

@ -1,4 +1,6 @@
using Bunny.Dao.Models.System;
using Bunny.Common.Context;
using Bunny.Dao.Entity.Base;
using Bunny.Dao.Entity.System;
using Microsoft.EntityFrameworkCore;
namespace Bunny.Common.Connect;
@ -19,9 +21,84 @@ public class EfCoreContext : DbContext
public DbSet<Product> Products { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseSqlite($"Data Source={DbPath}");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 添加过滤器
modelBuilder.Entity<BaseEntity>()
.HasQueryFilter(e => !e.IsDeleted);
// 默认值为false表示未删除
modelBuilder.Entity<BaseEntity>()
.Property(e => e.IsDeleted)
.HasDefaultValue(false);
base.OnModelCreating(modelBuilder);
}
public override int SaveChanges()
{
SetSystemField();
return base.SaveChanges();
}
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
SetSystemField();
return base.SaveChanges(acceptAllChangesOnSuccess);
}
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new())
{
SetSystemField();
return base.SaveChangesAsync(cancellationToken);
}
public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess,
CancellationToken cancellationToken = new())
{
SetSystemField();
return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
/// <summary>
/// 系统字段赋值
/// </summary>
private void SetSystemField()
{
foreach (var item in ChangeTracker.Entries())
if (item.Entity is BaseEntity entity)
switch (item.State)
{
//添加操作
case EntityState.Added:
{
if (entity.Id == string.Empty) entity.Id = Guid.NewGuid().ToString();
entity.CreateTime = DateTime.Now;
entity.UpdateTime = DateTime.Now;
entity.CreateUserId = BaseContext.GetUserId()!.Value;
entity.UpdateUserId = BaseContext.GetUserId()!.Value;
break;
}
//修改操作
case EntityState.Modified:
entity.UpdateTime = DateTime.Now;
entity.UpdateUserId = BaseContext.GetUserId()!.Value;
break;
case EntityState.Detached:
break;
case EntityState.Unchanged:
break;
case EntityState.Deleted:
entity.UpdateTime = DateTime.Now;
entity.UpdateUserId = BaseContext.GetUserId()!.Value;
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}

View File

@ -0,0 +1,35 @@
namespace Bunny.Common.Context;
public class BaseContext
{
// 使用Lazy初始化确保线程安全
public static readonly ThreadLocal<long?> UserId = new();
public static readonly ThreadLocal<string?> Token = new();
// 用户id相关
public static long? GetUserId()
{
return UserId.Value;
}
public static void SetUserId(long? userId)
{
UserId.Value = userId;
}
public static string? GetToken()
{
return Token.Value;
}
public static void SetToken(string token)
{
Token.Value = token;
}
public static void RemoveUser()
{
Token.Value = null;
UserId.Value = null;
}
}

View File

@ -1,12 +1,16 @@
using Bunny.Common.Exception;
using Bunny.Dao.Entity.Constant;
using Bunny.Dao.Result;
using Bunny.Dao.Entity.Result;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
namespace Bunny.Common.Filter;
/// <summary>
/// 全局异常处理器
/// </summary>
/// <param name="logger"></param>
public class GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger) : IExceptionFilter
{
public void OnException(ExceptionContext context)

View File

@ -0,0 +1,24 @@
using System.Net;
using Bunny.Dao.Entity.Result;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace Bunny.Common.Filter;
/// <summary>
/// 全局请求表单验证拦截器
/// </summary>
public class ValidateModelStateAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
if (actionContext.ModelState.IsValid) return;
// 异常返回结果包装 也可以自定自定义返回类型
var errorMessage = actionContext.ModelState.Values.First().Errors.First().ErrorMessage;
var result = Result<string>.Error(HttpStatusCode.BadRequest, errorMessage);
// 重新复写返回结果
actionContext.Result = new ObjectResult(result);
}
}

View File

@ -1,5 +1,5 @@
using System.Net;
using Bunny.Dao.Result;
using Bunny.Dao.Entity.Result;
using Microsoft.AspNetCore.Mvc;
namespace Bunny.Common.Utils.Net;

View File

@ -5,10 +5,14 @@ public class BaseEntity
public string? Id { get; set; }
public DateTime CreateTime { get; set; }
}
// public DateTime UpdateTime { get; set; }
// public long CreateUserId { get; set; }
// public long UpdateUserId { get; set; }
// public string? OperationMessage { get; set; }
// public bool IsDelete { get; set; }
public DateTime UpdateTime { get; set; }
public long CreateUserId { get; set; }
public long UpdateUserId { get; set; }
public string? OperationMessage { get; set; }
public bool IsDeleted { get; set; }
}

View File

@ -1,9 +1,10 @@
namespace Bunny.Dao.Result.Constant;
namespace Bunny.Dao.Entity.Result.Constant;
/// <summary>
/// 发生时的错误敞亮
/// </summary>
public static class ErrorConstant
{
public static readonly string InternalServerError = "服务器错误";
public static readonly string ValidateCodeError = "输入验证码错误";
}

View File

@ -0,0 +1,6 @@
namespace Bunny.Dao.Entity.Result.Constant;
public class SuccessConstant
{
public static readonly string Success = "操作成功";
}

View File

@ -1,4 +1,4 @@
namespace Bunny.Dao.Result;
namespace Bunny.Dao.Entity.Result;
public class PageResult<T>
{

View File

@ -1,7 +1,8 @@
using System.Net;
using Bunny.Dao.Result.Enum;
using Bunny.Dao.Entity.Result.Constant;
using Microsoft.AspNetCore.Mvc;
namespace Bunny.Dao.Result;
namespace Bunny.Dao.Entity.Result;
[Serializable]
public class Result<T>(HttpStatusCode code, T? data, string? message)
@ -30,18 +31,17 @@ public class Result<T>(HttpStatusCode code, T? data, string? message)
public T? Data { get; set; } = data;
// 不再继承 IActionResult
// public Task ExecuteResultAsync(ActionContext context)
// {
// return new Task<Result<T>>(() => new Result<T>(code, data, message));
// }
public Task ExecuteResultAsync(ActionContext context)
{
return new Task<Result<T>>(() => new Result<T>(code, data, message));
}
/// <summary>
/// 操作成功
/// </summary>
public static Result<T> Success()
{
const ResultCodeEnum codeEnum = ResultCodeEnum.Success;
return new Result<T>((HttpStatusCode)codeEnum, default, codeEnum.GetDescription());
return new Result<T>(HttpStatusCode.OK, default, SuccessConstant.Success);
}
/// <summary>
@ -51,8 +51,7 @@ public class Result<T>(HttpStatusCode code, T? data, string? message)
/// <returns>返回的数据内容</returns>
public static Result<T> Success(T data)
{
const ResultCodeEnum codeEnum = ResultCodeEnum.Success;
return new Result<T>((HttpStatusCode)codeEnum, data, codeEnum.GetDescription());
return new Result<T>(HttpStatusCode.OK, data, SuccessConstant.Success);
}
/// <summary>
@ -74,8 +73,7 @@ public class Result<T>(HttpStatusCode code, T? data, string? message)
/// <returns>返回的数据内容</returns>
public static Result<T> Success(HttpStatusCode code, T data)
{
const ResultCodeEnum codeEnum = ResultCodeEnum.Success;
return new Result<T>(code, data, codeEnum.GetDescription());
return new Result<T>(code, data, SuccessConstant.Success);
}
/// <summary>
@ -86,19 +84,7 @@ public class Result<T>(HttpStatusCode code, T? data, string? message)
/// <returns>返回的数据内容</returns>
public static Result<T> Success(string message, T data)
{
const HttpStatusCode codeEnum = (HttpStatusCode)ResultCodeEnum.Success;
return new Result<T>(codeEnum, data, message);
}
/// <summary>
/// 自定义返回成功消息
/// </summary>
/// <param name="codeEnum">code枚举类</param>
/// <param name="data">数据内容分</param>
/// <returns>返回的数据内容</returns>
public static Result<T> Success(ResultCodeEnum codeEnum, T data)
{
return new Result<T>((HttpStatusCode)codeEnum, data, codeEnum.GetDescription());
return new Result<T>(HttpStatusCode.OK, data, message);
}
/// <summary>
@ -119,8 +105,7 @@ public class Result<T>(HttpStatusCode code, T? data, string? message)
/// <returns>返回的数据内容</returns>
public static Result<T> Error()
{
const ResultCodeEnum codeEnum = ResultCodeEnum.Error;
return new Result<T>((HttpStatusCode)codeEnum, default, codeEnum.GetDescription());
return new Result<T>(HttpStatusCode.InternalServerError, default, ErrorConstant.InternalServerError);
}
/// <summary>
@ -130,8 +115,7 @@ public class Result<T>(HttpStatusCode code, T? data, string? message)
/// <returns>返回的数据内容</returns>
public static Result<T> Error(HttpStatusCode code)
{
const ResultCodeEnum codeEnum = ResultCodeEnum.Error;
return new Result<T>(code, default, codeEnum.GetDescription());
return new Result<T>(code, default, ErrorConstant.InternalServerError);
}
/// <summary>
@ -141,19 +125,7 @@ public class Result<T>(HttpStatusCode code, T? data, string? message)
/// <returns>返回的数据内容</returns>
public static Result<T> Error(T? data)
{
const ResultCodeEnum codeEnum = ResultCodeEnum.Error;
return new Result<T>((HttpStatusCode)codeEnum, data, codeEnum.GetDescription());
}
/// <summary>
/// 返回错误对象
/// </summary>
/// <param name="codeEnum">code枚举类</param>
/// <returns>返回的数据内容</returns>
public static Result<T> Error(ResultCodeEnum codeEnum)
{
return new Result<T>((HttpStatusCode)codeEnum, default, codeEnum.GetDescription());
return new Result<T>(HttpStatusCode.InternalServerError, data, ErrorConstant.InternalServerError);
}
/// <summary>
@ -187,8 +159,7 @@ public class Result<T>(HttpStatusCode code, T? data, string? message)
/// <returns>返回的数据内容</returns>
public static Result<T> Error(HttpStatusCode code, T data)
{
const ResultCodeEnum codeEnum = ResultCodeEnum.Error;
return new Result<T>(code, data, codeEnum.GetDescription());
return new Result<T>(code, data, ErrorConstant.InternalServerError);
}
/// <summary>
@ -199,19 +170,7 @@ public class Result<T>(HttpStatusCode code, T? data, string? message)
/// <returns>返回的数据内容</returns>
public static Result<T> Error(string message, T data)
{
const HttpStatusCode codeEnum = (HttpStatusCode)ResultCodeEnum.Error;
return new Result<T>(codeEnum, data, message);
}
/// <summary>
/// 返回错误对象
/// </summary>
/// <param name="codeEnum">code枚举类</param>
/// <param name="data">数据内容分</param>
/// <returns>返回的数据内容</returns>
public static Result<T> Error(ResultCodeEnum codeEnum, T data)
{
return new Result<T>((HttpStatusCode)codeEnum, data, codeEnum.GetDescription());
return new Result<T>(HttpStatusCode.InternalServerError, data, message);
}
/// <summary>

View File

@ -0,0 +1,9 @@
using System.ComponentModel.DataAnnotations;
using Bunny.Dao.Entity.Base;
namespace Bunny.Dao.Entity.System;
public class Blog : BaseEntity
{
[Required(ErrorMessage = "邮箱是必填项")] public string Url { get; set; }
}

View File

@ -1,8 +1,8 @@
using Bunny.Dao.Models.Base;
using Bunny.Dao.Entity.Base;
namespace Bunny.Dao.Models.System;
namespace Bunny.Dao.Entity.System;
public class Post : BaseModel
public class Post : BaseEntity
{
public int PostId { get; set; }
public string? Title { get; set; }

View File

@ -1,8 +1,8 @@
using Bunny.Dao.Models.Base;
using Bunny.Dao.Entity.Base;
namespace Bunny.Dao.Models.System;
namespace Bunny.Dao.Entity.System;
public class Product : BaseModel
public class Product : BaseEntity
{
public string? CustomerId { get; set; }

View File

@ -1,8 +1,8 @@
using Bunny.Dao.Models.Base;
using Bunny.Dao.Entity.Base;
namespace Bunny.Dao.Models.System;
namespace Bunny.Dao.Entity.System;
public class User : BaseModel
public class User : BaseEntity
{
public string? UserName { get; set; }

View File

@ -1,15 +0,0 @@

namespace Bunny.Dao.Models.Base;
public class BaseModel
{
public string? Id { get; set; }
public DateTime CreateTime { get; set; }
public DateTime UpdateTime { get; set; }
public long CreateUserId { get; set; }
public long UpdateUserId { get; set; }
}

View File

@ -1,8 +0,0 @@
using Bunny.Dao.Models.Base;
namespace Bunny.Dao.Models.System;
public class Blog : BaseModel
{
public string Url { get; set; }
}

View File

@ -1,5 +0,0 @@
namespace Bunny.Dao.Result.Constant;
public class SuccessConstant
{
}

View File

@ -1,50 +0,0 @@
using System.ComponentModel;
namespace Bunny.Dao.Result.Enum;
/// <summary>
/// 返回结果状态码枚举
/// </summary>
public enum ResultCodeEnum
{
// 成功操作 200
[Description("操作成功")] Success = 200,
// 验证错误 201
[Description("账号或密码错误")] LoginError = 201,
// 数据相关 206
[Description("非法请求")] IllegalRequest = 206,
// 身份过期 208
[Description("请先登陆")] LoginAuth = 206,
[Description("身份验证过期")] AuthenticationExpired = 207,
[Description("会话过期")] SessionExpiration = 208,
[Description("该账户被封禁")] FailNoAccessDeniedUserLocked = 209,
// 提示错误
[Description("URL编码失败")] UrlEncodeError = 216,
[Description("非法回调请求")] IllegalCallbackRequestError = 217,
[Description("获取用户信息失败")] FetchUserinfoError = 219,
// 无权访问 403
[Description("无权访问")] FailNoAccessDenied = 403,
// 系统错误 500
[Description("请求失败")] Error = 500
}
/// <summary>
/// 自定义属性
/// </summary>
public static class ResultCodeExtensions
{
public static string GetDescription(this ResultCodeEnum eCodeEnum)
{
var fieldInfo = eCodeEnum.GetType().GetField(eCodeEnum.ToString());
if (fieldInfo == null) return string.Empty;
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : eCodeEnum.ToString();
}
}

View File

@ -34,7 +34,6 @@ public class AuthorizationFilter : IAuthorizationFilter
// 不匹配直接返回
if (!matchPath) return;
// 检查token
CheckToken(context);

View File

@ -1,6 +1,4 @@
using Bunny.Dao.Models.System;
namespace Bunny.Service.IService;
namespace Bunny.Service.IService;
public interface IBaseService
{

View File

@ -1,5 +1,5 @@
using Bunny.Dao.Models.System;
using Bunny.Dao.Result;
using Bunny.Dao.Entity.Result;
using Bunny.Dao.Entity.System;
namespace Bunny.Service.IService;

View File

@ -1,10 +1,8 @@
using Bunny.Dao.Models.System;
namespace Bunny.Service.IService.Service;
namespace Bunny.Service.IService.Service;
public class BaseService : IBaseService
{
public string TestIndex()
public string TestIndex()
{
const string result = "bunny-template 实现自动注入成功";
return result;

View File

@ -1,6 +1,6 @@
using Bunny.Common.Connect;
using Bunny.Dao.Models.System;
using Bunny.Dao.Result;
using Bunny.Dao.Entity.Result;
using Bunny.Dao.Entity.System;
namespace Bunny.Service.IService.Service;

View File

@ -1,5 +1,5 @@
using Bunny.Common.Connect;
using Bunny.Dao.Models.System;
using Bunny.Dao.Entity.System;
using Newtonsoft.Json;
using StackExchange.Redis;

View File

@ -1,5 +1,5 @@
using Bunny.Common.Connect;
using Bunny.Dao.Models.System;
using Bunny.Dao.Entity.System;
using NUnit.Framework;
namespace Bunny.Test.Until.EfCoreTest;

View File

@ -1,7 +1,6 @@
using System.Net;
using Bunny.Dao.Entity.Constant;
using Bunny.Dao.Result;
using Bunny.Dao.Result.Enum;
using Bunny.Dao.Entity.Result;
using Newtonsoft.Json;
using NUnit.Framework;
@ -10,14 +9,6 @@ namespace Bunny.Test.Until;
[TestFixture]
public class TestResultCodeEnum
{
[Test]
public void TestResultCodeExtensions()
{
const ResultCodeEnum resultCodeEnum = ResultCodeEnum.Success;
Console.WriteLine(resultCodeEnum);
Console.WriteLine(resultCodeEnum.GetDescription());
}
[Test]
public void TestSuccessResult()
{

View File

@ -19,14 +19,15 @@
&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;/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;
@ -46,6 +47,7 @@
&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.NetUtilTest.NetTest2&lt;/TestId&gt;&#xD;
&lt;/TestAncestor&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/SessionState&gt;</s:String>

View File

@ -47,6 +47,7 @@ public static class ServiceRegistration
builder.Services.AddControllers(option =>
{
option.Filters.Add<GlobalExceptionFilter>();
option.Filters.Add<ValidateModelStateAttribute>();
option.Filters.Add<AuthorizationFilter>();
});
}

View File

@ -1,5 +1,5 @@
using Bunny.Dao.Models.System;
using Bunny.Dao.Result;
using Bunny.Dao.Entity.Result;
using Bunny.Dao.Entity.System;
using Bunny.Service.IService;
using Microsoft.AspNetCore.Mvc;
@ -24,10 +24,10 @@ public class BlogController : ControllerBase
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost]
public Result<string> AddBlog(Blog dto)
public Result<object> AddBlog(Blog dto)
{
_blogService.AddBlog(dto);
return Result<string>.Success();
return Result<object>.Success();
}
/// <summary>
@ -47,10 +47,10 @@ public class BlogController : ControllerBase
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost]
public Result<string> UpdateBlog(Blog dto)
public Result<object> UpdateBlog(Blog dto)
{
_blogService.UpdateBlog(dto);
return Result<string>.Success();
return Result<object>.Success();
}
/// <summary>

View File

@ -1,5 +1,5 @@
using Bunny.Dao.Result;
using Bunny.Dao.Result.Constant;
using Bunny.Dao.Entity.Result;
using Bunny.Dao.Entity.Result.Constant;
using Lazy.Captcha.Core;
using Microsoft.AspNetCore.Mvc;

View File

@ -1,4 +1,4 @@
using Bunny.Dao.Result;
using Bunny.Dao.Entity.Result;
using Bunny.Service.IService;
using Microsoft.AspNetCore.Mvc;

View File

@ -1,4 +1,4 @@
using Bunny.Dao.Result;
using Bunny.Dao.Entity.Result;
using Bunny.Service.IService;
using Microsoft.AspNetCore.Mvc;
using Minio.DataModel;

View File

@ -1,4 +1,4 @@
using Bunny.Dao.Result;
using Bunny.Dao.Entity.Result;
using Bunny.Service.IService;
using Microsoft.AspNetCore.Mvc;

View File

@ -1,4 +1,4 @@
using Bunny.Dao.Result;
using Bunny.Dao.Entity.Result;
using Bunny.Service.IService;
using Microsoft.AspNetCore.Mvc;