5. 更新数据库
运行 Acme.BookStore.DbMigrator
应用程序来更新数据库,将Acme.BookStore.DbMigrator设置为启动程序,然后运行即可,如下所示:
执行成功后,打开数据库管理工具,即可看到新生成的数据表,如下所示:
以上则表示数据库创建成功。
6. 创建应用程序
应用程序层由两个分离的项目组成:
Acme.BookStore.Application.Contracts
包含你的DTO和应用服务接口.Acme.BookStore.Application
包含你的应用服务实现.
在本部分中,创建一个应用程序服务,使用ABP Framework的 CrudAppService
基类来获取,创建,更新和删除书籍.
6. 1 创建BookDto类
在Abp中,需要创建Book实体的Dto类,在Acme.BookStore.Application.Contracts项目中,添加BootDto类,如下所示:
namespace Acme.BookStore { public class BookDto : AuditedEntityDto<Guid> { public string Name { get; set; } public BookType Type { get; set; } public DateTime PublishDate { get; set; } public float Price { get; set; } } }
- DTO类被用来在 表示层 和 应用层 传递数据.
- 为了在页面上展示书籍信息,
BookDto
被用来将书籍数据传递到表示层. BookDto
继承自AuditedEntityDto<Guid>
.跟上面定义的Book
实体一样具有一些审计属性.
在将书籍返回到表示层时,需要将Book
实体转换为BookDto
对象. AutoMapper库可以在定义了正确的映射时自动执行此转换. 启动模板配置了AutoMapper,因此你只需在Acme.BookStore.Application
项目的BookStoreApplicationAutoMapperProfile
类中定义映射:
namespace Acme.BookStore { public class BookStoreApplicationAutoMapperProfile : Profile { public BookStoreApplicationAutoMapperProfile() { /* You can configure your AutoMapper mapping configuration here. * Alternatively, you can split your mapping configurations * into multiple profile classes for a better organization. */ CreateMap<Book, BookDto>(); } } }
6.2 CreateUpdateBookDto
在Acme.BookStore.Application.Contracts
项目中创建一个名为 CreateUpdateBookDto
的DTO类:
namespace Acme.BookStore.Books { public class CreateUpdateBookDto { [Required] [StringLength(128)] public string Name { get; set; } [Required] public BookType Type { get; set; } = BookType.Undefined; [Required] [DataType(DataType.Date)] public DateTime PublishDate { get; set; } = DateTime.Now; [Required] public float Price { get; set; } } }
- 这个DTO类被用于在创建或更新书籍的时候从用户界面获取图书信息.
- 它定义了数据注释属性(如
[Required]
)来定义属性的验证. DTO由ABP框架自动验证.
就像上面的BookDto
一样,创建一个从CreateUpdateBookDto
对象到Book
实体的映射,最终映射配置类如下:
namespace Acme.BookStore { public class BookStoreApplicationAutoMapperProfile : Profile { public BookStoreApplicationAutoMapperProfile() { /* You can configure your AutoMapper mapping configuration here. * Alternatively, you can split your mapping configurations * into multiple profile classes for a better organization. */ CreateMap<Book, BookDto>(); CreateMap<CreateUpdateBookDto, Book>(); } } }
7. 创建应用程序服务
7.1 创建IBookAppService
下一步是为应用程序定义接口,在Acme.BookStore.Application.Contracts
项目中定义一个名为IBookAppService
的接口:
- 框架定义应用程序服务的接口不是必需的. 但是,它被建议作为最佳实践.
ICrudAppService
定义了常见的CRUD方法:GetAsync
,GetListAsync
,CreateAsync
,UpdateAsync
和DeleteAsync
. 你可以从空的IApplicationService
接口继承并手动定义自己的方法(将在下一部分中完成).ICrudAppService
有一些变体, 你可以在每个方法中使用单独的DTO,也可以分别单独指定(例如使用不同的DTO进行创建和更新).
7.2 创建 BookAppService
在Acme.BookStore.Application
项目中创建名为 BookAppService
的 IBookAppService
实现:
namespace Acme.BookStore.Books { public class BookAppService : CrudAppService< Book, //The Book entity BookDto, //Used to show books Guid, //Primary key of the book entity PagedAndSortedResultRequestDto, //Used for paging/sorting CreateUpdateBookDto>, //Used to create/update a book IBookAppService //implement the IBookAppService { public BookAppService(IRepository<Book, Guid> repository) : base(repository) { } } }
BookAppService
继承了CrudAppService<...>
.它实现了ICrudAppService
定义的CRUD方法.BookAppService
注入IRepository <Book,Guid>
,这是Book
实体的默认仓储. ABP自动为每个聚合根(或实体)创建默认仓储. 请参阅仓储文档BookAppService
使用IObjectMapper
将Book
对象转换为BookDto
对象, 将CreateUpdateBookDto
对象转换为Book
对象. 启动模板使用AutoMapper库作为对象映射提供程序. 我们之前定义了映射, 因此它将按预期工作.
8. 自动生成API Controllers
你通常创建Controller以将应用程序服务公开为HTTP API端点. 因此允许浏览器或第三方客户端通过AJAX调用它们.
ABP可以自动按照惯例将你的应用程序服务配置为MVC API控制器.
9. Swagger UI
启动模板配置为使用Swashbuckle.AspNetCore运行swagger UI. 运行应用程序并在浏览器中输入https://localhost:XXXX/swagger/
(用你自己的端口替换XXXX)作为URL.
你会看到一些内置的接口和Book
的接口,它们都是REST风格的:
10. 创建页面
在Acme.BookStore.Web项目的Pages文件夹下,创建Books目录,然后新增Razer Pages,如下所示:
添加成功后,如下所示:
Index.cshtml页面代码如下所示:
@page @using Acme.BookStore.Web.Pages.Books @model IndexModel <h2>Books</h2>
11. 将Book页面添加到主菜单
打开 Menus
文件夹中的 BookStoreMenuContributor
类,在 ConfigureMainMenuAsync
方法的底部添加如下代码:
namespace Acme.BookStore.Web.Menus { public class BookStoreMenuContributor : IMenuContributor { public async Task ConfigureMenuAsync(MenuConfigurationContext context) { if (context.Menu.Name == StandardMenus.Main) { await ConfigureMainMenuAsync(context); } } private async Task ConfigureMainMenuAsync(MenuConfigurationContext context) { var administration = context.Menu.GetAdministration(); var l = context.GetLocalizer<BookStoreResource>(); context.Menu.Items.Insert( 0, new ApplicationMenuItem( BookStoreMenus.Home, l["Menu:Home"], "~/", icon: "fas fa-home", order: 0 ) ); if (MultiTenancyConsts.IsEnabled) { administration.SetSubItemOrder(TenantManagementMenuNames.GroupName, 1); } else { administration.TryRemoveMenuItem(TenantManagementMenuNames.GroupName); } administration.SetSubItemOrder(IdentityMenuNames.GroupName, 2); administration.SetSubItemOrder(SettingManagementMenuNames.GroupName, 3); //添加book菜单 context.Menu.AddItem( new ApplicationMenuItem( "BooksStore", l["Menu:BookStore"], icon: "fa fa-book" ).AddItem( new ApplicationMenuItem( "BooksStore.Books", l["Menu:Books"], url: "/Books" ) ) ); } } }
运行Acme.BookStore.Web项目,等录以后,便可以查看菜单,如下所示:
点击菜单后,跳转到默认的Book首页,如下所示:
12. 修改Book首页
将 Pages/Book/Index.cshtml
改成下面的样子:
@page @using Acme.BookStore.Localization @using Acme.BookStore.Web.Pages.Books @using Microsoft.Extensions.Localization @model IndexModel @inject IStringLocalizer<BookStoreResource> L @section scripts { <abp-script src="/Pages/Books/Index.js" /> } <abp-card> <abp-card-header> <h2>@L["Books"]</h2> </abp-card-header> <abp-card-body> <abp-table striped-rows="true" id="BooksTable"></abp-table> </abp-card-body> </abp-card>
其中引用的Index.js位于Pages/Books目录下,如下所示:
$(function () { var l = abp.localization.getResource('BookStore'); var dataTable = $('#BooksTable').DataTable( abp.libs.datatables.normalizeConfiguration({ serverSide: true, paging: true, order: [[1, "asc"]], searching: false, scrollX: true, ajax: abp.libs.datatables.createAjax(acme.bookStore.books.book.getList), columnDefs: [ { title: l('Name'), data: "name" }, { title: l('Type'), data: "type", render: function (data) { return l('Enum:BookType:' + data); } }, { title: l('PublishDate'), data: "publishDate", render: function (data) { return luxon .DateTime .fromISO(data, { locale: abp.localization.currentCulture.name }).toLocaleString(); } }, { title: l('Price'), data: "price" }, { title: l('CreationTime'), data: "creationTime", render: function (data) { return luxon .DateTime .fromISO(data, { locale: abp.localization.currentCulture.name }).toLocaleString(luxon.DateTime.DATETIME_SHORT); } } ] }) ); });
然后运行项目,结果如下所示:
以上就是Abp的简单入门介绍,旨在抛转引玉,一起学习,共同进步。
可点击示例源码下载
备注
浣溪沙·一曲新词酒一杯【作者】晏殊 【朝代】北宋
一曲新词酒一杯,去年天气旧亭台。夕阳西下几时回?
无可奈何花落去,似曾相识燕归来。小园香径独徘徊。