1.1前置内容
1.1.1什么是javascript
概念:遵循ECMAScript标准,是ECMAscript的具体实现,并且支持浏览器的API,BOM和DOM,并且支持node.js的API.
1.1.2什么是node.js
概念:基于chromev8引擎实现的javascript运行环境。
1.2Node.js下载安装
官网下载
1.3配置npm全局安装目录
进入高级系统设置,环境变量中找到系统变量中找到path中添加文件路径就可以了
1.4配置系统环境变量
2.0Node.js的核心API
2.1文件操作
步骤:
第一步:引入’fs’模块
代码:
// 引入fs模块
var fs = require(fs);
第二步:操作API
示例代码
同步写入
var fs = require(fs);
//同步写入
let rel = fs.writeFileSync('./abc.txt','你好')
console.log(rel);
异步写入
fs.writeFile('孤勇者.txt','爱你孤身走暗巷,爱你不跪的模样',function (err,) {
if (err) {
return console.error('输出错误',err);
}
console.log('输出完毕');
});
同步读取
let data = fs.readFileSync('./abc.txt')
console.log(data.toString());
异步读取
fs.readFile('./abc.txt',function(err,data){
console.log(data.toString());
})
删除文件
fs.unlink('./abc.txt',function(){
console.log('删除成功')
})
创建目录
fs.mkdir("./小钱钱",function(err){
if (err) {
return console.error(err);
}
console.log("目录创建成功。");
});
删除目录
fs.rmdir("./小钱钱",function(err){
if (err) {
return console.error(err);
}
console.log("读取 /tmp 目录");
});
创建递归目录
fs.mkdir("./得爱者/孤勇者",{recursive : true},function(err){
if (err) {
return console.error(err);
}
console.log("目录创建成功。");
});
2.2路径操作
示例代码
引入路径模块
var path = require('path')
返回当前执行脚本的绝对路径
let url = path.resolve('dist')
console.log(url);
拼接一个路径(!加__dirname是绝对路径,不加是相对路径。)
let url = path.join(__dirname,'a,b,c,d.txt')
console.log(url);
2.3node全局对象
1.__filename(当前正在执行的脚本文件名)
2.__dirname(当前正在执行的脚本所在目录)
3.setTimeout(全局函数在指定毫秒数后执行指定函数)
4.clearTimeout(全局函数用于停止一个之前通过 setTimeout() 创建的定时器)
5.setInterval( 全局函数在指定的毫秒(ms)数后执行指定函数(cb))
6.console
7.process(process 是一个全局变量,即 global 对象的属性)
2.4web模块
var http = require('http')
var fs = require('fs')
var url = require('url')
var querystring = require('querystring')
var app = http.createServer(function(req,res){
//使用 url 模块解析get请求的路由和参数对象
let path = url.parse(req.url,true)
console.log(path.pathname); //请求的路由
console.log(path.query); //请求参数对象
//使用querystring解析post请求
let postData = ''
req.on('data', function(data){
postData += data
})
req.on('end', function(){
//解析后的post请求参数对象
let body = querystring.parse(postData)
})
/*
根据路由判断请求的页面,使用fs响应 html 页面内容
*/
// let url = req.url
// let filePath = '.'
// console.log(url);
// if(url === '/' || url === '/index.html'){
// filePath += '/index.html'
// }else if(url === '/job.html'){
// filePath += url
// }else if(url === '/about.html'){
// filePath += url
// }else{
// }
// if(url === '/'){
// url = '/index.html'
// }
// if(url !== '/favicon.ico'){
// let data = fs.readFileSync(`.${url}`)
// res.write(data.toString())
// }
res.end()
})
app.listen(9990)
3.0Express框架
3.1、搭建 Express
开发环境
# 安装express脚手架,此命令不需要每次执行
$ cnpm i express-generator -g
# 创建项目
$ express -e jd-server
# 进入项目根目录
$ cd jd-server
# 初始化依赖
$ cnpm i
在 package.json
文件中,修改启动命令:
{
"scripts": {
"start": "nodemon ./bin/www"
}
}
3.2、项目目录结构
- public 服务器的静态资源文件管理目录
- routes 路由管理目录
- views 网页模板文件管理目录
- app.js 入口文件
- package.json NPM配置文件
3.3、创建模块的流程
以学生模块为例,创建步骤:
第1步:创建路由文件
在 routes
目录下创建 stu.js
, /routes/stu.js
示例代码:
var router = require('express').Router();
//跳转添加学生页面
router.get('/page/add', function(req,res){
//渲染模板
res.render('stu_add')
})
module.exports = router
第2步:创建一级路由
在 app.js
入口文件中注册一级路由,app.js
示例代码:
var express = require('express')
//引入路由文件
var stuRouter = require('./routes/stu.js')
var app = express()
//声明一级路由
app.use('/stu', stuRouter)
第3步:创建模板文件
在 /views
目录下创建 stu_add.ejs
文件,/views/stu_add.ejs
示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>添加学生</h1>
<form action="/stu/add" method="POST">
<div>
学生姓名:<input type="text" name="stuname">
</div>
<div>
学生年龄:<input type="text" name="age">
</div>
<div>
<button type="submit">提交</button>
</div>
</form>
</body>
</html>
第4步:创建添加学生数据的路由
在 /routes/stu.js
文件中添加 /add
二级路由,/routes/stu.js
示例代码:
var router = require('express').Router();
router.get('/page/add', function(req,res){
res.render('stu_add')
})
//添加以下代码
router.post('/add', function(req,res){
//接收post请求参数
let stu = req.body
//添加数据库
})
module.exports = router
4、Mongodb
数据库
4.1、安装 Mongodb
和 Mongodb Compass
略
4.2、Node
中操作 Mongodb
4.2.1、使用 mongoose
安装
$ cnpm i mongoose --save
$ cnpm i cors --save
4.2.2、连接数据库
例如,在 express
项目中的某个路由文件中实现连接数据库操作,routes/index.js
文件,示例代码:
var express = require('express');
var router = express.Router();
//1.引入mongoose
var mongoose = require('mongoose')
//2.连接数据库
mongoose.connect('mongodb://localhost:27017/blog',{
useNewUrlParser:true
}).then(()=>{
console.log('数据库连接成功');
}).catch(err=>{
console.log('数据库连接失败');
})
//3.创建文档模型对象
var schema = new mongoose.Schema({
title: String,
createTime: Number,
author: String,
content: String
})
var Article = mongoose.model('articles',schema)
//查询文章
router.get('/find', (req,res)=>{
//find(where) 查询多条数据的方法,参数为查询条件
Article.find().then(result=>{
//查询到的结果数组
})
})
//添加文章
router.post('/add', (req,res)=>{
//create(obj) 添加方法,参数为要添加的对象
Article.create().then(result=>{
//result 为添加成功的对象
})
})
module.exports = router;
文档对象的 API
(以 Goods
为例):
//添加数据,create(g)参数为要添加的对象,执行成功后返回的是添加成功的对象
Goods.create(g).then(rel=>{}).catch(err=>{})
//修改数据,updateOne()参数1为修改条件,参数2为要修改的新对象,返回修改的结果对象,当 rel.n > 0 时表示修改成功
Goods.updatOne(where,params).then(rel=>{}).catch(err=>{})
//删除数据,findOneAndDelete()参数为删除条件,返回删除成功的对象
Goods.findOneAndDelete(where).then(rel=>{}).catch(err=>{})
//查询所有,find()参数为查询条件
Goods.find(where).then(rel=>{}).catch(err=>{})
//排序查询所有,sort()参数为排序条件 {price: 1}为价格升序,{price: -1}为价格降序,多条件语法 {price:1, sal: -1}
Goods.find().sort({price: -1,createTime: -1}).then(rel=>{}).catch(err=>{})
//分页查询,start表示查询的起始位置(索引),pageSize表示每页查询的条数
//start = (当前页码 - 1) × 每页条数
Goods.find().skip(start).limit(pageSize).then(rel=>{}).catch(err=>{})
//查询总记录数,find()参数为查询条件,返回当前数据的总数量
//总页数 = Math.ceil(count/pageSize)
Goods.find(where).count().then(rel=>{}).catch(err=>{})
Goods.find(where).countDocuments().then(rel=>{}).catch(err=>{})
//模糊查询,查询对象为一个包含正则表达式的条件对象
Goods.find({title: {$regex: /['裤']|['男']/}}).then(rel=>{}).catch(err=>{})
//比较查询,查询条件中 $gt表示大于,$lt表示小于
Goods.find({price: {$gt: 200, $lt: 300}}).then(rel=>{}).catch(err=>{})
//自增
Goods.updateOne({_id: goods._id}, {$inc: {see: 1}}).then(rel=>{}).catch(err=>{})
此处以添加商品分类为例。
4.2.3、前端请求
使用 jquery
中的异步请求方法:
$.get(url, callback)
$.post(url, params, callback)
使用 vue.js
实现页面 DOM
渲染:
//实例化vue
new Vue({
//选项
})
Vue的选项:
- el
- data
- methods
- created
- filters
- watch
Vue的指令:
- v-text
- v-html
- v-if/v-else-if/v-else
- v-show
- v-for
- v-bind
- v-on
- v-model
扩展:
- layer 弹框插件
- layui 前端框架
- wangEditor 富文本编辑器
- ECharts 数据可视化
4.3、Node 服务端模块的实现流程
4.3.1、核心业务逻辑封装
连接数据库
在项目根目录下创建 db/index.js
文件,代码:
var mongoose = require('mongoose')
function dbConnect(){
mongoose.connect('mongodb://localhost:27017/blog',{}).then(()=>{]}).catch(()=>{})
}
module.export = dbConnect
在 app.js
入口文件引入并调用连接数据库的方法:
var express = require('express')
var dbConnect = require('./db/index.js')
var app = express()
dbConnect()
封装模型对象
以文章模块Article
为例,创建 models/Article.js
文件,代码:
var mongoose = require('mongoose')
//创建配置对象的规则
var schema = new mongoose.Schema({
title: String,
see: { //查看次数
type: Number,
default: 0
}
})
//创建模型对象
var Article = mongoose.model('articles', schema)
module.exports = Article
把 Article.js
在 models/index.js
中向外暴露,代码:
module.exports = {
Article: require('./Article.js')
}
在其他文件中使用 Article
模块,代码:
// routes/article.js文件
var Model = require('../models')
Model.Article //获取Article模型对象
封装CRUD代码
创建 controller/index.js
文件,代码:
/**
* 添加数据的方法
* @param {*} model 模型对象
* @param {*} params 要添加的参数对象
* @param {*} res 响应对象
*/
function add(model, params, res){
model.create(params).then(rel=>{
if(rel){
res.json({
code: 200,
msg: '添加成功'
})
}else{
res.json({
code: 300,
msg: '添加失败'
})
}
}).catch(err=>{
res.json({
code: 400,
msg: '添加时出现异常'
})
})
}
/**
* 修改数据的方法
* @param {*} model 模型对象
* @param {*} where 修改条件
* @param {*} params 修改后的对象
* @param {*} res 响应对象
*/
function update(model, where, params, res){
model.updateOne(where, params).then(rel=>{
if(rel.modifiedCount > 0){
res.json({
code: 200,
msg: '修改成功'
})
}else{
res.json({
code: 300,
msg: '修改失败'
})
}
}).catch(err=>{
res.json({
code: 400,
msg: '修改时异常'
})
})
}
/**
* 删除数据的方法
* @param {*} model 模型对象
* @param {*} where 删除条件
* @param {*} res 响应对象
*/
function remove(model, where, res){
model.findOneAndDelete(where).then(rel=>{
if(rel){
res.json({
code: 200,
msg: '删除成功'
})
}else{
res.json({
code: 300,
msg: '删除失败'
})
}
}).catch(err=>{
res.json({
code: 400,
msg: '删除时异常'
})
})
}
/**
* 分页查询所有数据
* @param {*} model 模型对象
* @param {*} page 当前页
* @param {*} pageSize 每页条数
* @param {*} where 查询条件
* @param {*} sort 排序条件
* @param {*} res 响应对象
*/
async function find(model,page,pageSize,where,sort,res){
//判断page是否存在
if(!page){
page = 1
}else{
page = parseInt(page)
if(isNaN(page)){ //判断是否为数字
page = 1
}else{
if(page < 1){ //判断当前页码不能小于1
page = 1
}
}
}
//判断pageSize是否存在
if(!pageSize){
pageSize = 10
}else{
pageSize = parseInt(pageSize)
if(isNaN(pageSize)){
pageSize = 10
}else{
if(pageSize < 1){
pageSize = 3
}else if(pageSize > 100){
pageSize = 100
}
}
}
//总条数
var count = 0
await model.find(where).countDocuments().then(rel=>{
count = rel
})
//计算总页数
var totalPage = Math.ceil(count/pageSize)
//判断page的最大值
if(totalPage > 0 && page > totalPage){
page = totalPage
}
//计算起始位置
var start = (page - 1)*pageSize
await model.find(where).sort(sort).skip(start).limit(pageSize).then(result=>{
if(result && result.length > 0){
res.json({
code: 200,
msg: '查询成功',
data: result,
page,
pageSize,
count,
totalPage
})
}else{
res.json({
code: 300,
msg: '没有查询到数据',
data: []
})
}
}).catch(err=>{
res.json({
code: 400,
msg: '查询时出现异常',
data: []
})
})
}
/**
* 不分页查询所有数据
* @param {*} model 模型对象
* @param {*} where 查询条件
* @param {*} sort 排序条件
* @param {*} res 响应对象
*/
function query(model,where,sort,res){
model.find(where).sort(sort).then(rel=>{
if(rel && rel.length > 0){
res.json({
code: 200,
msg: '查询成功',
data: rel,
})
}else{
res.json({
code: 300,
msg: '没有查询到数据',
data: []
})
}
}).catch(err=>{
res.json({
code: 400,
msg: '查询时出现异常',
data: []
})
})
}
/**
* 查询单条数据
* @param {*} model 模型对象
* @param {*} where 查询条件
* @param {*} res 响应对象
*/
function findOne(model, where, res){
model.findOne(where).then(rel=>{
if(rel){
res.json({
code: 200,
msg: '查询成功',
data: rel,
})
}else{
res.json({
code: 300,
msg: '没有查询到数据',
data: {}
})
}
}).catch(err=>{
res.json({
code: 400,
msg: '查询时出现异常',
data: null
})
})
}
module.exports = {
add,
update,
remove,
find,
findOne,
query
}
4.3.2、JWT
使用
安装 jsonwebtoken
:
$ cnpm i jsonwebtoken --save
生成token
一般会在登录的路由中生成 token
,例如 routes/user.js
文件中:
var router = require('express').Router()
var jwt = require('jsonwebtoken')
//管理员登录
router.post('/login',async function(req,res){
let u = req.body //接收参数
//数据库查询,查询成功后,生成token
let user = {}
// expiresIn 有效期,单位秒
let token = jwt.sign(user,'密钥',{expiresIn: 60 * 60 * 24 * 7})
res.json({
code: 200,
token
})
})
module.exports = router
前端接收token
login.html
<script>
$.post('url', {}, function(res){
if(res.code === 200){
localStorage.token = res.token
}
})
</script>
验证token
前端发送请求,将 token
放到请求头
<script>
$.ajax({
url: '',
headers: {
token: localStorage.token
}
})
</script>
在服务端验证 token
,一般会放到 app.js
的中间件内:
app.js
代码:
var express = require('express')
var jwt = require('jsonwebtoken')
var app = express()
//验证token(中间件)
//配置不进行校验的路由
let pathRule = [
'/admin/user/login',
'/user/reg',
'/user/login',
]
app.use(function(req,res,next){
if(pathRule.includes(req.path)){
next()
return
}
//获取token
var token = req.headers.token
let result = null
//验证token
jwt.verify(token,'密钥',function(err,data){
if(err){
switch(err.name){
case 'JsonWebTokenError':
result = {
errCode: 1,
msg: '无效token'
}
break;
case 'TokenExpiredError':
result = {
errCode: 2,
msg: 'token过期'
}
break;
}
}else{
result = {
errCode: 0,
data: {
username: data.username,
role: data.role
}
}
}
})
if(result.errCode == 0){
next()
}else{
res.json(result)
}
})
//路由
app.use('/user', xxx)