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

优化 Web 推送框架:WebSocket、SSL、JSON、AngularJS 和 MySQL 的使用

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.79/5 (15投票s)

2014 年 11 月 30 日

CPOL

8分钟阅读

viewsIcon

41247

downloadIcon

1489

WebSocket、SSL、JSON、MySQL 全部结合在一起,通过推送框架构建了一个与 AngularJs Web 前端交互的 C++ 服务器。该应用程序展示了实现 CRUD 的简便性。

引言

如今,使用 C++ 作为 Web 应用程序的后端听起来可能有些奇怪。在本文中,我将向您展示一种技术组合,它会让您改变看法。通过演示一些常见场景的实现,读者可以判断将其扩展到实际应用案例的复杂程度。

目标

在这里,我们来定义我们的目标。首先,我们问:开发者在实现过程中会面临哪些常见场景?

答案必须很简单

  • 必须定义和持久化一类项目 T1、T2 等。
  • 给定一个类型 T,用户希望前端显示可用项目的列表
  • 前端必须提供一种方式来显示一个表单,用于创建或编辑给定类型 T 的实例
  • 给定一个 UI,我们需要一种方式让用户轻松查找给定类型 T 的项目。在这种情况下,一个常见的情况是,当一个类型 T1 与一个类型 T2 有外部关系时,意味着编辑 T1 的一个实例需要选择 T2 的一个实例。

即使有些人可能不同意这个答案,但我相信他们仍然会同意,这些场景足够重要,足以让他们欣赏任何简单且可扩展的实现方式。因此,我们的目标是证明实现这些场景非常容易。

AngularJs

如今的设备和操作系统太多了。使用 HTML5 和 Javascript 的 Web 应用程序正成为构建跨平台前端的最佳答案。随着 AngularJS 等新库的出现,Javascript 开发真正开始变得有意义。这里开发的演示应用程序,其前端部分将使用 AngularJS 构建的控件进行编码。

 

WebSocket

WebSocket 是一种基于 TCP 的协议,如今大多数浏览器都支持它。它允许网页与兼容的服务器建立全双工 TCP 连接。需要注意的是,这是一个比 Ajax 强大得多的概念。

AngularJs + WebSocket = ?

这两种技术的结合使得创建桌面级 UI 成为可能,其中大部分交互逻辑在客户端执行,而所有数据和命令都流向一个与访问应用程序的 Web 服务器完全无关的实时服务器。在我们这里的演示中,Web 服务器仅用于将应用程序机器上的资产下载到最终用户的设备。

推送框架

推送框架将用于构建将与前端交互的服务器,通过接收命令并发送回数据。

第 3 版优化了设计,使得可以

  • 插入任何协议实现。(将协议逻辑分离到单独的抽象库:协议基础)
  • 水平和垂直地插入任意数量的协议
    • 推送框架服务器可以通过不同的端口进行监听。每个端口都可以指定不同的协议栈。这是水平方向。
    • 对于每个端口,我们可以将不同的协议作为层叠在一起:这是垂直方向。
  • 插入任何类型的序列化方法,而无需考虑协议选择。

为推送框架构建协议

在构建服务器应用程序之前,我们需要解决 3 个问题。首先,由于 Javascript 将打开 WebSocket 连接,因此我们需要服务器能够解码此协议。因此,我们需要 WebSocket 的协议层实现。其次,许多人需要通过 TLS 进行安全连接。因此,我们需要 TLS 的层实现。第三,由于 JSON 是 Javascript 默认的集成序列化方法,因此我们需要服务器能够以该方式接收结构化数据。因此,我们需要 JSON 序列化实现。

MySQL

对于那些希望开始新项目,但又不想在昂贵的 Oracle 或 SQL Server 许可上浪费资金的人来说,这个服务器是一个不错的选择。我们将使用 MySQL++ 库轻松与服务器通信。该库还实现了连接池,这对于应用程序速度非常有利。

DAO、DTO 和服务器端分页

MySQL++ 库极大地简化了与 MySQL 默认 API 的交互,用于发送 SQL 查询并在查询执行后检索数据。然而,如今许多人习惯了持久化框架,它们会自动完成与 DBMS 交互的所有工作。由于 C++ 中没有这样的框架,因此本文采用了代码生成的方法。

  • 使用提供的生成器,您可以连接到现有的 MySQL 数据库并选择一个 SQL 表。
  • 生成器创建 .h 和 .cpp 文件,其中包含表示您的 DAO 的 C++ 类。例如,如果您有一个名为 Person 的表,您将获得一个名为 Person 的 C++ 类,该类继承自一个名为 BaseDAO 的基对象。该类将所有表字段作为属性包含在内。它还包含getter和setter,并实现基类以下成员的虚拟逻辑:
    • bool SaveChanges();
    • bool GetFromDatabase(int _id);
    • void SerializeToJson(Json::Value& jsonObjVal);
    • void UpdateFromJson(Json::Value& jsonObjVal);
    • bool deleteFromDB(int id);
  • C++ 类拥有将自身转换为可发送到客户端的 DTO 的所有逻辑。
  • 辅助类 View 使您可以轻松访问 SQL 视图。这用于返回 DTO 列表,这些 DTO 可以为客户端网格或查找控件提供数据,所有分页逻辑都在服务器端执行。

 

首先运行应用程序

让我们确保您能够成功获取应用程序代码、编译并运行它。

  1. 解压包
  2. 可选地将 WebApp 目录部署到 Web 服务器。它包含 Index.html,您可以导航到它,或本地打开它。
  3. 使用 Visual Studio 2012 打开 Demo.sln 解决方案文件(Demo.sln 位于 Example 目录下)
  4. 编译 Debug 版本
  5. 成功编译后,"Output" 目录将包含二进制文件。
  6. 服务器应用程序构建完成后,在启动它之前,我们需要设置数据库。
  7. 从 Internet 下载并设置 MySQL 服务器。可选地下载并设置 MySQL Workbench 以方便管理服务器。
  8. Database 目录包含一个 sql 脚本。使用该脚本创建数据库以及视图和表,并用数据填充它们。
  9. 在运行 DemoAngularJsServer.exe 之前,修改 DemoAngularJsServer.ini 以反映您环境中特定的数据库设置。
  10. 运行服务器。它将开始监听 81 端口。
  11. 打开 WebApp 起始页。您应该会看到一个项目网格。
  12. 选择网格中的一行并单击编辑。使用表单编辑项目的属性,然后单击保存。

解释发生的情况

  • 页面打开时,AngularJs 控制器(HeaderCtrl)会请求与服务器建立 WebSocket 连接。
  • 另外两个控制器 EmployeeListCtrl 和 CompanyListCtrl 将调用以检索项目列表(员工和公司)并在它们的网格中显示它们。
  • 当网格初始化、表头排序或单击网格分页时,会进行 Javascript 回调,提供所有允许服务器访问 SQL 视图并返回有限行集的选项。
  • 当单击“编辑选定项”时,将网格行的对象的 ID 发送到服务器以获取对象的完整详细信息。
  • 当对象的完整详细信息收到后,它们将在 Web 表单中显示。
  • 更改表单将更改绑定到它的 Javascript 对象。
  • 单击保存会将修改后的对象发送到 C++ 服务器,服务器准备一个 DAO,使用传入的 JSON 对象中的更改更新它,然后调用 SaveToDatabase,其中包含负责调用数据库、执行 UPDATE 语句的生成代码。

支持新类型的复杂性。

添加新类型时,只需执行以下步骤

  1. 手动为新类型创建 MySQL 表。
  2. 执行 MySQL.Codegen.exe,输入数据库信息、表名,然后单击生成
  3. 将生成的 .h 和 .cpp 类文件移动到 C++ 服务器项目。将它们添加到项目文件列表中。
  4. 修改 AngularClient::getDAOByName,以便它可以支持新类型。
  5. 如果需要显示项目列表或在客户端进行查找,请为该类型创建 SQL 视图。如果该类型与其他类型有外部关系,则可以通过丰富来自外部类型的列来改进视图。例如,每个员工行都有一个 companyId,但在显示员工列表时,我们也会显示公司名称。
  6. 在此阶段,服务器端只需要这些工作。第 4 步只需手动编写两行代码
  7. 在客户端,添加一个新的所需视图和控制器,并将它们与应用程序(主要在 app.js 中)链接。
  8. 要添加与现有类型(公司和员工)类似的行为,您可以复制文件。真正改变的是以下内容
    1. 为了使网格正常工作,当它调用 WebsocketService.getView 时,请为它提供您创建的正确SQL 视图名称
    2. 为了使表单正常工作,将您的控件绑定到完全相同的表字段名,然后无论何时控制器调用 WebsocketService.getItem 或 WebsocketService.deleteItem,请确保提供正确的类型名称
  9. 如果类型有外部关系,您需要允许用户在编辑表单时设置这些关系。为此,请查看现有的 Employee Form 代码:所有需要的是
    1. 对于编辑,将关系字段绑定到 typeahead 控件
    2. 要显示编辑/显示对象中 ID 所代表的实体的名称,请在控制器开始时进行查找以检索外部对象,并使用适当的字段初始化 typeahead 显示文本。

从这些步骤,可以判断实现所有这些标准场景需要多少精力。

历史

这目前是本文的初稿。

© . All rights reserved.