Node.js Koa2 MongoDB Redis egg.js

216 阅读5分钟

基于Chrome V8引擎的JavaScript运行时

  • V8是chrome的js引擎,以速度著称
  • 运行时:代码的运行环境
  • 之前只有浏览器能运行js

安装node

  • nodejs.cn
  • msi
  • node -v

npm

  • node package manage nodejs软件包管理工具
  • npmjs.com
  • 会随着nodejs一起被安装
  • npm init 生成package.json其中包括项目所有依赖

nodemon

  • 当检测到目录中的文件更改时,它会自动重启node应用程序。
  • npm i nodemon --save-dev
  • 使用了nodemon 就可以使用npm run dev ,只有node,使用node xx.js

common.js ES6模块化

注意导出用{},导入也要用{}接收 image.png

image.png

image.png

image.png

const sum =required(./地址)//多个用大括号
module.exports={sum,text}

区别

image.png

image.png

image.png这个会报错,ES Module必须放在最外层

nodejs debug

image.png

image.png

image.png

image.png

node处理http

image.png

image.png

image.png

image.png

image.png

Get请求

  • 引入queryString
  • queryString.parse(str)产生一个包含键值对的对象

Post请求体通过流的形式

Koa2 框架

  • 安装脚手架 npm i -g koa-generator //-g全局安装
  • 查看是否安装成功 koa2 --version
  • cd到文件夹在命令行输入koa2
  • 在命令行输入npm i / npm run start
  • 访问http://localhost:3000/
  • app.use(...)里都是中间件
  • 每个中间件都是async函数

写一个接口(动态参数)

  • 在routes文件夹下新建js文件
const router = require('koa-router')()
router,prefix('/api')
router.get('/json', async (ctx) => {
  ctx.body = 'api list'
})
//ctx是res,rep的集合。ctx.query可以获取到queryString/ctx.request.body获取请求体
router.get('/:id',loginCheck,async function (ctx,next){
const id = ctx.params.id
const address = await getAddressById(id)
ctx.body = new SuccessModel(address)
})
module.exports = router
//数据库里tabs:[all,a,b,c] in里面的内容表示tabs属性要包含all
const list =await Product.find({shopId,tabs:{
 $in:all
}}).sort( _id:-1)
//数据库里_id是一个字符串,in里是一个数组,表示_id在这个ids数组中就能被找到
const list =await Product.find({shopId,_id:{
 $in:ids
}})
  • 在app.js里引入,注册
const index = require('./routes/index')
app.use(index.routes(), index.allowedMethods())

svg验证码

svg-captcha

 ctx.body = svgCaptcha.create({
    size:5,
    ignoreChars:'0olil',
    color:true,
    noise:3
  }).data

邮箱nodemailer

npm i nodemailer -S 配置文件

module.exports = {
    host: 'smtp.qq.com',
    port: 465,
    secure: true,
    auth: {
      user: '2252647301@qq.com',
      pass: 'aptwbjjnhvlqdjjg'
    }
  };

在route里引入使用

const nodemailer = require('nodemailer');
const config = require('../mailconfig.js');

router.get('/string', async (ctx, next) => {
  const mailOptions = {
    from: '2252647301@qq.com',
    to: '2252647301@qq.com',
    subject: 'Test email',
    text: 'This is a test email',
    html: `<title>HTML email</title>`
  };
  const transporter = nodemailer.createTransport(config);
  try {
    const info = await transporter.sendMail(mailOptions);
    console.log('Email sent: ' + info.response);
    ctx.body = { success: true };
  } catch (error) {
    console.log(error);
    ctx.body = { success: false };
  }
})
后续要封装成方法

密码加密

//封装成一个加密方法
const crypto=require('crypto')
module.exports = str=> crypto.createHash('md5').update(str).digest('hex')

  password: {
        type:String,
        required:true,
        set:value=>md5(value),
        select:false//以后都不会返回密码
    }//这样存入数据库的技术加密后的密码

中间件

app.use(async (ctx, next) => {
  const start = new Date()
  await next()//只有await执行完之后才能执行之后的代码,next()表示执行下一个中间件
  const ms = new Date() - start
  console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
})
//多个中间件(p1,p2),按顺序执行next之前的代码,之后回过头来执行p2里next后的方法,p1里的next之后的方法

MongoDB

  • mongodb.com production 社区服务 msi
  • 接受条框后点Custom
  • 不要勾选MongoDB compass
  • 如果失败重新安装
  • 如果弹出错误忽略

image.png

  • 查看安装的MongoDB文件夹是是否有data log文件夹没有就新建,在data里新建db文件夹,在log里新建mongod.log
  • 在bin文件夹下打开控制台输入启动mongo//mongodb.exe可关,mongod.exe不能关

image.png

  • 图形界面,在官网sofeware下载compass 打开点击connect
  • 如果连接失败,把data里的db里的mongod.lock删除,重新启动

使用compass

collect约等于表,document约等于表里的一项数据

  • create database
  • create collection
  • 查询

image.png

  • 排序 1正序 -1逆序

image.png

MongoDB连接nodejs

  • 安装npm i mongodb --save
// nodejs 连接 mongodb
// 体会 nodejs 连接 mongodb 的能力,不会真正的用到路由上
// mongoose 对接路由的功能

const MongoClient = require('mongodb').MongoClient

const url = 'mongodb://localhost:27017' // 本地启动的 mongodb 服务
const dbName = 'comment1' // 数据库(留言板项目的数据库 )

MongoClient.connect(url, {
    useUnifiedTopology: true,
    useNewUrlParser: true
}, (err, client) => {
    if (err) {
        console.error('mongodb 连接出错', err)
        return
    }
    console.log('mongodb 连接成功')

    // 切换数据库 database
    const db = client.db(dbName)

    // 切换到指定的集合 collection
    const userCollection = db.collection('users')

    // // 查询数据
    // userCollection.find().sort({ _id: -1 }).toArray((err, result) => {
    //     if (err) {
    //         console.error('查询数据出错', err)
    //         return
    //     }
    //     console.log('查询结果', result)
    // })

    // // 新增数据
    // userCollection.insertOne({
    //     username: 'shuangyue',
    //     password: 'abc',
    //     age: 30,
    //     city: 'beijing'
    // }, (err, result) => {
    //     if (err) {
    //         console.error('插入数据出错', err)
    //         return
    //     }
    //     console.log('插入后的返回结果', result.insertedCount, result.insertedId)//插入数量,插入的数据id
    // })

    // // 修改数据
    // userCollection.updateOne(
    //     { username: 'zhangsan' }, // 修改的条件
    //     { $set: { age: 21 , city: 'beijing'} }, // 修改的内容
    //     (err, result) => {
    //         if (err) {
    //             console.error('修改数据出错', err)
    //             return
    //         }
    //         console.log('修改后的返回结果', result.modifiedCount)
    //     }
    // )

    // 删除数据
    userCollection.deleteOne({ username: 'wangwu' }, (err, result) => {
        if (err) {
            console.error('删除数据出错', err)
            return
        }
        console.log('删除成功')
    })

    // 关闭
    // client.close()
})

规范连接 mongoose

image.png

  • 在文件夹路径上唤出控制台,输入npm i mongoose --save
  • 新建文件夹,新建js文件
  • 一定要先启动mongod.exe

image.png

image.png db.js

// 连接数据库(mongodb 的服务端)

const mongoose = require('mongoose')

const url = 'mongodb://localhost:27017'
const dbName = 'comment2'

mongoose.set('useCreateIndex', true)
mongoose.set('useFindAndModify', true)

// 开始连接
mongoose.connect(`${url}/${dbName}`, {
    useNewUrlParser: true,
    useUnifiedTopology: true
})

const conn = mongoose.connection

conn.on('error', err => {
    console.error('mongoose 连接出错', err)
})

module.exports = mongoose

创建schema,定义了model会自动创建collection加一个s model.js

// 数据模型(规范数据格式)

const mongoose = require('./db')

// 定义 User Schema (数据规范)
const UserSchema = mongoose.Schema({
    username: {
        type: String,
        required: true, // 必需
        unique: true // 唯一,不重复
    },
    password: String,
    age: Number,
    city: String,
    // 性别
    gender: {
        type: Number,
        default: 0 // 0 - 保密,1 男,2 女
    }
}, {
    timestamps: true // 时间戳,自动添加文档的创建时间、更新时间
})

// 定义 User Model
const User = mongoose.model('user', UserSchema)

// 定义 Comment Schema
const CommentSchema = mongoose.Schema({
    content: {
        type: String,
        required: true // 必需
    },
    username: String // 用户名
}, { timestamps: true })

// 定义 Comment Model
const Comment = mongoose.model('comment', CommentSchema)

module.exports = {
    User,
    Comment
}

新建文件夹查询新增

// 使用 model 操作数据

const { User } = require('./model')

// 定义一个 async 的匿名函数,并执行。为了里面能用 await
!(async () => {
    // // 新增数据 - 1
    // const zhangsan = new User({
    //     username: 'zhangsan',
    //     password: 'abc',
    //     age: 20,
    //     city: 'beijing',
    //     gender: 1
    // })
    // zhangsan.save()

    // // 新增数据 - 2
    // const lisi = await User.create({
    //     username: 'lisi',
    //     password: '123',
    //     age: 23,
    //     city: 'shanghai'
    // })
    // console.log('lisi 创建完成', lisi)

    // // 查询列表数据,返回的是数组
    // const userList = await User.find({ username: 'zhangsan' })
    // const userList = await User.find().sort({ _id: -1 })
    // console.log('userList 查询结果', userList)

    // 查询单条数据,返回的对象
    const user = await User.findOne({ username: 'zhang' })
    console.log('user 查询结果', user)
})()

新建文件夹更新删除

// 使用 model 操作数据

const { User } = require('./model')

// 定义一个 async 的匿名函数,并执行。为了里面能用 await
!(async () => {
    // // 更新
    // const updateResult = await User.findOneAndUpdate(
    //     { username: 'zhangsan' }, // 条件
    //     { age: 30 }, // 更新的内容
    //     {
    //         new: true // 返回更新后的数据
    //     }
    // )
    // console.log('更新的返回结果', updateResult)

    // // 删除
    // const removeResult = await User.remove({ username: 'lisi' })
    // console.log('删除的返回结果', removeResult)
})()

session cookie

cookie

image.png 在koa2使用cookie

image.png session是在服务端存储的用户信息

image.png

image.png image.png

koa2使用session,解决跨域

  • npm i koa-generic-session --save// npm i koa2-cors --save
  • 通过ctx.session使用session
  • 在appjs写
const session = require('koa-generic-session')
const cors = require('koa2-cors')
//cors配置
app.use(cors({
    origin: 'http://localhost:8080',//前端origin
    credentials:true //允许跨域带cookie
}))
//session配置
app.keys = ['wertwe^&&*UUI123123'] // 秘钥
    // 自定配置了 cookie 和 session
app.use(session({
    // 配置 cookie
    cookie: {
        path: '/', // cookie 在根目录下有效
        httpOnly: true, // cookie 只允许服务端来操作
        maxAge: 24 * 60 * 60 * 1000 // cookie 的过期时间
    }
}))
  • 在controller层设置session ctx.session.userInfo={username}
  • 使用session的数据 const username = ctx.session.userInfo.username

开发流程

数据库

  • mongodb创建数据库和集合
  • 使用mongoose定义schema和model

规范目录

新建文件夹 image.png image.png

  • 移动之后在bin-www修改app require('../src/app')

统一返回类

成功

class SuccessModel{
   constructor(data){
   this.errno = 0
   if(data!=null){
   this.data=data
   }
}
}
module.exports = SuccessModel

失败

class ErrorModel{
   constructor(errno=-1,message='error'){
   this.errno = errno
   this.message=message
}
}
module.exports = ErrorModel

如何使用

ctx.body = new SuccessModel(data)
ctx.body = new ErrorModel(10001,`注册失败 - ${ex.message}`)

登录验证中间件

image.png

router.get('/:id',loginCheck,async function (ctx,next)//loginCheck是中间件,使用前需要require。如果没登陆,不允许访问

Redis

  • GUI Another Redis Desktop Manager
  • 执行redis-server.exe redis.windows.conf
  • 创建一个新cmd,执行redis-cli.exe -h 127.0.0.1 -p 6379
  • 一般redis有一个数据库DB0,但也支持多个数据库例如select 12

cli命令

# 五大常见的数据类型之 String # 五大常见的数据类型之 Hash # 五大常见的数据类型之 List # 五大常见的数据类型之 Set # 五大常见的数据类型之 Zset

发布订阅 subscribe zhang fang 监听多个管道 publish zhang "hello" 发送信息