实现幼教平台的幼教资源部分功能,主要熟悉Node中前后端交互以及和数据库进行交互
幼教平台完整项目代码
这个项目陆陆续续看了有两三遍,终于完整的整理完了,Node的项目主要还是做后端服务器的提供接口的,前端界面还是主要用Vue、react来做,Vue可以参考实战Vue:基于Vue的移动端购物商城
前端界面展示

项目目录结构
(一)项目初始化(不借助express-genertor)
新建文档school
在school文档下新建app.js入口文件
进行npm初始化
使用express搭建服务器
① 安装express
npm install express --save
② 启动服务器
③ 匹配基础路径
④ 完成设置
配置babel,实现高阶语法转化
① 配置转化环境:根目录新建
.babelrc
,并在里面添加如下代码
安装并设置为开发依赖
npm install babel-preset-env --save-dev
② 安装babel-register转化工具
npm i babel-register --save-dev
设置不再使用app.js向外暴露,新建src文件夹,将app.js放在src目录下。新建main.js。
main.js中,首先引入语法转换工具,然后引入app.js。就可以将app.js中的高阶语法转换为低阶语法。
babel高阶语法转化演示
① 安装
npm install -g babel-cli
全局安装
npm install babel-cli --save-dev
项目中安装
② 通过
babel 文件名
进行演示
③ 通过
babel src -d dist
将src中文件转换为低阶语法版本
设置package.json中,实现开发和生产分离
设置完成后,就可以使用
npm run dev
命令进行项目运行,并且可以使用es6语法了,同时使用
npm run build
命令进行打包将高阶语法转化为低阶语法,使用
npm run start
命令运行低阶语法版本
(二)项目分析
幼教平台是一个全栈项目,应该分为三部分
在实际开发过程中,一般先打通后端接口,前端只需要进行请求即可。
前端主要做幼教资源部分,一通百通,其他界面都类似:
后台管理系统
(三)项目开发
1. 配置依赖资源
新建public、views文件夹,引入静态资源
① 新建public文件夹,存放公共资源
② 新建views文件夹,存放所有界面
③ 因为要区分前后端,所以public和views中,各自新建back、web文件夹
集成静态资源文件
将静态界面以及资源内容放到对应文件夹中
配置全局路径
① src目录下新建config.js,并在里面设置路径代码
② 在app.js中引入并配置全局资源
配置新的模板引擎(使用Nunjucks)
① 安装Nunjucks
npm install nunjucks --save
② 在app.js中进行配置
配置全局路由
① 新建routes文件夹,存放各种路由
② routes文件夹下,新建index.js。该文件用于配置首页路由
③ 配置index.js。因为最后在语法转换的时候,src文件夹下的文件进行转换,所以在index.js中,使用common.js或者es6语法均可。
④ 在app.js中,引入路由并进行路由挂载
⑤ 此时就可以通过
访问后端界面
⑥ 同理,可以在index.js中配置前端路由
配置nodemon:自动重启项目工程
① 安装
npm install -g nodemon
② 更改package.json中的开发命令
服务器启动后
此时更改代码后,就可以自动更新了
2. 路由重定向
服务器接收命令后,使用
res.redirect(url)
进行路由重定向
在这里,将
'/'’
重定向为
'/web'
,也就是访问
后,会直接重定向到
3. 配置公共代码模板
后端界面可以将头部以及侧边栏进行抽离,别的界面在使用的时候,直接使用Nunjucks进行集成就可以
设置完基础模板后,在index.html中进行继承即可
4. 配置简单的404界面
-
- 书写简单404界面
实战Node:幼教平台幼教资源部分实现 - 在app.js所有中间件最后配置404错误界面
实战Node:幼教平台幼教资源部分实现 - 此时访问没有的资源就会出现错误提示
实战Node:幼教平台幼教资源部分实现
5. 配置前台界面
-
- 配置幼教资源以及具体文章路由
实战Node:幼教平台幼教资源部分实现 - 在界面上,将a标签跳转链接,改为路由的形式
实战Node:幼教平台幼教资源部分实现
6. 幼教资源中轮播图的实现
在routes中,新建sowing.js,用来配置轮播图接口路由,并配置基础路由代码
路由设计
① 图示:实现以下界面数据动态化
② 新增一张轮播图
ⅰ请求方法:POST
ⅱ请求路径:/sowing/add
ⅲ 请求参数
-
- image_url 图片路径
- image_link 跳转链接
- image_title 图片标题
- s_time 上架时间
- e_time 下架时间
- l_edit 最后编辑
- c_time 添加时间
③ 获取所有轮播图
ⅰ请求方法:GET
ⅱ请求路径:/sowing/api/list
④ 通过ID获取一条轮播图
ⅰ请求方法:GET
ⅱ请求路径:/sowing/api/singer/:sowingId
ⅲ 注意:通过url拼接的方法,获取轮播图ID
⑤ 根据ID修改轮播图
ⅰ请求方法:POST
ⅱ请求路径:/sowing/api/edit
ⅲ 请求参数
-
- ID 轮播图ID
- image_url 新图片路径
- image_link 新跳转链接
- image_title 新图片标题
- s_time 新上架时间
- e_time 新下架时间
- l_edit 新最后编辑
- c_time 新添加时间
⑥ 根据ID删除轮播图
ⅰ请求方法:GET
ⅱ请求路径:/sowing/api/remove/:sowingId
ⅲ 注意:通过url拼接获取轮播图ID
后台管理轮播图实现
可以直接使用req.body获取数据的原因是配置了POST请求中间件。
① 新增一张轮播图
配置接口API
配置添加轮播图页面路由
② 获取所有轮播图
配置接口API
加载轮播图列表路由配置
这里采用的是服务器端渲染的方法,所以首先查询了所有的数据,并将数据作为参数传递给sowing_list界面,并在界面中调用模板语法进行渲染
③ 通过ID获取一张轮播图/font>
- 配置接口API
实战Node:幼教平台幼教资源部分实现
④ 根据ID修改轮播图
配置接口API
修改轮播图路由配置
在轮播图列表中,点击删除按钮后,可以通过两种方式在编辑界面获取数据:① 直接将所有数据从列表界面获取,传递到编辑界面。② 向编辑界面传递一个图片id,编辑界面通过id调用接口,获取一张轮播图的数据。这里采用第二种方式。
在轮播图编辑界面中,首先需要通过路径截取id,获取一张轮播图数据,并注入界面。
图片缩略图的地方,需要监听文件变化,当文件变化的时候,监听事件并读取文件,当文件读取完毕,将缩略图路径赋值为新的图片路径
当用户修改完数据提交后,发起新的提交表单请求
⑤ 根据ID删除轮播图
-
- 配置接口API
实战Node:幼教平台幼教资源部分实现 - 修改删除路由配置
实战Node:幼教平台幼教资源部分实现
前端展示界面实现
① 后端在返回路由的时候,直接将所有的轮播图数据查询出来,并且返回
② 前端直接使用模板语法进行渲染即可
7. 用户中心版块
用户模型
接口处理
① 添加管理员接口,在后面/user会被屏蔽,不会进行用户名密码的判断
② 用户和密码登录接口
在验证用户存在后,如果密码匹配成功,会将user._id用户的id信息存储在req.session.token中,即在session中存储客户端的信息。同时,再返回的结果中,将用户ID存储在token中,方便前端存储在localStorage中
在前端界面,也将md5加密后的用户名密码传递到服务器进行处理
③ 退出登录
④ 获取用户信息——部分
用户信息修改
⑤ 获取用户信息——全部
前端个人中心界面展示
⑥ 根据ID(token)修改一条数据信息
⑦ 根据ID(token)修改密码
路由配置
权限控制
在服务器端,使用session存储用户数据,并将session保存到MongoDB数据库。同时,使用中间件进行判断。
Node.js:使用session存储用户信息 ① 在middle_wares文件夹下,新建login_pass.js文件,同时设置中间件
② 在app.js中,进行引入并挂载中间件
③ 在所有的轮播图接口前面,加上/back
④ 这样在访问后端接口或页面的时候,就必须先登录才能访问了。
8. 后端幼教资源管理
用户模型
接口处理
① 图片上传到upload文件夹
② 向数据库中插入一条新记录
③ 根据ID修改文章
④ 根据ID删除文章
路由配置
9. 前端幼教资源展示
-
-
接口设置
① 获取总页数
② 获取列表页数据实战Node:幼教平台幼教资源部分实现 ③ 前台获取资源列表实战Node:幼教平台幼教资源部分实现 ④ 前台获取详情页数据实战Node:幼教平台幼教资源部分实现 ⑤ 前端详情页页面阅读量处理实战Node:幼教平台幼教资源部分实现 实战Node:幼教平台幼教资源部分实现 - 界面动态请求接口加载数据渲染界面
实战Node:幼教平台幼教资源部分实现
10. 使用Mongoose与MongoDB交互,存储数据
使用
npm i mongoose --save
安装mongoose
建模:Schema(模式对象),Schema对象定义约束了数据库中的文档结构
① 在根目录下,新建models文件夹,存放所有模型
② 在models下新建Sowing.js,规定轮播图模式,模式的作用就是mongoose在与数据库进行交互,进行增删改查的时候,进行借鉴使用的
③ 在Sowing.js中,进行导入mongoose并连接数据库,并监听连接成功或失败
④ 创建模式Schema,并创建一个Model向外暴露。Mongoose 的一切始于 Schema。每个 schema 都会映射到一个 MongoDB collection ,并定义这个collection里的文档的构成。
在sowing.js轮播图路由中,引入Sowing模式,并进行相关操作,配置接口。
11. Node中POST请求
Node.js:POST请求、文件上传
12. Node中,使用中间件处理POST请求
在根目录下新建middle_wares文件夹存储中间件。
过滤get请求
如果是普通表单(application/x-www-form-urlencoded)提交,要处理,以拼接的形式;如果有文件(图片、音视频····multipart/form-data),不要处理
其他情况,需要进行处理。
① 数据流拼接
② 使用querystring解析和格式化字符串。
完整的POST中间件
import querystring from 'querystring'
// 处理post请求
export default (req, res, next) => {
// 1. 过滤get请求
if (req.method.toLowerCase() === 'get') {
return next();
}
// 2. 如果是普通表单提交,要处理,以拼接的形式
// application/x-www-form-urlencoded
// 如果有文件(图片、音视频····),不要处理,multipart/form-data
if (req.headers['content-type'].startsWith("multipart/form-data")) {
return next();
}
// 3. 数据流的拼接
let data = "";
req.on("data", (chunk) => {
data += chunk;
});
req.on("end", () => {
req.body = querystring.parse(data);
next();
})
}
挂载中间件,在app.js中引入body_parse,并且在所有路由前进配置数据处理中间件
13. Node中,使用中间件处理error
-
- 需求:出现错误的时候,通过中间件,将错误存储到数据库中
- 在models中,新建Error.js,新建错误模型
实战Node:幼教平台幼教资源部分实现 - 在middle_wares文件夹中,新建error_log.js,作为错误中间件处理错误。
实战Node:幼教平台幼教资源部分实现 - 在app.js中引入并挂载错误中间件
实战Node:幼教平台幼教资源部分实现
14. 路由跳转
与Vue直接在页面中通过router跳转不同的是,Node项目中,使用html的a标签跳转,直接将路径放在a标签的href属性内即可。
15. 模板的渲染
在之前的基础学习中,是使用ejs进行渲染的。在这个项目中,使用的是Nunjucks进行渲染。这两种服务器端渲染方法都大同小异。
Nunjucks文档## 标题
EJS文档
16. 在src目录下,有一个config.js配置文件。
在这个文件夹下,定义了一些路径,定义好后,在app.js中引入,就可以在别的文件中使用了。
17. 模糊路径匹配
在路径中,使用
路径/:name
,冒号后面的就是模糊匹配
在服务器接口中,使用
req.params.name
获取值
18. 图片、文件等资源的上传,使用formidable
Node.js:借助formidable文件上传
19. 集成文本编辑器 wangEditor
20. 分页
有刷新
给上一页下一页按钮绑定路由仍然为source_list
在点击后,页面相当于进行刷新,此时,后端接口会接收两个参数, 页数和每一页显示的数量,根据公式查询结果,并渲染界面返回前端
无刷新:集成分页插件:
twbs-pagination
twbs-pagination文档 配置获取总页数接口以及获取列表页面数据的接口,供分页插件使用
21. 项目的重构
后端
async/await
① 概念
-
- 现在最常用的异步变成方案
- async函数时Generator函数的语法糖
-
具备特点
① 内置执行器
Generator函数的执行必须依靠执行器,而async函数自带执行器,调用方式和普通函数的调用一样
② 更好的语义
async和await相较于*和yield更加语义化
③ 更广的适用性
co模块约定,yield命令后面只能是Thunk函数或Promise对象
而async函数的await命令后面则可以是Promise或者原始类型的值(Number、string、boolean,但这时等同于同步操作)
④ 返回值是promise
async函数返回值是Promise对象,比Generator函数返回的Iterator对象方便,可以直接使用then()方法进行调用
② 使用
-
- async是“异步”的简写,async function用于声明一个function是异步的;await,可以认为是async wait的简写,用于等待一个异步方法执行完成
- async/await是一个用同步思维解决异步问题的方案(等结果出来之后,代码才会继续执行)
- 可以通过多层async function的同步写法代替传统的callback嵌套
在项目中如果要是用async/await,需要安装和配置
transform-runtime
① 步骤:
npm i babel-plugin-transform-runtime -D
② 配置
.babelrc
③ 不安装则会报错
regeneratorRuntime is not defined
错误
MVC设计模式
将项目转换为MVC模式,首先要将业务逻辑从router中抽离出来,下面以sowing.js为例
① 新建controller文件夹,并在controller文件夹下新建sowing文件夹,并在sowing文件夹下新建SowingController.js
② 将sowing.js中的业务逻辑,全部放到SowingController.js中
在sowing.js中
而在SowingController.js中
此时,只需要在sowing.js中引入SowingController.js,并且在接口处使用SowingController中的方法即可。
所有的接口转移完成后
sowing.js中
SowingController.js中
端口号配置
各个环境下,nodejs可以通过process.env.PORT去设置端口号
比如
① linux环境下
PORT=1234 node app.js
使用上面命令每次都需要重新设置,如果想设置一次永久生效,使用下面命令
export PORT=1234
node app.js
② windows环境下
set PORT=1234
node app.js
package.json配置文件
实操
在package.json中设置
在config.js中设置
在app.js中监听
中间件session抽取——config.js
实操:
在config.js中设置常量
在app.js中直接使用config.js中的数据进行配置即可
集成插件chalk
① 简介:chalk是一个颜色的插件,可以通过比如:
chalk.blue("hello world")
之类的方法来改变颜色
② 使用
-
- 下载:
npm install chalk
- 引入:
import chalk from 'chalk'
- 显示:
console.log(chalk.blue("Hello world!"));
封装数据库连接
① 简介:全局连接数据库
② 实现:
-
- 在根目录下新建文件夹db,在bd文件夹下新建db.js,db.js中实现连接数据库
'use strict';
import mongoose from 'mongoose';
import config from './../src/config';
mongoose.connect(config.db_url, {useNewUrlParser: true});
mongoose.Promise = global.Promise;
const db = mongoose.connection;
db.once('open' ,()=>{
console.log('连接数据库成功~~~~~~');
});
db.on('error', (error)=>{
console.error('连接数据库时发生错误: ' + error);
mongoose.disconnect();
});
db.on('close', function() {
console.log('数据库断开,重新连接数据库');
mongoose.connect(config.db_url, {useNewUrlParser: true});
});
export default db;
在app.js中引入