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

本文涉及的产品
云数据库 MongoDB,通用型 2核4GB
简介: 项目实战:构建一个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
目录
相关文章
|
2天前
|
缓存 移动开发 前端开发
【专栏:HTML与CSS前端技术趋势篇】HTML与CSS在PWA(Progressive Web Apps)中的应用
【4月更文挑战第30天】PWA(Progressive Web Apps)结合现代Web技术,提供接近原生应用的体验。HTML在PWA中构建页面结构和内容,响应式设计、语义化标签、Manifest文件和离线页面的创建都离不开HTML。CSS则用于定制主题样式、实现动画效果、响应式布局和管理字体图标。两者协同工作,保证PWA在不同设备和网络环境下的快速、可靠和一致性体验。随着前端技术进步,HTML与CSS在PWA中的应用将更广泛。
|
2天前
|
前端开发 JavaScript 搜索推荐
【专栏:HTML 与 CSS 前端技术趋势篇】HTML 与 CSS 在 Web 组件化中的应用
【4月更文挑战第30天】本文探讨了HTML和CSS在Web组件化中的应用及其在前端趋势中的重要性。组件化提高了代码复用、维护性和扩展性。HTML提供组件结构,语义化标签增进可读性,支持用户交互;CSS实现样式封装、布局控制和主题定制。案例展示了导航栏、卡片和模态框组件的创建。响应式设计、动态样式、CSS预处理器和Web组件标准等趋势影响HTML/CSS在组件化中的应用。面对兼容性、代码复杂度和性能优化挑战,需采取相应策略。未来,持续发掘HTML和CSS潜力,推动组件化开发创新,提升Web应用体验。
|
2天前
|
缓存 前端开发 JavaScript
探索现代Web应用的性能优化策略移动应用开发的未来之路:跨平台与原生之争
【4月更文挑战第30天】随着互联网技术的迅猛发展,Web应用已成为信息交流和商业活动的重要平台。用户对Web应用的响应速度和稳定性有着极高的期望,这促使开发者不断寻求提升应用性能的有效途径。本文将深入探讨针对现代Web应用进行性能优化的关键策略,包括前端优化、后端优化以及数据库层面的调优技巧,旨在为开发者提供一套全面的优化工具箱,帮助他们构建更快速、更高效的Web应用。
|
2天前
|
运维 前端开发 JavaScript
【专栏:HTML进阶篇】HTML与Web标准:构建可访问与可维护的网页
【4月更文挑战第30天】本文探讨了HTML与Web标准的关系,强调遵循标准对创建高质量、可访问、可维护网页的重要性。通过使用语义化标签、提供文本替代、合理使用表格和列表,可提升网页可访问性;通过结构化文档、添加注释、分离结构与表现,能增强网页可维护性。遵循Web标准,可确保网页在不同设备上的兼容性,并满足各类用户需求。
|
2天前
|
开发框架 JavaScript 前端开发
【JavaScript 与 TypeScript 技术专栏】TypeScript 在 Web 开发中的前沿应用
【4月更文挑战第30天】TypeScript在Web开发中日益重要,以其强大的类型系统提升代码质量,支持组件化开发,与React、Vue、Angular等框架良好集成。在大型项目管理中,TypeScript助于代码组织和优化,提高团队协作效率。此外,它提升开发体验,提供智能提示和错误检测。众多成功案例证明其前沿应用,未来将在Web开发领域持续发挥关键作用。
|
2天前
|
移动开发 JavaScript 前端开发
【JavaScript技术专栏】Web Worker在JavaScript中的应用
【4月更文挑战第30天】HTML5的Web Worker API解决了JavaScript单线程性能瓶颈问题,允许在后台线程运行JS代码。本文介绍了Web Worker的基本概念、类型、用法和应用场景,如复杂计算、图像处理和数据同步。通过实例展示了搜索建议、游戏开发和实时数据分析等应用,并提醒注意其无法直接访问DOM、需消息传递通信以及移动端资源管理。Web Worker为前端开发提供了多线程能力,提升了Web应用性能和用户体验。
|
2天前
|
开发框架 Dart 前端开发
【Flutter前端技术开发专栏】Flutter中的Web支持:构建跨平台Web应用
【4月更文挑战第30天】Flutter,Google的开源跨平台框架,已延伸至Web领域,让开发者能用同一代码库构建移动和Web应用。Flutter Web通过将Dart代码编译成JavaScript和WASM运行在Web上。尽管性能可能不及原生Web应用,但适合交互性强、UI复杂的应用。开发者应关注性能优化、兼容性测试,并利用Flutter的声明式UI、热重载等优势。随着其发展,Flutter Web为跨平台开发带来更多潜力。
【Flutter前端技术开发专栏】Flutter中的Web支持:构建跨平台Web应用
|
11天前
|
开发框架 前端开发 .NET
C#编程与Web开发
【4月更文挑战第21天】本文探讨了C#在Web开发中的应用,包括使用ASP.NET框架、MVC模式、Web API和Entity Framework。C#作为.NET框架的主要语言,结合这些工具,能创建动态、高效的Web应用。实际案例涉及企业级应用、电子商务和社交媒体平台。尽管面临竞争和挑战,但C#在Web开发领域的前景将持续拓展。
|
3天前
|
前端开发 JavaScript 测试技术
【PHP开发专栏】PHP Web开发基础与流程
【4月更文挑战第29天】本文介绍了PHP Web开发的基础和流程,帮助初学者入门。内容包括Web服务器与PHP解释器的工作原理、HTML/CSS/JavaScript基础知识、PHP语法与数据库操作。开发流程涵盖项目规划、环境搭建、数据库设计、代码编写、测试与调试,以及部署与维护。此外,文中还强调了使用框架、代码组织、安全性及性能优化等进阶知识和最佳实践,旨在培养优秀PHP开发者。
|
3天前
|
前端开发 JavaScript 开发者
前端技术栈:探索现代Web开发的核心要素与代码实践
前端技术栈:探索现代Web开发的核心要素与代码实践
9 1