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

使用数据库数据构建动态 React 应用

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2019年4月22日

CPOL
viewsIcon

7634

本文将详细介绍如何设置 CData API Server 以创建 SQLite 数据库的 REST API,以及如何创建一个可以实时访问数据库数据的简单 React Web 应用程序。

React 是一个声明式、高效且灵活的 JavaScript 库,用于构建用户界面。CData API Server 使您能够为 100 多个数据源生成 REST API,包括本地和基于云的数据库。本文将详细介绍如何设置 CData API Server 以创建 SQLite 数据库的 REST API,以及如何创建一个可以实时访问数据库数据的简单 React Web 应用程序。React 应用程序根据数据库数据动态构建和填充 HTML 表格。虽然本文详细介绍了大部分代码,但您可以下载 示例 React 项目和 SQLite 数据库,查看完整的源代码并亲自测试其功能。

设置 API Server

如果您尚未下载 CData API Server,请立即下载。安装 API Server 后,请按照以下步骤运行应用程序,配置应用程序以连接到您的数据(本文中的说明适用于随附的示例数据库),然后配置应用程序以为您希望在 React 应用程序中访问的任何表创建 REST API。

启用 CORS

如果 React Web 应用程序和 API Server 位于不同的域,则 React 将生成跨域请求。这意味着必须在 React Web 应用程序查询的任何服务器上启用 CORS(跨域资源共享)。您可以在 SETTINGS 页面中的“Server”选项卡上为 API Server 启用 CORS

  1. 勾选复选框以启用跨域资源共享 (CORS)。
  2. 勾选复选框以允许所有域而不使用“*”,或者在 **Access-Control-Allow-Origin** 中指定允许连接的域。
  3. 将 **Access-Control-Allow-Methods** 设置为 "GET,PUT,POST,OPTIONS"。
  4. 将 **Access-Control-Allow-Headers** 设置为 "authorization"。
  5. 点击“保存更改”。

配置您的数据库连接

按照以下步骤配置 API Server 以连接到您的数据库

  1. 导航到 SETTINGS 页面上的“Connections”选项卡。
  2. 点击“Add Connection”。
  3. 在出现的对话框中配置连接:命名您的连接,选择 SQLite 作为数据库,并使用 SQLite 数据库的完整路径填充“Database”字段(随附的数据库是来自 SQLite Tutorial 的 chinook.db)。

配置用户

接下来,创建一个用户,通过 API Server 访问您的数据库数据。您可以在 SETTINGS 页面的“Users”选项卡上添加和配置用户。在这个简单的 React 数据查看应用程序中,创建一个具有只读访问权限的用户:点击“Add”,为用户命名,为“Privileges”选择“GET”,然后点击“Save Changes”。

然后为该用户生成一个 authtoken。您可以在“Users”选项卡上找到每个用户的 authtoken 和其他信息

访问表格

创建用户后,您就可以启用对数据库表的访问了

  1. 点击 SETTINGS 页面“Resources”选项卡上的“Add Resources”按钮。
  2. 选择您希望访问的数据连接,然后点击“Next”。
  3. 选择连接后,通过选择每个表名并点击“Next”来启用资源。

REST API 的示例 URL

配置了数据库连接,创建了用户,并向 API Server 添加了资源后,您现在就拥有了一个基于 OData 协议的易于访问的 REST API。下面,您将看到一个表格列表以及访问它们的 URL。有关访问表格的更多信息,您可以从导航栏打开 API 页面。要与 React 一起使用,您可以将 `@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`。

构建 React Web 应用程序

API Server 设置完成后,您就可以构建示例 React 应用程序了。以下步骤将详细介绍 .zip 文件中包含的 React 应用程序的源文件,并指出任何相关的代码部分。

index.html

这是示例 React Web 应用程序的主页。它完善了 HTML `head` 和 `body`,并确定了用于显示 Web 应用程序的容器和脚本。

main.js

此 TypeScript 文件导入必要的库、模块和 React 类。主 React 类的属性或 `props` 也在此处定义。

package.json

此 JSON 文件包含 React 应用程序的属性,包括依赖项。此文件是自动生成的。

webpack.config.js

此 JavaScript 文件定义了 React 应用程序的各种配置。

App.jsx

此 JavaScript XML 文件包含构建 React 应用程序所需的代码。`App` 类包含从 API Server 检索数据和渲染 React 应用程序不同部分所需的所有函数。方法如下所述。

构造函数

App 类的构造函数。其中,`state` 包含用于构建 Web 应用程序的动态数据。您还可以将其他方法绑定到 `this`,以便在这些方法中修改 `state`。

  constructor(props) {
    super(props);

    this.state = {
      selectedTable: '',
      selectedColumns: [],
      tables: [],
      columns: [],
      tableData: [],
      auth: 'Basic ' + btoa(props.user + ':' + props.pass),
    };
    
    this.onTableChange = this.onTableChange.bind(this);
    this.onColumnChange = this.onColumnChange.bind(this);
    this.renderTableHeaders = this.renderTableHeaders.bind(this);
    this.renderTableBody = this.renderTableBody.bind(this);
    this.getColumnList = this.getColumnList.bind(this);
    this.getData = this.getData.bind(this);    
    
  }

componentDidMount

根据 React 规范,`componentDidMount` 方法在 `render` 方法之前调用,可以在构造函数运行后用于更新应用程序的 `state` 变量。在此方法中,您可以向 API Server 发送 HTTP 请求以获取表列表,并设置 `tables` 和 `selectedTable` 状态变量。

在示例中,调用 `getColumnList` 方法检索第一个(当前选定)表的可用列列表。

  componentDidMount() {
    Object.assign(axios.defaults, {headers: {authorization: this.state.auth}});
    axios.get(`${this.props.baseUrl}`)
      .then(res => {
        const tables = res.data.value;
        this.setState({ tables });
        this.setState({ selectedTable: tables[0].name});
      })
      .catch(function (error) {
        if (error.response) {
          alert('Code: ' + error.response.data.error.code + '\r\nMessage: ' + error.response.data.error.message);
        } else {
          console.log('Error', error.message);
        }
      });
    this.getColumnList();
  }

getColumnList

此函数检索 `selectedTable` 参数(如果参数未定义,则为 UI 中当前选定的表)可用的列列表。它执行 HTTP 请求并解析响应,设置 `columns` 和 `selectedColumns` 状态。

  getColumnList(selectedTable) {
    if (!selectedTable) {
      selectedTable = this.state.selectedTable;
    }
    Object.assign(axios.defaults, {headers: {authorization: this.state.auth}});
    axios.get(`${this.props.baseUrl}/${selectedTable}/$metadata?@json`)
      .then(res => {
        let columns = res.data.items[0]["odata:cname"];
        this.setState({ 
          columns,
          selectedColumns: [], 
        });
      })
      .catch(error => {
        if (error.response) {
          alert('Code: ' + error.response.data.error.code + '\r\nMessage: ' + error.response.data.error.message);
        } else {
          console.log('Error', error.message);
        }
      });
  }

renderTableList

此函数使用 `tables` 状态变量为用于选择表的 HTML 下拉选择框构建选项。

  renderTableList() {
    let tablesHTML = [];
    for (let i = 0; i < this.state.tables.length; i++) {
      let table = this.state.tables[i];
      tablesHTML.push({table.name});
    }
    return tablesHTML;
  }

renderColumnList

此函数使用 `columns` 状态变量为用于选择列的 HTML 多选框构建选项。

  renderColumnList() {
    let columnsHTML = [];
    for (let i = 0; i < this.state.columns.length; i++){
      let column = this.state.columns[i];
      columnsHTML.push({column});
    }
    return columnsHTML;
  }

renderTable

此函数根据从 API Server 检索的数据为 HTML 表格提供基本框架。它使用两个辅助函数 `renderTableHeaders()` 和 `renderTableBody()` 来构建表格标题和数据行。

  renderTable() {
    return (
      <table>
        <thead>
          { this.renderTableHeaders() }
        </thead>
        { this.renderTableBody() }
      </table>
    );
  }

renderTableHeaders

此函数使用 `selectedColumns` 状态变量为用于显示 API Server 数据的 HTML 表格构建标题。

  renderTableHeaders() {
    let headers = [];
    for (let i = 0; i < this.state.selectedColumns.length; i++) {
      let col = this.state.selectedColumns[i];
      headers.push(<th key={col} style={{backgroundColor: '#177CB8', color: 'white', border: '1px solid grey', borderCollapse: 'collapse', padding: '5px'}}>{col}</th>)
    }
    return (<tr>{headers}</tr>);
  }

renderTableBody

此函数使用 `tableData` 和 `selectedColumns` 状态变量为用于显示 API Server 数据的 HTML 表格构建数据行。

  renderTableBody() {
    let rows = [];
    this.state.tableData.forEach(function(row) {
      rows.push(
        <tr key={btoa('row'+rows.length)}>
          {this.state.selectedColumns.map(col =>
            <td key={col} style={{border: '1px solid grey', borderCollapse: 'collapse', padding: '5px'}}>{row[col]}</td>
          )}
        </tr>
      )
    }.bind(this));
    return (<tbody>{rows}</tbody>);
  }

getData

此函数从 API Server 检索数据,根据 `selectedColumns` 状态变量构建 `$select` 参数的列表,并使用 `selectedTable` 状态变量确定从哪个资源请求数据。API Server 返回的数据存储在 `tableData` 状态变量中。

  getData() {
    let columnList = '';
    columnList = this.state.selectedColumns.join(',');
    Object.assign(axios.defaults, {headers: {authorization: this.state.auth}});
    axios.get(`${this.props.baseUrl}/${this.state.selectedTable}/?$select=${columnList}`)
      .then(res => {
        const tableData = res.data.value;
        this.setState({ tableData });
      })
      .catch(error => {
        if (error.response) {
          alert('Code: ' + error.response.data.error.code + '\r\nMessage: ' + error.response.data.error.message);
        } else {
          console.log('Error', error.message);
        }
      });
  }

onTableChange

此函数处理用于选择表的 HTML 下拉选择框上的更改事件。在该函数中,`selectedTable` 状态变量被设置为选定值,`tableData` 状态变量被清除所有值。此外,调用 `getColumnList` 函数会更新用于选择列的 HTML 多选元素。

  onTableChange(event) {
    const selectedTable = event.target.value;
    this.setState({
      selectedTable,
      tableData: [],
    });
    this.getColumnList(selectedTable);
  }

onColumnChange

此函数处理用于选择要检索和显示的列的 HTML 多选框上的更改事件。在确定选择的列后,`selectedColumns` 状态变量会更新,`tableData` 状态变量会清除。

  onColumnChange(event) {
    let options = event.target.options;
    let selectedColumns = [];
    for (let i = 0; i < options.length; i++){
      if (options[i].selected){
        selectedColumns.push(options[i].value);
      }
    }
    this.setState({
      selectedColumns, 
      tableData: [],    
      });    
  }

render

此函数是控制各种 HTML 元素的布局和显示的函数。它包含所有静态 HTML 功能,以及调用那些渲染动态元素的函数的函数调用。

  render() {    
    return (
      <div>
        <h1 style={{fontSize: '1.2em', color: '#177CB8', marginBottom: '0'}}>CData API Server React Demo</h1>
        <br/>
        <label>Select a Table</label>
        <br/>
        <select className='tableDropDown' onChange={this.onTableChange}>
          { this.renderTableList() }
        </select>
        <br/>
        <br/>
        <label>Select {this.state.selectedTable} Columns</label>
        <br/>
        <select className='columnMultiSelect' onChange={this.onColumnChange} multiple>
          { this.renderColumnList() }
        </select>
        <br/>
        <br/>
        { this.state.selectedColumns.length > 0 ? <button onClick={this.getData}>Get [{ this.state.selectedTable }] Data</button> : null }
        <br/>
        <br/>
        { this.state.tableData.length > 0 ? this.renderTable() : null }
      </div>
    );
  }

配置 React 应用程序

配置好数据连接并审查了 React 应用程序的源文件后,您现在就可以运行 React Web 应用程序了。您需要在计算机上安装 node.js 才能运行 React 应用程序。在运行应用程序之前,您还需要安装几个模块。

全局模块

为了运行 React 应用程序,请从命令行全局安装 `babel` 和 `babel-cli` 模块

  • npm install -g babel
  • npm install -g babel-cli

设置项目

在接下来的步骤中,您将设置您的 React 项目,创建并填充您的 package.json 文件。

  1. 在命令行中,切换到源文件所在的目录
        cd ./apiserver-react
  2. 进入目录后,使用预配置的 package.json 文件安装必要的模块。
        npm install

运行 React 应用程序

现在您已经创建了 package.json 文件并安装了必要的模块,您就可以运行 React 应用程序了。为此,您只需在命令行界面中导航到 React 应用程序的目录并执行以下命令

npm start

当 React 应用程序启动时,将显示标题和一个用于选择表的下拉菜单。表列表从 API Server 检索,并包含您在配置 API Server 时添加为资源的所有表。

当您选择一个表时,将出现用于列的下拉多选菜单,然后您可以选择希望在表中看到的列。当您选择列时,表头将出现。

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

免费试用和更多信息

现在您已经完成了在动态网页中连接到数据库数据所需的步骤,下载 API Server,开始使用来自您的本地和基于云的数据库(包括 SQLite、MySQL、SQL Server、Oracle 和 PostgreSQL)的实时数据构建动态网页!一如既往,我们世界一流的支持团队随时准备回答您可能遇到的任何问题。

© . All rights reserved.