65.9K
CodeProject 正在变化。 阅读更多。
Home

Angular2 + CData API 服务器: 数据驱动的动态 Web 应用

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2017年2月10日

CPOL

9分钟阅读

viewsIcon

18475

使用 CData Software API Server 为您的数据库创建 OData 服务,并基于数据库数据构建动态 Web 应用。

Angular2 是一个用于动态 Web 应用的更新框架,它建立在 Angular JS 的原理之上并对其进行了扩展。CData API Server 可以为您生成本地和云端数据库的 REST API。本文将指导您完成设置 CData API Server 以创建 SQLite 数据库的 REST API,并创建一个能够实时访问数据库数据的简单单页应用 (SPA)。该 SPA 将根据数据库数据动态构建和填充 HTML 表格。虽然本文档会介绍大部分代码,但您可以下载 示例 Angular2 项目和 SQLite 数据库 来查看完整的源代码并自行测试功能。

设置 API Server

如果您还没有这样做,则需要下载 CData API Server。安装 API Server 后,您需要运行该应用程序,配置驱动程序以连接到您的数据(本文中的说明适用于包含的示例数据库),然后配置驱动程序以创建任何您希望在 SPA 中访问的表的 REST API。

启用 CORS

如果 Angular2 Web 应用和 API Server 位于不同的域,那么 Angular2 将生成跨域请求。这意味着 CORS(跨域资源共享)必须在 Angular2 Web 应用查询的任何服务器上启用。我们可以通过导航到 API Server 的 SETTINGS 页面的 Server 选项卡来为 API Server 启用 CORS。您需要调整以下设置:

  • 勾选“启用跨域资源共享 (CORS)”复选框。
  • 勾选“允许所有域(不含 '*')”复选框,或在 Access-Control-Allow-Origin 中指定允许连接的域。
  • Access-Control-Allow-Methods 设置为“GET,PUT,POST,OPTIONS”。
  • Access-Control-Allow-Headers 设置为“authorization”。
  • 点击“保存更改”。

配置数据库连接

要配置 API Server 连接到您的数据库,您需要导航到 SETTINGS 页面的 Connections 选项卡。在那里,点击 Add Connection。对于本文,我们将连接到 SQLite 数据库。配置连接时,您可以为连接命名,选择 SQLite 作为数据库,并在 Database 字段中填入 SQLite 数据库的完整路径(包含的数据库是来自 SQLite 教程 的 chinook.db)。

配置用户

接下来,创建一个用户以通过 API Server 访问您的数据库数据。您可以在 SETTINGS 页面的 Users 选项卡上添加和配置用户。由于我们只创建一个简单的 SPA 来查看数据,因此我们将创建一个具有只读访问权限的用户。点击 Add,为用户命名,为 Privileges 选择 GET,然后点击 Save Changes。

正如您在屏幕截图中所见,我们已经配置了一个具有读写访问权限的用户。对于本文,我们将使用只读用户以及关联的 authtoken 来访问 API Server。

访问表

创建用户后,我们就可以启用对数据库表的访问。要启用表,请点击 SETTINGS 页面的 Resources 选项卡上的 Add Resources 按钮。选择您希望访问的数据连接,然后点击 Next。选择连接后,您可以通过点击表名并点击 Next 来开始启用资源。您需要一次添加一个资源。在此示例中,我们启用了所有表。

REST API 的示例 URL

配置好数据库连接,创建了用户,并在 API Server 中添加了资源后,我们就拥有了一个基于 OData 协议且易于访问的 REST API。下面将列出表以及访问它们的 URL。有关访问表的信息,您可以导航到 API Server 的 API 页面。对于 URL,您需要 API Server 的 addressport。由于我们使用的是 Angular2,我们将把 @json 参数附加到默认不返回 JSON 数据的 URL 的末尾。

表格URL
实体(表)列表http://address:port/api.rsc/
表 albums 的元数据http://address:port/api.rsc/albums/$metadata?@json
albums 数据http://address:port/api.rsc/albums

与标准的 OData Feed 一样,如果您希望限制返回的字段,可以在查询中添加 $select 参数,以及其他标准的 URL 参数,如 $filter$orderby$skip$top

构建单页应用

完成 API Server 设置后,我们就可以构建 SPA 了。我们将逐一介绍 .zip 文件中 SPA 的源文件,并留意相关的代码部分。其中一些源文件 loosely 基于 angular.io 提供的 Angular2 教程。

index.html

这是我们 SPA 的主页,其源代码主要由 script 元素组成,用于导入必要的 Angular2 库。

app/main.ts

此 TypeScript 文件用于引导应用程序。

app/rxjs-extensions.ts

此 TypeScript 文件用于导入必要的 Observable 扩展和操作符。

app/app.module.ts

此 TypeScript 文件用于创建一个类,该类可以在其他文件中使用,以导入创建和运行我们的 SPA 所需的模块。

app/app.component.css

此文件创建 CSS 规则集,用于修改我们 HTML 中的 h1h2thtd 元素。

app/app.component.html

此文件是我们 SPA 的模板。模板包含一个标题、一个用于选择可用表的下拉列表、一个用于(多)选择要显示的表中列的下拉列表、一个用于检索数据的按钮以及一个用于显示数据的表。不同的部分会根据 *ngIf 指令中的条件启用/禁用,菜单和表会根据调用 API Server 的结果动态构建,使用 *ngFor 指令循环遍历返回的数据。

所有对 API Server 的调用以及变量值的赋值都在 AppComponent 和 AppService 类中完成。

<h1>{{title}}</h1>
<br>
<label>Select a Table</label>
<br>
<select [(ngModel)]="selectedTable" (change)="tableChanged()">
  <option *ngFor="let sel_table of availableTables" [value]="sel_table">{{sel_table}}</option>
</select>
<br>
<br>
<label>Select Columns</label>
<br>
<select *ngIf="selectedTable" [(ngModel)]="selectedColumns" (change)="columnsChanged()" multiple>
  <option *ngFor="let sel_column of availableColumns" [value]="sel_column">{{sel_column}}</option>
</select>
<br>
<br>
<button *ngIf="selectedTable && selectedColumns" (click)="dataButtonClicked()">Get [{{selectedTable}}] Data</button>
<br>
<br>
<table *ngIf="selectedTable && selectedColumns">
  <thead>
  <tr>
    <th *ngFor="let column of selectedColumns">{{ column }}</th>
  </tr>
  </thead>
  <tbody>
  <tr *ngFor="let row of tableData">
    <td *ngFor="let column of selectedColumns">{{ row[column] }}</td>
  </tr>
  </tbody>
</table>

app/app.service.ts

此 TypeScript 文件构建了从 API Server 检索数据的服务。其中,我们有用于检索表列表、检索特定表的列列表以及从表中检索数据的功能。我们还有一个类,用于表示 API Server 返回的表的元数据。

API_Table

API Server 返回的表的元数据包括表的名称、种类和 URL。我们只使用 name 字段,但传递整个对象以防万一我们需要这些其他信息来扩展我们的 SPA。

export class API_Table {
  name: string;
  kind: string;
  url: string;
}

constructor()

在构造函数中,我们创建 Http 类的一个私有实例,并根据之前创建的用户凭据/authtoken 设置 Authorization HTTP 头。然后,我们在 HTTP 请求中包含此头。

constructor(private http: Http) {
  this.headers.append('Authorization', 'Basic ' + btoa(this.userName+":"+this.authToken));
}

getTables()

此函数返回一个表列表。该列表是通过向 API Server 的基本 URL:https://:8153/api.rsc 发送 HTTP GET 请求(包括 Authorization 头)来检索的。

getTables(): Promise<API_Table[]> {
  return this.http.get(this.baseUrl, {headers: this.headers})
    .toPromise()
    .then(response => response.json().value )
    .catch(this.handleError);
}

getColumns()

此函数返回由 tableName 指定的表的列列表。由于 $metadata 端点默认返回 XML 格式的数据,因此我们在 URL 中传递 @json 参数以确保我们从 API Server 获得 JSON 数据。一旦获得 JSON 数据,我们就可以深入提取列名列表。

getColumns(tableName: string): Promise<string[]> {
  return this.http.get(`${this.baseUrl}/${tableName}/$metadata?@json`, {headers: this.headers})
    .toPromise()
    .then(response => response = response.json().items[0]["odata:cname"] )
    .catch(this.handleError);
}

getTableData()

此函数返回指定表和列的数据行。我们将 tableName 放在 URL 中,然后将列列表(一个逗号分隔的字符串)作为 $select URL 参数的值传递。`</p>

getTableData(tableName:string, columnList: string): Promise<Object[]> {
  return this.http.get(`${this.baseUrl}/${tableName}/?$select=${columnList}`, {headers: this.headers})
    .toPromise()
    .then(response => response = response.json().value )
    .catch(this.handleError);
}

app/app.component.ts

在此 TypeScript 文件中,我们定义了响应 SPA 中事件的函数;在这些函数中,我们调用 AppService 中的函数,并使用结果填充 SPA 的各种元素。这些函数相对简单,会根据需要为不同的变量赋值。

ngOnInit()

在此函数中,我们调用 AppService 中的 getTables 函数。由于 getTables 返回我们 API Server 表查询的原始数据对象,我们需要仅将每个结果中的 name 字段推送到可用表数组中,而不是推送整个对象。

ngOnInit(): void {
  this.appService
    .getTables()
    .then( tables => {
      for (let tableObj of tables) {
        this.availableTables.push( tableObj.name )
      }
    });
}

tableChanged()

每当用户在 SPA 的下拉菜单中选择不同表时,都会调用此函数。该函数会调用 API Server 以检索给定表的列列表,从而填充另一个下拉菜单。

tableChanged(): void {
  this.appService
    .getColumns(this.selectedTable)
    .then( columns => this.availableColumns = columns );

  this.selectedColumns = [];
}

columnsChanged()

每当用户更改下拉菜单中选定的列时,都会调用此函数。它只是清除表数据,以便在单击按钮后选择的列与最初选择的列不同时,我们不会显示空表。

columnsChanged(): void {
  this.tableData = [];
}

dataButtonClicked()

此函数用于将选定列的数组连接成一个逗号分隔的字符串,这正是 OData 查询中的 $select 参数所要求的,并将表名和列表传递给 AppService 中的 getTableData 函数。然后,结果数据将用于填充 HTML 表。

dataButtonClicked(columnList: string): void {
  columnList = this.selectedColumns.join(',');
  this.appService
    .getTableData( this.selectedTable, columnList )
    .then( data => this.tableData = data );
}

运行单页应用

配置好数据连接并审查了 SPA 的源文件后,我们就可以运行单页应用了。您需要在您的机器上安装 node.js 和 npm 才能运行 SPA。示例下载中包含了一个 http-server 实例,它将在您的机器上创建一个轻量级服务器来运行 SPA。要启动服务器,您只需在 SPA 的根目录中运行 start.sh 脚本。

> bash .\start.sh

SPA 启动后,您将看到标题和一个用于选择表的下拉菜单。表列表是从 API Server 检索的,包括您在配置 API Server 时添加为资源的所有表。

选择表后,会出现用于列的多选下拉菜单,允许您选择要在表中显示的列。您可以看到,当您选择列时,表头就会出现。

选择好表和列后,您可以点击 Get [table] Data 按钮,通过 API Server 从数据库检索数据。HTML 表将根据您在点击按钮前选择的表和列来填充数据。

免费试用和更多信息

现在您已经看到了将数据库数据连接到动态网页的基本示例,请访问我们的 API Server 页面,了解有关 API Server 的更多信息并下载 API Server。开始使用来自本地和云端数据库(包括 SQLite、MySQL、SQL Server、Oracle 和 PostgreSQL!)的实时数据构建动态网页!一如既往,我们世界一流的 支持团队 随时准备回答您的任何问题。

© . All rights reserved.