蓝桥送了我三天会员 不知道过期了以后还能不能看了 所以把教程粘下来

第一章

实验介绍

实验内容
本实验将教大家使用 Node.js 技术完成一个私人笔记本项目。

实验重点部分源码:

wget https://labfile.oss.aliyuncs.com/courses/446/part_of_louNote.zip

知识点
Express 基础
适合人群
本课程难度一般,属于初级课程,适合具有 Node.js 基础的用户,学习 Node.js Web 开发。

实验步骤

本课程将通过使用 Node.js 及与其配合良好的 Web 应用框架 Express 搭建服务端,配合 mongoDB 存储数据,使用 ejs 模板渲染前端页面的方式完成一个简单的私人笔记应用。

这次实验不通过 Express 指令自动生成应用框架,而是选择从 npm init 开始,初始化项目,并一步步实现所有功能。

package.json 配置文件
首先新建一个文件夹 louNote,作为项目的根目录,同时也是我们的项目名称,然后执行命令 - cd louNote && npm init

会出现许多配置项需要你输入,同时这一过程也是引导你创建一个package.json 文件:

package name:项目名称
version:版本号
description:对项目的描述
entry point:项目的入口文件
test command:项目启动时执行脚本文件的命令(默认为 node app.js )
git repository:git 的仓库地址
keywords:项目关键字
author:作者
license:发行项目需要的证书
推荐一路使用回车,使用默认配置,完成配置项填写后,此文件就存在根目录 /louNote 下了。

使用 Express
项目还需要 Express 做服务托管,执行命令 - npm install express --save,

这里的 --save 参数就是将安装的模块及其使用版本号记录到 package.json 文件中。

这样当我们需要将代码提交到代码托管时就不必将 node_modules 下的所有模块都提交,项目部署时执行命令 npm install 即可安装依赖模块。

启动文件

根目录 /louNote 下执行命令

npm install --save body-parser

npm install --save ejs

在 /louNote 下新建 app.js 文件作为项目的启动文件,并敲入以下代码:

var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var crypto = require('crypto');// 生成一个 express 实例
var app = express();// 设置视图文件存放目录
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');// 设置静态文件存放目录
app.use(express.static(path.join(__dirname, 'public')));// 解析 urlencoded 请求体必备
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));// '/' 路由
app.get('/', function (req, res) {res.render('index', {title: '首页',});
});app.listen(8080, function (req, res) {console.log('app is running at port 8080');
});

copy
以上就是简单的服务端代码,接着在 /louNote 下新建 /views/index.ejs, 并敲入以下代码:

<!DOCTYPE html>
<html><head><meta charset="utf-8" /><title><%= title %></title></head><body><%= title %></body>
</html>

copy
作为首页的视图文件,在命令行中执行服务启动指令 - node app.js,当出现代码中的一段话 app is running at port 8080 时,说明服务已经启动,服务端口为 8080,打开工具,Web 服务 即可成功访问。

当你在自己的主机上操作的时候,要按照上述 localhost:8080 访问。但由于实验楼采用的是线上实验环境,localhost:8080 对应工具栏里 Web 服务打开后页面地址栏中的地址。localhost:8080 只需要打开工具 Web 服务即可,如果出现路由,例如 localhost:8080/login,只需在地址栏后缀上/login 即可。后续步骤、实验都采用相同的操作,不再赘述。

以后就需要通过不断修改 app.js 这个文件来完善这个项目。但在修改过后需要重启应用服务才能看到修改效果,这样会影响到开发效率。解决办法就是安装 supervisor 模块,这个模块能在保存修改的文件后自动重启应用服务,省去了手动重启服务的过程,非常方便。安装 supervisor 模块:

npm install supervisor -g
copy
需要提醒的是,安装 supervisor 模块后,项目的启动指令对应改为 supervisor app.js 。

路由及视图文件

接着需要设计路由控制访问不同的页面,并创建对应的视图文件。

功能设计
项目需要的功能有:

注册
登录
发布笔记
笔记列表
笔记详情
退出登录
对应的路由为:

app.get('/', function (req, res) {res.render('index', {title: '首页',});
});app.get('/reg', function (req, res) {res.render('register', {title: '注册',});
});app.post('/reg', function (req, res) {// TO DO
});app.get('/login', function (req, res) {res.render('login', {title: '登录',});
});app.post('/login', function (req, res) {// TO DO
});app.get('/quit', function (req, res) {console.log('退出成功!');return res.redirect('/login');
});app.get('/post', function (req, res) {res.render('post', {title: '发布',});
});app.post('/post', function (req, res) {// TO DO
});app.get('/detail/:_id', function (req, res) {res.render('detail', {title: '笔记详情',});
});

copy
路由设计完毕,逻辑处理都会在这里完成,我们会在下一节中完善这些逻辑处理功能。接下来我们需要创建对应的视图文件。

创建文件
依据定下功能及设计好的路由,我们在 /louNote/views 目录下创建对应的视图文件:

// 登录 login.ejs // 注册 register.ejs // 发布笔记 post.ejs // 笔记详情
detail.ejs // 统一内容,此页面在下一节中被用作笔记列表。 index.ejs

<!DOCTYPE html>
<html><head><meta charset="utf-8" /><title><%= title %></title></head><body><%= title %></body>
</html>

copy
暂时使用统一内容做填充,待第二节中具体实现功能时再将他们补充完整。

使用 Bootstrap

为了使页面设计美观,同时要求不拘泥与设计,重点放在逻辑代码上,项目使用 Bootstrap 响应式框架,同时推荐 bower 管理前端资源依赖。

安装 bower
bower 需要全局安装,才可以使用相关命令,执行命令 npm install -g bower 即可。

安装 Bootstrap、jquery, 下载 common.css
在 /louNote 目录下新建 public 文件夹作为静态资源的存放目录,并在此目录下执行命令 bower install bootstrap jquery,完成后目录下会多出一个 bower_components 文件夹,其中就包含我们需要的 Bootstrap 以及其依赖的 jquery ,bower 能依据配置文件自动下载相关依赖,非常方便,这也是推荐使用 bower 的原因之一。

另外,我们还为页面写了一个 css 文件,在 /public 下创建 /css 文件夹,进入该文件夹,键入以下命令获取 css 文件:

wget https://labfile.oss.aliyuncs.com/courses/446/common.css

使用 ejs

在之前的代码中,已经有使用 ejs 模板的数据标签 <%= %>,这里再学着使用 ejs 模板的 include 机制 改造之前设计好的视图文件。

在之前的步骤中,我们已经安装了 ejs module 。

在 /louNote/views 目录下新建 header.ejs 文件,敲入以下代码:

<!DOCTYPE html>
<html><head><meta charset="utf-8" /><title><%= title %></title><linkrel="stylesheet"type="text/css"href="/bower_components/bootstrap/dist/css/bootstrap.min.css"/><link rel="stylesheet" type="text/css" href="/css/common.css" /><script src="/bower_components/jquery/dist/jquery.min.js"></script><script src="/bower_components/bootstrap/dist/js/bootstrap.min.js"></script></head><body><div class="text-center page-title"><%= title %></div></body>
</html>

copy
这里将所有需要加载的静态资源文件写到一起,作为所有视图文件的共有页面,再通过 include 机制 引入各个视图中。

改造每个视图文件:

<%- include header %><!-- 待编辑部分 --></body>
</html>

copy
待编辑部分便是今后各个页面不同的部分。

这样就通过 ejs 统一加载了静态资源。

新建文件夹

在 /project 下执行以下命令:

mkdir -p /home/project/louNote/data/db

mkdir -p /home/project/louNote/data/log/mongodb
copy
mkdir -p 命令的含义是:确保目录名称存在,如果目录不存在的就新创建一个。

当上述命令执行完毕之后,就可以在 louNote/data 中看到新建立的两个文件夹。

启动 mongoDB 服务

在 Terminal 中输入如下命令:

sudo mongod --dbpath /home/project/louNote/data/db --logpath /home/project/louNote/data/log/mongodb/mongod.log
copy
在文件区右击空白处选择 Open in Terminal 打开一个新的命令行,输入 mongo 启动 mongoDB 服务。

连接 mongoDB 服务

执行命令 - npm install --save mongoose 安装 mongoose,mongoose 是 mongoDB 的模型工具,方便我们简化代码。

在 /louNote/app.js 中添加代码:

// 引入 mongoose
var mongoose = require('mongoose');// 使用 mongoose 连接服务
mongoose.connect('mongodb://localhost:27017/notes', {useMongoClient: true,
});
mongoose.connection.on('error', console.error.bind(console, '连接数据库失败'));
copy

重启服务后没有出现 “连接数据库失败”即说明连接服务成功,通过 mongoDB 命令可以查看数据内容:

mongo 即可进入数据库进行操作;
show dbs 显示数据库列表;
use notes 切换数据库;
show collections 显示当前数据库中的集合(collection),当然现在还没有数据。

设计数据模型
接着需要设计数据模型,mongoDB 的数据结构类似 json 格式,所以这一步骤也可以简单理解为设计 json 文件格式。

在 /louNote 目录下新建 models/models.js ,并敲入

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

copy
用户数据模型
在 /louNote/models/models.js 文件下定义用户数据模型

var userSchema = new Schema({username: String,password: String,email: String,createTime: {type: Date,default: Date.now,},
});exports.User = mongoose.model('User', userSchema);

copy
笔记数据模型
在 /louNote/models/models.js 文件下定义笔记户数据模型

var noteSchema = new Schema({title: String,author: String,tag: String,content: String,createTime: {type: Date,default: Date.now,},
});exports.Note = mongoose.model('Note', noteSchema);

copy
这样,前期的框架搭建及数据库服务就准备完毕,接下来就是控制层的代码实现。请进入下一个实验。

总结

在本节中,我们完成了私人笔记的大致框架的编码,具体内容还需要再下节实验中进行填充。我们简单的操作了 mongoDB,对该数据库作了一定的了解。对于本实验的步骤,请大家一定要仔细阅读,小心编码,实验的步骤到实验二的结束才真正完成,项目才能很好的运行起来,在这之前会有一些小瑕疵,请大家耐心的跟随实验步骤进行操作。

逻辑功能实现和路由限制

逻辑功能实现

在第一节实验中,我们完成了私人笔记的大致框架的搭建和数据库的连接以及简单操作,接下来我们将会将框架里的具体内容一一补充完整,这需要大家对实验一框架进行一定的理解,大致体会每一部分的功能,这样在本节对框架内容进行填充的时候,才不会出现因为理解错误所导致的编码错误。

建立表单

修改 /louNote/views/register.ejs 文件为:

<%- include header %><div class="container"><div class="row"><div class="col-md-4 group-center"><form method="post"><!-- 用户名表单 --><div class="form-group"><input type="text" class="form-control" name="username" placeholder="用户名"></div><!-- 密码表单 --><div class="form-group"><input type="password" class="form-control" name="password" placeholder="密码"></div><!-- 确认密码表单 --><div class="form-group"><input type="password" class="form-control" name="passwordRepeat" placeholder="确认密码"></div><!-- 注册按钮 --><button type="submit" class="btn btn-default center-block">注册</button></form></div></div><div></body>
</html>
copy

编写逻辑代码
修改 /louNote/app.js 文件的 /reg 路由为:

// get 请求
app.get('/reg', function (req, res) {res.render('register', {title: '注册',user: req.session.user,page: 'reg',});
});// post 请求
app.post('/reg', function (req, res) {var username = req.body.username,password = req.body.password,passwordRepeat = req.body.passwordRepeat;//检查两次输入的密码是否一致if (password != passwordRepeat) {console.log('两次输入的密码不一致!');//重定向到 /regreturn res.redirect('/reg');}//检查用户名是否已经存在User.findOne({ username: username }, function (err, user) {if (err) {console.log(err);return res.redirect('/reg');}if (user) {console.log('用户名已经存在');return res.redirect('/reg');}//对密码进行 md5 加密var md5 = crypto.createHash('md5'),md5password = md5.update(password).digest('hex');var newUser = new User({username: username,password: md5password,});// 判断是否注册成功newUser.save(function (err, doc) {if (err) {console.log(err);return res.redirect('/reg');}console.log('注册成功!');newUser.password = null;delete newUser.password;req.session.user = newUser;return res.redirect('/');});});
});

登录

建立表单
修改 /louNote/views/login.ejs 文件为:

<%- include header %><div class="container"><div class="row"><div class="col-md-4 group-center"><form method="post"><div class="form-group"><!-- 登录用户名表单 --><input type="text" class="form-control" name="username" placeholder="用户名"></div><div class="form-group"><!-- 登录密码表单 --><input type="password" class="form-control" name="password" placeholder="密码"></div><!-- 登录按钮 --><button type="submit" class="btn btn-default center-block">登录</button></form></div></div></div></body>
</html>
copy

编写逻辑代码
修改 /louNote/app.js 文件中的 /login 路由为:

// get 请求
app.get('/login', function (req, res) {res.render('login', {title: '登录',user: req.session.user,page: 'login',});
});// post 请求
app.post('/login', function (req, res) {var username = req.body.username,password = req.body.password;// 检查用户名是否存在User.findOne({ username: username }, function (err, user) {if (err) {console.log(err);return next(err);}if (!user) {console.log('用户不存在!');return res.redirect('/login');}//对密码进行 md5 加密var md5 = crypto.createHash('md5'),md5password = md5.update(password).digest('hex');// 进行密码判断if (user.password !== md5password) {console.log('密码错误!');return res.redirect('/login');}console.log('登录成功!');user.password = null;delete user.password;req.session.user = user;return res.redirect('/');});
});
copy

会话机制

完成以上两步就实现了项目的注册和登录功能,但运行时会报错,原因有二:

上一个实验的末尾创建了两个数据模型 userSchema 和 noteSchema,我们还没有引入模型就开始数据操作,当然会报错,需要 app.js 文件头部引入模型并实例化:
// 引入模型并实例化
var models = require(’./models/models’);
var User = models.User;
var Note = models.Note;
copy
是为了方便讲解,提前运用 session 机制,但还没有引入相关的模块。接着就开始学习运用 web 开发里很常见的 session 机制。
建立 session 模型
在 Express 框架中需要安装两个模块 express-session 和 connect-mongo,执行命令 npm install --save express-session connect-mongo,并在 app.js 文件中添加以下代码:

// 引入建立 session 必备的模块
var session = require(‘express-session’);
var MongoStore = require(‘connect-mongo’)(session);

// 建立 session 模型

app.use(session({key: 'session',secret: 'Keboard cat',cookie: { maxAge: 1000 * 60 * 60 * 24 },store: new MongoStore({db: 'notes',mongooseConnection: mongoose.connection,}),resave: false,saveUninitialized: true,})
);
copy

保存会话
项目需要通过 seesion 判断用户的登录状态,所以只需要保存用户的登录后的基本信息,注册和登录的操作就需要保存这一信息,也就是上面代码中的 req.session.user = user 一句。

有了保存会话功能,我们就能通过判断用户的登录状态来显示不同的信息,修改 /louNote/views/header.ejs 文件,在header.ejs文件中,进行用户登录状态的判断,修改为:

<!DOCTYPE html>
<html><head><meta charset="utf-8" /><title><%= title %></title><linkrel="stylesheet"type="text/css"href="/bower_components/bootstrap/dist/css/bootstrap.min.css"/><link rel="stylesheet" type="text/css" href="/css/common.css" /><script src="/bower_components/jquery/dist/jquery.min.js"></script><script src="/bower_components/bootstrap/dist/js/bootstrap.min.js"></script></head><body><div class="clearfix page-nav"><!--如果用户已经登录,则显示发布和退出按钮--><% if(user) { %><div class="pull-left nav-username">Hello! <a href="/"><%= user.username %></a></div><div class="pull-left"><a href="/post">发表</a></div><div class="pull-right nav-quit"><a href="/quit">退出</a></div><% } else { %><!--如果用户未登录,则显示注册和登录按钮--><% if(page == 'login') { %><div class="pull-right nav-register"><a href="/reg">注册</a></div><% } else { %><div class="pull-right nav-login"><a href="/login">登录</a></div><% } %> <% } %></div><div class="text-center page-title"><%= title %></div></body>
</html>
copy

当用户登录后,就能看到发布和退出按钮,未登录时则看到注册和登录按钮,这也很符合逻辑操作。

发布笔记

建立表单
修改 /louNote/views/post.ejs 文件为:

<%- include header %><div class="container"><div class="row"><div class="col-md-5 group-center"><form method="post"><div class="form-group"><!-- 笔记标题 --><input type="text" class="form-control" name="title" placeholder="标题"></div><div class="form-group"><!-- 笔记标签 --><input type="text" class="form-control" name="tag" placeholder="标签"></div><div class="form-group"><!-- 笔记内容 --><textarea class="form-control" name="content" placeholder="文章内容"></textarea></div><!-- 发表按钮 --><button type="submit" class="btn btn-default center-block">发表</button></form></div></div></div></body>
</html>
copy

编写逻辑代码
修改 /louNote/app.js 文件中的 /post 路由为:

// get 请求
app.get('/post', function (req, res) {res.render('post', {title: '发布',user: req.session.user,});
});// post 请求
app.post('/post', function (req, res) {var note = new Note({title: req.body.title,author: req.session.user.username,tag: req.body.tag,content: req.body.content,});// 检查文章发表状况note.save(function (err, doc) {if (err) {console.log(err);return res.redirect('/post');}console.log('文章发表成功!');return res.redirect('/');});
});
copy

笔记列表和详情

对于笔记列表,我们修改 /louNote/views/index.ejs 文件 为:

<%- include header %><div class="container"><div class="row"><% arts.forEach(function(art) { %><div class="col-xs-8 col-xs-offset-2 group-center"><div class="article-box"><!-- 笔记标题 --><a href="/detail/<%= art._id %>"><h3 class="text-center"><%= art.title %></h3></a><p class="text-center"><!-- 笔记标签 --><span class="label label-info"><%= art.tag %></span> |<!-- 笔记创建时间 --><span class="create-time"><span class="text-bold">时间:</span><%= art.createTime %></span></p></div></div><% }); %></div></div></body>
</html>
copy

这里还运用到了 ejs 模板另一标签 <% %>,可以直接执行 javascript 语句,这里我们遍历了由模板传来的 arts 数据,就生成了所有的笔记列表,笔记列表用于展示用户创建的所有笔记,笔记详情只展示其中一个,所以就不需要这个遍历,将其删去,所以修改笔记详情页面 /louNote/views/detail.ejs 为:

<%- include header %><div class="container"><div class="row"><div class="col-xs-8 group-center"><div class="article-box"><h3 class="text-center"><%= art.title %></h3><p class="text-center"><span class="label label-info"><%= art.tag %></span> |<span class="create-time"><span class="text-bold">时间:</span><%= art.createTime %></span></p><p><%= art.content %></p></div></div></div></div></body>
</html>
copy

编辑笔记列表和笔记详情的逻辑代码,修改 /louNote/app.js 文件中的 / 和 /detail 路由为:

// 笔记列表

app.get('/', function (req, res) {Note.find({ author: req.session.user.username }).exec(function (err, arts) {if (err) {console.log(err);return res.redirect('/');}res.render('index', {title: '笔记列表',user: req.session.user,arts: arts,//需引入 moment 模块//moment: moment(art.createTime).format('MMMM Do YYYY, h:mm:ss a')});});
});// 笔记详情
app.get('/detail/:_id', function (req, res) {Note.findOne({ _id: req.params._id }).exec(function (err, art) {if (err) {console.log(err);return res.redirect('/');}if (art) {res.render('detail', {title: '笔记详情',user: req.session.user,art: art,//需引入 moment 模块//moment: moment(art.createTime).format('MMMM Do YYYY, h:mm:ss a')});}});
});
copy

其中我们可以看到两者的区别就是查询条件,一个是 find() 方法,另一个是 findOne() 方法,由字面意义也能看出前者返回所有数据,后者只返回一个数据,这样就分别实现了笔记列表和笔记详情所对应的需求功能。

逻辑设计·

完成以上步骤,项目的基本功能已经初步实现,但还存在一些 bug 需要修复,比如当我们未登录时,访问 localhost:8080 会因为 session 未保存用户登录信息,会报出错误。这就需要我们对访问做出限制。

当用户已登录时,使用户不能通过输入 url 访问登录和注册页面。
当用户未登录时,使用户不能通过输入 url 访问笔记列表页、笔记详情和发布笔记页面。

检测登录状态

新建 /louNote/checkLogin.js 文件,该文件用于判断用户是否已经登录并完成访问限制功能,代码如下:

// 已登录
function login(req, res, next) {if (req.session.user) {console.log('您已经登录!');return res.redirect('back'); //返回之前的页面}next();
}// 未登录
function noLogin(req, res, next) {if (!req.session.user) {console.log('抱歉,您还没有登录!');return res.redirect('/login'); //返回登录页面}next();
}exports.login = login;
exports.noLogin = noLogin;
copy

修改 app.js 文件,将路由修改为如下的形式。即在每一个路由的逻辑处理函数之前,再添加一个同样的路由,只不过处理函数为 checkLogin.js 提供的两个接口:login 和 noLogin,利用这样的两次路由,即可实现路由限制:

// 引入检测登录文件
var checkLogin = require('./checkLogin.js');// 在注册和登录的 get 请求前加入已登录判断,即在实际处理的路由之前,添加一个使用 checkLogin 提供的接口对登录状态进行判断的路由
app.get('/reg', checkLogin.login);
app.get('/reg', function (req, res) {//原路由处理函数
});app.get('/login', checkLogin.login);
app.get('/login', function (req, res) {//原路由处理函数
});// 在笔记列表、发布笔记和笔记详情前加入未登录判断
app.get('/', checkLogin.noLogin);
app.get('/', function (req, res) {//原路由处理函数
});app.get('/post', checkLogin.noLogin);
app.get('/post', function (req, res) {//原路由处理函数
});app.get('/detail/:_id', checkLogin.noLogin);
app.get('/detail/:_id', function (req, res) {//原路由处理函数
});

copy
这样就基本完成了项目功能,当然还有许多可扩展的功能和可以优化的细节。比如,允许修改、删除和查询笔记,显示笔记的创建时间。推荐大家在实验结束之后按照自己的理想需求进行相关拓展,大胆尝试一下你会有不一样的收获哦。下面就演示一下显示笔记创建时间功能的拓展。

笔记的创建时间
如果想要添加显示笔记的创建时间功能,我们还需要在/louNote 下载 moment 模块:

npm install --save moment
copy
在 app.js 头部引入 var moment = require(‘moment’); , 并将笔记列表和笔记详情逻辑部分的对 moment 的注释去除,然后将 index.ejs 和 detail.ejs 下的 art.createTime 改为 moment。

app.js 完整代码
完成后需要调整 app.js 代码顺序为如下,否则可能因为模块相互间的依赖问题而报错

var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var crypto = require('crypto');
// 引入 mongoose
var mongoose = require('mongoose');
var models = require('./models/models');
var User = models.User;
var Note = models.Note;
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
var checkLogin = require('./checkLogin.js');
//引入 moment.js
var moment = require('moment');
var app = express();// 设置视图文件存放目录
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');// 设置静态文件存放目录
app.use(express.static(path.join(__dirname, 'public')));
// 解析 urlencoded 请求体必备
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// 建立 session 模型
app.use(session({key: 'session',secret: 'Keboard cat',cookie: { maxAge: 1000 * 60 * 60 * 24 },store: new MongoStore({db: 'notes',mongooseConnection: mongoose.connection,}),resave: false,saveUninitialized: true,})
);app.get('/reg', checkLogin.login);
// get 请求
app.get('/reg', function (req, res) {res.render('register', {title: '注册',user: req.session.user,page: 'reg',});
});// post 请求
app.post('/reg', function (req, res) {var username = req.body.username,password = req.body.password,passwordRepeat = req.body.passwordRepeat;//检查两次输入的密码是否一致if (password != passwordRepeat) {console.log('两次输入的密码不一致!');//重定向到 /regreturn res.redirect('/reg');}//检查用户名是否已经存在User.findOne({ username: username }, function (err, user) {if (err) {console.log(err);return res.redirect('/reg');}if (user) {console.log('用户名已经存在');return res.redirect('/reg');}//对密码进行md5加密var md5 = crypto.createHash('md5'),md5password = md5.update(password).digest('hex');var newUser = new User({username: username,password: md5password,});newUser.save(function (err, doc) {if (err) {console.log(err);return res.redirect('/reg');}console.log('注册成功!');newUser.password = null;delete newUser.password;req.session.user = newUser;return res.redirect('/');});});
});
app.get('/login', checkLogin.login);
app.get('/login', function (req, res) {res.render('login', {title: '登录',user: req.session.user,page: 'login',});
});app.post('/login', function (req, res) {var username = req.body.username,password = req.body.password;User.findOne({ username: username }, function (err, user) {if (err) {console.log(err);return next(err);}if (!user) {console.log('用户不存在!');return res.redirect('/login');}//对密码进行md5加密var md5 = crypto.createHash('md5'),md5password = md5.update(password).digest('hex');if (user.password !== md5password) {console.log('密码错误!');return res.redirect('/login');}console.log('登录成功!');user.password = null;delete user.password;req.session.user = user;return res.redirect('/');});
});app.get('/post', checkLogin.noLogin);
app.get('/post', function (req, res) {res.render('post', {title: '发布',user: req.session.user,});
});app.post('/post', function (req, res) {var note = new Note({title: req.body.title,author: req.session.user.username,tag: req.body.tag,content: req.body.content,});note.save(function (err, doc) {if (err) {console.log(err);return res.redirect('/post');}console.log('文章发表成功!');return res.redirect('/');});
});
app.get('/', checkLogin.noLogin);
app.get('/', function (req, res) {Note.find({ author: req.session.user.username }).exec(function (err, arts) {if (err) {console.log(err);return res.redirect('/');}res.render('index', {title: '笔记列表',user: req.session.user,arts: arts,//需引入 moment 模块moment: moment(arts.createTime).format('MMMM Do YYYY, h:mm:ss a'),});});
});
app.get('/detail/:_id', checkLogin.noLogin);
// 笔记详情
app.get('/detail/:_id', function (req, res) {Note.findOne({ _id: req.params._id }).exec(function (err, art) {if (err) {console.log(err);return res.redirect('/');}if (art) {res.render('detail', {title: '笔记详情',user: req.session.user,art: art,//需引入 moment 模块moment: moment(art.createTime).format('MMMM Do YYYY, h:mm:ss a'),});}});
});// 使用 mongoose 连接服务
mongoose.connect('mongodb://localhost:27017/notes', {useMongoClient: true,
});
mongoose.connection.on('error', console.error.bind(console, '连接数据库失败'));app.listen(8080, function (req, res) {console.log('app is running at port 8080');
});
copy

到此为止,我们使用 Node.js 实现了私人笔记的大部分功能,达到了我们实验的目的。通过这个实验,我们能够掌握 ejs 的书写,express 框架的使用,以及路由限制的实现。本实验内容稍微有一些繁琐,希望大家耐下心来,仔细阅读实验步骤,按照实验步骤的要求进行实验。

蓝桥云课 Node.js 实现私人笔记本相关推荐

  1. 蓝桥云课之新手入门指南

    这是蓝桥云课学习人数最多的课程: 新手入门指南之玩转蓝桥云课 460896 人学过 27739 次评价 作者: 云课管理员 难度: 初级 综合评分: 9.4 复习一遍,里面共有3中课程模式: 第一种, ...

  2. 基于阿里云的 Node.js 稳定性实践

    前言 如果你看过 2018 Node.js 的用户报告,你会发现 Node.js 的使用有了进一步的增长,同时也出现了一些新的趋势. Node.js 的开发者更多的开始使用容器并积极的拥抱 Serve ...

  3. js提交出现post错误_阿里云的 Node.js 稳定性实践

    整理人:前端自习课 前言 如果你看过 2018 Node.js 的用户报告,你会发现 Node.js 的使用有了进一步的增长,同时也出现了一些新的趋势. Node.js 的开发者更多的开始使用容器并积 ...

  4. ROS域名解析问题记录(蓝桥云课ros.asc)

    需要用到的网站: ipaddress.com 需要自己查阅: 然后可以尝试ping一下如下: IPv4和IPv6都支持的 Microsoft Windows [版本 10.0.22572.201] ( ...

  5. 蓝桥杯书的笔记(二:接上篇蓝桥云课里的内容,C++)

    https://www.lanqiao.cn/courses/3993/learning/?id=248899 蓝桥云课的笔记 打表法和模拟法 算式问题 求值 既约分数 天干地支 总结 递推法与递归法 ...

  6. 蓝桥云课 Python新手入门课 笔记

    Python 新手入门课_Python - 蓝桥云课 目录 Python 新手入门课_Python - 蓝桥云课 实验一  进入编程大门 实验二  认识Linux 实验三  认识Python 实验四 ...

  7. 新手入门指南之玩转蓝桥云课

    新手入门指南之玩转蓝桥云课 文档1  你好,蓝桥云课 实验1 Linux 桌面环境使用指南 本实验采用的就是图形界面的 Linux 桌面环境.图形界面使用的是非常优秀的 Ubuntu Linux 操作 ...

  8. 蓝桥云课ROS机器人发布5年啦(原实验楼ROS机器人在线云实践课程)

    在2017年春开发了这款课程,到2022年春已经5年了,并在近期逐步在博客公开了课程的扩展功能.当然这些工作都在2019年之前完成测试工作,后续全力转入ROS2课程及其相关应用型课程中. 感谢易科机器 ...

  9. 蓝桥云课linux入门3:用户及文件权限管理

    内容转自蓝桥云课 目录 1.内容 2.Linux用户管理 2.1查看用户 2.2创建用户 2.3用户组 将其它用户加入 sudo 用户组 2.4删除用户和用户组 3.Linux文件权限 3.1查看文件 ...

最新文章

  1. R语言绘制空白图实战
  2. 一文看懂Python(六)-----类与对象篇
  3. 百度智能云开物再收“一个奖状”
  4. java技术突破要点
  5. ActiveRecord多表查询
  6. [转]IIS 允许/禁止 目录浏览
  7. 化学专业尽早转行_尽早查看针对Java 11的功能
  8. 机器学习之 朴素贝叶斯、贝叶斯网络
  9. BZOJ4810:[YNOI2017]由乃的玉米田(莫队,bitset)
  10. ajax post 请求 一直提示 404 not found textStatus error
  11. Python: ord()函数
  12. [转载] Numpy_索引操作
  13. 近乎 5.3 发布,SNS 社区系统
  14. TeamTalk Lock模块
  15. 解决Python包下载慢/超时的方法
  16. 计算机说课稿模板小学数学,小学数学说课万能模板精简
  17. uni-app开发之编辑器HBuilderX(一)
  18. powereshell判断目录如果存在pdf文件则打包文件发送到指定邮箱
  19. 接口报错500是什么意思_500错误原因解决办法?错误页面怎么解决?到底是什么问题?...
  20. 【手绘漫画】面试必考之图解逆转单链表/单链表逆序

热门文章

  1. win10会无缘故自动关机,解决办法如下
  2. C语言学习:简单的小游戏 走迷宫、推箱子
  3. 小度智能音响拆解 芯片_拆解报告:DOSS小度版智能音箱
  4. 华为网路设置常用命令
  5. linux shell random 3,Linux-Shell(三)
  6. XML_ERROR_MISMATCHED_ELEMENT
  7. 第二篇 值函数Based——基于值函数逼近的强化学习方法
  8. 【强化学习】你应该理解的一些关键概念
  9. 追女孩儿,从入门到精通大法
  10. 如何使用野狗搭建视频聊天室-WebRTC的技术实践