node-express,MongoDB;回调

封弘伟
2023-12-01

Express

原生的http在某些方面表现不足以应对开发需求,需要使用框架加快开发效率,让我们的代码高度统一。

在node中很多Web开发框架,此处学习express为主

官网:http://expressjs.com/

起步

安装

npm install --save express

hello world

//生成默认的package.json
//npm init -y

var express = require('express')

var app = express()

app.get('/',function (req,res) {
    res.send('hello world')
})

app.listen(3000,function () {

    console.log('express app is running')

})

基本路由

什么是路由(router)?

作为分发的。路由其实就是一张表,表中存储着具体的映射关系。

当请求’/xxx’的时候,执行后面对应的function

路由器

  • 请求方法
  • 请求路径
  • 请求处理函数

get:

//当你以GET方法请求/的时候,执行对应的处理函数
app.get('/',function (req,res) {
    res.send('hello world')
})

app.get('/login',function (req,res) {
    res.send('login page')
})

post:

//当你以POST方法请求/的时候,执行对应的处理函数
app.post('/',function (req,res) {
    res.send('Got a Post request')
})

静态服务

//直接访问public中的资源
app.use(express.static('./public'))

//必须是/a/public目录中的资源具体路径,就是给public起了个别名叫a
//也就是use中第一个参数是在浏览器输入的url,第二个参数是实际的指定的目录名字
app.use('/a/',express.static('./public/'))

//大多数用的方式
//当以/public/开头的时候,去./public/目录中找对应的资源
app.use('/public/',express.static('./public'))

在Express中使用art-template模板引擎

安装

npm install --save art-template
npm install --save express-art-template 

配置

//配置使用art-template模板引擎
//第一个参数表示当渲染以.art结尾的文件的时候,使用art-template模板引擎
//express-art-template是专门用来在Express中把art-template整合到Express中
//虽然我们在这没有需要用到art-template,但是express-art-template依赖了它,所以也要安装一下
// app.engine('art',require('express-art-template'))
app.engine('html',require('express-art-template'))

使用

//Express为Response响应对象提供了一个方法:render
//render方法需要配置模板引擎才能使用
//res.render('html模板名',{模板数据})
//第一个参数不能写路径,默认会去views目录中查找该模板文件
//Express默认认为开发人员把所有的视图文件都放到views中

//如果想修改默认的views目录,可以用app.set('views',render函数的默认路径)

app.get('/',function (req,res) {
    res.render('404.html')

})

修改视图目录路径v

//第一个参数表示需要修改views,第二个参数给出路径
app.set('views',render函数的默认路径)

修改完代码自动重启

使用第三方命名航工具 nodemon 来帮助我们解决频繁修改代码重启服务器问题,它是一个基于nodejs开发的第三方命令行工具,需要独立安装:

//在任意目录执行该命令都可以,因为是配置全局的
npm install --global nodemon

使用

//原来执行
node app.js

//使用nodemon
nodemon app.js

只要是通过nodemon app.js启动的服务,它会监视文件变化,文件发生变化时自动重启服务器

在Express中获取表单GET请求体数据

Express内置了req.query来使用

req.query

在Express中获取表单POST请求体数据

Express中没有内置获取表单POST请求体的API,只能结合插件body-parser实现

安装

npm install --save body-parser

配置

//引包
var bodyParser = require('body-parser')

//只要加入这个配置,则在req请求对象上会多出来一个属性:body
app.use(bodyParser.urlencoded({extended:false}))
app.use(bodyParser.json())

使用

app.use(function(req.res){
   
})

crud简单案例

  • 处理模板
  • 配置开放静态资源
  • 配置模板引擎
  • 简单路由:/students渲染静态页
  • 路由设计
  • 提取路由模块
  • 由于crud都需要处理文件数据,所以封装一个student.js来做crud的封装
  • 实现具体功能
    • 通过路由收到请求
    • 接收请求的数据(get/post)
    • 调用数据操作API处理数据
    • 根据操作结果给客户端发送响应

MongoDB

安装

npm i -S mongoose

demo

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test', {useNewUrlParser: true, useUnifiedTopology: true});

//设计一个模型,即设计一个数据库
//
var Cat = mongoose.model('Cat', { name: String });

//实例化一个Cat
var kitty = new Cat({ name: 'Zildjian' });

//持久化保存kitty实例
kitty.save().then(() => console.log('meow'));

启动mongod

连接mongo

退出连接exit

关闭打Ctrl+C或者直接关闭服务窗口

查看显示所有数据库show dbs

切换到指定数据库,如果没有,会自动创建出来use 数据库名称

查看当前操作的数据库db

插入数据db.集合名.InsertOne({"属性名":"属性值"})

查询

查询所有

//查询所有
User.find({username:'admin'},function (err,ret) {
    if(err){
        console.log('查询失败')
    }else{
        console.log('查询成功')
        console.log(ret)
    }

})

单个查询

//条件查询
//第一个参数是条件,返回的是查到的第一个
User.findOne({username:'admin'},function (err,ret) {
    if(err){
        console.log('查询失败')
    }else{
        console.log('查询成功')
        console.log(ret)
    }

})

删除数据

根据条件删除所有

//删除数据
User.remove({
    username:'admin'
},function (err,ret) {
    if(err){
        console.log('删除失败')
    }else{
        console.log('删除成功')
        console.log(ret)
    }

})

根据条件删除一个

Model.findOneAndRemove(条件,[options],[callback])

根据ID删除一个

Model.findByIdAndRemove(id,[options],[callback])

使用Node操作MySQL数据库

Socket.io

安装npm i -S socket.io

//引包
var app = require('express')()
var server = require('http').Server(app)
var io = require('socket.io')(server)

socket.on表示注册某个事件,socket.emit表示触发某个事件

如果我服务端要获取浏览器的数据,则在服务端注册一个事件,等待浏览器触发;

如果浏览器需要获取服务端的数据,则在浏览器注册一个事件,等待服务端触发。

//注册
//第一个参数是事件名,可以随便取;
//第二个参数是获取到的数据
socket.on('hehe',data=>{
    console.log(data.msg)
})
//触发
//第一个参数是事件名
//
socket.emit('hehe',{
msg:'hello'
)

其他

JSON

JSON 语法规则

  • 数据为 键/值 对。
  • 数据由逗号分隔。
  • 大括号保存对象
  • 方括号保存数

相关函数

函数描述
JSON.parse()用于将一个 JSON 字符串转换为 JavaScript 对象。
JSON.stringify()用于将 JavaScript 值转换为 JSON 字符串。

文件操作路径和模块操作路径

文件操作路径:

//在模块加载中,相对路径中的./不能省
//如果不加的话,会去整个磁盘的根目录找,本文件磁盘根目录是E:/
// ./data是相对与当前目录的
// data 也是相对于当前目录
// ./data是绝对路径
// fs.readFile('./data/a.txt',function (err,data) {
//
//     if(err){
//         console.log('读取失败')
//     }
//
//     console.log(data.toString())
//
// })

模块操作路径:

//require也不能省.
require('./data/foo')

//如果忽略了. 则是当前文件绝对路径
require('/data/foo')

异步编程

回调函数

异步操作情况

这是js带有的,不是node导致的。这种情况必须通过回调函数

  • setTimeout
  • readFile
  • writeFile
  • ajax

回调

//形参名一般叫call
function(x,y,callback){
    setTimeout(function(){
        var ret = x+y
        callback(ret)
    },1000)
}

//上层定义一个
add(10,20,function(ret){
    console.log(ret)
})

promise

  • 异步操作无法保证顺序,如何保证顺序?通过嵌套可以保证执行顺序---->回调地狱
  • 为了解决回调地狱带来的问题,ES6中新增了一个promise
  • promise本身不是异步,是promise中用于存放异步的任务

Promise基础语法:

var fs = require('fs')

//p1是一个承诺实例
var p1 = new Promise(function (resolve, reject) {
  fs.readFile('./data/a.txt', 'utf8', function (err, data) {
    if (err) {
      reject(err)
    } else {
      resolve(data)
    }
  })
})

p1
  .then(function (data) {
    console.log(data)
  }, function (err) {
    console.log('读取文件失败了', err)
  })

Promise解决回调地狱

var fs = require('fs')

var p1 = new Promise(function (resolve, reject) {
  fs.readFile('./data/a.txt', 'utf8', function (err, data) {
    if (err) {
      reject(err)
    } else {
      resolve(data)
    }
  })
})

var p2 = new Promise(function (resolve, reject) {
  fs.readFile('./data/b.txt', 'utf8', function (err, data) {
    if (err) {
      reject(err)
    } else {
      resolve(data)
    }
  })
})

var p3 = new Promise(function (resolve, reject) {
  fs.readFile('./data/c.txt', 'utf8', function (err, data) {
    if (err) {
      reject(err)
    } else {
      resolve(data)
    }
  })
})

p1
  .then(function (data) {
    console.log(data)
    // 当 p1 读取成功的时候
    // 当前函数中 return 的结果就可以在后面的 then 中 function 接收到
    // 当你 return 123 后面就接收到 123
    //      return 'hello' 后面就接收到 'hello'
    //      没有 return 后面收到的就是 undefined
    // 上面那些 return 的数据没什么卵用
    // 真正有用的是:我们可以 return 一个 Promise 对象
    // 当 return 一个 Promise 对象的时候,后续的 then 中的 方法的第一个参数会作为 p2 的 resolve
    // 
    return p2
  }, function (err) {
    console.log('读取文件失败了', err)
  })
  .then(function (data) {
    console.log(data)
    return p3
  })
  .then(function (data) {
    console.log(data)
    console.log('end')
  })

Promise

  • http://es6.ruanyifeng.com/#docs/promise
  • callback hell 回调地狱
  • 回调函数中套了回调函数
  • Promise(EcmaScript 6 中新增了一个语法 API)
  • 容器
    • 异步任务(pending)
    • resolve
    • reject
  • then 方法获取容器的结果(成功的,失败的)
  • then 方法支持链式调用
    / 当 return 一个 Promise 对象的时候,后续的 then 中的 方法的第一个参数会作为 p2 的 resolve
    //
    return p2
    }, function (err) {
    console.log(‘读取文件失败了’, err)
    })
    .then(function (data) {
    console.log(data)
    return p3
    })
    .then(function (data) {
    console.log(data)
    console.log(‘end’)
    })

Promise

+ http://es6.ruanyifeng.com/#docs/promise
+ callback hell 回调地狱
+ 回调函数中套了回调函数
+ Promise(EcmaScript 6 中新增了一个语法 API)
+ 容器
  * 异步任务(pending)
  * resolve
  * reject
+ then 方法获取容器的结果(成功的,失败的)
+ then 方法支持链式调用
+ 可以在 then 方法中返回一个 promise 对象,然后在后面的 then 方法中获取上一个 then 返回的 promise 对象的状态结果
 类似资料: