文章简介
在 基于 Node.js 和 Express 搭建并部署个人博客系统(一)中,我们搭建完成了项目的主体结构,规划了项目目录,并对入口文件做了简单的处理,将项目划分为前台、后台、API 几个部分,并对接口做了设计,本篇将介绍具体功能的开发。
第一步 路由封装
路由处理是项目开发中频繁操作的一项工作,而且需要对各个模块各自定义,因此我们需要将路由合理划分,根据上一篇所划分的方式,我们分别在 Router 目录下新建 API, admin, main 三个文件定义各自的路由。我们以 admin 为例来说明路由文件的结构:
1 2 3 4 5 6 7 8 9 10 11 |
var express = require('express') var router = express.Router() // 注:此处不需要在前面加上/admin了,因为在入口文件中已经加上这个前缀了 // 当客户端发送/admin/user的请求时,匹配到该路由,回调中进行处理 router.get('/user', function (req, res, next) { res.send('admin User') }) module.exports = router |
第二步 初始化数据库结构
我们选择的数据库是 MongoDB,所以请自行去官网下载安装 MongoDB,安装完毕后继续进行,安装过程不做详细介绍。
在继续往下进行开发时,有必要先简单说明 MongoDB 中的一些概念先,我们将其和 MySQL 做一个简单的对照:
- MongoDB 中的集合相当于 MySQL 中的表
- MongoDB 中的文档相当于 MySQL 中的一行记录
- MongoDB 中的键 ( key ) 相当于 MySQL 中的列字段
- MongoDB 中的值 ( value ) 相当于 MySQL 中的字段值
接下来我们需要在 app.js 入口文件中引入 Mongoose 模块,初始化数据库连接:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
var mongoose = require('mongoose') app.use('/admin', require('./routers/admin')) app.use('/api', require('./routers/api')) app.use('/', require('./routers/main')) // 连接本地localhost上监听于27017端口的MongoDB数据库下的blog数据库 mongoose.connect('mongodb://localhost:27017/blog', function (err) { if (err) { console.log('数据库连接失败') } else { console.log('数据库连接成功') app.listen(8081) } }) |
注:
- 数据库连接失败时会出现一系列异常,因此只在连接成功时开启了服务器
- 数据库连接成功之后,就使用该连接进行后续的增删改操作即可,无需多次连接,因此要将
mongoose.connect
放在接口请求处理的后面
接下来先初始化 User 集合结构,在 Schemas 目录下新建 users.js 文件,先定义 username password 两个字段:
1 2 3 4 5 6 7 8 |
var mongoose = require('mongoose') var Schema= mongoose.Schema module.exports = new Schema({ username: String, password: String }) |
此处需说明一下,一个 Schema 代表数据库中的一个集合,也可以理解为一张表。
第三步 创建用户模型类 User
通常我们通过模型类的方法来操作数据库,在 models 目录下新建 User.js 用户模型文件:
1 2 3 4 5 |
var mongoose = require('mongoose') var usersSchema = require('../schemas/users') module.exports = mongoose.model('User', usersSchema) |
第四步 前台首页、前端注册逻辑
此时我们需要对模板文件和静态文件的目录结构做一些相应的调整:
- Views 下新建 main、admin 两个目录分别用来存放前台、后台相关的模板
- Public 下也同样新建 main、admin 两个目录分别用来存放前台、后台相关的JS、CSS
在处理前台请求的 main 目录下,配置访问首页的请求:
1 2 3 4 5 6 7 8 9 10 11 |
var express = require('express') var router = express.Router() router.get('/', function (req, res, next) { // res.send('index') // render方法会去模板目录,即views下按照views/main/index去寻找对应的模板文件 res.render('main/index') }) module.exports = router |
在 main 目录下创建 index.html
作为前台首页模板文件:
前端注册的 JS 逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$(function () { $('.register .regBtn').click(function () { $.ajax({ type: 'post', url: '/api/user/register', data: { username: $('.register input[name="username"]').val(), password: $('.register input[name="password"]').val(), }, dataType: 'json', success: function (res) { console.log(res) } }) }) }) |
第五步 后台注册逻辑
注册无论在前台还是后台都有所使用,是服务端为客户端提供的一个 API i方法,所以这个服务应该放在 API 下。在 routers/api.js
文件中配置路由:
1 2 3 4 |
router.post('/user/register', function (req, res, next) { console.log(req, res) }) |
此处控制台打印出的 req 和 res 两个对象内容非常多,我们需要从中提取出前端传过来的参数,需要用到一个名为 body-parser
的模块。
首先,需要在入口文件 app.js
中引入该模块,并做一些初始化配置:
1 2 3 4 5 6 |
var bodyParser = require('body-parser') app.use(bodyParser.urlencoded({ extended: true })) |
这样一来,我们就可以在每次请求的 request 对象上得到一个 body 属性,值就是通过 post 方式传来的数据,在 routers/api.js
对该请求的后续操作中就可以通过 body 属性访问到前端入参。
用户注册时需要做一些验证,这些验证分为两类:
- 基本验证:用户名不能为空、密码符合一定规则
- 需要连接数据库做的验证:用户是否已经被注册
还有一点需要注意:为了方便前端处理,返回给前端的数据格式应尽量统一,所以需要定义一个统一的返回数据结构,例如在 routers/api.js
中定义的 resData 变量。
此外,在每次处理请求时,如果遇到错误,则应该立即返回,而不应该继续执行下面的逻辑,因此每次遇到错误就应该直接调用 res.json(resData)
,这条语句将会把我们定义的 resData 对象作为返回值返回到前端。
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 |
var resData router.use(function () { resData = { code: 0, message: '' } }) router.post('/user/register', function (req, res, next) { var username = req.body.username var password = req.body.password if (username === '') { resData.code = 1 resData.message = '用户名不能为空' res.json(resData) return } if (password === '') { resData.code = 2 resData.message = '密码不能为空' res.json(resData) return } // 所有条件都通过之后 resData.message = '注册成功' res.json(resData) }) |
第六步 连接数据库查询用户是否已经被注册
我们和数据库的操作是通过模型层 ( M 层 ) 来实现的,所以需要将模型对象引入 api/routers.js
才可以调用其方法。至于模型对象上操作数据库的方法,可以查看 Mongoose 的官方文档。
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 |
var express = require('express') var router = express.Router() var User = require('../models/User') router.post('/user/register', function (req, res, next) { var username = req.body.username var password = req.body.password if (username === '') { resData.code = 1 resData.message = '用户名不能为空' res.json(resData) return } if (password === '') { resData.code = 2 resData.message = '密码不能为空' res.json(resData) return } User.findOne({ username: username }).then(function (userInfo) { if (userInfo) { resData.code = 3 resData.message = '用户名已经被注册' res.json(resData) } var user = new User({ username: username, password: password }) return user.save() }).then(function (newUserInfo) { // 所有条件都通过之后 console.log(newUserInfo) resData.message = '注册成功' res.json(resData) }) }) |
插入数据库成功后,控制台打印出返回的结果为:
1 2 3 4 5 6 7 8 9 |
{ _id: 5c1f932a9370e653943ebb66, username: 'myj', password: '123', __v: 0 } 其中_id和__v是数据库自己添加的字段 |
注:
- 通过 require(‘../models/User’) 引入的是一个模型类,而并不是模型对象
- 查询方法 findOne 是类上的静态方法,而插入方法 save 是实例上的实例化方法
- 数据库增删改查方法,例如 findOne、save 返回的都是 Promise 对象,所以需要做异步处理
结语
至此,注册流程基本实现完毕,下一篇中我们将继续实现登录等其他具体业务。
本文作者:穆英杰