Web应用程序开发教程 - 第二章: 图书列表页面

    • Entity Framework Core 做为ORM提供程序.
    • MVC / Razor Pages 做为UI框架.

    本教程分为以下部分:

    下载源码

    本教程根据你的UIDatabase偏好有多个版,我们准备了两种可供下载的源码组合:

    通常在 JavaScript 端通过AJAX调用HTTP API端点. 你可以使用 $.ajax 或其他工具来调用端点. 但是ABP提供了更好的方法.

    ABP动态为所有API端点创建 JavaScript代理. 所以你可以像调用Javascript本地方法一样使用任何端点.

    你可以在自己喜欢的浏览器的开发者控制台轻松的测试JavaScript代理. 运行应用程序,打开浏览器的开发者人员工具(快捷键通常是F12),切换到控制台选项卡,输入以下代码然后按回车:

    • acme.bookStore.booksBookAppService 的命令空间转换成形式.
    • bookBookAppService 的约定名称(删除AppService后缀并且转换为小驼峰).
    • getListCrudAppService 基类定义的 GetListAsync 方法的约定名称(删除Async后缀并且转换为小驼峰).
    • {} 参数将空对象发送到 GetListAsync 方法,该方法通常需要一个类型为 PagedAndSortedResultRequestDto 的对象,该对象用于将分页和排序选项发送到服务器(所有属性都是可选的,具有默认值. 因此你可以发送一个空对象).
    • getList 函数返回一个 promise. 你可以传递一个回调到 then(或done)函数来获取从服务器返回的结果.

    运行该代码会产生以下输出:

    你可以看到服务端返回的 图书列表. 你也可以在开发者人员工具的 网络 选项卡查看客户端到服务端的通信:

    Let’s create a new book using the create function:

    让我们使用 create 函数创建一本书:

    1. acme.bookStore.books.book.create({
    2. name: 'Foundation',
    3. type: 7,
    4. publishDate: '1951-05-24',
    5. price: 21.5
    6. }).then(function (result) {
    7. console.log('successfully created the book with id: ' + result.id);
    8. });

    您应该在控制台中看到类似以下的消息:

    1. successfully created the book with id: 439b0ea8-923e-8e1e-5d97-39f2c7ac4246

    检查数据库中的 Books 表你会看到新的一行. 你可以自己尝试使用 get, updatedelete 函数.

    本地化

    开始的UI开发之前,我们首先要准备本地化的文本(这是你通常在开发应用程序时需要做的).

    本地化文本位于 Acme.BookStore.Domain.Shared 项目的 Localization/BookStore 文件夹下:

    打开 en.json (英文翻译)文件并更改内容,如下所示:

    • 本地化关键字名称是任意的. 你可以设置任何名称. 对于特定的文本类型,我们更喜欢遵循一些约定:
      • 为按钮项添加 Menu: 前缀.
      • 使用 Enum:<enum-type>:<enum-value> 命名约定来本地化枚举成员. 当您这样做时ABP可以在某些适当的情况下自动将枚举本地化.

    如果未在本地化文件中定义文本,则文本将回退到本地化键(作为ASP.NET Core的标准行为).

    是时候创建可见的和可用的东西了! 代替经典的MVC,我们将使用微软推荐的Razor Pages UI.

    Acme.BookStore.Web 项目的 Pages 文件夹下创建一个名为新的 Books 的文件夹. 然后在文件夹右键选择 添加 > Razor Page 菜单. 输入名称 Index:

    打开 Index.cshtml 并把内容修改成下面这样:

    1. @page
    2. @using Acme.BookStore.Web.Pages.Books
    3. <h2>Books</h2>

    Index.cshtml.cs 内容应该是:

    1. namespace Acme.BookStore.Web.Pages.Books
    2. {
    3. public class IndexModel : PageModel
    4. {
    5. public void OnGet()
    6. {
    7. }
    8. }
    9. }

    打开 Menus 文件夹中的 BookStoreMenuContributor 类,在 ConfigureMainMenuAsync 方法的底部添加如下代码:

    运行项目,使用用户名 admin 和密码 1q2w3E* 登录到应用程序. 看到新菜单项已添加到顶部栏:

    点击BookStore下的Books子菜单项就会跳转到空的图书页面.

    We will use the Datatables.net jQuery library to show the book list. Datatables library completely work via AJAX, it is fast, popular and provides a good user experience.

    我们将使用JQuery插件来显示页面上的表格列表. Datatables可以完全通过AJAX工作,速度快,并提供良好的用户体验.

    Index.cshtml

    Pages/Book/Index.cshtml 改成下面的样子:

    1. @page
    2. @using Acme.BookStore.Localization
    3. @using Acme.BookStore.Web.Pages.Books
    4. @using Microsoft.Extensions.Localization
    5. @model IndexModel
    6. @inject IStringLocalizer<BookStoreResource> L
    7. @section scripts
    8. {
    9. <abp-script src="/Pages/Books/Index.js" />
    10. }
    11. <abp-card>
    12. <abp-card-header>
    13. <h2>@L["Books"]</h2>
    14. </abp-card-header>
    15. <abp-card-body>
    16. <abp-table striped-rows="true" id="BooksTable"></abp-table>
    17. </abp-card-body>
    18. </abp-card>
    • abp-script tag helper用于将外部的 脚本 添加到页面中.它比标准的script标签多了很多额外的功能.它可以处理 最小化版本.查看获取更多信息.
    • abp-cardabp-table 是为Twitter Bootstrap的card component封装的 tag helpers.ABP中有很多tag helpers,可以很方便的使用大多数组件.你也可以使用原生的HTML标签代替tag helpers.使用tag helper可以通过智能提示和编译时类型检查减少HTML代码并防止错误.查看tag helpers 文档.

    Index.js

    Pages/Books/ 文件夹中创建 index.js文件

    index.js 的内容如下:

    1. $(function () {
    2. var l = abp.localization.getResource('BookStore');
    3. var dataTable = $('#BooksTable').DataTable(
    4. abp.libs.datatables.normalizeConfiguration({
    5. serverSide: true,
    6. order: [[1, "asc"]],
    7. searching: false,
    8. scrollX: true,
    9. ajax: abp.libs.datatables.createAjax(acme.bookStore.books.book.getList),
    10. {
    11. title: l('Name'),
    12. data: "name"
    13. },
    14. {
    15. title: l('Type'),
    16. data: "type",
    17. render: function (data) {
    18. return l('Enum:BookType:' + data);
    19. }
    20. },
    21. {
    22. title: l('PublishDate'),
    23. data: "publishDate",
    24. render: function (data) {
    25. return luxon
    26. .DateTime
    27. .fromISO(data, {
    28. locale: abp.localization.currentCulture.name
    29. }).toLocaleString();
    30. }
    31. },
    32. {
    33. title: l('Price'),
    34. data: "price"
    35. },
    36. {
    37. title: l('CreationTime'), data: "creationTime",
    38. render: function (data) {
    39. return luxon
    40. .DateTime
    41. .fromISO(data, {
    42. locale: abp.localization.currentCulture.name
    43. }).toLocaleString(luxon.DateTime.DATETIME_SHORT);
    44. }
    45. }
    46. ]
    47. })
    48. );
    49. });
    • abp.localization.getResource 获取一个函数,该函数用于使用服务器端定义的相同JSON文件对文本进行本地化. 通过这种方式你可以与客户端共享本地化值.
    • abp.libs.datatables.normalizeConfiguration是另一个辅助方法.不是必须的, 但是它通过为缺少的选项提供常规值来简化数据表配置.
    • abp.libs.datatables.createAjax是帮助ABP的动态JavaScript API代理跟的格式相适应的辅助方法.
    • 是动态JavaScript代理函数(上面已经介绍过了)
    • luxon 库也是该解决方案中预先配置的标准库,你可以轻松地执行日期/时间操作.

    运行最终应用程序

    你可以运行应用程序!该部分的最终用户界面如下所示:

    Book list

    这是一个完全正常工作的服务端分页,排序和本地化的图书列表.

    查看本教程的.