1. 项目环境搭建
1.1 多人博客管理系统
- 博客内容展示
- 博客管理功能
1.2 案例初始化
-
建立项目所需文件夹
- public 静态资源
- model 数据库操作
- route 路由
- views 模板
-
初始化项目描述文件
- npm init -y
-
下载项目所需第三方模块
npm install express mongoose art-template express-art-template
- express: 用来创建网站服务器和路由
- mongoose: 用来操作数据库
- art-template: 用来渲染模板
-
创建网站服务器
-
构建模块化路由
-
构建博客管理页面模板
错误记录
在构建模块化路由时app.use('/home', home)误写成app.use('./home', home),导致页面一直返回Cannot GET,特此记录。
笔记
在模板路径中外链资源要写绝对路径,/代表绝对路径。
Cannot set headers after they are sent to the client
出现这个错误就表示,在一个关闭的链接上又做了一些操作,翻看代码,删除一个res.send()后解决。
2. 项目功能实现
2.1 登录
- 创建用户集合,初始化用户
- 连接数据库
- 创建用户集合
- 初始化用户
- 为登录表单项设置请求地址、请求方式以及表单项name属性
- 当用户点击登录按钮时,客户验证用户是否填写了登录表单
- 如果其中一项没有输入,阻止表单提交
- 服务器端接收请求参数,验证用户是否填写了登录表单
- 如果其中一项没有输入,为客户端做出响应,阻止程序向下执行
- 根据邮箱地址查询用户信息
- 如果用户不存在,为客户端做出响应,阻止程序向下执行
- 如果用户存在,,将用户名和密码进行比对
- 比对成功,用户登录成功
- 比对失败,用户登录失败
2.2 新增用户
- 为用户列表页面的新增用户按钮添加链接
- 添加一个链接对应的路由,在路由处理函数中渲染新增用户模板
- 为新增用户表单指定请求地址、请求方式、为表单项添加name属性
- 增加实现添加用户的功能路由
- 接收到客户端传递过来的请求参数
- 对请求参数的格式进行验证
- 验证当前要注册的邮箱地址1是否已经注册过
- 对密码进行加密处理
- 将用户信息添加到数据库中
- 重定向页面到用户列表页面
2.3 数据分页
当数据库中的数据非常多是,数据需要分批次显示,这时就需要用到数据分页功能。
分页功能核心要素:
- 当前页,用户通过点击上一页或者下一页或者页码产生,客户端通过get参数方式传递到服务器端
- 总页数,根据总页数判断当前页是否为最后一页,根据判断结果做响应操作
2.4 用户信息修改
- 将要修改的用户ID传递到服务器端
- 建立用户信息修改功能对应的路由
- 接收客户端表单传递过来的请求参数
- 根据id查询用户信息,并将客户端传递过来的密码和数据库中的密码进行比对
- 如果比对失败,对客户端做出响应
- 如果密码对比成功,将用户信息更新到数据库中
2.5 用户信息删除
- 在确认删除框中添加隐藏域用以存储要删除用户的ID值
- 为删除按钮添自定义属性用以存储要删除用户的ID值
- 为删除按钮添加点击事件,在点击事件处理函数中获取自定义属性中存储的ID值并将ID值存储在表单的隐藏域中
- 为删除表单添加提交地址以及提交方式
- 在服务器端建立删除功能路由
- 接收客户端传递过来的id参数
- 根据id删除用户
2.6 开发环境与生产环境
什么是开发环境与生产环境
环境,就是指项目运行的地方,当项目处于开发阶段,项目运行在开发人员的电脑上,项目所处的环境就是开发环境。当项目开发完成以后,要将项目放到真实的网站服务器电脑中运行,项目所处的环境就是生产环境。
为什么要区分开发环境与生产环境
因为在不同的环境中,项目的配置是不一样的,需要在项目代码中判断当前项目运行的环境,根据不同的环境应用不同的项目配置。
3. 项目包含的知识点
3.1 密码加密 bcrypt
哈希加密是单程加密方式:1234 => abcd 在加密的密码中加入随机字符串可以增加密码被破解的难度。
// 导入bcrypt模板
const bcrypt = require('bcrypt');
// 生成随机字符串 gen => generate 生成salt 盐
let salt = await bcrypt.genSalt(10);
// 使用随机字符串对密码进行加密
let pass = await bcrypt.hash('明文密码', salt);
// 密码比对
let isEqual = await bcrypt.compare('明文密码', '加密密码');
bcrypt依赖的其他环境
- python 2.x
- node-gyp npm install -g node-gyp
- windows-build-tools npm install --global --production windows-buil-tools
3.2 cookie与session
cookie:浏览器在电脑硬盘中开辟的一块空间,主要供服务器端存储数据。
- cookie中的数据是以域名的形式进行区分的。
- cookie中的数据是有过期时间的,超过时间数据会被浏览器自动删除。
- cookie中的数据会随着请求被自动发送到服务器端。
session: 实际上就是一个对象,存储在服务器端的内存中,在session对象中也可以存储多条数据,每一条数据都有一个sessionid做为唯一标识。
例子: sessionId存储在cookie中,相当于将卡号写在一张卡上,session对象相当于记录本,客户端发送请求到服务器端携带cookie信息,相当于客人在店里购物出示卡片,用来证明客人的身份。
cookie相当于服务器端发给客户端的验证身份的标识,每一次客户端访问服务器端的时候都要带着这个标识,以证明自己的身份。服务器端的session就是记录身份的对象,服务器端收到客户端发来的sessionId后会在session对象中查找语句。
利用cookie和session实现登录功能
在node.js中需要借助express-session实现session功能。
const session = require('express-session');
app.use(session({ secret: 'secret key' }));
当网站重启的时候,服务器端的session对象就会失效
express 方法下的重定向
redirect('需要跳转的地址')
使用locals存储对象
将用户信息存放在locals公共对象下,在所有的模板中都可以访问到userInfo
req.app.locals.userInfo = user;
在需要插入的art模板下:
{{userInfo && userInfo.username}}
3.3 Joi
JavaScript对象的规则描述语言和验证器。
- 引入joi模块
- 定义对象的验证规则
Joi.object({}) - 通过
schema.validateAsync({})实施验证
- string():是字符串类型
- alphanum():字母类型
- number(): 数字类型
- required():在joi中如果不加required,则都不是必填项,加了required就是必填项
- error(new Error('错误信息')):自定义错误信息
const Joi = require('joi');
const schema = Joi.object({
username: Joi.string().alphanum().min(3).max(30).required().error(new Error(‘错误信息’)),
password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),
access_token: [Joi.string(), Joi.number()],
birthyear: Joi.number().integer().min(1900).max(2013),
email: Joi.string().email()
});
try {
// 实施验证
await schema.validateAsync({ username: 'ab' });
} catch (ex) {
console.log(ex);
return;
}
console.log('验证通过');