从零学习node.js之利用express搭建简易论坛(七)

平面设计 2025-04-05 23:38www.168986.cn平面设计培训

一、搭建简易论坛:Node.js与Express的完美结合

在这个数字化时代,论坛作为交流的平台日益受到人们的青睐。本文将引导你利用Node.js和Express框架搭建一个简易论坛,实现注册、登录、发布主题和回复主题等功能。让我们一步步走进这个充满智慧的创造过程吧!

1. 应用生成器的魔力

让我们从搭建应用框架开始。得益于Express的应用生成器,我们可以迅速创建一个应用的基础框架。安装应用生成器的命令如下:

```bash

$npm install -g express-generator

```

运行`express --version`检查是否安装成功。接下来,创建我们的论坛项目:

```bash

$express node_express_forum

```

这将在当前目录下生成一个名为`node_express_forum`的文件夹,里面包含了应用的基础结构和文件。

2. 生成的框架

进入项目目录:

```bash

$cd node_express_forum

```

浏览生成的框架结构,主要包括以下部分:

`app.js`:应用的入口文件。

`package.json`:依赖模块列表。

`bin`、`public`、`routes`和`views`等文件夹分别包含启动脚本、静态文件、路由定义和视图模板。

3. 安装依赖模块

在`package.json`文件中,我们可以看到还需要安装一些模块来完善我们的论坛功能。运行以下命令安装开发依赖:

```bash

$npm install --save-dev

```

4. 框架运行与调试

完成依赖安装后,我们的基本框架已搭建完毕。运行命令启动应用:

```bash

$npm start

```

然后在浏览器中输入`127.0.0.1:3000`,你将看到Express的欢迎页面。此刻,我们的论坛雏形已经展现。

二、论坛准备工作:模板引擎、模型与数据库、路由的整合之旅

基本框架已经创建好了,接下来我们进入论坛的准备工作阶段。这个阶段主要包括三个关键部分:模板引擎、模型与数据库、路由。我们将逐步如何整合这些元素,构建出功能完善的论坛系统。敬请期待后续章节的详细介绍!一、模板引擎与视图重构

在Express框架中,模板引擎是用于渲染动态网页的重要工具。虽然默认使用的是Jade模板引擎,但我们可以根据个人喜好选择其他模板引擎。我选择使用EJS,因为它更接近HTML,更方便维护和修改。通过运行命令 `$npm install ejs --save-dev` 安装EJS模板引擎。

安装完成后,我们需要在app.js中更改模板引擎设置。将原有的 `'jade'` 更改为 `'ejs'`,即 `app.set('view engine', 'ejs');`。随后,我们可以清空views目录中的.jade文件,并开始使用.ejs编写模板。

二、模型、数据库与模块化路由

在构建论坛应用时,模型、数据库和路由是核心部分。模型(M)主要负责与数据库的连接和操作,我们创建一个models目录来存放相关文件。数据库我们选择MySQL,并创建一个名为“forum”的数据库。其中包含用户表(user)、主题表(list)和回复表(reply)。

至于路由(Router),Express提供了express.Router类来创建模块化路由。这是一个“mini-app”,可以包含中间件和路由系统。在routes/user.js文件中,我们实例化一个router对象,并定义主页和注册页面的路由。当访问/user和/user/reg时,会加载相应的页面模板并传递数据。在app.js中,我们通过`app.use('/user', user);`加载这个路由模块。这样,我们就可以方便地扩展其他路由。

三、注册与登录功能实现

数据库连接与注册功能实现

一、数据库连接

引入强大的mysql模块,利用mysql.createPool()方法创建数据库连接池,确保数据交互的稳定性和高效性。通过运行$npm install mysql --save-dev命令,将mysql模块添加到项目依赖中。

在项目的models目录下,创建db.js文件,作为数据库连接的统一管理中心。其他需要操作数据库的文件,通过引入db.js即可轻松获取数据库连接。

代码如下:

```javascript

var mysql = require('mysql');

var pool = mysql.createPool({

host : '127.0.0.1',

user : 'root',

password : '123',

database : 'forum'

});

module.exports = pool;

```

二、注册功能实现

注册功能作为用户管理的基础功能之一,其流程包括加载注册页面、用户输入数据后提交以及处理表单数据并进行数据库操作。

在routes/user.js文件中,创建一个以get方式访问的/reg路由,用于加载注册页面。

代码如下:

```javascript

// routes/user.js

router.get('/reg', function(req, res, next) {

res.render('reg', { errmsg: '' }); // 加载reg.ejs模板

});

```

接着,在views目录下创建reg.ejs文件,作为注册页面的展示界面。设计简洁明了,包含注册表单、错误信息提示以及回到首页的链接。

运行程序后,通过浏览器访问127.0.0.1:3000/user/reg,即可看到注册页面。用户可以在此页面输入用户名、密码等信息,提交后进行后续处理。

整个注册流程设计得十分人性化,从页面加载到数据提交,都为用户提供了良好的体验。而数据库连接的稳定与高效,则为注册功能的正常运行提供了坚实的基础。在充满活力的现代Web应用中,用户注册是不可或缺的一环。我们需要在`routes/user.js`中创建一个通过POST方式提交的注册路由,用以处理用户的注册请求。通过POST方式提交的数据,我们不能使用`req.query`获取,而应通过`req.body`来访问。

下面是`routes/user.js`中的注册路由代码:

```javascript

// 在user.js的路由中处理注册请求

router.post('/reg', function(req, res, next) {

var username = req.body.username || '',

password = req.body.password || '',

password2 = req.body.password2 || '';

// 检查两次输入的密码是否一致

if(password != password2){

res.render('reg', {errmsg:'密码不一致'});

return;

}

var password_hash = user_m.hash(password), // 对密码进行加密处理

regtime = parseInt(Date.now()/1000); // 获取当前时间戳

// 调用models中的注册函数处理数据库操作

user_m.reg(username, password_hash, regtime, function(result) {

// 根据数据库操作结果进行相应的处理

if (result && result.isExisted) { // 如果用户名已存在

res.render('reg', {errmsg:'用户名已存在'});

} else { // 注册成功或发生其他错误

res.render('success', {msg:'注册成功'}); // 假设成功页面为success

}

});

});

```

在`models/user.js`中,我们定义了注册功能及相关数据库操作:

```javascript

var pool = require('./db'), // 连接数据库

crypto = require('crypto'); // 引入加密模块来处理密码加密

module.exports = {

// 对字符串进行SHA1加密并附加“love”作为密钥进行更新操作

hash : function(str){

return crypto.createHmac('sha1', str).update('love').digest('hex');

},

// 注册功能实现,包含数据库操作回调处理逻辑

reg : function(username, password, regtime, cb){

pool.getConnection(function(err, connection){

if(err) throw err; // 处理数据库连接错误

connection.beginTransaction(); // 开始事务处理(可选)以保证数据一致性

try { // 数据库操作异常处理放在try内执行,出现异常可回滚事务并释放连接资源。这里需要根据实际数据库操作来调整事务逻辑。

// 检测用户名是否存在,这里使用异步查询方法并传入回调函数处理结果,不能直接return返回结果。注意查询时需要对用户名进行参数化绑定防止SQL注入攻击。

注册功能完善

在user.js文件中,我们看到了注册功能的实现。当用户通过POST方式提交注册请求时,我们的应用将执行以下操作:

引入user模型,用于与数据库进行交互。接着,处理数据库注册操作。如果用户名已存在,将提示用户重新注册;如果注册成功,将用户重定向到首页;否则,将显示注册失败的提示信息。

接下来,我们转向登录功能。登录过程与注册类似,但更为简单。只需查询数据库中是否存在对应的用户名和密码即可。为了完成这一功能,我们需要创建一个登录页面。

在login.ejs文件中,我们构建了一个简单的登录页面。这个页面包含了基本的HTML结构,以及一个表单用于用户输入用户名和密码。我们使用了CSS来美化页面元素,并提供了返回首页的链接。当用户在表单中输入信息并提交时,我们将处理登录请求并验证用户的输入。

在构建用户登录功能的过程中,我们需要对数据库进行登录操作,并在成功登录后保存用户的登录状态。接下来,让我们一起深入了解这一过程。

我们需要在model/user.js中添加对数据库的登录操作。具体来说,我们使用一个名为login的函数来实现这一功能。这个函数通过查询数据库中的用户表来验证用户名和密码是否匹配。如果验证成功,它会返回一个结果集;如果失败,则会抛出错误。在这个过程中,我们使用了连接池来获取数据库连接,并在查询完成后释放连接。以下是该函数的代码示例:

```javascript

module.exports = {

// ...其他代码

// 登录功能

login: function(username, password, callback) {

pool.getConnection(function(err, connection) {

if (err) throw err; // 如果出现错误,抛出异常

connection.query('SELECT `id` FROM `user` WHERE `username`=? AND `password`=?', [username, password], function(err, result) {

if (err) throw err; // 如果查询过程中出现错误,抛出异常

callback(result); // 调用回调函数处理查询结果

connection.release(); // 释放数据库连接

});

});

}

}

```

接下来,在routes/user.js中,我们需要添加登录路由。我们创建一个GET请求来渲染登录页面。然后,我们创建一个POST请求来处理登录请求。在这个处理函数中,我们从请求体中获取用户名和密码,并对密码进行哈希处理。然后,我们调用user_m模块的login函数来验证用户名和密码是否匹配。如果验证成功,我们将登录成功的消息发送给客户端;如果失败,我们将错误信息渲染到登录页面。以下是该路由的代码示例:

```javascript

// routes/user.js

const router = require('express').Router(); // 引入express路由模块

const user_m = require('./model/user'); // 引入用户模型模块

// 渲染登录页面

router.get('/login', function(req, res, next) {

res.render('login', {errmsg: ''}); // 渲染登录页面,并传递错误信息到页面

});

// 处理登录请求

router.post('/login', function(req, res, next) {

const username = req.body.username || ''; // 从请求体中获取用户名

const password = req.body.password || ''; // 从请求体中获取密码并进行哈希处理

const password_hash = user_m.hash(password); // 密码哈希处理(假设user_m模块提供hash函数) 这一步确保数据库存储的是加密后的密码而非明文密码以增加安全性。注意实际开发中密码存储需要更复杂的加密策略和安全措施。此处仅为示例代码。请确保在实际项目中遵循最佳安全实践。在真实环境中进行密码存储时,不应直接存储明文密码或简单的哈希值。通常的做法是使用强加密算法(如bcrypt)进行加密并存储加密后的密码和相应的盐值(salt)。此部分涉及到实际应用场景下的安全问题以及对应的处理方式和技术选择需要根据具体情况进行深入和实施。)然后我们通过调用user_m模块的login函数来验证用户名和密码是否匹配。如果验证成功,我们将用户信息保存到session中,并重定向到首页;如果失败,我们渲染登录页面并显示错误信息。以下是代码示例:以下是该处理的代码示例:如果登录成功的话呢?我们需要保存用户的登录状态以便于后续的用户操作比如浏览商品等于是我们通常会使用session来保存用户的登录状态在这里express框架并没有提供对session的处理功能所以我们需要引入额外的模块express-session来处理session模块的安装命令是npm install express-session --save-dev安装完成后在appjs中引用该模块并配置session的相关参数以下是配置session的代码示例配置完成后我们就可以使用session来保存数据了这里以登录成功后保存数据为例我们知道当用户的用户名和密码通过验证后应该将其信息保存在session中以保持用户的登录状态这样用户在下一次访问网站时可以直接从session中获取用户信息而无需再次输入用户名和密码这是通过下面的代码实现的如果用户已经成功登录了那么我们将用户的uid和用户名保存到名为user的session中并通过重定向到首页来实现页面的跳转如果用户未成功登录则渲染登录页面并显示错误信息最后还有一个问题如何把session中的数据传递给模板呢比如在没有登录时显示注册登录连接而在登录后显示用户名登录信息对于这个问题我们可以使用中间件的方式来将session中的数据传递给模板这样就可以在模板中直接使用这些数据了这是一个典型的用户管理功能在实际项目中非常常见通过理解这个例子我们可以更好地掌握如何使用express框架来处理用户登录和用户状态管理的问题在 app.js 中,我们添加了一个中间件,它的作用在于根据用户的登录状态,将用户信息添加到模板变量中。这一功能的实现,离不开我们对 session 的利用。在每一次请求来临时,都会经过这个中间件的检验。

如果 session 中存在用户信息,那么说明用户已经登录。我们会将用户的 uid 和 username 提取出来,封装到一个对象中,并将其赋值给 res.locals.user。这样,在后续的模板渲染中,我们就可以轻松获取到用户的信息。如果用户尚未登录,那么我们将 res.locals.user 设置为一个空对象。

如此操作之后,无论在登录还是未登录状态下,我们的模板都能够灵活地处理用户信息。在模板中,我们可以通过简单的条件判断,来决定展示哪些内容。例如:

如果用户已登录(即存在 user.uid):

展示用户的主题列表,并允许用户发表新主题和对已发布主题进行回复。点击链接进入详情页后,用户可以对该主题进行各种操作。

如果用户未登录:

展示一些公共内容,例如网站公告、主题等。用户无法发表主题或进行回复,但可以浏览和阅读已发布的内容。

首页展示与主题发表

在构建我们的应用时,我们首先需要在`models`目录下的`list.js`文件中从数据库中获取主题列表。让我们深入了解这一过程。

models/list.js

为了与数据库进行交互,我们首先引入了数据库连接池:

```javascript

var pool = require('./db');

```

在模块中,我们定义了一个对象,其中包含了获取首页主题列表的方法:

```javascript

module.exports = {

// 获取首页的主题列表

getIndexList: function(callback) {

pool.getConnection(function(err, connection) {

if (err) throw err;

// 执行连表查询,同时获取作者的用户名

connection.query('SELECT `list`.`title`, username FROM `list`, `user` WHERE `list`.`uid`=`user`.`id`', function(err, result) {

if (err) throw err;

// 调用回调函数传递查询结果

callback(result);

// 释放数据库连接并返回连接池

connection.release();

});

});

}

}

```

在`routes`目录下的`index.js`文件中,我们调用刚刚定义的`getIndexList`方法来获取数据,并选择`index.ejs`模板来渲染页面。

routes/index.js

```javascript

var list_m = require('../models/list');

router.get('/', function(req, res, next) {

list_m.getIndexList(function(result) {

// 选择index模板并传递数据

res.render('index', { data: result });

});

});

```

views/index.ejs

```html

主题列表

<% for(var i=0, len=data.length; i

<% } %>

标题 作者 创建时间
<%=data[i].title %> <%=data[i].username %> <%=data[i].createtime %>

<% if(user.username){ %>

<% } %>

```

当用户在前端提交内容时,他们的点击触发了一场无形的魔法。在这段JavaScript代码中,隐藏着一个重要的任务:向服务器提交数据并展示结果。这个提交过程就像是开启了一扇通往另一个世界的大门,数据就是那扇门的钥匙。

这个关键的前端脚本负责监听用户的点击事件,当用户点击提交按钮时,它会获取用户输入的标题和内容。如果这些输入为空,它会温柔地提醒用户:“输入不能为空哦”。如果输入有效,它就会显示一个提示信息:“数据正在飞奔到服务器中”。

在服务器端,我们有一个名为'list.js'的路由文件负责处理这个'/list/addic'接口。它会检查用户是否已经登录。如果用户已登录,它会获取用户的输入和登录状态信息,然后调用模型中的addTopic方法来添加数据。如果添加成功,它会返回一个包含链接、标题、作者和创建时间的JSON对象;如果添加失败,它会告诉用户:“尝试添加失败了”。如果用户未登录,它会提醒用户先登录。整个过程严谨而有序,像是一个高效的魔法仪式。

至于详情页的部分,用户在首页列表中看到的链接是以'/list/1.html'的形式呈现的。我们也可以采用其他方式设置链接,比如'/list?pid=1',只要我们在后端正确设置了相应的路由即可。这就像是在魔法地图上标注新的目的地,用户可以点击链接跳转到他们想要查看的详情页。

想象一下你正在访问一个,如

router.get('/:pid.html', function(req, res) {

var pid = req.params.pid || 1; // 获取参数 pid,若无则默认为 1。

Async的并行处理流程即将开始,这是为了确保我们的代码执行既高效又准确。我们分别获取主题的详情信息和相关的回复信息。当这两个任务都完成时,我们将渲染页面并展示结果。这个过程可以描述为:我们正在启动一场信息的“接力赛”,一边获取主题的详细信息,一边收集对它的回复。当两个任务都完成时,我们会将这些信息传递给前端模板进行展示。这就像是给用户提供一场精心准备的数据盛宴。

});

// 根据id查询主题的详情信息

您已经成功返回到首页,此刻我们正在为您展示一篇精彩纷呈的文章详情。以下是您所关注的文章标题和内容:

【文章标题】 <%=data[0].title %>

【文章内容】 <%=data[0].content %>

深入阅读这篇文章,您会发现其中蕴含了丰富的知识和观点,让人不禁沉浸其中。每一句话、每一个段落都值得我们细细品味。

接下来,让我们来这篇文章的评论区域。以下是读者们的精彩留言:

【评论区域】

H2:评论

【评论内容】

<% for(var i=0, len=data[1].length; i

<% } %>

<%= (i+1) %> <%=data[1][i].content %> <%=data[1][i].createtime %>

每一条评论都是读者们的心声,他们分享了对于文章的看法和感受。您可以从中了解到不同的观点和态度,也可以留下自己的评论,与更多人交流分享。

我们还想分享一些关于SEO优化的知识。狼蚁网站的SEO优化示例代码已经为大家准备好,您可以下载学习。希望这些内容能对您的网站优化有所帮助。如果您需要更多的帮助和建议,欢迎随时联系我们。

【下载地址】 您可以点击此处下载狼蚁网站SEO优化示例代码。

本文内容至此结束,感谢您的阅读。如果您有任何疑问或建议,欢迎在评论区留言,我们会尽快回复。也欢迎您分享本文至您的社交媒体,让更多人了解并受益。再次感谢您的支持!

让我们用一句富有哲理的话语来结束本文:文章的好坏不在于篇幅的长短,而在于内容的和广度。愿您在阅读本文的过程中,收获满满的知识与感悟。再次感谢您选择我们的网站,祝您生活愉快!

上一篇:php 发送带附件邮件示例 下一篇:没有了

Copyright © 2016-2025 www.168986.cn 狼蚁网络 版权所有 Power by