使用单层解决方案构建待办事项应用程序教程
本教程是一个单部分的快速入门指南,将指导你使用 ABP 框架构建一个简单的待办事项应用程序。以下是最终应用程序的截图:
你可以在这里找到已完成应用程序的源代码。
本文档在 YouTube 上配有视频教程!!你可以在这里观看:
前置要求
支持 .NET 9.0+ 开发的 IDE(例如 Visual Studio)。
创建新解决方案
在本教程中,我们将使用 ABP CLI 创建一个基于 ABP 的示例应用程序。如果你尚未安装 ABP CLI,可以在命令行终端中运行以下命令来安装:
dotnet tool install -g Volo.Abp.Studio.Cli
然后创建一个空文件夹,打开命令行终端并在其中执行以下命令:
abp new TodoApp -t app-nolayers -u angular
这将创建一个名为 TodoApp 的新解决方案,其中包含 angular 和 aspnet-core 文件夹。解决方案准备就绪后,请在你喜欢的 IDE 中打开 aspnet-core 文件夹下的解决方案。
运行应用程序前的准备工作
如果你使用 ABP CLI 创建了解决方案,可以跳过此部分直接阅读运行应用程序章节。因为 CLI 会自动执行以下步骤。但是,有时可能需要手动执行这些步骤。例如,如果你从源代码控制系统克隆了应用程序代码,则需要手动执行。
创建数据库
你可以在 项目的根目录下(与 .csproj 文件同级的文件夹) 运行以下命令来创建数据库并填充初始数据:
dotnet run --migrate-database
此命令将为你创建数据库并填充初始数据。你也可以执行解决方案根文件夹中包含的 migrate-database.ps1 脚本。
安装客户端包
在解决方案的根目录下运行 abp install-libs 命令以安装所有必需的 NPM 包:
abp install-libs
运行应用程序
在开始开发之前,最好先运行一下应用程序。解决方案有两个主要应用程序:
TodoApp(在 .NET 解决方案中)托管服务器端 HTTP API,以便 Angular 应用程序可以调用它。(服务器端应用程序)angular文件夹包含 Angular 应用程序。(客户端应用程序)
首先,在你喜欢的 IDE 中运行 TodoApp 项目(或在项目目录中运行 dotnet run CLI 命令),在 Swagger UI 上查看服务器端 HTTP API:
你可以使用此 UI 来探索和测试你的 HTTP API。如果它正常工作,那么我们就可以运行 Angular 客户端应用程序了。
你可以使用以下命令(或 yarn start)来运行应用程序:
npm start
此命令需要一些时间,但最终会运行并在你的默认浏览器中打开应用程序:
你可以点击 登录 按钮,使用 admin 作为用户名,1q2w3E* 作为密码登录应用程序。
好的,我们可以开始编码了!
定义实体
这个应用程序将有一个单一的实体,我们可以从创建它开始。在 项目 的 Entities 文件夹下创建一个新的 TodoItem 类:
using Volo.Abp.Domain.Entities;
namespace TodoApp.Entities;
public class TodoItem : BasicAggregateRoot<Guid>
{
public string Text { get; set; } = string.Empty;
}
BasicAggregateRoot 是创建根实体的最简单基类,这里的 Guid 是实体的主键(Id)。
数据库集成
下一步是配置 Entity Framework Core。
映射配置
打开 TodoAppDbContext 类(在 Data 文件夹中),并向该类添加一个新的 DbSet 属性:
public DbSet<TodoItem> TodoItems { get; set; }
然后在同一个类中找到 OnModelCreating 方法,并为 TodoItem 实体添加以下映射代码:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* 将模块包含到你的迁移数据库上下文中 */
builder.ConfigurePermissionManagement();
...
/* 在这里配置你自己的表/实体 */
builder.Entity<TodoItem>(b =>
{
b.ToTable("TodoItems");
});
}
我们已经将 TodoItem 实体映射到了数据库中的 TodoItems 表。下一步是创建迁移并将更改应用到数据库。
代码优先迁移
启动解决方案已配置为使用 Entity Framework Core 代码优先迁移。由于我们更改了数据库映射配置,因此应该创建一个新的迁移并将更改应用到数据库。
在 项目的根目录下(与 .csproj 文件同级的文件夹) 打开命令行终端,并键入以下命令:
dotnet ef migrations add Added_TodoItem
这将在项目中添加一个新的迁移类。你应该能在 Migrations 文件夹中看到新的迁移:
然后,你可以在同一命令行终端中使用以下命令将更改应用到数据库:
dotnet ef database update
完成数据库集成后,现在我们可以开始创建应用服务方法并实现我们的用例了。
创建应用服务
应用服务用于执行应用程序的用例。在这个应用程序中,我们需要执行以下用例:
- 获取待办事项列表
- 创建新的待办事项
- 删除现有的待办事项
在开始实现这些用例之前,我们首先需要创建一个将在应用服务中使用的 DTO 类。
创建数据传输对象 (DTO)
应用服务通常获取和返回 DTO(数据传输对象),而不是实体。因此,在 Services/Dtos 文件夹下创建一个新的 TodoItemDto 类:
namespace TodoApp.Services.Dtos;
public class TodoItemDto
{
public Guid Id { get; set; }
public string Text { get; set; } = string.Empty;
}
这是一个非常简单的 DTO 类,其属性与 TodoItem 实体相同。现在,我们准备好实现我们的用例了。
应用服务实现
在 你的项目 的 Services 文件夹下创建一个 TodoAppService 类,如下所示:
using TodoApp.Services.Dtos;
using TodoApp.Entities;
using Volo.Abp.Domain.Repositories;
namespace TodoApp.Services;
public class TodoAppService : TodoAppAppService
{
private readonly IRepository<TodoItem, Guid> _todoItemRepository;
public TodoAppService(IRepository<TodoItem, Guid> todoItemRepository)
{
_todoItemRepository = todoItemRepository;
}
// TODO: 在这里实现方法...
}
该类继承自 TodoAppAppService,而 TodoAppAppService 继承自 ABP 的 ApplicationService 类,并实现我们的用例。ABP 为实体提供了默认的泛型仓储。我们可以使用它们来执行基本的数据库操作。该类注入了 IRepository<TodoItem, Guid>,它是 TodoItem 实体的默认仓储。我们将使用它来实现我们的用例。
获取待办事项
让我们从实现 GetListAsync 方法开始,该方法用于获取待办事项列表:
public async Task<List<TodoItemDto>> GetListAsync()
{
var items = await _todoItemRepository.GetListAsync();
return items
.Select(item => new TodoItemDto
{
Id = item.Id,
Text = item.Text
}).ToList();
}
我们只是从仓储中获取 TodoItem 列表,将它们映射到 TodoItemDto 对象,然后返回结果。
创建新的待办事项
下一个方法是 CreateAsync,我们可以如下实现:
public async Task<TodoItemDto> CreateAsync(string text)
{
var todoItem = await _todoItemRepository.InsertAsync(
new TodoItem {Text = text}
);
return new TodoItemDto
{
Id = todoItem.Id,
Text = todoItem.Text
};
}
仓储的 InsertAsync 方法将给定的 TodoItem 插入数据库并返回同一个 TodoItem 对象。它还会设置 Id,因此我们可以在返回对象中使用它。我们通过从新的 TodoItem 实体创建一个 TodoItemDto 来返回它。
删除待办事项
最后,我们可以如下实现 DeleteAsync 方法:
public async Task DeleteAsync(Guid id)
{
await _todoItemRepository.DeleteAsync(id);
}
应用服务现在已准备就绪,可以从 UI 层调用了。那么,让我们来实现它。
用户界面
是时候在 UI 上显示待办事项了!在开始编写代码之前,最好先回顾一下我们要构建的内容。以下是最终 UI 的示例截图:
服务代理生成
ABP 提供了一个方便的功能,可以自动创建客户端服务,以便轻松使用服务器提供的 HTTP API。
你首先需要运行 TodoApp 项目,因为代理生成器从服务器应用程序读取 API 定义。
一旦你运行了 TodoApp 项目(将显示 Swagger API 定义),在 angular 文件夹的目录中打开命令行终端,并运行以下命令:
abp generate-proxy -t ng
如果一切顺利,它应该会生成如下输出:
CREATE src/app/proxy/generate-proxy.json (182755 bytes)
CREATE src/app/proxy/README.md (1000 bytes)
CREATE src/app/proxy/services/todo.service.ts (833 bytes)
CREATE src/app/proxy/services/dtos/models.ts (71 bytes)
CREATE src/app/proxy/services/dtos/index.ts (26 bytes)
CREATE src/app/proxy/services/index.ts (81 bytes)
CREATE src/app/proxy/index.ts (61 bytes)
然后,我们可以使用 TodoService 来调用服务器端 HTTP API,就像我们将在下一节中做的那样。
home.component.ts
打开 /angular/src/app/home/home.component.ts 文件,并将其内容替换为以下代码块:
import { ToasterService } from "@abp/ng.theme.shared";
import { Component, OnInit, inject } from '@angular/core';
import { TodoItemDto } from "@proxy/services/dtos";
import { TodoService } from "@proxy/services";
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss'],
})
export class HomeComponent implements OnInit {
todoItems: TodoItemDto[];
newTodoText: string;
private readonly todoService = inject(TodoService);
private readonly toasterService = inject(ToasterService);
ngOnInit(): void {
this.todoService.getList().subscribe(response => {
this.todoItems = response;
});
}
create(): void {
this.todoService.create(this.newTodoText).subscribe((result) => {
this.todoItems = this.todoItems.concat(result);
this.newTodoText = null;
});
}
delete(id: string): void {
this.todoService.delete(id).subscribe(() => {
this.todoItems = this.todoItems.filter(item => item.id !== id);
this.toasterService.info('已删除待办事项。');
});
}
}
我们使用了 TodoService 来获取待办事项列表,并将返回值分配给 todoItems 数组。我们还添加了 create 和 delete 方法。这些方法将在视图端使用。
home.component.html
打开 /angular/src/app/home/home.component.html 文件,并将其内容替换为以下代码块:
<div class="container">
<div class="card">
<div class="card-header">
<div class="card-title">待办事项列表</div>
</div>
<div class="card-body">
<!-- 新建待办事项表单 -->
<form class="row row-cols-lg-auto g-3 align-items-center" (ngSubmit)="create()">
<div class="col-12">
<div class="input-group">
<input name="NewTodoText" type="text" [(ngModel)]="newTodoText" class="form-control" placeholder="输入内容..." />
</div>
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary">提交</button>
</div>
</form>
<!-- 待办事项列表 -->
<ul id="TodoList">
<li *ngFor="let todoItem of todoItems">
<i class="fa fa-trash-o" (click)="delete(todoItem.id)"></i> {{ todoItem.text }}
</li>
</ul>
</div>
</div>
</div>
home.component.scss
作为最后的润色,打开 /angular/src/app/home/home.component.scss 文件,并在文件末尾添加以下代码块:
#TodoList{
list-style: none;
margin: 0;
padding: 0;
}
#TodoList li {
padding: 5px;
margin: 5px 0px;
border: 1px solid #cccccc;
background-color: #f5f5f5;
}
#TodoList li i
{
opacity: 0.5;
}
#TodoList li i:hover
{
opacity: 1;
color: #ff0000;
cursor: pointer;
}
这是待办事项页面的简单样式。我们相信你可以做得更好 :)
现在,你可以再次运行应用程序以查看结果。
结论
在本教程中,我们构建了一个非常简单的应用程序来熟悉 ABP。请查看Web 应用程序开发教程,以了解使用 分层应用程序启动模板 在分层架构中进行的真实 Web 应用程序开发。
源代码
你可以在这里找到已完成应用程序的源代码。
抠丁客






