13、构建功能丰富的 Web 客户端:认证、添加与删除功能实现

构建功能丰富的 Web 客户端:认证、添加与删除功能实现

1. 开启拓展之旅

恭喜你,已经拥有一个可运行的 Web 客户端了!不过,这还不是终点。接下来,你将为这个客户端添加更多强大的功能,具体如下:
- 添加认证功能,保障用户账户安全。
- 赋予账户添加新表情符号条目的能力。
- 支持从账户中删除表情符号条目。

Stencil 是一个强大的模板框架,你可以在其 GitHub 仓库 中深入了解它。

2. 完善 Web 布局

首先,你要通过编写 HTML 来布局用户管理所需的工具。这里可以借助一个简单的 JS 弹出库,并编写一些 jQuery 代码将所有适当的操作与之关联起来。

需要提醒的是,你并非必须使用 Xcode 来编辑文件,像 Visual Studio Code 等编辑器都是不错的选择。

具体操作步骤如下:
1. 打开项目,待 Xcode 解析完依赖后,构建并运行服务器。
2. 在浏览器中打开两个标签页,分别访问以下地址:
- http://localhost:8080/openapi/ui
- http://localhost:8080/client
3. 利用 Kitura OpenAPI UI 为不同用户添加一两个日记条目。例如,点击 POST /user 路由,添加以下两个用户:

{ 
  "id": "bill", 
  "password": "excellent" 
}
{ 
  "id": "ted", 
  "password": "adventure" 
}
  1. 为每个用户添加一两个日记条目,确保日期以大数字形式表示,如:
{ 
  "emoji":"( ", 
  "date": 563725805.57661498 
}
  1. Sources/Application/Routes/WebClientRoutes.swift 文件中设置断点,检查 webEntries 数组,确保有两个条目属于不同用户。
  2. 打开 Views/home.stencil 文件,在 <div class='menu-container'> 下方添加以下代码:
<div id="user-info-popup" style="align-self: auto;"> 
  <input id="username-field" placeholder="username"> 
  <br> 
  <input id="password-field" type="password"  
    placeholder="password"> 
  <br> 
  <button id="cancel-signup-button"  
    onclick="cancelButtonTapped()">Cancel</button> 
  <button id="signup-button" onclick="createUser()"> 
    Sign Up 
  </button> 
  <button id="login-button" onclick="login()">Login</button> 
  <button id="logout-button" onClick="logout()">Logout</button> 
</div>
  1. 刷新浏览器,你会在左上角看到新添加的元素。
  2. 滚动到文件底部,在导入 JavaScript 文件的代码块末尾添加以下代码:
<script src="https://cdn.rawgit.com/vast-engineering/jquery-popup-overlay/1.7.13/jquery.popupoverlay.js"></script>
  1. 在第一个没有显式调用 URL 导入的 <script> 标签下方,添加以下代码:
$(document).ready(() => { 
  $('#user-info-popup').popup({ 
    color: '#FFF', 
    opacity: 0.9 
  }) 
})
  1. 刷新浏览器,登录窗口会暂时隐藏。
  2. 找到 home.stencil 文件中类似以下的代码块:
<div class="wrapper"> 
  <div class='title'><h1>&  EmojiJournal & </h1></div> 
</div>

将其替换为:

<div class="wrapper"  
  style="display: grid;grid-template-columns: 1fr 1fr 1fr;"> 
  <div id="logged-in" style= 
    "display:flex;margin:0;align-items:center;color:white;"> 
  </div> 
  <div class='title'>
    <h1>&  EmojiJournal & </h1> 
  </div> 
  <div class="wrapper"  
    style="display: flex;align-items: center;margin: 0;"> 
    <div class="title-login" onclick="signupClicked()"  
      style="margin-left: auto;color: white;"> 
      User Management 
    </div> 
  </div> 
</div>

这里有几点需要注意:
- 可以使用内联样式规则覆盖 index.css 文件中的样式,但不要过度使用。
- HTML 组件可以是 div ,并可分配 class onClick 等属性。 class 便于在 jQuery 中引用 HTML 文档, onClick 用于指定点击元素时要运行的 JS 函数。
- 代码中多次使用的 flex 与 Flexbox 布局库相关,你可以在 这里 了解更多。

刷新浏览器,你会看到网页顶部出现一个白色的 “User Management” 链接。点击它,目前可能没有反应,因为还需要定义 signupClicked 函数。在文件底部的 <script> 块中添加以下代码:

function signupClicked() { 
  $('#user-info-popup').popup('show') 
}
3. 让网页按钮生效

现在,你要为新添加的对话框添加关闭功能。在 JavaScript 部分的 signupClicked 函数下方添加以下代码:

function cancelButtonTapped() { 
  $('#user-info-popup').popup('hide') 
}

保存文件并刷新浏览器,点击 “User Management” 链接,再点击 “Cancel” 按钮,对话框就会关闭。

接下来,为了实现认证功能,需要添加处理浏览器 Cookie 的函数。在 cancelButtonTapped 函数下方添加以下代码:

function setCookie(cookiename, cookievalue, hours) { 
  var date = new Date(); 
  date.setTime(date.getTime() + Number(hours) * 3600 * 1000); 
  document.cookie = cookiename + "=" + cookievalue +  
    "; path=/;expires = " + date.toGMTString(); 
} 

function getCookie(name) { 
  var value = "; " + document.cookie; 
  var parts = value.split("; " + name + "="); 
  if (parts.length == 2) return parts.pop().split(";").shift(); 
}

同时,更新 signupClicked 函数:

function signupClicked() { 
  $('#username-field').val(getCookie("username")) 
  $('#password-field').val(getCookie("password"))
  $('#user-info-popup').popup('show') 
}

这样,每次对话框弹出时,jQuery 会用最新存储的 Cookie 预填充字段。

以下是整个流程的 mermaid 流程图:

graph LR
    A[打开项目并运行服务器] --> B[在浏览器打开指定页面]
    B --> C[使用 Kitura OpenAPI UI 添加用户和条目]
    C --> D[设置断点检查条目]
    D --> E[编辑 home.stencil 文件添加元素]
    E --> F[添加 JavaScript 代码关联操作]
    F --> G[定义按钮点击函数]
    G --> H[添加 Cookie 处理函数]
    H --> I[更新 signupClicked 函数]
4. 实现注册和登录功能

在真正使用 JournalEntry API 之前,你需要编写注册和登录方法。

4.1 注册功能

在 JavaScript 代码底部添加以下函数:

function createUser() { 
  var userID = $('#username-field').val() 
  var password = $('#password-field').val() 
  var xhr = new XMLHttpRequest() 
  xhr.open("POST", "/user") 
  xhr.setRequestHeader("Content-Type", "application/json") 
  xhr.onreadystatechange = (() => { 
    if (xhr.readyState == XMLHttpRequest.DONE) { 
      $('#new-user-popup').popup('hide') 
      if (xhr.status == 201) { 
        var result =  
          confirm(`Created a new user: ${userID} - want to login?`) 
        if (result) { 
          login() 
        } 
      } else { 
        alert(`There was an error creating this user profile:  
          ${xhr.statusText}`) 
      } 
    }
  }) 
  var body = JSON.stringify({"id": userID,  
    "password": password}) 
  xhr.send(body) 
}

这个函数通过 XMLHttpRequest 对象向服务器发送 POST 请求来创建新用户。当请求完成且状态码为 201 时,表示用户创建成功,会提示用户是否登录。

4.2 登录功能

createUser 函数下方添加以下代码:

function login() { 
  var userID = $('#username-field').val() 
  var password = $('#password-field').val() 
  var xhr = new XMLHttpRequest() 
  xhr.open("GET", "/entries") 
  xhr.setRequestHeader("Content-Type", "application/json") 
  xhr.setRequestHeader("Authorization", "Basic " +  
    btoa(userID + ":" + password)) 
  xhr.onreadystatechange = (() => { 
    if (xhr.readyState == XMLHttpRequest.DONE) { 
      if (xhr.status == 200) { 
        // 1 
        setCookie("username", userID, 24) 
        setCookie("password", password, 24) 

        // 2 
        $('#user-info-popup').popup('hide') 

        // 3 
        alert(`Logged in as ${userID}`) 

        // 4 
        var loggedInUser = document.getElementById('logged-in') 
        loggedInUser.innerHTML = "Logged in as: " + userID 
        location.reload() 

      } else { 
        alert(`Login failed: ${xhr.statusText}`) 
      } 
    }
  })
  xhr.send() 
}

这个函数通过 GET 请求检查用户凭证。若状态码为 200,表示登录成功,会将用户名和密码保存为 Cookie,隐藏用户管理弹出窗口,提示用户登录成功,并更新页面显示。

4.3 注销功能

login 函数下方添加以下代码:

function logout() { 
  if (confirm("Are you sure you want to log out?")) { 
    setCookie("username", "", 24) 
    setCookie("password", "", 24) 
    location.reload() 
  } 
}

当用户确认注销时,会清除存储的 Cookie 并刷新页面。

5. 测试功能

保存文件并刷新网页,尝试使用新用户 “socrates” 和密码 “philosophy” 进行注册。注册成功后点击 “OK” 登录,你将看到已成功登录为 “Socrates”。刷新页面,你会发现仍然显示之前的日记条目,因为还未添加按用户过滤日记条目的逻辑。

以下是注册、登录和注销功能的操作步骤表格:
| 功能 | 操作步骤 |
| ---- | ---- |
| 注册 | 输入用户名和密码,点击 “Sign Up” 按钮,根据提示操作 |
| 登录 | 输入用户名和密码,点击 “Login” 按钮,若凭证正确则登录成功 |
| 注销 | 点击 “Logout” 按钮,确认后清除 Cookie 并刷新页面 |

整个功能实现的流程可以用以下 mermaid 流程图表示:

graph LR
    A[输入注册信息] --> B[调用 createUser 函数]
    B --> C{请求状态码是否为 201}
    C -- 是 --> D[提示是否登录]
    D -- 是 --> E[调用 login 函数]
    C -- 否 --> F[提示创建用户错误]
    E --> G{请求状态码是否为 200}
    G -- 是 --> H[保存 Cookie,隐藏窗口,提示登录成功,更新页面]
    G -- 否 --> I[提示登录失败]
    J[点击 Logout 按钮] --> K[调用 logout 函数]
    K --> L[清除 Cookie 并刷新页面]

通过以上步骤,你已经为 Web 客户端添加了认证、添加和删除功能,使其更加完善和实用。后续你可以进一步优化和拓展这些功能,如添加按用户过滤日记条目的逻辑等。

构建功能丰富的 Web 客户端:认证、添加与删除功能实现

6. 深入理解代码逻辑

为了更好地掌握已实现的功能,我们来深入分析一下代码逻辑。

6.1 XMLHttpRequest 的使用

在注册和登录功能中,都使用了 XMLHttpRequest 对象来与服务器进行通信。这个对象是浏览器提供的用于发送 HTTP 请求的工具,它的基本使用步骤如下:
1. 创建 XMLHttpRequest 对象: var xhr = new XMLHttpRequest()
2. 打开请求: xhr.open(method, url) ,其中 method 可以是 GET POST 等, url 是请求的地址。
3. 设置请求头: xhr.setRequestHeader(header, value) ,例如设置请求的内容类型为 JSON。
4. 监听请求状态变化: xhr.onreadystatechange = callback ,在回调函数中处理请求结果。
5. 发送请求: xhr.send(data) ,如果是 POST 请求,需要将数据作为参数传递。

以下是一个简单的对比表格,展示注册和登录请求的不同:
| 请求类型 | 方法 | URL | 请求头 | 数据 |
| ---- | ---- | ---- | ---- | ---- |
| 注册 | POST | /user | Content-Type: application/json | {“id”: userID, “password”: password} |
| 登录 | GET | /entries | Content-Type: application/json
Authorization: Basic [base64(username:password)] | 无 |

6.2 Cookie 的管理

Cookie 用于在浏览器中存储用户的登录信息,方便后续的请求使用。 setCookie getCookie 函数分别用于设置和获取 Cookie。

setCookie 函数的逻辑如下:
1. 创建一个 Date 对象,并设置过期时间。
2. 将 Cookie 名称、值和过期时间组合成一个字符串。
3. 将该字符串赋值给 document.cookie

getCookie 函数的逻辑如下:
1. 获取当前浏览器的所有 Cookie,并将其拼接成一个字符串。
2. 按名称分割字符串,找到对应的 Cookie 值。
3. 返回 Cookie 值。

7. 优化建议

虽然目前已经实现了基本的注册、登录和注销功能,但还有一些可以优化的地方。

7.1 错误处理

在实际应用中,应该对各种可能的错误情况进行更详细的处理。例如,当网络请求失败时,除了显示错误信息,还可以提供重试机制。可以在 xhr.onreadystatechange 回调函数中添加更多的错误处理逻辑,如下所示:

xhr.onreadystatechange = (() => {
  if (xhr.readyState == XMLHttpRequest.DONE) {
    if (xhr.status == 200) {
      // 处理成功响应
    } else if (xhr.status == 401) {
      alert('Unauthorized: Invalid credentials');
    } else if (xhr.status == 404) {
      alert('Not Found: The requested resource does not exist');
    } else {
      alert(`An error occurred: ${xhr.statusText}`);
    }
  }
})
7.2 用户体验优化
  • 可以添加加载动画,在发送请求时显示,让用户知道请求正在处理中。
  • 对输入字段进行验证,例如检查用户名和密码是否为空,避免无效请求。

以下是一个简单的输入验证示例:

function createUser() {
  var userID = $('#username-field').val();
  var password = $('#password-field').val();

  if (userID === '' || password === '') {
    alert('Please enter a valid username and password');
    return;
  }

  // 继续发送请求的代码
}
8. 总结

通过以上步骤,我们成功地为 Web 客户端添加了认证、注册、登录和注销功能。整个过程涉及到 HTML、JavaScript、jQuery 和 HTTP 请求等多个方面的知识。

以下是整个功能实现的关键步骤列表:
1. 完善 Web 布局,添加用户管理界面。
2. 让网页按钮生效,实现对话框的显示和关闭功能。
3. 管理 Cookie,存储用户登录信息。
4. 实现注册、登录和注销功能,与服务器进行通信。
5. 测试功能,确保各项操作正常。

未来,你可以进一步拓展这些功能,例如添加按用户过滤日记条目的逻辑,或者实现更复杂的用户权限管理。

整个功能实现的流程图如下:

graph LR
    A[完善 Web 布局] --> B[按钮生效]
    B --> C[管理 Cookie]
    C --> D[实现注册、登录、注销功能]
    D --> E[测试功能]
    E --> F[拓展功能]

希望这篇文章能帮助你更好地理解和实现 Web 客户端的认证和用户管理功能。如果你有任何问题或建议,欢迎留言讨论。

Delphi 12.3 作为一款面向 Windows 平台的集成开发环境,由 Embarcadero Technologies 负责其持续演进。该环境以 Object Pascal 语言为核心,并依托 Visual Component Library(VCL)框架,广泛应用于各类桌面软件、数据库系统及企业级解决方案的开发。在此生态中,Excel4Delphi 作为一个重要的社区开源项目,致力于搭建 Delphi Microsoft Excel 之间的高效桥梁,使开发者能够在自研程序中直接调用 Excel 的文档处理、工作表管理、单元格操作及宏执行等功能。 该项目以库文件组件包的形式提供,开发者将其集成至 Delphi 工程后,即可通过封装良好的接口实现对 Excel 的编程控制。具体功能涵盖创建编辑工作簿、格式化单元格、批量导入导出数据,乃至执行内置公式宏指令等高级操作。这一机制显著降低了在财务分析、报表自动生成、数据整理等场景中实现 Excel 功能集成的技术门槛,使开发者无需深入掌握 COM 编程或 Excel 底层 API 即可完成复杂任务。 使用 Excel4Delphi 需具备基础的 Delphi 编程知识,并对 Excel 对象模型有一定理解。实践中需注意不同 Excel 版本间的兼容性,并严格遵循项目文档进行环境配置依赖部署。此外,操作过程中应遵循文件访问的最佳实践,例如确保目标文件未被独占锁定,并实施完整的异常处理机制,以防数据损毁或程序意外中断。 该项目的持续维护依赖于 Delphi 开发者社区的集体贡献,通过定期更新以适配新版开发环境 Office 套件,并修复已发现的问题。对于需要深度融合 Excel 功能的 Delphi 应用而言,Excel4Delphi 提供了经过充分测试的可靠代码基础,使开发团队能更专注于业务逻辑用户体验的优化,从而提升整体开发效率软件质量。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值