node入门

目录

一、什么是npm

二、命令行程序

三、commander.js

四、npm包管理

五、node提供一个链接可以下载图片

六、使用node原生http模块写接口

七、使用node原生http模块实现购物车所有接口(不需要装包,不需要中间件)

八、node原生写接口,搭建静态web服务器,处理前端history路由

九、安装FileZilla服务端

十、安装FileZilla客户端

十一、阿里云配置支持FTP

十二、colors

十三、express脚手架

十三、npm view指令

十四、String

十五、node是单线程

十六、错误处理

十七、process.nextTick(callback)

十八、根据下标打印动物

十九、node通过网页读取文件目录

二十、重命名文件或文件夹

二十一、js区分对象函数和数组

二十二、事件触发器

二十三、手动封装事件

二十四、父子进程通信

二十五、docker

二十六、koa

二十七、node如何打断点调试

二十八、mysql里char和varchar的区别

二十九、mysql语句参考

三十、mysql主键

三十一、安装虚拟机


Node.js是单线程的,基于事件循环,非阻塞 IO的。事件循环中使用一个事件队列,在每个时间点上,系统只会处理一个事件,即使电脑有多个CPU核心,也无法同时并行的处理多个事件。因此,node.js适合处理I/O型的应用,不适合那种CPU运算密集型的应用。在I/O型的应用中,给每一个输入输出定义一个回调函数,node.js会自动将其加入到事件轮询的处理队列里,当I/O操作完成后,这个回调函数会被触发,系统会继续处理其他的请求。

一、什么是npm

npm是javascript的包管理工具,是前端模块化下的一个标志性产物。简单地地说,就是通过npm下载模块,复用已有的代码,提高工作效率。

  • 1.从社区的角度:把针对某一特定问题的模块发布到npm的服务器上,供社区里的其他人下载和使用,同时自己也可以在社区里寻找特定的模块的资源,解决问题
  • 2.从团队的角度:有了npm这个包管理工具,复用团队既有的代码也变的更加地方便

新建一个项目,cd进去,然后执行npm init来初始化项目的配置。

在执行npm init之前,有两点需要我们注意一下:

  • 包名不能重复
  • npm对包名的限制:不能有大写字母/空格/下划线

npm init 一路回车

或者:npm init -y

生成的package.json文件:

name和version组成唯一标识。每次发包时都要修改版本号。

description:描述

main:入口,别人安装你的npm包后,import时自动找到这个文件

scripts: 脚本 npm run test或者yarn test

keywords:关键字。放简介,字符串。方便别人查找。

author: 作者

license: 许可证

ISC许可证:ISC许可证_百度百科

MIT许可证:MIT许可证_百度百科

files:files是一个包含项目中的文件的数组。如果命名了一个文件夹,那也会包含文件夹中的文件。

{
  "name": "xu-20191024",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
{
  "name": "xu-20191024",
  "version": "1.0.2",
  "description": "1705E,项目实战",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": ["1705E","1706E"],
  "author": "徐同保",
  "license": "ISC"
}

检查包名是否存在:

https://www.npmjs.com/package/xu-20191025

node入门_第1张图片
 

通过keywords找:

node入门_第2张图片

repository:npm和git关联

  "repository": {
    "type": "git",
    "url": "https://github.com/xutongbao"
  },

node入门_第3张图片

homepage: 项目官网

  "homepage": "https://blog.csdn.net/xutongbao",

node入门_第4张图片

dependencies与devDependencies的区别:

在发布npm包的时候,本身dependencies下的模块会作为依赖,一起被下载;devDependencies下面的模块就不会自动下载了;但对于项目而言,npm install 会自动下载devDependencies和dependencies下面的模块。

当别人使用我们的插件时,peerDependencies就会告诉明确告诉使用方,你需要安装该插件哪个宿主版本:

  "dependencies": {
    "axios": "^0.19.0"
  },
  "devDependencies": {
    "element-ui": "^2.12.0"
  },
  "peerDependencies": {
    "react": "^16.11.0"
  },
  "optionalDependencies": {
    "redux": "^4.0.4"
  }

node入门_第5张图片

参考链接:

https://blog.csdn.net/yq_oxygen/article/details/90040392

如何解决NPM 的UNMET PEER DEPENDENCY问题? - 问答 - 云+社区 - 腾讯云

Peer Dependencies | Node.js

optionalDependencies:

可选依赖,如果有一些依赖包即使安装失败,项目仍然能够运行或者希望npm继续运行,就可以使用optionalDependencies。另外optionalDependencies会覆盖dependencies中的同名依赖包,所以不要在两个地方都写。

bin字段:

参考链接:

package.json bin的作用_feng98ren的专栏-CSDN博客

src/index.js:

请确保你的index.js文件里面最开头写上 #!/usr/bin/env node,否则文件里的脚本不会再Node环境下执行

#!/usr/bin/env node
console.log(1)
  "bin": {
    "myapp": "./src/index.js"
  },

node入门_第6张图片

node入门_第7张图片

全局安装:

node入门_第8张图片

node入门_第9张图片

常用命令:

npm config list

npm config ls -l

安装npm包,安装到dependencies:

npm install commander --save-prod

npm install commander --save

npm install commander -S

npm install commander

npm add commander

npm i commander

安装npm包,安装到devDependencies:

npm install commander --save-dev

npm install commander -D

卸载npm包:

npm uninstall commander

npm unlink commander

npm remove commander

npm rm commander

npm un commander

npm r commander

安装到全局:

npm install create-react-app -g

从全局删除:

npm un create-react-app -g 

二、命令行程序

console.log('hello world!')

node入门_第10张图片

命令行参数:

1)

console.log('hello world!', process.argv[2])

2)

console.log('hello world!', process.argv[1])

三、commander.js

使用.option()方法定义commander的选项options

短标志可以作为单个arg传递,例如-abc相当于-a -b -c。

多词组成的选项,像“--template-engine”会变成 program.templateEngine 等

<>代表必填,[]代表选填,选填可以设置默认值

.version('0.0.1')  使用node app -V查版本

.version('0.0.1', '-v, --version')   使用node app -v或node app --version查版本

使用node app -h或node app --help查看帮助

program.parse方法用于解析process.argv,解析后可以program.xxx使用

const program = require('commander');
 
program
  .version('0.0.1')  //node app -V
  //.version('0.0.1', '-v, --version')   //node app -v
  .option('-d, --debug', 'output extra debugging')
  .option('-s, --small', 'small pizza size')
  .option('-p, --pizza-type ', 'flavour of pizza');
  
program.parse(process.argv);
 
if (program.debug) console.log(program.opts());
console.log('pizza details:');
if (program.small) console.log('- small pizza size');
if (program.pizzaType) console.log(`- ${program.pizzaType}`);

node入门_第11张图片

求和:

const program = require('commander');
 
program
  .version('0.0.1')
  .option('-a, --my-a, ', '第一个值')
  .option('-b, --my-b, ', '第二个值')
  .parse(process.argv);

console.log(program.myA)
console.log(program.myB)
console.log(program.myA*1 + program.myB*1)

求和二:

const program = require('commander');
 
program
  .version('0.0.1')
  .option('-a, --add', '求和')
  .parse(process.argv);
  
if (program.add) {
  let sum = 0
  program.args.forEach(item => {
    sum += item * 1
  })
  console.log(sum)
}

阶乘:

const program = require('commander');
 
program
  .version('0.0.1')
  .option('-a, --add', '求和')
  .option('-f, --factorial ', '阶乘')
  .parse(process.argv);

const factorial = (num) => {
  if (num < 0) {
    return -1
  } else if (num === 0 || num === 1) {
    return 1
  } else {
    return num * factorial(num - 1)
  }
}

if (program.add) {
  let sum = 0
  program.args.forEach(item => {
    sum += item * 1
  })
  console.log(sum)
} else if (program.factorial) {
  let result = factorial(program.factorial)
  console.log(result)
}

node入门_第12张图片

多单词形式:

const program = require('commander');
 
program
  .version('0.0.1')
  .option('-a, --my-add', '求和,多单词形式')
  .parse(process.argv);

//驼峰
if (program.myAdd) {
  let sum = 0
  program.args.forEach(item => {
    sum += item * 1
  })
  console.log(sum)
}


以--no形式开头的选项,代表后面紧跟单词的相反面:

const program = require('commander');
 
program
  .version('0.0.1')
  .option('-a, --no-add', '求和,以--no形式开头的选项,代表后面紧跟单词的相反面')
  .parse(process.argv);

console.log(program)  

if (program.add) {
  let sum = 0
  program.args.forEach(item => {
    sum += item * 1
  })
  console.log(sum)
} else {
  console.log('取反')
}

node入门_第13张图片

command方法,自定义命令

description方法, 命令的描述性语句

action方法,定义命令的回调函数

const program = require('commander');
program
  .version('1.0.0')
  .command('my-add ')
  .option('-a, --add, ', '加法')
	.action((num, cmd) => {
    console.log(num, cmd.add)
  })

program
  .option('-u, --upadte', '更新')  
  .description('描述信息!!!')
  
program.parse(process.argv)

node入门_第14张图片

参考链接:

掘金

commander - npm

四、npm包管理

发布npm包:

1.先注册一个npm账号

2.在终端登录npm账号:npm login 回车输入用户名密码和邮箱

3.新建一个文件夹,cd到新创建的文件夹,使用npm init 生成package.json

4.使用npm publish上传npm包,你会收到一封邮件,在npm官网可以看到刚上传的npm包

yarn更新包:

yarn upgrade

五、node提供一个链接可以下载图片

const fs = require('fs')
const request = require('request')
const program = require('commander')

program
  .option('-d, --down ', '下载')
  .parse(process.argv)
  
let url = program.down

const name = url.slice(url.lastIndexOf('/') + 1)
request(url).pipe(fs.createWriteStream('./' + name));

//node app -d https://n3-q.mafengwo.net/s15/M00/16/18/CoUBGV2xnO6ALntcAB_DZLkVUnY568.png
//node app -d https://p4-q.mafengwo.net/s15/M00/B3/B1/CoUBGV2wYYmAAByNACD9lHJSPKY794.png
//node app --down https://n2-q.mafengwo.net/s15/M00/D0/E4/CoUBGV2vBYGAbzADAB1W_rqrlCM012.png

六、使用node原生http模块写接口

跨域:

所以ajax跨域请求附带自定义响应头时,被请求服务器除了添加Access-Control-Allow-Origin响应头,还得注意注意添加Access-Control-Allow-Headers响应头为对应的自定义请求头的名称,多个自定义请求头用英文状态下逗号分开。

  //跨域
  res.setHeader('Access-Control-Allow-Origin', '*')  //可以把 * 改成 http://localhost:3000 避免xss攻击
  //res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,PATCH,DELETE,HEAD,OPTIONS')   //放行的方法
  res.setHeader('Access-Control-Allow-Headers', 'content-type')  //放行的请求头
  res.setHeader('Access-Control-Max-Age', 1800)  //隔30分钟才发起预检请求,1800秒

url.parse:

url.parse('http://localhost:3000/api/list?id=0')  :

node入门_第15张图片

url.parse('http://localhost:3000/api/list?id=0', true)  :

node入门_第16张图片

204状态码:

请求收到,但返回信息为空。请求执行成功,但是没有数据,浏览器不用刷新页面.也不用导向新的页面。常用于跨域请求。

node入门_第17张图片

node入门_第18张图片

 跨域请求:

node入门_第19张图片

OPTIONS是一种“预检请求”,浏览器在处理跨域访问的请求时如果判断请求为复杂请求,则会先向服务器发送一条预检请求,根据服务器返回的内容浏览器判断服务器是否允许该请求访问。如果web服务器采用cors的方式支持跨域访问,在处理复杂请求时这个预检请求是不可避免的。 

跨域不可避免,预检请求也不可避免,那我们能做的,就是减少预检请求,处理办法就是设置跨域的有效期Access-Control-Max-Age,这样就只会跨域预检一次了。

浏览器的同源策略,就是出于安全考虑,浏览器会限制从脚本发起的跨域HTTP请求(比如异步请求GET, POST, PUT, DELETE, OPTIONS等等),所以浏览器会向所请求的服务器发起两次请求,第一次是浏览器使用OPTIONS方法发起一个预检请求,第二次才是真正的异步请求,第一次的预检请求获知服务器是否允许该跨域请求:如果允许,才发起第二次真实的请求;如果不允许,则拦截第二次请求。

Access-Control-Max-Age用来指定本次预检请求的有效期,单位为秒,,在此期间不用发出另一条预检请求。

例如:

res.setHeader('Access-Control-Max-Age', 1800) 表示隔30分钟才发起预检请求。也就是说,发送两次请求

七、使用node原生http模块实现购物车所有接口(不需要装包,不需要中间件)

const http = require('http')
const fs = require('fs')
const url = require('url')
const { bookNavData, bookMallData, userList } = require('./data')

let bookList = []

const server = http.createServer((req, res) => {
  //跨域
  res.setHeader('Access-Control-Allow-Origin', '*')  //可以把 * 改成 http://localhost:3000 避免xss攻击
  //res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,PATCH,DELETE,HEAD,OPTIONS')   //放行的方法
  res.setHeader('Access-Control-Allow-Headers', 'content-type')  //放行的请求头
  res.setHeader('Access-Control-Max-Age', 1800)  //隔30分钟才发起预检请求,1800秒
  
  let { pathname } = url.parse(req.url, true)
  console.log(req.method, url.parse(req.url, true))
  console.log(pathname)

  if (req.url === '/') {   //hello world!
    res.writeHead(200, { 'Content-Type': 'text/html' })
    res.write('hello world!')
    res.end()
  } else if (req.url === '/home') {  //路由
    res.writeHead(200, { 'Content-Type': 'text/html' })
    const home = fs.readFileSync('./index.html')   //读文件
    res.end(home)
  } else if (req.url === '/banner01') {   //图片
    //res.writeHead(200, { 'Content-Type': 'image/jpg' })
    const banner01 = fs.readFileSync('./images/banner01.jpg')  //读图片
    res.end(banner01)
  } else if (req.method == 'OPTIONS') { //跨域,处理options请求
    res.writeHead(204) //204 无内容
    res.end()
  } else if (req.method === 'POST' && pathname === '/api/login') { //登录
    let body = ''

    // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到body变量中
    req.on('data', (chunk) => {
      body += chunk
    })

    // 在end事件触发后,通过JSON.parse将body解析为真正的POST请求格式
    req.on('end', () =>{
      body = JSON.parse(body)
      let { username, password } = body
      let user = userList.find(item => item.username === username)
      res.writeHead(200, { 'Content-Type': 'application/json' })
      if (user) {
        if (user.password === password) {
          res.write(JSON.stringify({
            code: 200,
            data: {
              username
            },
            message: '登录成功'
          }))
        } else {
          res.write(JSON.stringify({
            code: 400,
            message: '密码错误'
          }))
        }
      } else {
        res.write(JSON.stringify({
          code: 400,
          data: body,
          message: '用户不存在'
        }))
      }
      res.end()
    })
  } else if (pathname === '/api/nav') {  //导航
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({
      code: 200,
      data: bookNavData,
      message: '导航'
    }))
  } else if (pathname === '/api/list') {  //列表
    let { id } = url.parse(req.url, true).query
    let list = bookMallData.find(item => item.id == id).list
    list.forEach(item => {
      if (bookList.findIndex(book => book.id === item.id) >= 0) {
        item.is_in_my_book = true
      } else {
        item.is_in_my_book = false
      }
    })
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({
      code: 200,
      data: list,
      message: '列表'
    }))
  } else if (pathname === '/api/get_book_list') { //书包
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({
      code: 200,
      data: bookList,
      message: '书包'
    }))
  } else if (pathname === '/api/add') {  //添加到书包
    let body = ''
    req.on('data', (chunk) => {
      body += chunk
    })

    req.on('end', () => {
      body = JSON.parse(body)
      let { item } = body
      bookList.push(item)
      res.writeHead(200, { 'Content-Type': 'application/json' })
      res.end(JSON.stringify({
        code: 200,
        data: bookList,
        message: '添加成功'
      }))
    })
  } else if (pathname === '/api/detail') {   //详情
    let { id } = url.parse(req.url, true).query
    let detail
    bookMallData.forEach(listItem => {
      listItem.list.forEach(book => {
        if (book.id == id) {
          detail = book
        }
      })
    })

    if (bookList.find(book => book.id === detail.id)) {
      detail.is_in_my_book = true
    } else {
      detail.is_in_my_book = false
    }
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({
      code: 200,
      data: detail,
      message: '详情'
    }))
  } else if (pathname === '/api/delete') {  //删除
    let body = ''
    req.on('data', (chunk) => {
      body +=chunk
      console.log('chunk:', chunk)
    })
    req.on('end', () => {
      body = JSON.parse(body)
      let { ids } = body
      bookList = bookList.filter(item => !ids.find(id => id === item.id))
      res.writeHead(200, { 'Content-Type': 'application/json' })
      res.end(JSON.stringify({
        code: 200,
        data: bookList,
        message: '删除成功'
      }))
    })
  } else if (pathname === '/api/update') {
    let body = ''
    req.on('data', (chunk) => {
      body += chunk
    })
    req.on('end', () => {
      body = JSON.parse(body)
      let { bookListNew } = body
      bookList = bookListNew
      res.writeHead(200, { 'Content-Type': 'application/json' })
      res.end(JSON.stringify({
        code: 200,
        data: bookList,
        message: '更新成功'
      }))
    })
  } else {   //404
    res.writeHead(404, { 'Content-Type': 'text/html' })
    res.end('404')
  }
})

server.listen(9999, () => {
  console.log(9999)
})

八、node原生写接口,搭建静态web服务器,处理前端history路由

参考链接:

connect - npm

connect-history-api-fallback - npm

项目上线啦:

http://39.97.238.175/index/home

const http = require('http')
const url = require('url')
const path = require('path')
const fs = require('fs')
const connect = require('connect')
const history = require('connect-history-api-fallback')
const { bookNavData, bookMallData, userList } = require('./data')

let bookList = []

//使原生http模块可以使用中间件功能
const app = connect()

//处理react前端路由(BrowserRoute),vue前端路由(mode:history)
app.use(history())

//跨域,静态web服务器
app.use((req, res, next) => {
  //跨域
  res.setHeader('Access-Control-Allow-Origin', '*')  //可以把 * 改成 http://localhost:3000 避免xss攻击
  //res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,PATCH,DELETE,HEAD,OPTIONS')   //放行的方法
  res.setHeader('Access-Control-Allow-Headers', 'content-type')  //放行的请求头
  res.setHeader('Access-Control-Max-Age', 1800)  //隔30分钟才发起预检请求,1800秒

  let { pathname } = url.parse(req.url, true)
  let extName = path.extname(pathname)
  console.log(pathname, extName)
  if (pathname === '/') {
    pathname = '/index.html'
  }
  if  (pathname.indexOf('/api') >= 0) {
    next()
  } else {
    fs.readFile(`./public/${pathname}`, (err, data) => {
      if (err) {
        res.writeHead(404, {'Content-Type': 'text/html' })
        res.end('404')
      } else {
        if (extName === '.css') {
          res.writeHead(200, {'Content-Type': 'text/css'})
        }
        res.end(data)
      }
    })
  }
})

//接口
app.use((req, res) => {
  let { pathname } = url.parse(req.url, true)

  if (req.method == 'OPTIONS') { //跨域,处理options请求
    res.writeHead(204) //204 无内容
    res.end()
  } else if (req.method === 'POST' && pathname === '/api/login') { //登录
    let body = ''

    // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到body变量中
    req.on('data', (chunk) => {
      body += chunk
    })

    // 在end事件触发后,通过JSON.parse将body解析为真正的POST请求格式
    req.on('end', () =>{
      body = JSON.parse(body)
      let { username, password } = body
      let user = userList.find(item => item.username === username)
      res.writeHead(200, { 'Content-Type': 'application/json' })
      if (user) {
        if (user.password === password) {
          res.write(JSON.stringify({
            code: 200,
            data: {
              username
            },
            message: '登录成功'
          }))
        } else {
          res.write(JSON.stringify({
            code: 400,
            message: '密码错误'
          }))
        }
      } else {
        res.write(JSON.stringify({
          code: 400,
          data: body,
          message: '用户不存在'
        }))
      }
      res.end()
    })
  } else if (pathname === '/api/nav') {  //导航
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({
      code: 200,
      data: bookNavData,
      message: '导航'
    }))
  } else if (pathname === '/api/list') {  //列表
    let { id } = url.parse(req.url, true).query
    let list = bookMallData.find(item => item.id == id).list
    list.forEach(item => {
      if (bookList.findIndex(book => book.id === item.id) >= 0) {
        item.is_in_my_book = true
      } else {
        item.is_in_my_book = false
      }
    })
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({
      code: 200,
      data: list,
      message: '列表'
    }))
  } else if (pathname === '/api/get_book_list') { //书包
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({
      code: 200,
      data: bookList,
      message: '书包'
    }))
  } else if (pathname === '/api/add') {  //添加到书包
    let body = ''
    req.on('data', (chunk) => {
      body += chunk
    })

    req.on('end', () => {
      body = JSON.parse(body)
      let { item } = body
      bookList.push(item)
      res.writeHead(200, { 'Content-Type': 'application/json' })
      res.end(JSON.stringify({
        code: 200,
        data: bookList,
        message: '添加成功'
      }))
    })
  } else if (pathname === '/api/detail') {  //详情
    let { id } = url.parse(req.url, true).query
    let detail
    bookMallData.forEach(listItem => {
      listItem.list.forEach(book => {
        if (book.id == id) {
          detail = book
        }
      })
    })

    if (bookList.find(book => book.id === detail.id)) {
      detail.is_in_my_book = true
    } else {
      detail.is_in_my_book = false
    }
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({
      code: 200,
      data: detail,
      message: '详情'
    }))
  } else if (pathname === '/api/delete') {  //删除
    let body = ''
    req.on('data', (chunk) => {
      body +=chunk
      console.log('chunk:', chunk)
    })
    req.on('end', () => {
      body = JSON.parse(body)
      let { ids } = body
      bookList = bookList.filter(item => !ids.find(id => id === item.id))
      res.writeHead(200, { 'Content-Type': 'application/json' })
      res.end(JSON.stringify({
        code: 200,
        data: bookList,
        message: '删除成功'
      }))
    })
  } else if (pathname === '/api/update') {  //更新
    let body = ''
    req.on('data', (chunk) => {
      body += chunk
    })
    req.on('end', () => {
      body = JSON.parse(body)
      let { bookListNew } = body
      bookList = bookListNew
      res.writeHead(200, { 'Content-Type': 'application/json' })
      res.end(JSON.stringify({
        code: 200,
        data: bookList,
        message: '更新成功'
      }))
    })
  } else {   //404
    res.writeHead(404, { 'Content-Type': 'text/html' })
    res.end('404')
  }
})

const server = http.createServer(app)

server.listen(9998)
console.log(9998)

九、安装FileZilla服务端

下载filezilla客户端和服务端:

FileZilla - The free FTP solution

安装server端:

node入门_第20张图片

node入门_第21张图片

node入门_第22张图片

node入门_第23张图片

node入门_第24张图片

node入门_第25张图片

node入门_第26张图片

node入门_第27张图片

node入门_第28张图片

node入门_第29张图片

node入门_第30张图片

node入门_第31张图片

node入门_第32张图片

十、安装FileZilla客户端

node入门_第33张图片

node入门_第34张图片

node入门_第35张图片

node入门_第36张图片

node入门_第37张图片

node入门_第38张图片

node入门_第39张图片

node入门_第40张图片

node入门_第41张图片

node入门_第42张图片

node入门_第43张图片

十一、阿里云配置支持FTP

node入门_第44张图片

node入门_第45张图片

node入门_第46张图片

node入门_第47张图片

node入门_第48张图片

十二、colors

装包:

yarn add colors

node代码:

const color = require('colors')

console.log('hello world!'.green)
console.log('hello world!'.underline.red)
console.log('hello world!'.inverse)
console.log('hello world!'.rainbow)

效果:

node入门_第49张图片

十三、express脚手架

装包:

yarn global add express-generator

运行:

express --view=pug m-express-demo

cd m-express-demo

yarn

yarn start

node入门_第50张图片

十三、npm view指令

显示npm包的相关信息:

npm view axios

npm show axios

npm info axios

npm v axios

node入门_第51张图片

查询npm包的所有版本号:

npm view axios versions

node入门_第52张图片

查询npm包的所有版本号和所有依赖:

npm view axios versions dependencies

node入门_第53张图片

十四、String

    let a = 'hello'
    let b = 'hello'
    let c = new String('hello')

    console.log(a === b)  //true
    console.log(a === c)  //false
    console.log(typeof a) //string
    console.log(typeof c) //object
    console.log(a instanceof String) //false
    console.log(c instanceof String) //true

十五、node是单线程

    let start = Date.now()
    console.log(start)
    setTimeout(() => {
      console.log(Date.now() - start)  //1000左右
      for (let i = 0; i < 5000000000; i++) {
        
      }
    }, 1000)
    setTimeout(() => {
      console.log(Date.now() - start)  //大于2000,具体大多少,取决于上面for循序的次数
    }, 2000)

node入门_第54张图片

十六、错误处理

错误堆栈:

test.js:

const a = () => {
  console.log(obj.name)
}

const b = () => {
  a()
}

b()

node入门_第55张图片

在异步函数中,堆栈信息将丢失:

const a = () => {
  setTimeout(() => {
    console.log(obj.name)
  }, 10)
}

const b = () => {
  a()
}

b()

node入门_第56张图片

uncaughtException捕获异常(丢失了错误发生位置的上下文):

process.on('uncaughtException', (error) => {
  console.error("xu:", error)
})

const a = () => {
  console.log(obj.name)
}

const b = () => {
  a()
}

b()

node入门_第57张图片

domain模块:

当res是上下文时,可以把错误信息返回给前端!

参考链接:Node.js Domain 模块 | 菜鸟教程

const domain = require('domain')

const d = domain.create()

let name = 'tom'


d.on('error', (error) => {
  console.log('上下文环境:', name)
  console.log('domain捕获到的异常信息:', error.stack)
})

d.run(() => {
  console.log(obj.name)
})

node入门_第58张图片

十七、process.nextTick(callback)

在事件循环的下一次循环中调用 callback 回调函数。

console.log(1)

process.nextTick(() => {
  console.log(2)
})

console.log(3)

十八、根据下标打印动物

const program = require('commander')
const fs = require('fs')
const packageInfo = require('./package.json')

program.version(packageInfo.version)
  .option('-i, --index ', "下标")

program.parse(process.argv)

console.log(program.index)

fs.readFile('./animals.txt', 'utf-8', (err, data) => {
  if (err) {
    return
  }
  let animalsArr = data.split('===============++++SEPERATOR++++====================')
  console.log(animalsArr[program.index])
})

node入门_第59张图片

动物数据:

链接:百度网盘 请输入提取码
提取码:g1sv

十九、node通过网页读取文件目录

const program = require('commander')
const fs = require('fs')
const http = require('http')
const { exec } = require('child_process')
const path = require('path')
const packageInfo = require('./package.json')

program.version(packageInfo.version)
  .option('-p, --port ', "set port")

program.parse(process.argv)

let PORT = program.port || 8000

const app = http.createServer((req, res) => {
  let rootPath = process.cwd()
  if (req.url === '/favicon.ico') {
    res.end()
    return
  }
  let myPath = path.join(rootPath, req.url)
  console.log('a', myPath)
  if (fs.statSync(myPath).isFile()) {
    fs.readFile(myPath, 'utf8', (err, data) => {
      res.end(data)
    })
  } else {
    let list = fs.readdirSync(myPath).map(filePath => {
      return ``
    }).join('')
    let html = fs.readFileSync(__dirname + '/public/index.html', 'utf8')
    html = html.replace("{{list}}", list)
    res.end(html)
  }
})

app.listen(PORT, () => {
  //exec(`start http://localhost:${PORT}`)
})

node入门_第60张图片

node入门_第61张图片

二十、重命名文件或文件夹

const fs = require('fs')
const path = require('path')

let target = process.argv[2]
let rename = process.argv[3]
let rootPath = process.cwd()

target = path.join(rootPath, target)
if (fs.existsSync(target)) {
  fs.renameSync(target, path.join(rootPath, rename))
} else {
  console.log('文件或文件夹不存在')
}

二十一、js区分对象函数和数组

const fs = require('fs')
const path = require('path')

let obj = {}

console.log(obj instanceof Object)  //true
console.log(typeof obj)  //object
console.log(Object.prototype.toString.call(obj))  //[object Object]

let fun = () => {}

console.log(fun instanceof Function)  //true
console.log(fun instanceof Object)  //true
console.log(typeof fun)   //function
console.log(Object.prototype.toString.call(fun))  //[object Function]

let arr = []

console.log(arr instanceof Array)  //true
console.log(arr instanceof Object)  //true
console.log(typeof arr)   //object

console.log(Object.prototype.toString.call(arr))  //[object Array]

node入门_第62张图片

二十二、事件触发器

const EventEmitter = require('events')
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()

myEmitter.on('myEventName', (a, b) => {
  console.log(a, b)
})

myEmitter.emit('myEventName', 1, 2)
myEmitter.emit('myEventName', 1, 2)

myEmitter.once('myOnce', () => {
  console.log('只触发一次')
})

myEmitter.emit('myOnce')
myEmitter.emit('myOnce')

myEmitter.on('error', (err) => {
  console.error(err)
})

myEmitter.emit('error', new Error('错误'))

node入门_第63张图片

二十三、手动封装事件

class MyEmitter {
  constructor() {
    this.events = {}
  }
  on(eventName, callback) {
    if (this.events[eventName]) {
      this.events[eventName].push(callback)
    } else {
      this.events[eventName] = [callback]
    }
  }

  emit(eventName, ...arg) {
    let callbackArr = this.events[eventName]
    callbackArr && callbackArr.forEach(item => {
      if (Object.prototype.toString.call(item) === '[object Function]') {
        item(...arg)
      } else if (Object.prototype.toString.call(item) === '[object Object]') {
        if (item.once) {
          item.callback(...arg)
          item.callback = () => {}
        }
      }
    })
  }

  once(eventName, callback) {
    if (this.events[eventName]) {
      this.events[eventName].push({
        once: true,
        callback
      })
    } else {
      this.events[eventName] = [{
        once: true,
        callback
      }]
    }
  }
}
const myEmitter = new MyEmitter()

module.exports = myEmitter

二十四、父子进程通信

app.js:

const child_process = require('child_process')

const child = child_process.fork('./compute.js')

child.send({ type: 'start' })
child.on('message', (action) => {
  if (action.type === 'sum') {
    console.log('子进程计算出来的结果:', action.sum)
    process.exit()
    
  }
})

process.on('exit', () => {
  console.log('主进程结束')
})

console.log('运行到这里')

compute.js:


const computeSum = () => {
  let sum = 0
  for (let i = 0; i < 1000000; i++) {
    sum += i
  }
  return sum
}

process.on('message', (action) => {
  if (action.type === 'start') {
    let sum = computeSum()
    process.send({
      type: 'sum',
      sum
    })
  }
})

node入门_第64张图片

二十五、docker

docker:码头工人

doctor:医生

docker toolbox下载链接:Releases · docker-archive/toolbox · GitHub

docker toolbox 国内下载地址:Index of /docker-toolbox/windows/docker-toolbox/

docker官网:Empowering App Development for Developers | Docker

docker hub官网:Docker Hub

docker菜鸟教程:Docker 教程 | 菜鸟教程

安装:

node入门_第65张图片

node入门_第66张图片

node入门_第67张图片

node入门_第68张图片

node入门_第69张图片

node入门_第70张图片

node入门_第71张图片

node入门_第72张图片

node入门_第73张图片

下载最新版的 boot2docker.iso 放在本地缓存文件夹里,否则启动时会联网下载最新版的,切很难下载下来,会报错

可以去百度云盘下载:

链接:百度网盘 请输入提取码
提取码:esp0

也可以去github下载:

https://github.com/boot2docker/boot2docker/releases

 
node入门_第74张图片

hello world:

docker run ubuntu:15.10 /bin/echo "hello world"

node入门_第75张图片

运行交互式的容器:

docker run -i -t ubuntu:15.10 /bin/bash

ctrl + D 或者 exit 退出

docker run -d ubuntu:15.10 /bin/sh -c "while true; do echo hello; sleep 5;done"

docker ps

docker logs determined_meitner

node入门_第76张图片

进入容器:

docker attach determined_meitner

二十六、koa

koa:框架

koa-router:路由

koa-bodyparser:解析post

koa2-cors:跨域

koa-static:静态资源

koa-logger:日志

@koa/multer multer:上传文件

koa:

const Koa = require('koa')
const app = new Koa()
const { bookNavData } = require('./data')

app.use(ctx => {
  ctx.body = {
    code: 200,
    data: bookNavData,
    message: '导航'
  }
})

app.listen(84)
console.log(84)

koa-router:

const Koa = require('koa')
const Router = require('koa-router')
const app = new Koa()
const router = new Router()
const { bookNavData } = require('./data')

router.get('/api/nav', ctx => {
  ctx.body = {
    code: 200,
    data: bookNavData,
    message: '导航'
  }
})

app.use(router.routes())

app.listen(84)
console.log(84)

koa-bodyparser:

const Koa = require('koa')
const Router = require('koa-router')
const bodyParser = require('koa-bodyparser')
const app = new Koa()
const router = new Router()
const { bookNavData } = require('./data')

//用户列表
const userList = [{
  id: '001',
  username: 'admin',
  password: '123456'
}, {
  id: '002',
  username: 'xu',
  password: '123'
}, {
  id: '003',
  username: 'a',
  password: '123456'
}]

//登录
router.post('/api/login', ctx => {
  let { username, password } = ctx.request.body
  let user = userList.find(item => item.username === username)
  if (user) {
    if (user.password === password) {
      ctx.body = {
        code: 200,
        data: {
          username
        },
        message: '登录成功'
      }
    } else {
      ctx.body = {
        code: 400,
        message: '密码错误'
      }
    }
  } else {
    ctx.body = {
      code: 400,
      message: '用户不存在'
    }
  }
})

//导航
router.get('/api/nav', ctx => {
  ctx.body = {
    code: 200,
    data: bookNavData,
    message: '导航'
  }
})

app.use(bodyParser())
app.use(router.routes())

app.listen(84)
console.log(84)

koa-compose:

const Koa = require('koa')
const Router = require('koa-router')
const bodyParser = require('koa-bodyparser')
const cors = require('koa2-cors')
const static = require('koa-static')
const logger = require('koa-logger')
const compose = require('koa-compose')
const app = new Koa()
const router = new Router()
const { bookNavData } = require('./data')

//用户列表
const userList = [{
  id: '001',
  username: 'admin',
  password: '123456'
}, {
  id: '002',
  username: 'xu',
  password: '123'
}, {
  id: '003',
  username: 'a',
  password: '123456'
}]

//登录
router.post('/api/login', ctx => {
  let { username, password } = ctx.request.body
  let user = userList.find(item => item.username === username)
  if (user) {
    if (user.password === password) {
      ctx.body = {
        code: 200,
        data: {
          username
        },
        message: '登录成功'
      }
    } else {
      ctx.body = {
        code: 400,
        message: '密码错误'
      }
    }
  } else {
    ctx.body = {
      code: 400,
      message: '用户不存在'
    }
  }
})

//导航
router.get('/api/nav', ctx => {
  ctx.body = {
    code: 200,
    data: bookNavData,
    message: '导航'
  }
})

// //跨域
// app.use(cors())
// //日志
// app.use(logger())
// //解析post请求
// app.use(bodyParser())
// //静态资源
// app.use(static(__dirname + '/public'))
// //路由
// app.use(router.routes())

const middlewares = compose([cors(), logger(), bodyParser(), static(__dirname + '/public'), router.routes()])
app.use(middlewares)


app.listen(84)
console.log(84)

GitHub - koajs/compose: Middleware composition utility

koa-router:

const Router = require('koa-router')

const router = new Router()

//导航
router.get('/api/nav', (ctx, next) => {
  ctx.body = {
    code: 200,
    data: bookNavData,
    message: '导航'
  }
})

//登录
router.post('/api/login', async (ctx, next) => {
  let { username, password } = ctx.request.body
    
  ctx.body = {
    code: 200,
    data: {
      username
    },
    message: '登录成功'
  }
})


//路由
app.use(router.routes())

koa-router - npm

koa-static:

const static = require('koa-static')

//静态资源
//app.use(static('public'))
app.use(static(__dirname + '/public'))

@koa/multer multer(上传单个文件):

const Koa = require('koa')
const Router = require('koa-router')
const bodyParser = require('koa-bodyparser')
const cors = require('koa2-cors')
const static = require('koa-static')
const logger = require('koa-logger')
const compose = require('koa-compose')
const multer = require('@koa/multer')
const app = new Koa()
const router = new Router()
const { bookNavData } = require('./data')

//用户列表
const userList = [{
  id: '001',
  username: 'admin',
  password: '123456'
}, {
  id: '002',
  username: 'xu',
  password: '123'
}, {
  id: '003',
  username: 'a',
  password: '123456'
}]

const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, __dirname + '/upload')
  },
  filename: (req, file, cb) => {
    cb(null, `${Date.now()} - ${file.originalname}`)
  }
})

const upload = multer({ storage })

//登录
router.post('/api/login', ctx => {
  let { username, password } = ctx.request.body
  let user = userList.find(item => item.username === username)
  if (user) {
    if (user.password === password) {
      ctx.body = {
        code: 200,
        data: {
          username
        },
        message: '登录成功'
      }
    } else {
      ctx.body = {
        code: 400,
        message: '密码错误'
      }
    }
  } else {
    ctx.body = {
      code: 400,
      message: '用户不存在'
    }
  }
})

//导航
router.get('/api/nav', ctx => {
  ctx.body = {
    code: 200,
    data: bookNavData,
    message: '导航'
  }
})

//上传文件
router.post('/api/upload', upload.single('img'), ctx => {
  ctx.body = {
    code: 200,
    data: ctx.request.file,
    message: '上传成功'
  }
})

// //跨域
// app.use(cors())
// //日志
// app.use(logger())
// //解析post请求
// app.use(bodyParser())
// //静态资源
// app.use(static(__dirname + '/public'))
// //路由
// app.use(router.routes())

const middlewares = compose([cors(), logger(), bodyParser(), static(__dirname + '/public'), router.routes()])
app.use(middlewares)


app.listen(84)
console.log(84)

@koa/multer multer(上传多个文件):

const Koa = require('koa')
const Router = require('koa-router')
const bodyParser = require('koa-bodyparser')
const cors = require('koa2-cors')
const static = require('koa-static')
const logger = require('koa-logger')
const compose = require('koa-compose')
const multer = require('@koa/multer')
const app = new Koa()
const router = new Router()
const { bookNavData } = require('./data')

//用户列表
const userList = [{
  id: '001',
  username: 'admin',
  password: '123456'
}, {
  id: '002',
  username: 'xu',
  password: '123'
}, {
  id: '003',
  username: 'a',
  password: '123456'
}]

const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, __dirname + '/upload')
  },
  filename: (req, file, cb) => {
    cb(null, `${Date.now()} - ${file.originalname}`)
  }
})

const upload = multer({ storage })

//登录
router.post('/api/login', ctx => {
  let { username, password } = ctx.request.body
  let user = userList.find(item => item.username === username)
  if (user) {
    if (user.password === password) {
      ctx.body = {
        code: 200,
        data: {
          username
        },
        message: '登录成功'
      }
    } else {
      ctx.body = {
        code: 400,
        message: '密码错误'
      }
    }
  } else {
    ctx.body = {
      code: 400,
      message: '用户不存在'
    }
  }
})

//导航
router.get('/api/nav', ctx => {
  ctx.body = {
    code: 200,
    data: bookNavData,
    message: '导航'
  }
})

//上传文件
router.post('/api/upload', upload.array('img', 9), ctx => {
  ctx.body = {
    code: 200,
    data: ctx.request.files,
    message: '上传成功'
  }
})

// //跨域
// app.use(cors())
// //日志
// app.use(logger())
// //解析post请求
// app.use(bodyParser())
// //静态资源
// app.use(static(__dirname + '/public'))
// //路由
// app.use(router.routes())

const middlewares = compose([cors(), logger(), bodyParser(), static(__dirname + '/public'), router.routes()])
app.use(middlewares)


app.listen(84)
console.log(84)

二十七、node如何打断点调试

inspect    检查;查看;审视;视察

指令解释:

//在 host:port 上激活检查器
--inspect[=[host:]port]   



//在 host:port 上激活检查器,并默认在第一行打断点
--inspect-brk[=[host:]port]  

 

node入门_第77张图片

 参考链接:

命令行选项 | Node.js API 文档

//使用node启动
node --inspect-brk app

//使用nodemon启动
nodemon --inspect-brk app

//默认不在第一行打断点
nodemon --inspect app

 --nolazy没有官方文档,可以参考这个链接:

What does the Node.js `--nolazy` flag mean? - Stack Overflow

 node入门_第78张图片

chrome地址栏里输入:

chrome://inspect/#devices

node入门_第79张图片

打断点:

node入门_第80张图片

看日志:

node入门_第81张图片

二十八、mysql里char和varchar的区别

varchar(100)  100 代表一百个字符

char是固定长度的,而varchar会根据具体的长度来使用存储空间

参考链接:mysql varchar(n) 问题 char与varchar选择问题_超Sir丶的博客-CSDN博客

二十九、mysql语句参考

U

-- 选择数据库
USE demo;
USE test2;

-- 删除数据库
DROP TABLE `admin`;

-- 管理员
CREATE TABLE `admin` (
	`uid` INT UNSIGNED AUTO_INCREMENT,
	`username` VARCHAR(20) NOT NULL,
	`password` VARCHAR(30) NOT NULL,
	`create_time` DATETIME NOT NULL,
	PRIMARY KEY (`uid`)
);

-- 老师
DROP TABLE `teacher`;
CREATE TABLE `teacher` (
	`uid` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY COMMENT '老师的ID',
	`username` VARCHAR(20) NOT NULL COMMENT '老师登录平台的用户名',
	`password` VARCHAR(30) NOT NULL COMMENT '老师登录平台的密码',
	`age` INT UNSIGNED COMMENT '老师的年龄',
	`gender` enum('男', '女', '保密') DEFAULT '保密' COMMENT '老师的性别',
	`email` VARCHAR(50) COMMENT '邮箱',
	`create_time` DATETIME NOT NULL COMMENT '老师加入平台的时间'
);

-- 显示表格各列的信息,包括注释
SHOW FULL COLUMNS FROM teacher;

-- 查
SELECT * FROM `admin`;
SELECT username FROM admin;
SELECT `password`, `username` FROM admin WHERE uid = 1;

-- LIKE 可以做模糊搜索 AND 表示并且  OR 表示或者
SELECT * FROM admin WHERE username LIKE '%admi%';
SELECT * FROM admin WHERE username LIKE '%a%' AND `password` = '123';
SELECT * FROM admin WHERE username LIKE '%a%' OR `password` = '123';

-- 查询以x开头的两位用户名
SELECT * FROM admin WHERE username LIKE 'x_';

-- 查询用户名中不包含a的
SELECT * FROM admin WHERE username NOT LIKE '%a%';

-- 用户名中包含x或者包含u或者包含a或者包含l
SELECT * FROM admin WHERE username RLIKE '[xual]';

-- REGEXP 和 RLIKE 一样
SELECT * FROM admin WHERE username REGEXP '[xa]';

-- 包含a
SELECT * FROM admin WHERE username RLIKE '[a]+';
SELECT * FROM admin WHERE username RLIKE 'a+';

-- a开头
SELECT * FROM admin WHERE username RLIKE '^[a]+';

-- x或a开头
SELECT * FROM admin WHERE username RLIKE '^[xa]+';

-- 查询以x开头的两位用户名, "."匹配单个字符
SELECT * FROM admin WHERE username RLIKE 'x.';

SELECT username, `password`
FROM admin



-- 排序 默认升序, 升序:asc ascend ,降序:desc descend
SELECT * FROM admin ORDER BY username;
SELECT * FROM admin ORDER BY username ASC;
SELECT * FROM admin ORDER BY username DESC;

-- 先用创建时间排序,再用用户名排序
SELECT * FROM admin ORDER BY create_time DESC, username ASC;

-- 只要前两条
SELECT * 
FROM admin 
LIMIT 2;

-- 分页 第一个数是起始点,从零开始,第二个数是每页的数量
SELECT * FROM admin LIMIT 0, 4;
SELECT * FROM admin LIMIT 4, 1;

-- 和 LIMIT 4, 1相同
SELECT * FROM admin LIMIT 1 OFFSET 4;


-- 排序后分页
SELECT * FROM admin ORDER BY username ASC LIMIT 1, 2;

-- 数量
SELECT COUNT(*) FROM admin;

-- 完全限定的表名
SELECT admin.username FROM admin;

-- 增
INSERT INTO `admin` (`username`, `password`, `create_time`) VALUES ('admin', '123456', '2019-02-20 10:36:06');

-- 增,自动获取系统时间
INSERT INTO `admin` (`username`, `password`, `create_time`) VALUES ('xu', '123', NOW());
INSERT INTO `admin` (`username`, `password`, `create_time`) VALUES ('zhangsan', '123', NOW());
INSERT INTO `admin` (`username`, `password`, `create_time`) VALUES ('lisi', '123', NOW());
INSERT INTO `admin` (`username`, `password`, `create_time`) VALUES ('wangwu', '123', NOW());

-- 1号老师张三 男
INSERT INTO `teacher` 
	(`username`, `password`, `age`, `gender`, `email`, `create_time`) 
	VALUES ('zhangsan', 'zhangsan', 30, '男', '[email protected]', NOW());

-- 2号老师李四 女
INSERT INTO `teacher` 
	(`username`, `password`, `age`, `gender`, `email`, `create_time`) 
	VALUES ('lisi', 'lisi123', 31, '女', '[email protected]', NOW());

-- 3号老师王五 性别保密
INSERT INTO `teacher` 
	(`username`, `password`, `age`, `email`, `create_time`) 
	VALUES ('wangwu', 'wangwu123', 32, '[email protected]', NOW());

-- 4号老师xu 既是老师又是管理员
INSERT INTO `teacher`
	(`username`, `password`, `age`, `email`, `create_time`) 
	VALUES ('xu', 'xu', 30, '[email protected]', NOW());

INSERT INTO `teacher`
	(`username`, `password`, `age`, `email`, `create_time`)
	VALUES ('lilei', 'lilei', 36, '[email protected]', NOW());

SELECT * FROM teacher;
SELECT * FROM teacher WHERE age > 30;
SELECT * FROM teacher WHERE age >= 30;
SELECT * FROM teacher WHERE age != 30;
SELECT * FROM teacher WHERE age < 31;
SELECT * FROM teacher WHERE age <= 31;

-- 查询两个表
SELECT * FROM admin, teacher;

-- 关联查询
SELECT * FROM admin, teacher WHERE admin.username = teacher.username; 

-- 关联查询,重复名称起个别名
SELECT admin.username as '管理员表里的用户名', teacher.username as '老师表里的用户名'
	FROM admin, teacher WHERE admin.username = teacher.username;

-- 两个表里都有username字段,导致报错
SELECT username FROM admin, teacher WHERE admin.username = teacher.username;

-- 别名
SELECT username as `name` FROM admin;

-- 两个表有相同的字段时
SELECT admin.username FROM admin, teacher;

SELECT admin.username as admin_username FROM admin, teacher;

-- 不等于 和 != 一样
SELECT * FROM teacher WHERE age <> 30;

-- 去重
SELECT DISTINCT age from teacher;

-- 把两次查询的结果合并后去重
SELECT username FROM admin
	UNION
	SELECT username FROM teacher;

-- 把两次查询的结果合并后全部展示
SELECT username FROM admin
	UNION ALL
	SELECT username FROM teacher;

-- 求和
SELECT SUM(age) FROM teacher;

-- 求平均值
SELECT AVG(age) FROM teacher;

-- 求数量
SELECT COUNT(age) FROM teacher;

-- 按年龄分组,并统计分组的数量
SELECT age, COUNT(age) FROM teacher GROUP BY age;

-- 按年龄分组后求和
SELECT age, SUM(age) FROM teacher GROUP BY age;

-- WITH ROLLUP 汇总,分组后再汇总
SELECT age, COUNT(age) FROM teacher GROUP BY age WITH ROLLUP;

-- 使用COALESCE把null字段变成“汇总”
SELECT COALESCE(age, '汇总'), COUNT(age) FROM teacher GROUP BY age WITH ROLLUP;


-- 删除某个老师
DELETE FROM teacher WHERE uid = 1;

-- 删除某个管理员
DELETE FROM `admin` WHERE uid = 2;

-- 改
UPDATE admin SET `password` = '123456' WHERE uid = 2;
SELECT * FROM admin;

UPDATE admin SET username = 'xu123', `password` = '12' WHERE uid = 2;

-- 删
DELETE FROM admin WHERE uid = 2;


node入门_第82张图片

create.sql:

-- 删除数据库
DROP TABLE IF EXISTS `admin`;

-- 管理员
CREATE TABLE IF NOT EXISTS `admin` (
	`uid` INT UNSIGNED AUTO_INCREMENT,
	`username` VARCHAR(20) NOT NULL,
	`password` VARCHAR(30) NOT NULL,
	`create_time` DATETIME NOT NULL,
	PRIMARY KEY (`uid`)
);

-- 老师
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE IF NOT EXISTS `teacher` (
	`uid` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY COMMENT '老师的ID',
	`username` VARCHAR(20) NOT NULL COMMENT '老师登录平台的用户名',
	`password` VARCHAR(30) NOT NULL COMMENT '老师登录平台的密码',
	`age` INT UNSIGNED COMMENT '老师的年龄',
	`gender` enum('男', '女', '保密') DEFAULT '保密' COMMENT '老师的性别',
	`email` VARCHAR(50) COMMENT '邮箱',
	`create_time` DATETIME NOT NULL COMMENT '老师加入平台的时间'
);

insert.sql:

-- 增
INSERT INTO `admin` (`username`, `password`, `create_time`) VALUES ('admin', '123456', '2019-02-20 10:36:06');

-- 增,自动获取系统时间
INSERT INTO `admin` (`username`, `password`, `create_time`) VALUES ('xu', '123', NOW());
INSERT INTO `admin` (`username`, `password`, `create_time`) VALUES ('zhangsan', '123', NOW());
INSERT INTO `admin` (`username`, `password`, `create_time`) VALUES ('lisi', '123', NOW());
INSERT INTO `admin` (`username`, `password`, `create_time`) VALUES ('wangwu', '123', NOW());
INSERT INTO `admin` (`username`, `password`, `create_time`) VALUES ('Abc', '123', NOW());
INSERT INTO `admin` (`username`, `password`, `create_time`) VALUES ('bcd', '123', NOW());
INSERT INTO `admin` (`username`, `password`, `create_time`) VALUES ('Bcd', '123', NOW());


-- 1号老师张三 男
INSERT INTO `teacher` 
	(`username`, `password`, `age`, `gender`, `email`, `create_time`) 
	VALUES ('zhangsan', 'zhangsan', 30, '男', '[email protected]', NOW());

-- 2号老师李四 女
INSERT INTO `teacher` 
	(`username`, `password`, `age`, `gender`, `email`, `create_time`) 
	VALUES ('lisi', 'lisi123', 31, '女', '[email protected]', NOW());

-- 3号老师王五 性别保密
INSERT INTO `teacher` 
	(`username`, `password`, `age`, `email`, `create_time`) 
	VALUES ('wangwu', 'wangwu123', 32, '[email protected]', NOW());

-- 4号老师xu 既是老师又是管理员
INSERT INTO `teacher`
	(`username`, `password`, `age`, `email`, `create_time`) 
	VALUES ('xu', 'xu', 30, '[email protected]', NOW());

INSERT INTO `teacher`
	(`username`, `password`, `age`, `email`, `create_time`)
	VALUES ('lilei', 'lilei', 36, '[email protected]', NOW());

INSERT INTO `teacher`
	(`username`, `password`, `age`, `email`, `create_time`)
	VALUES ('Abc', 'Abc', 36, '[email protected]', NOW());

 select.sql:

-- 查
SELECT * FROM `admin`;
SELECT * FROM teacher;

SELECT username FROM admin;
SELECT `password`, `username` FROM admin WHERE uid = 1;

-- LIKE 可以做模糊搜索 AND 表示并且  OR 表示或者
SELECT * FROM admin WHERE username LIKE '%admi%';
SELECT * FROM admin WHERE username LIKE '%a%' AND `password` = '123';
SELECT * FROM admin WHERE username LIKE '%a%' OR `password` = '123';

-- 查询以x开头的两位用户名
SELECT * FROM admin WHERE username LIKE 'x_';

-- 查询用户名中不包含a的
SELECT * FROM admin WHERE username NOT LIKE '%a%';

-- 用户名中包含x或者包含u或者包含a或者包含l
SELECT * FROM admin WHERE username RLIKE '[xual]';

-- REGEXP 和 RLIKE 一样
SELECT * FROM admin WHERE username REGEXP '[xa]';

-- 包含a
SELECT * FROM admin WHERE username RLIKE '[a]+';
SELECT * FROM admin WHERE username RLIKE 'a+';

-- a开头
SELECT * FROM admin WHERE username RLIKE '^[a]+';

-- x或a开头
SELECT * FROM admin WHERE username RLIKE '^[xa]+';

-- 查询以x开头的两位用户名, "."匹配单个字符
SELECT * FROM admin WHERE username RLIKE 'x.';

SELECT username, `password`
FROM admin

-- 区分大小写,只查询A开头的用户名
SELECT * FROM admin WHERE username LIKE BINARY('A%');
SELECT * FROM admin WHERE BINARY username LIKE 'a%';

-- 区分大小写排序 https://www.jianshu.com/p/f8707b8461d3
SELECT * FROM admin ORDER BY username collate utf8mb4_bin;
SELECT * FROM admin ORDER BY username COLLATE utf8mb4_bin DESC;

-- 排序 默认升序, 升序:asc ascend ,降序:desc descend
SELECT * FROM admin ORDER BY username;
SELECT * FROM admin ORDER BY username ASC;
SELECT * FROM admin ORDER BY username DESC;

-- 先用创建时间排序,再用用户名排序
SELECT * FROM admin ORDER BY create_time DESC, username ASC;

-- 只要前两条
SELECT * 
FROM admin 
LIMIT 2;

-- 分页 第一个数是起始点,从零开始,第二个数是每页的数量
SELECT * FROM admin LIMIT 0, 4;
SELECT * FROM admin LIMIT 4, 1;

-- 和 LIMIT 4, 1相同
SELECT * FROM admin LIMIT 1 OFFSET 4;


-- 排序后分页
SELECT * FROM admin ORDER BY username ASC LIMIT 1, 2;

-- 数量
SELECT COUNT(*) FROM admin;

-- 完全限定的表名
SELECT admin.username FROM admin;


SELECT * FROM teacher;
SELECT * FROM teacher WHERE age > 30;
SELECT * FROM teacher WHERE age >= 30;
SELECT * FROM teacher WHERE age != 30;
SELECT * FROM teacher WHERE age < 31;
SELECT * FROM teacher WHERE age <= 31;

-- 查询两个表
SELECT * FROM admin, teacher;

-- 关联查询
SELECT * FROM admin, teacher WHERE admin.username = teacher.username; 

-- 关联查询,重复名称起个别名
SELECT admin.username as '管理员表里的用户名', teacher.username as '老师表里的用户名'
	FROM admin, teacher WHERE admin.username = teacher.username;

-- 两个表里都有username字段,导致报错
SELECT username FROM admin, teacher WHERE admin.username = teacher.username;

-- 别名
SELECT username as `name` FROM admin;

-- 两个表有相同的字段时
SELECT admin.username FROM admin, teacher;

SELECT admin.username as admin_username FROM admin, teacher;

-- 不等于 和 != 一样
SELECT * FROM teacher WHERE age <> 30;

-- 去重
SELECT DISTINCT age from teacher;

-- 把两次查询的结果合并后去重
SELECT username FROM admin
	UNION
	SELECT username FROM teacher;

-- 把两次查询的结果合并后全部展示
SELECT username FROM admin
	UNION ALL
	SELECT username FROM teacher;

-- 求和
SELECT SUM(age) FROM teacher;

-- 求平均值
SELECT AVG(age) FROM teacher;

-- 求数量
SELECT COUNT(age) FROM teacher;

-- 按年龄分组,并统计分组的数量
SELECT age, COUNT(age) FROM teacher GROUP BY age;

-- 按年龄分组后求和
SELECT age, SUM(age) FROM teacher GROUP BY age;

-- WITH ROLLUP 汇总,分组后再汇总
SELECT age, COUNT(age) FROM teacher GROUP BY age WITH ROLLUP;

-- 使用COALESCE把null字段变成“汇总”
SELECT COALESCE(age, '汇总'), COUNT(age) FROM teacher GROUP BY age WITH ROLLUP;















other.sql:

-- 选择数据库
USE demo;
USE test2;

-- 显示表格各列的信息,包括注释
SHOW FULL COLUMNS FROM teacher;


-- 删除某个老师
DELETE FROM teacher WHERE uid = 1;

-- 删除某个管理员
DELETE FROM `admin` WHERE uid = 2;

-- 改
UPDATE admin SET `password` = '123456' WHERE uid = 2;
SELECT * FROM admin;

UPDATE admin SET username = 'xu123', `password` = '12' WHERE uid = 2;

-- 删
DELETE FROM admin WHERE uid = 2;

-- 显示建表语句
SHOW CREATE TABLE admin;


三十、mysql主键

MySQL主键设计原则:

  • MySQL主键应当是对用户没有意义的。
  • MySQL主键应该是单列的,以便提高连接和筛选操作的效率(当然复合主键是可以的,只是不建议)
  • 永远也不要更新MySQL主键
  • MySQL主键不应包含动态变化的数据,如时间戳、创建时间列、修改时间列等
  • MySQL主键应当有计算机自动生成。

主键有哪几种:

(1). 自增序列;

(2). UUID()函数生成的随机值;

(3). 用户注册的唯一性帐号名称,字符串类型,一般长度为:40个字符;

(4). 基于一套机制生成类似自增的值,比如序列生成器;

mysql使用自增主键有何优势:
1) 数据库自动编号,速度快,而且是增量增长,聚集型主键按顺序存放,对于检索非常有利。

2) 数字型,占用空间小,易排序,在程序中传递方便。

mysql使用自增主键有何优势 - 简书

三十一、安装虚拟机

1)获取软件

链接:百度网盘 请输入提取码
提取码:vi1e

win7、win10等系统镜像获取网址:

MSDN, 我告诉你 - 做一个安静的工具站

2)安装,默认安装就可以

VMware创建虚拟机的时候遇到一个经典报错:

Attempting to start up from:

EFI VMware Virtual SCSI Hard Drive (0.0) … unsuccessful.

EFI VMware Virtual SATA CDROM Drive (1.0) … unsuccessful.

EFI Network...

解决方法:

node入门_第83张图片

1. 在虚拟机的安装目录里找到vmx文件

2. 删掉里面的 firmware="efi"

3. 保存重启虚拟机即可正常安装

3)新建虚拟机,并安装win7系统

node入门_第84张图片

node入门_第85张图片

node入门_第86张图片

node入门_第87张图片

node入门_第88张图片

node入门_第89张图片

node入门_第90张图片

node入门_第91张图片

4)安装VMware tools

1.在虚拟机win7的光驱里放入vmware tools的iso镜像文件

2.启动虚拟机

3.在打开虚拟机菜单,在下拉列表里选择安装VMware tools

4.等一会会弹出对话框,点击运行setup.exe,一步步安装即可

5.安装后重启,以后系统里的文件就可以直接拷贝的虚拟机了

三十二、磨课笔记

npm config list

npm init -y

npm install/i --save-dev / -D

npm install/i --save / -S

注册信息:

http://registry.npmjs.org/react

http://registry.npmjs.org/react/latest

更新包(如果已经安装再次安装并不会更新,所以需要update命令)

npm update react

命令行登录npm:

D:\source\m-apps\demo\ts\npm>npm login
Username: xutongbao
Password:
Email: (this IS public) [email protected]
Logged in as xutongbao on https://registry.npmjs.org/.

查询镜像源:

D:\source\m-apps\demo\ts\npm>npm get registry
https://registry.npmjs.org/

设置镜像源:

npm set registry 'https://registry.npmjs.org'

通过第三方镜像源管理工具来管理npm的镜像:

npm i nrm -g

nrm ls

* npm -------- https://registry.npmjs.org/
  yarn ------- https://registry.yarnpkg.com/
  cnpm ------- http://r.cnpmjs.org/
  taobao ----- https://registry.npm.taobao.org/
  nj --------- https://registry.nodejitsu.com/
  npmMirror -- https://skimdb.npmjs.com/registry/
  edunpm ----- http://registry.enpmjs.org/

nrm use taobao

nrm use npm

发包:

npm publish

"version": "1.0.2"

大版本,小功能版本,补丁版本

取消发布包:

npm unpublish --force

废弃一个包:

npm deprecate

你可能感兴趣的:(web前端,node)