功能列表
- 用户管理(登录和注册)
- 用户设置(修改基本信息,修改密码,退出登录)
- 创建微博,暂不显示微博列表
- 个人主页,显示个人微博列表和个人信息,暂不做关注功能
- 广场页(使用缓存)
- 关注和取消关注,显示粉丝和关注人
- 首页,显示我的微博和我关注的人的微博
- @和回复
- @提到我的
用户管理
- 页面:模板和路由
- 数据建模
- 开发注册功能
- 开发登录功能
- 抽离loginCheck中间件
- 单元测试
注册
创建页面:模板和路由
回顾技术方案
注册页直接通过一个api来判断用户名是否已存在,不需要点击注册后才通过请求从后端获取来判断是否重复,提高用户体验
统一的header和footer:通过一些参数来判断是否显示导航
步骤
- 查看缓存是否清空:
git status
- 增加项目分支:
git checkout -b feature-login
- 增加的项目分支是新功能则
git checkout -b feature-xxx
,修改bug则git checkout -b fix-xxx
- 增加的项目分支是新功能则
- 创建2个模板,src-views下新建register.ejs、login.ejs
- 创建路由,routes-views下新建user.js:
- 注册路由,app.js中引入并注册路由:
- 运行程序,访问登录、注册页:
数据建模
回顾技术方案
这里先只用到users表(DECIMAL是非常小的数据类型,很适合性别)
步骤
- src-db下新建types.js封装sequelize的数据类型,这样在建表时就不需要每次都引一下sequelize了:
- src-db下新建model文件夹-新建User.js 创建用户数据模型(users表):补充:
unique:true
规定“数据唯一”,也就是说无法传入同样的2个数据到这一列。defaultValue
规定“默认值”,即这一项什么也没传入数据表中时的默认数据 - src-db-model文件夹下新建index.js 数据模型入口文件,也就是做统一输出:
- 执行sequelize同步数据库时,src-db-sync.js中,注意引入需要同步的数据模型:
- 测试:手动删除原先的users表(users表中有blogs的外键,所以需要先删除blogs表),执行
node src/db/sync.js
将sequelize同步数据库:
开发注册功能(注册接口)
回顾技术方案
- routes层:根据路由,将相应的数据(req)传给controller层
- controller层:获取routes层传递的数据,调用service层的方法处理业务逻辑,并返回统一处理格式的数据
- service层:创建 增删查改的方法,并定义数据表的某些默认数据
- db层:连接数据库,定义模型(创建表)
路由和分层
- 【routes层】创建注册页需要的路由:src-routes-api下新建user.js,创建2个src-views-register.ejs中需要用到的接口:
- 注册路由,app.js中:
- 【controller层】书写业务逻辑并统一返回格式:src下新建controller文件夹-新建user.js:
- 【services层】处理数据:src下新建services文件夹-新建user.js:(关于**
Object.assign()
合并对象**可参考笔记https://huanglizhu.github.io/2019/11/13/ES6%E6%89%A9%E5%B1%95%20%E5%AF%B9%E8%B1%A1%E6%89%A9%E5%B1%95/#Object-assign-合并对象-类似-扩展运算符)
格式化用户信息
- conf下新建constant.js 存放所以常量:
- 【services层】创建格式化用户信息的formatUser方法:src-services文件夹下新建_format.js:(注意**区分typeof和instanceof运算符**)
- 【services层】使用formatUser方法 格式化数据: src-services-user.js:
完成isExist(判断用户名是否已存在)
- 创建统一格式的模型: src下新建model文件夹-新建ResModel.js 用于统一返回格式:(大写字母开头的js文件一般表示 返回一个class)
- 统一管理错误信息:model文件夹下新建ErrorInfo.js:
- 【controller层】判断用户名是否已存在,并使用模型统一返回格式: src-controller-user.js中,根据services层返回的数据判断用户名是否已存在:
- 【路由层】判断用户名是否已存在: src-routes-api-user.js中,引入isExist,判断用户名是否已存在:
- 测试:运行程序,进入注册页,输入用户名:
完成register
- 【路由层】将注册相关数据传给controller层在src-routes-api-users.js中,通过解析前端post请求中所带数据调用controller层的register方法进行注册
- 【controller层】接受路有层传递的数据,使用services层的createUser方法来创建用户(使用对象的解构赋值可以传入乱序的函数参数)
- 【services层】新建在users表中创建用户的createUser方法:
- 测试:注册了1次zhangsan后无法再次进行注册:
密码加密
- 统一管理密钥常量: conf文件夹下新建secretKeys.js,统一管理session和用户密码的密钥常量:
- 修改session密钥:app.js中给session配置的密钥换成从secretKeys.js中获取:
- 创建加密方法: utils文件夹下新建cryp.js:(可参考crypto库 md5加密)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27/**
* @description 加密方法
* @author hlz
*/
const crypto = require('crypto')
const { CRYPTO_SECRET_KEY } = require('../conf/secretKeys')
/**
* md5 加密(hex:16进制)
* @param {string} content 明文
*/
function _md5(content) {
const md5 = crypto.createHash('md5')
return md5.update(content).digest('hex')
}
/**
* 加密方法
* @param {string} content 明文
*/
function doCrypto(content) {
const str = `password=${content}&key=${CRYPTO_SECRET_KEY}`
return _md5(str)
}
module.exports = doCrypto - 【controller层】引入并使用cryp.js中的doCrypto方法对密码加密:
1
const doCrypto = require('../utils/cryp')
- 测试:注册lisi,输入密码为123,存储到数据库的是加密后的16进制密码:
schema格式校验
- 在routes层对页面传来的数据进行格式校验,比如微博的长度、登录校验等
- 在这我们使用json schema设置格式校验的校验规则
- 当数据从页面传到routes层时,我们就进行数据的格式校验,不符合规则的数据直接不往后传递,不再等到数据库才判断格式是否符合要求,提高用户体验
- 此时前端就算不做校验,也会在路由层就报错回去
- 在这规定用户名是字母开头,字母数字下划线结尾。可自定义规则
ajv库
- ajv库可帮助操作schema校验
- 项目中安装ajv库:
npm i ajv --save
- 使用示例:
- 参数1:schema校验规则
- 参数2:需要校验的数据
步骤
- 创建验证工具: validator文件夹下新建_validate.js,借助ajv创建 执行json schema 校验 的通用函数:
- 进行user的数据格式校验:src下新建validator文件夹-新建user.js,使用_validate.js中的函数并传入json schema的校验规则和需要校验的数据进行格式校验:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57/**
* @description user 数据格式校验
* @author hlz
*/
const validate = require('./_validate')
// 校验规则
const SCHEMA = {
type: 'object',
properties: {
userName: {
type: 'string',
pattern: '^[a-zA-Z][a-zA-Z0-9_]+$', // 字母开头,字母数字下划线
maxLength: 255,
minLength: 2
},
password: {
type: 'string',
maxLength: 255,
minLength: 3
},
newPassword: {
type: 'string',
maxLength: 255,
minLength: 3
},
nickName: {
type: 'string',
maxLength: 255
},
picture: {
type: 'string',
maxLength: 255
},
city: {
type: 'string',
maxLength: 255,
minLength: 2
},
gender: {
type: 'number',
minimum: 1,
maximum: 3
}
}
}
/**
* 校验用户数据格式(data默认值为{})
* @param {Object} data 用户数据
*/
function userValidate(data = {}) {
return validate(SCHEMA, data)
}
module.exports = userValidate - 注册路由(src-routes-api-user.js)中添加一个中间件进行格式校验,先执行格式校验再执行注册操作。这个中间件在很多地方都有可能使用,所以我们先抽离中间件
抽离中间件(格式校验)
- 创建”生成json schema 验证中间件“的方法: src下新建middlewares文件夹-新建validator.js:
- 注册路由中添加 验证中间件 进行格式校验: src-routes-users.js中:
- 测试:在前端我并没做密码长度的限制,但在路由中使用schema规则规定了密码长度最小是3:所以不会走到注册,可以看到数据表中无增加数据