0
点赞
收藏
分享

微信扫一扫

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入门_跨域


 

通过keywords找:

node入门_node_02

repository:npm和git关联

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

node入门_跨域_03

homepage: 项目官网

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

node入门_服务器_04

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入门_node_05

参考链接:

​​javascript:void(0)​​

​​如何解决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入门_服务器_06

node入门_node.js_07

全局安装:

node入门_node.js_08

node入门_跨域_09

常用命令:

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入门_node.js_10

命令行参数:

1)

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

node入门_node.js_11

2)

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

node入门_跨域_12

三、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 <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入门_node_13

求和:

const program = require('commander');

program
.version('0.0.1')
.option('-a, --my-a, <a>', '第一个值')
.option('-b, --my-b, <b>', '第二个值')
.parse(process.argv);

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

node入门_跨域_14

求和二:

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)
}

node入门_跨域_15

阶乘:

const program = require('commander');

program
.version('0.0.1')
.option('-a, --add', '求和')
.option('-f, --factorial <num>', '阶乘')
.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入门_服务器_16

node入门_服务器_17

多单词形式:

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入门_服务器_18

command方法,自定义命令

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

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

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

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

program.parse(process.argv)

node入门_跨域_19

参考链接:

​​掘金​​

​​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 <url>', '下载')
.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入门_服务器_20

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

node入门_node.js_21

204状态码:

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

node入门_跨域_22

node入门_node.js_23

 跨域请求:

node入门_node.js_24

node入门_服务器_25

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入门_服务器_26

node入门_服务器_27

node入门_node_28

node入门_跨域_29

node入门_node_30

node入门_node.js_31

node入门_node_32

node入门_跨域_33

node入门_服务器_34

node入门_服务器_35

node入门_跨域_36

node入门_node.js_37

node入门_跨域_38

十、安装FileZilla客户端

node入门_服务器_39

node入门_node_40

node入门_服务器_41

node入门_服务器_42

node入门_跨域_43

node入门_node.js_44

node入门_node.js_45

node入门_node.js_46

node入门_node.js_47

node入门_node.js_48

node入门_node.js_49

十一、阿里云配置支持FTP

node入门_node.js_50

node入门_node_51

node入门_node.js_52

node入门_服务器_53

node入门_服务器_54

十二、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入门_服务器_55

十三、express脚手架

装包:

yarn global add express-generator

运行:

express --view=pug m-express-demo

cd m-express-demo

yarn

yarn start

node入门_跨域_56

十三、npm view指令

显示npm包的相关信息:

npm view axios

npm show axios

npm info axios

npm v axios

node入门_node.js_57

查询npm包的所有版本号:

npm view axios versions

node入门_node.js_58

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

npm view axios versions dependencies

node入门_node_59

十四、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入门_服务器_60

十六、错误处理

错误堆栈:

test.js:

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

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

b()

node入门_node.js_61

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

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

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

b()

node入门_node.js_62

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

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

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

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

b()

node入门_跨域_63

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入门_跨域_64

十七、process.nextTick(callback)

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

console.log(1)

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

console.log(3)

node入门_node.js_65

十八、根据下标打印动物

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

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

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入门_服务器_66

动物数据:

链接:​​百度网盘 请输入提取码​​ 提取码: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 <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 `<div>
<a href="${path.join(req.url, filePath)}">${filePath}</a>
</div>`
}).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入门_跨域_67

node入门_服务器_68

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

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入门_跨域_69

二十二、事件触发器

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入门_服务器_70

二十三、手动封装事件

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入门_跨域_71

二十五、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入门_node_72

node入门_node.js_73

node入门_跨域_74

node入门_跨域_75

node入门_node_76

node入门_node_77

node入门_跨域_78

node入门_服务器_79

node入门_服务器_80

node入门_服务器_81

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

可以去百度云盘下载:

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

也可以去github下载:

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

 

node入门_跨域_82

hello world:

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

node入门_跨域_83

运行交互式的容器:

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

node入门_服务器_84

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入门_跨域_85

node入门_node_86

进入容器:

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入门_node.js_87

node入门_跨域_88

 参考链接:

​​命令行选项 | 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入门_node.js_89

chrome地址栏里输入:

chrome://inspect/#devices

node入门_服务器_90

打断点:

node入门_跨域_91

看日志:

node入门_服务器_92

二十八、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, '男', '1183391880@qq.com', NOW());

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

-- 3号老师王五 性别保密
INSERT INTO `teacher`
(`username`, `password`, `age`, `email`, `create_time`)
VALUES ('wangwu', 'wangwu123', 32, 'lisi@qq.com', NOW());

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

INSERT INTO `teacher`
(`username`, `password`, `age`, `email`, `create_time`)
VALUES ('lilei', 'lilei', 36, 'lilei@qq.com', 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入门_node.js_93

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, '男', '1183391880@qq.com', NOW());

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

-- 3号老师王五 性别保密
INSERT INTO `teacher`
(`username`, `password`, `age`, `email`, `create_time`)
VALUES ('wangwu', 'wangwu123', 32, 'lisi@qq.com', NOW());

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

INSERT INTO `teacher`
(`username`, `password`, `age`, `email`, `create_time`)
VALUES ('lilei', 'lilei', 36, 'lilei@qq.com', NOW());

INSERT INTO `teacher`
(`username`, `password`, `age`, `email`, `create_time`)
VALUES ('Abc', 'Abc', 36, 'abc@qq.com', 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入门_跨域_94

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

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

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

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

node入门_跨域_95

node入门_服务器_96

node入门_node_97

node入门_node_98

node入门_服务器_99

node入门_服务器_100

node入门_node_101

node入门_node_102

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 <package name> --save-dev / -D

npm install/i <package name> --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) 1183391880@qq.com
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 <pkg>

举报

相关推荐

0 条评论