项目实战:构建一个Web应用(上篇)

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介: 项目实战:构建一个Web应用(上篇)

## 1. 项目简介

### 1.1 技术栈

以下是本项目实战所使用的技术栈:

- 后端:Node.js、Express

- 数据库:MongoDB

- 前端(下篇文章中):HTML、CSS、JavaScript、Bootstrap、jQuery

- 版本控制:Git

## 2. 项目准备

### 2.1 安装相关工具

确保你已经安装了以下工具:

1. [Node.js](https://nodejs.org/)

2. [npm](https://www.npmjs.com/)(Node.js包管理工具,通常与Node.js一起安装)

3. [Git](https://git-scm.com/)

4. [MongoDB](https://www.mongodb.com/)

### 2.2 创建项目文件夹

打开命令行工具,创建项目文件夹并进入:

1. mkdir todo-app
2. cd todo-app

### 2.3 初始化Git仓库

在项目文件夹中初始化Git仓库:

git init

创建`.gitignore`文件,排除一些不需要跟踪的文件和文件夹:

node_modules/
*.log

## 3. 后端搭建

### 3.1 初始化项目

运行`npm init`,按照提示填写信息,初始化项目。这将生成一个`package.json`文件,用于管理项目依赖和配置。

### 3.2 安装依赖

安装后端所需的依赖:

npm install express mongoose bcryptjs jsonwebtoken

- express:Web应用框架

- mongoose:MongoDB对象模型工具

- bcryptjs:加密库

- jsonwebtoken:生成和验证JSON Web Token(JWT

### 3.3 搭建服务器

创建一个名为`server.js`的文件,并写入以下代码:

const express = require("express");
const app = express();
// 使用JSON中间件来解析请求体
app.use(express.json());
app.get("/", (req, res) => {
  res.send("Hello World!");
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

运行`node server.js`启动服务器,访问`http://localhost:3000`,你应该看到"Hello World!"。

### 3.4 数据库连接

确保你已经安装并启动了MongoDB。在`server.js`中添加以下代码以连接数据库:

const mongoose = require("mongoose");
mongoose.connect("mongodb://localhost:27017/todo_app", {
  useNewUrlParser: true,
  useUnifiedTopology: true,
})
  .then(() => console.log("Connected to MongoDB"))
  .catch((err) => console.error("Could not connect to MongoDB", err));

现在,我们已经成功连接到了MongoDB数据库。接下来,我们将创建用户认证和待办事项相关的接口。

### 3.5 用户认证

首先,我们要创建用户模型。在项目根目录下创建一个名为`models`的文件夹。然后,在`models`文件夹中创建一个名为`user.js`的文件,并添加以下代码:

const mongoose = require("mongoose");
const bcrypt = require("bcryptjs");
const userSchema = new mongoose.Schema({
  username: {
    type: String,
    required: true,
    unique: true,
  },
  password: {
    type: String,
    required: true,
  },
});
// 在保存用户之前,对密码进行哈希处理
userSchema.pre("save", async function (next) {
  if (!this.isModified("password")) return next();
  this.password = await bcrypt.hash(this.password, 10);
  next();
});
// 验证密码的实例方法
userSchema.methods.validatePassword = function (password) {
  return bcrypt.compare(password, this.password);
};
const User = mongoose.model("User", userSchema);
module.exports = User;

接下来,我们将创建注册和登录接口。在项目根目录下创建一个名为`routes`的文件夹。然后,在`routes`文件夹中创建一个名为`auth.js`的文件,并添加以下代码:

const express = require("express");
const router = express.Router();
const jwt = require("jsonwebtoken");
const User = require("../models/user");
router.post("/register", async (req, res) => {
  try {
    const user = new User(req.body);
    await user.save();
    res.status(201).send({ message: "User registered successfully" });
  } catch (err) {
    res.status(400).send({ error: err.message });
  }
});
router.post("/login", async (req, res) => {
  try {
    const user = await User.findOne({ username: req.body.username });
    if (!user || !(await user.validatePassword(req.body.password))) {
      throw new Error("Invalid username or password");
    }
    const token = jwt.sign({ userId: user._id }, "your_jwt_secret");
    res.send({ token });
  } catch (err) {
    res.status(401).send({ error: err.message });
  }
});
module.exports = router;

最后,在`server.js`中添加以下代码来挂载认证路由:

const authRoutes = require("./routes/auth");
// ...
app.use("/auth", authRoutes);
// ...

现在,我们已经完成了用户认证相关的接口。可以使用Postman等API测试工具测试注册和登录接口。

### 3.6 待办事项接口

首先,我们要创建待办事项模型。在`models`文件夹中创建一个名为`todo.js`的文件,并添加以下代码:

const mongoose = require("mongoose");
const todoSchema = new mongoose.Schema({
  userId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "User",
    required: true,
  },
  title: {
    type: String,
    required: true,
  },
  completed: {
    type: Boolean,
    default: false,
  },
});
const Todo = mongoose.model("Todo", todoSchema);
module.exports = Todo;

接下来,我们将创建待办事项相关的接口。在`routes`文件夹中创建一个名为`todos.js`的文件,并添加以下代码:

const express = require("express");
const router = express.Router();
const Todo = require("../models/todo");
router.get("/", async (req, res) => {
  try {
    const todos = await Todo.find({});
    res.send(todos);
  } catch (err) {
    res.status(500).send({ error: err.message });
  }
});
router.post("/", async (req, res) => {
  try {
    const todo = new Todo(req.body);
    await todo.save();
    res.status(201).send(todo);
  } catch (err) {
    res.status(400).send({ error: err.message });
  }
});
router.put("/:id", async (req, res) => {
  try {
    const todo = await Todo.findByIdAndUpdate(req.params.id, req.body, {
      new: true,
      runValidators: true,
    });
    if (!todo) throw new Error("Todo not found");
    res.send(todo);
  } catch (err) {
    res.status(400).send({ error: err.message });
  }
});
router.delete("/:id", async (req, res) => {
  try {
    const todo = await Todo.findByIdAndDelete(req.params.id);
    if (!todo) throw new Error("Todo not found");
    res.send({ message: "Todo deleted successfully" });
  } catch (err) {
    res.status(400).send({ error: err.message });
  }
});
module.exports = router;

最后,在`server.js`中添加以下代码来挂载待办事项路由:

1. const todoRoutes = require("./routes/todos");
2. 
3. // ...
4. 
5. app.use("/todos", todoRoutes);
6. 
7. // ...

至此,我们已经完成了待办事项接口的开发。可以使用Postman等API测试工具测试待办事项相关接口。

## 4. 启动Web应用

在完成上篇文章中的步骤后,我们已经搭建好了后端服务器。现在我们需要启动后端服务器:

1. 确保已经安装并运行了MongoDB。

2. 打开命令行(终端),进入项目文件夹`todo-app`。

1. cd todo-app
2. ```

3. 运行`server.js`文件以启动服务器:

node server.js
```
如果一切正常,你应该看到以下输出:
````sh
Server running on port 3000
Connected to MongoDB
```

现在,后端服务器已经在端口3000上运行,并与MongoDB数据库连接。接下来,我们将构建前端部分。

## 5. 前端搭建

### 5.1 创建前端文件夹和文件

在项目根目录下创建一个名为`public`的文件夹,用于存放前端文件。接下来,在`public`文件夹中创建以下文件:

- `index.html`:主页面

- `style.css`:样式表

- `script.js`:JavaScript脚本

### 5.2 编写前端页面

编辑`index.html`文件,添加以下代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Todo App</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <h1 class="text-center mt-5">Todo App</h1>
        <!-- 在这里添加表单和待办事项列表 -->
    </div>
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    <script src="script.js"></script>
</body>
</html>

5.3 添加表单和待办事项列表

index.html文件的<!-- 在这里添加表单和待办事项列表 -->位置添加以下代码:

<form class="mt-4" id="todo-form">
    <div class="form-group">
        <label for="title">Title</label>
        <input type="text" class="form-control" id="title" placeholder="Enter todo title">
    </div>
    <button type="submit" class="btn btn-primary">Add Todo</button>
</form>
<div class="mt-4">
    <h3 class="mb-3">Todo List</h3>
    <ul class="list-group" id="todo-list">
        <!-- 在这里显示待办事项 -->
    </ul>
</div>

5.4 编写CSS样式

编辑style.css文件,添加以下代码:

body {
    font-family: Arial, sans-serif;
}
.completed {
    text-decoration: line-through;
}

5.5 编写JavaScript脚本

编辑script.js文件,添加以下代码:

$(document).ready(function () {
  // 获取待办事项列表
  function getTodos() {
    // 在这里编写获取待办事项列表的代码
  }
  // 添加待办事项
  function addTodo() {
    // 在这里编写添加待办事项的代码
  }
  // 修改待办事项状态
  function toggleTodo() {
    // 在这里编写修改待办事项状态的代码
  }
  // 删除待办事项
  function deleteTodo() {
    // 在这里编写删除待办事项的代码
  }
  // 事件绑定
  $("#todo-form").on("submit", function (event) {
    event.preventDefault();
    addTodo();
  });
  $("#todo-list").on("click", ".toggle-todo", function () {
    toggleTodo();
  });
  $("#todo-list").on("click", ".delete-todo", function () {
    deleteTodo();
  });
  // 初始化
  getTodos();
});
``在`script.js`中,我们已经创建了基本的函数框架。接下来,我们需要实现这些函数,以便与后端服务器进行交互。
### 5.6 实现获取待办事项列表函数
在`getTodos`函数中添加以下代码:
```javascript
$.get("/api/todos", function (data) {
  $("#todo-list").empty();
  data.forEach(function (todo) {
    var listItem = $("<li class='list-group-item d-flex justify-content-between align-items-center'></li>");
    var title = $("<span class='todo-title'></span>").text(todo.title);
    if (todo.completed) {
      title.addClass("completed");
    }
    var buttonGroup = $("<div class='btn-group'></div>");
    var toggleButton = $("<button class='btn btn-sm btn-outline-secondary toggle-todo'></button>").text(todo.completed ? "Undo" : "Complete");
    var deleteButton = $("<button class='btn btn-sm btn-outline-danger delete-todo'></button>").text("Delete");
    buttonGroup.append(toggleButton, deleteButton);
    listItem.append(title, buttonGroup);
    listItem.data("id", todo._id);
    listItem.data("completed", todo.completed);
    $("#todo-list").append(listItem);
  });
});

5.7 实现添加待办事项函数

addTodo函数中添加以下代码:

var title = $("#title").val().trim();
if (title) {
  $.post("/api/todos", { title: title }, function () {
    $("#title").val("");
    getTodos();
  });
}

5.8 实现修改待办事项状态函数

toggleTodo函数中添加以下代码:

var listItem = $(this).closest("li");
var id = listItem.data("id");
var completed = listItem.data("completed");
$.ajax({
  url: "/api/todos/" + id,
  type: "PUT",
  data: { completed: !completed },
  success: function () {
    getTodos();
  }
});

5.9 实现删除待办事项函数

deleteTodo函数中添加以下代码:

var listItem = $(this).closest("li");
var id = listItem.data("id");
$.ajax({
  url: "/api/todos/" + id,
  type: "DELETE",
  success: function () {
    getTodos();
  }
});

至此,我们已经完成了前端页面的构建。现在,你可以运行后端服务器,然后在浏览器中访问http://localhost:3000来查看并使用这个待办事项应用。

为了使应用在 Express 服务器中正确运行,请确保在 server.js 文件中添加以下代码:

app.use(express.static("public"));

确保将其添加到其他中间件之前,例如:

const express = require("express");
const mongoose = require("mongoose");
const cors = require("cors");
const app = express();
const PORT = process.env.PORT || 3000;
mongoose.connect("mongodb://localhost/todo_app", { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.set("useFindAndModify", false);
app.use(cors());
app.use(express.json());
app.use(express.static("public")); // 将此行添加到此处
app.use("/api/todos", require("./routes/todos"));
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

其他内容我们下篇再继续 可以订阅本专栏 有更新 第一时间推送给你。

相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
目录
相关文章
docker快速部署OS web中间件 数据库 编程应用
通过Docker,可以轻松地部署操作系统、Web中间件、数据库和编程应用。本文详细介绍了使用Docker部署这些组件的基本步骤和命令,展示了如何通过Docker Compose编排多容器应用。希望本文能帮助开发者更高效地使用Docker进行应用部署和管理。
83 19
从模型托管到交互开发:DataV 如何简化三维 Web 应用构建?
从模型托管到交互开发:DataV 如何简化三维 Web 应用构建?
使用Web浏览器访问UE应用的最佳实践
在3D/XR应用开发中,尤其是基于UE(虚幻引擎)开发的高精度场景,传统终端因硬件局限难以流畅运行高帧率、复杂效果的三维应用。实时云渲染技术,将渲染任务转移至云端服务器,降低终端硬件要求,确保用户获得流畅体验。具备弹性扩展、优化传输协议、跨平台支持和安全性等优势,适用于多种终端和场景,特别集成像素流送技术,帮助UE开发者实现低代码上云操作,简化部署流程,保留UE引擎的强大开发能力,确保画面精美且终端轻量化。
213 17
使用Web浏览器访问UE应用的最佳实践
零基础构建开源项目OpenIM桌面应用和pc web- Electron篇
OpenIM 为开发者提供开源即时通讯 SDK,作为 Twilio、Sendbird 等云服务的替代方案。借助 OpenIM,开发者可以构建安全可靠的即时通讯应用,如 WeChat、Zoom、Slack 等。 本仓库基于开源版 OpenIM SDK 开发,提供了一款基于 Electron 的即时通讯应用。您可以使用此应用程序作为 OpenIM SDK 的参考实现。本项目同时引用了 @openim/electron-client-sdk 和 @openim/wasm-client-sdk,分别为 Electron 版本和 Web 版本的 SDK,可以同时构建 PC Web 程序和桌面应用(Wi
136 2
Web应用上云经典架构实战
本课程详细介绍了Web应用上云的经典架构实战,涵盖前期准备、配置ALB、创建服务器组和监听、验证ECS公网能力、环境配置(JDK、Maven、Node、Git)、下载并运行若依框架、操作第二台ECS以及验证高可用性。通过具体步骤和命令,帮助学员快速掌握云上部署的全流程。
107 1
实战经验分享:利用免费SSL证书构建安全可靠的Web应用
本文分享了利用免费SSL证书构建安全Web应用的实战经验,涵盖选择合适的证书颁发机构、申请与获取证书、配置Web服务器、优化安全性及实际案例。帮助开发者提升应用安全性,增强用户信任。
云端问道-Web应用上云经典架构方案教学
本文介绍了企业业务上云的经典架构设计,涵盖用户业务现状及挑战、阿里云业务托管架构设计、方案选型配置及业务初期低门槛使用等内容。通过详细分析现有架构的问题,提出了高可用、安全、可扩展的解决方案,并提供了按量付费的低成本选项,帮助企业在业务初期顺利上云。
基于Flink CDC 开发,支持Web-UI的实时KingBase 连接器,三大模式无缝切换,效率翻倍!
TIS 是一款基于Web-UI的开源大数据集成工具,通过与人大金仓Kingbase的深度整合,提供高效、灵活的实时数据集成方案。它支持增量数据监听和实时写入,兼容MySQL、PostgreSQL和Oracle模式,无需编写复杂脚本,操作简单直观,特别适合非专业开发人员使用。TIS率先实现了Kingbase CDC连接器的整合,成为业界首个开箱即用的Kingbase CDC数据同步解决方案,助力企业数字化转型。
221 5
基于Flink CDC 开发,支持Web-UI的实时KingBase 连接器,三大模式无缝切换,效率翻倍!
Python 高级编程与实战:深入理解 Web 开发与 API 设计
在前几篇文章中,我们探讨了 Python 的基础语法、面向对象编程、函数式编程、元编程、性能优化、调试技巧以及数据科学和机器学习。本文将深入探讨 Python 在 Web 开发和 API 设计中的应用,并通过实战项目帮助你掌握这些技术。

热门文章

最新文章