ABP使用學習純后端(二)
ABP使用學習
創建項目(純后端項目)
abp new 項目名稱 -u none (不包含前端) -v 6.0.0(版本號)
連接數據庫
- 修改Acme.BookStore.DbMigrator中的appsettings.json中的連接字符串
- Acme.BookStore.HttpApi.Host中的appsettings.json中的連接字符串
創建表并且遷移到數據庫
-
在Domain層中創建實體
-
一個實體對應一個文件夾(以Book為例)
-
//需要繼承 AuditedAggregateRoot<T>這個類(為審計字段) T為主鍵的類型,主鍵默認命名為Id public class Book:AuditedAggregateRoot<Guid> { public string BName { get; set; } public BookType BType { get; set; } public DateTime BPublishDate { get; set; } public float BPrice { get; set; } }
-
-
在Domain.Shared層創建枚舉之類的
-
在EntityFrameworkCore層的BookStoreDbContext的上下文創建實體
-
public class BookStoreDbContext : AbpDbContext<BookStoreDbContext>, IIdentityDbContext, ITenantManagementDbContext { public DbSet<Book> Books { get; set; }//創建Book表 }
-
-
在遷移時加入數據庫約束和數據
-
protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); /* Include modules to your migration db context */ builder.ConfigurePermissionManagement(); builder.ConfigureSettingManagement(); builder.ConfigureBackgroundJobs(); builder.ConfigureAuditLogging(); builder.ConfigureIdentity(); builder.ConfigureOpenIddict(); builder.ConfigureFeatureManagement(); builder.ConfigureTenantManagement(); /* Configure your own tables/entities inside here */ //跟以前的寫法一樣 builder.Entity<Book>(b => { b.ToTable(BookStoreConsts.DbTablePrefix + nameof(Book), BookStoreConsts.DbSchema); b.ConfigureByConvention(); //auto configure for the base class props //... b.Property(c => c.BName).IsRequired().HasMaxLength(50); }); }
-
-
遷移數據庫,將程序包管理器的默認項目設置為EntityFrameworkCore
- 正常使用數據庫遷移指令即可
創建服務和生成動態的API(自動生成)
-
在Application.Contracts層中創建一個類的文件夾
-
需要定義一個實體的顯示DTO和實體的添加修改DTO,服務接口
-
//需要繼承 AuditedEntityDto<T>帶審計字段DTO基類 T為主鍵的類型這個是用于顯示的 public class BookDTO:AuditedEntityDto<Guid> { public string BName { get; set; } public BookType BType { get; set; } public DateTime BPublishDate { get; set; } public float BPrice { get; set; } } -
//以這個表為添加和修改的DTO并且可以直接擱這里面加入約束,swagger中會根據該約束進行判斷 public class CreateUpdateBookDto { [Required] [StringLength(128)] public string BName { get; set; } [Required] public BookType BType { get; set; } = BookType.Undefined; [Required] [DataType(DataType.Date)] public DateTime BPublishDate { get; set; } = DateTime.Now; [Required] public float BPrice { get; set; } }
-
-
創建實體的服務接口
-
public interface IBookAppService : ICrudAppService< //Defines CRUD methods(創建CRUD方法,CRUD為增刪改查) BookDTO, //Used to show books(數據顯示的類型(直接用顯示的DTO)) Guid, //Primary key of the book entity(主鍵,刪除和修改根據主鍵進行) PagedAndSortedResultRequestDto, //Used for paging/sorting(分頁使用的表(DTO)) CreateUpdateBookDto> //Used to create/update a book(添加修改使用的DTO) { }
-
-
創建實體的服務
-
//需要繼承 CrudAppServic接口<實體,顯示的類型,主鍵,分頁,添加修改>(創建一個定義了Crud的服務實現),定義的接口 public class BookAppService : CrudAppService<Book, BookDTO, Guid, PagedAndSortedResultRequestDto, CreateUpdateBookDto>, IBookAppService { public BookAppService(IRepository<Book, Guid> repository) : base(repository) { } }
-
創建自定義服務和倉儲
-
在Application.Contracts層中創建一個類的文件夾
-
需要定義一個實體的顯示DTO和實體的添加修改DTO,并且包含實體的服務接口
-
//需要繼承IApplicationService(實現這個接口的類型應該被當作一個應用服務來對待) public interface IAuthorService:IApplicationService { Task<AuthorDTO> GetAsync(Guid id); }
-
-
BookStore.Domain層的實體文件夾定義實體的倉儲接口
-
//用于定義對數據庫中的數據實體進行操作的接口 public interface IAuthorRepository:IRepository<Author,Guid> { Task<Author> GetAsync(Guid id); }
-
-
EntityFrameworkCore層的實體文件夾中定義實體的倉儲實現
-
public class EFCoreAuthorRepository : EfCoreRepository<BookStoreDbContext, Author, Guid>, //EfCoreRepository(或類似的名稱)是 IRepository 接口的一個具體實現,它使用EF Core作為ORM(對象關系映射器)來與數據庫交互。 IAuthorRepository//繼承的接口 { //IDbContextProvider提供對 DbContext 的訪問 public EFCoreAuthorRepository(IDbContextProvider<BookStoreDbContext> dbContextProvider) : base(dbContextProvider) { } public async Task<Author> GetAsync(Guid id) { var dbSet=await GetDbSetAsync(); return await dbSet.FirstOrDefaultAsync(c => c.Id == id); } }
-
-
定義服務實現
-
public class AuthorService : BookStoreAppService, IAuthorService { private readonly IAuthorRepository repository; private readonly IMapper mapper; public AuthorService(IAuthorRepository repository, IMapper mapper) { this.repository = repository; this.mapper = mapper; } public async Task<AuthorDTO> GetAsync(Guid id) { var entity=repository.GetAsync(id); return mapper.Map<AuthorDTO>(entity); } }
結合使用
不用定義倉儲
-
定義服務的接口
-
//需要繼承IApplicationService(實現這個接口的類型應該被當作一個應用服務來對待) public interface IAuthorService:IApplicationService { Task<AuthorDTO> GetAsync(Guid id); }
-
-
定義服務的實現
-
可以直接使用IRepository實現倉儲的定義
-
public class AuthorService : BookStoreAppService, IAuthorService { private readonly IRepository<Admin,Guid> repository; private readonly IMapper mapper; public AuthorService(IRepository<Admin,Guid> repository, IMapper mapper) { this.repository = repository; this.mapper = mapper; } public async Task<AuthorDTO> GetAsync(Guid id) { var entity=repository.GetAsync(id); return mapper.Map<AuthorDTO>(entity); } } -
使用語法糖
-
//需要繼承 CrudAppServic接口<實體,顯示的類型,主鍵,分頁,添加修改>(創建一個定義了Crud的服務實現),定義的接口 public class BookAppService : CrudAppService<Book, BookDTO, Guid, PagedAndSortedResultRequestDto, CreateUpdateBookDto>, IBookAppService { public BookAppService(IRepository<Book, Guid> repository) : base(repository) { } //使用重寫直接重寫需要用的方法 public override async Task<BookDTO> CreateAsync(CreateUpdateBookDto input) { return base.CreateAsync(input); } }
-
-
繼承的區別
AuditedEntityDto和EntityDto的區別
- EntityDto:這是基于實體的DTO,用于在不同的層之間傳遞實體的基本信息。它可能只包含實體的標識符(ID)和一些基本屬性,不包含審計信息或完整的業務邏輯。(不包含審計字段)
- AuditedEntityDto:這個DTO繼承了CreationAuditedEntityDto,并在此基礎上封裝了額外的審計信息,如最后修改時間(
LastModificationTime)和最后修改者用戶ID(LastModifierUserId)。這些信息對于需要跟蹤數據更改歷史的場景非常有用。(包含審計字段)
CrudAppService
作用:自動創建一個實現Crud的服務實現,倉儲接口同理
public class BookAppService : CrudAppService<Book, BookDTO, Guid, PagedAndSortedResultRequestDto, CreateUpdateBookDto>
ICrudAppService
作用:自動創建一個實現Crud的服務接口,可以不帶實體,因為使用了范式,但是需要定義顯示DTO,主鍵和分頁的DTO還有添加修改的DTO
IRepository
作用:用于定義對數據庫中的數據實體進行操作的接口
EfCoreRepository
EfCoreRepository(或類似的名稱)是IRepository接口的一個具體實現,它使用EF Core作為ORM(對象關系映射器)來與數據庫交互。- 這個實現類會包含EF Core的
DbContext的引用,并通過它來執行數據庫操作。 - 它會將接口中的方法轉換為具體的EF Core查詢和命令。
如何將ABP改成自己需要的模式
注冊服務和使用服務:通過ABP中的HOST的層封裝好的HttpApiHostModule.cs文件中進行服務的注冊
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
var hostingEnvironment = context.Services.GetHostingEnvironment();
//注冊服務
YitIdHelper.SetIdGenerator(new IdGeneratorOptions());
//注冊上下文:AOP里面可以獲取IOC對象,如果有現成框架比如Furion可以不寫這一行
//context等于以前的builder
context.Services.AddHttpContextAccessor();
context.Services.AddMemoryCache();
//驗證碼
ConfigureCaptcha(context, configuration);
//允許使用Post
ConfigureAntiForgery();
//配置JWT(ABP自帶的JWT授權,需要我們自己修改成自己想要的)
ConfigureAuthentication(context);
//自帶
ConfigureBundles();
ConfigureUrls(configuration);
ConfigureConventionalControllers();
ConfigureLocalization();
ConfigureVirtualFileSystem(context);
ConfigureCors(context, configuration);
//配置swagger(ABP自帶,可以直接修改成我們想要的)
ConfigureSwaggerServices(context, configuration);
}
//例如
/// <summary>
/// 驗證碼配置
/// </summary>
/// <param name="context"></param>
/// <param name="configuration"></param>
private void ConfigureCaptcha(ServiceConfigurationContext context, IConfiguration configuration)
{
// 默認使用內存存儲(AddDistributedMemoryCache)
context.Services.AddCaptcha(configuration);
// 全部配置
context.Services.AddCaptcha(configuration, option =>
{
option.CaptchaType = CaptchaType.WORD; // 驗證碼類型
option.CodeLength = 6; // 驗證碼長度, 要放在CaptchaType設置后. 當類型為算術表達式時,長度代表操作的個數
option.ExpirySeconds = 30; // 驗證碼過期時間
option.IgnoreCase = true; // 比較時是否忽略大小寫
option.StoreageKeyPrefix = ""; // 存儲鍵前綴
option.ImageOption.Animation = true; // 是否啟用動畫
option.ImageOption.FrameDelay = 30; // 每幀延遲,Animation=true時有效, 默認30
option.ImageOption.Width = 150; // 驗證碼寬度
option.ImageOption.Height = 50; // 驗證碼高度
option.ImageOption.BackgroundColor = SkiaSharp.SKColors.White; // 驗證碼背景色
option.ImageOption.BubbleCount = 2; // 氣泡數量
option.ImageOption.BubbleMinRadius = 5; // 氣泡最小半徑
option.ImageOption.BubbleMaxRadius = 15; // 氣泡最大半徑
option.ImageOption.BubbleThickness = 1; // 氣泡邊沿厚度
option.ImageOption.InterferenceLineCount = 2; // 干擾線數量
option.ImageOption.FontSize = 36; // 字體大小
option.ImageOption.FontFamily = DefaultFontFamilys.Instance.Actionj; // 字體
/*
* 中文使用kaiti,其他字符可根據喜好設置(可能部分轉字符會出現繪制不出的情況)。
* 當驗證碼類型為“ARITHMETIC”時,不要使用“Ransom”字體。(運算符和等號繪制不出來)
*/
option.ImageOption.TextBold = true;// 粗體,該配置2.0.3新增
});
}
/// <summary>
/// 一起Program中的App
/// </summary>
/// <param name="context"></param>
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAbpRequestLocalization();
if (!env.IsDevelopment())
{
app.UseErrorPage();
}
app.UseCorrelationId();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
//app.UseAbpOpenIddictValidation();
//if (MultiTenancyConsts.IsEnabled)
//{
// app.UseMultiTenancy();
//}
app.UseUnitOfWork();
app.UseAuthorization();
app.UseSwagger();
app.UseSwaggerUI(c => {
c.SwaggerEndpoint("/swagger/v1/swagger.json", "基礎接口");
c.SwaggerEndpoint("/swagger/v2/swagger.json", "業務接口");
// 模型的默認擴展深度,設置為 -1 完全隱藏模型
c.DefaultModelsExpandDepth(0);
// API文檔僅展開標記
c.DocExpansion(DocExpansion.List);
// API前綴設置為空
c.RoutePrefix = string.Empty;
// API頁面Title
c.DocumentTitle = "??接口文檔 - 農業產品小組";
});
app.UseAuditing();
app.UseAbpSerilogEnrichers();
app.UseConfiguredEndpoints();
}
因為定義了swagger的分類和授權所以需要我們的接口加上授權驗證和接口分類
[ApiExplorerSettings(GroupName = "v1")]//方法分類
[Authorize]//授權

浙公網安備 33010602011771號