node
nodejs简介
node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境[后端];
node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效
nodejs特点【重点】:
1)、nodejs既是平台(****注:nodejs可以充当web服务器[软件]****)又是开发语言;
2)、单线程(相当于一个饭店只有一个服务员)、跨平台(既可以在windows上运行也可以在linux操作系统上运行)
3)、非阻塞、异步I/O模型
4)、事件驱动
nodejs运行环境安装:
直接双击"node-v10.15.1-x64.msi"来安装,安装完成在windows的字符界面(在windows"运行框"中输入"cmd")中输入: node -v ,来验证安装是否成功;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XKoh0Qc4-1615858479881)(D:\beijing1009\day04\笔记\node.png)]
注意:如果node运行环境安装完成后在windows的字符界面中输入"node -v"报不是内部命令时,需要手动设置windows的环境变量:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GKiLV1aW-1615858479893)(D:\beijing1009\day04\笔记\环境变量.png)]
常用的windows命令:
(1)cd: 切换目录
(2)两个特殊目录: .代表当前目录 …代表上一级目录
(3)dir: 显示当前目录中的内容
(4) 切换盘符: 盘符:
(5) cls: 清屏
(6)创建目录: mkdir
(7)删除目录: rmdir
运行nodejs代码的两种方式【重点】:
1)第一种:在windows命令窗口中使用node.exe来执行:
D:\beijing1009\day04>node 8-使用nodejs搭建web服务器.js
2)在visual code开发工具中安装插件“code runner”来运行nodejs代码
使用nodejs搭建web服务器【重点】
//1、引入http模块
const http = require('http');
// console.log(http);
//2、创建web服务器
const server = http.createServer();
//3、监听事件(请求):server.on('事件名',()=>{});
//req:reqest(请求)
//res:response(响应)
server.on('request', (req, res) => {
res.writeHead(200, 'ok', { 'content-type': 'text/html;charset=utf-8' });
//res.setHeader('content-type', 'text/html;charset=utf-8'); //设置响应的头信息
res.write('你好!<br>');
// res.end("Ha ha....");
res.write('Yes OK!<br>');
res.write('Hi...<br>');
// res.end();
res.end('Hello Node....'); //结束响应,只能使用一次并且必须要使用一次
});
//4、监听端口
server.listen(3000, () => {
console.log('server start at port 3000!');
});
//什么是计算机端口?
//计算机与外界通信的窗口,可以这样来理解:把计算机想像成一个封闭的空间,而端口就是这个封闭空间的大门,通过这个大门才才能跟外界沟通。
//计算机常用的端口有0至65535个端口,但要注意的是小于1024的端口被计算机常用服务所占用.
注意:
1)、res.end(): 结束响应,只能使用一次并且必须要使用一次
2)、res.write():可以多次使用,用来设置返回的数据
3)、res.writeHead()及res.setHeader()用来设置响应的头信息,只设置一次即可
什么是计算机端口?
计算机与外界通信的窗口,可以这样来理解:把计算机想像成一个封闭的空间,而端口就是这个封闭空间的大门,通过这个大门才才能跟外界沟通。
计算机常用的端口有0至65535个端口,但要注意的是小于1024的端口被计算机常用服务所占用.
B/S程序运行的原理:【重点】
B:browser(浏览器) S:server(服务器)
注意:不需要安装、只要有浏览器和网络能访问的应用程序都称为B/S结构应用程序。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mop61dV8-1615858479900)(D:\beijing1009\day04\笔记\bs结构.png)]
nodejs与javascript的区别?【重点】
Javascript不但实现了ECMAScript标准,还包含DOM、BOM
Nodejs只实现了ECMAScript标准,没有DOM、BOM,Node中可以使用ECMAscript提供的所有的内置对象:String Number Boolean Math Date RexExp Function Object Array,同时node中还封装出了其它的api方法(函数)。
http协议:
1、什么是计算机协议?
计算机协议就是计算机之间通信的标准,常用的计算机协议有http[s]、smtp(发邮件)、pop3(收邮件)、ftp(文件传输协议)
2、什么是http协议?【重点】
HTTP(Hyper Text Transfer Protocol,超文本传输协议),HTTP是一个基于请求与响应模式的、无状态的[没有记忆功能]、应用层的协议。
http与https[scure]:
http协议是明文传输数据,https是密文传输数据
3、http协议工作原理:【重点】
第一步:客户端(浏览器)与服务器建立连接;
第二步:客户端发送请求给服务器;
第三步:服务器接收、处理请求并返回响应;
第四步:客户端与服务器断开连接;
4、http协议报文数据格式:
【重点】
1)请求报文数据格式由三部分组成:请求行、消息报头、请求正文[可为空]
请求行也有由三部分组成【了解】:请求方式(get/post)、请求地址、协议版本
2)响应报文数据格式由三部分组成:状态行、消息报头、响应正文
状态行也有由三部分组成【了解】:协议版本、状态码、描述信息
5、http协议常见状态码:【重点】
2xx (成功):
200 表示成功
3xx (重定向):
301 永久重定向
302 临时重定向
4xx(请求错误) :
404 页面找不到
5xx(服务器错误):
500 服务器内部错误
502 错误网关
什么是nodejs路由?【重点】
根据请求中的不同path路径返回不同响应。
nodejs路由实现的步骤:【重点】
1)搭建web服务器;
2)获取请求中的path路径;
3)根据不同path路径返回不同响应内容;
//1、搭建web服务器
//引入http模块
const http = require('http');
//创建web服务器
const server = http.createServer();
//监听事件:
server.on('request', (req, res) => {
res.setHeader('content-type', 'text/html;charset=utf-8');
//获取请求中的path路径
let curpath = req.url;
// console.log(curpath);
if (curpath.startsWith('/index.html')) { //首页
res.write('这是首页!');
} else if (curpath.startsWith('/list.html')) { //列表页面
res.write('这是列表页面!');
} else { //404页面
res.write('404页面');
}
res.end();
});
//监听端口
server.listen(3000, () => {
console.log('at port 3000');
});
开放静态资源:
1、什么是开放静态资源?
就是让用户通过web服务器来访问我们的静态项目。
2、__dirname与__filename:【重点】
__dirname:动态获取当前文件所在的目录
__filename:动态获取当前文件的绝对路径(包含当前文件名)
3、实现开放静态资源步骤:
2.1)搭建web服务器;
2.2)获取用户请求中的path路径
2.3)根据path路径将对应的静态html文件内容读出来并作为响应返回给用户
//引入http模块
const http = require('http');
//引入fs模块
const fs = require('fs');
//创建web服务器
const server = http.createServer();
// console.log(__dirname, 111);
// console.log(__filename, 222);
//监听事件:
server.on('request', (req, res) => {
//获取path路径
let paths = req.url;
// console.log(paths, 999);
if (paths == '/') { //首页
paths = '/index.html';
}
//判断文件是否存在
if (fs.existsSync(`${__dirname}/baofeng${paths}`)) { //存在
let content = fs.readFileSync(`${__dirname}/baofeng${paths}`);
//console.log(content.toString());
res.write(content);
}
// if (paths.startsWith('/index.html')) { //首页
// // res.write('index.html');
// //读取文件内容:
// let content = fs.readFileSync('D:/beijing1009/day05/baofeng/index.html');
// //console.log(content.toString());
// res.write(content);
// } else if (paths.startsWith('/list.html')) { //列表页
// } else {
// }
res.end();
});
//监听端口
server.listen(4000, () => {
console.log('at port 4000');
});
events(事件触发器)
让用户自定义事件并触发事件
1、events模块使用:
//引入events模块
const eventsEmitter = require('events');
const events = new eventsEmitter();
//定义事件: events.on('事件名',()=>{});
events.on('cctv', function() {
console.log('Hello cctv');
});
//定义事件(只能被触发一次):events.once('事件名',()=>{});
events.once('demo', function() {
console.log('只能触发一次!!');
});
events.on('tv13', function() {
setTimeout(() => {
console.log('Hi tv13!!');
}, 2000);
});
//触发事件:events.emit('事件名');
events.emit('cctv');
events.emit('cctv');
events.emit('cctv');
events.emit('tv13');
events.emit('demo');
events.emit('demo');
url与path模块
1、完整的url地址格式如下:【重点】
协议,认证,主机名,端口,地址,参数,文件名
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
│ href │
├──────────┬──┬─────────────────────┬────────────────────────┬───────────────────────────┬───────┤
│ protocol │ │ auth │ host │ path │ hash │
│ │ │ ├─────────────────┬──────┼──────────┬────────────────┤ │
│ │ │ │ hostname │ port │ pathname │ search │ │
│ │ │ │ │ │ ├─┬──────────────┤ │
│ │ │ │ │ │ │ │ query │ │
" https: // user : pass @ sub.example.com : 8080 /p/a/t/h ? query=string #hash "
│ │ │ │ │ hostname │ port │ │ │ │
│ │ │ │ ├─────────────────┴──────┤ │ │ │
│ protocol │ │ username │ password │ host │ │ │ │
├──────────┴──┼──────────┴──────────┼────────────────────────┤ │ │ │
│ origin │ │ origin │ pathname │ search │ hash │
├─────────────┴─────────────────────┴────────────────────────┴──────────┴────────────────┴───────┤
│ href │
└────────────────────────────────────────────────────────────────────────────────────────────────┘
2、path.resolve()与path.join():【重点】
path.resolve
定的路径序列会从右到左进行处理,后面的每个 path
会被追加到前面,直到构造出绝对路径。 例如,给定的路径片段序列:/目录1
、 /目录2
、 目录3
,调用 path.resolve('/目录1', '/目录2', '目录3')
会返回 /目录2/目录3
,因为 '目录3'
不是绝对路径,但 '/目录2' + '/' + '目录3'
是。
语法
path.resolve('/目录1/目录2', './目录3');
// 返回: '/目录1/目录2/目录3'
path.resolve('/目录1/目录2', '/目录3/目录4/');
// 返回: '/目录3/目录4'
path.join()
方法会将所有给定的 path
片段连接到一起(使用平台特定的分隔符作为定界符),然后规范化生成的路径。
长度为零的 path
片段会被忽略。 如果连接后的路径字符串为长度为零的字符串,则返回 '.'
,表示当前工作目录。
**注意:**path.join():根据不同的操作系统使用的路径分隔符是不一样
windows使用反斜杠()作为路径分隔符
linux使用斜杠(/)作为路径分隔符
const url = require('url');
const path = require('path');
let cururl = "http://tom:1234@www.qq.com:8080/test/yesok.php?uid=123&usr=lisi";
let urlobj = url.parse(cururl);
console.log(urlobj, urlobj.hostname);
console.log('扩展名:' + path.extname(urlobj.pathname));
let curpath = path.resolve(__dirname, 'yesok/demo',
'index.html');//在当前文件的所有目录中找到‘yesok/demo下面的index.html
console.log(curpath);//\培训\demo33\day05\homework\yesok\demo\index.html
curpath = path.resolve(__dirname, '../yesok/demo',
'index.html');//在当前文件的所有的上上级目录中找到‘yesok/demo'下面的index.html
console.log(curpath);//e:\培训\demo33\day05\yesok\demo\index.html
fs模块:
1、fs操作文件:
fs操作一般文件常用方法:
读取文件:fs.readFile()、fs.readFileSync()
写文件:fs.writeFile()、fs.writeFileSync()
fs操作大文件常用方法:采用文件流方式操作
创建可读文件流: fs.createReadStream()
创建可写文件流: fs.createWriteStream()
const fs = require('fs');
const path = require('path');
//fs操作一般文件常用方法:
//读取文件:fs.readFile()、fs.readFileSync()
//写文件:fs.writeFile()、fs.writeFileSync()
//写文件:
// fs.writeFile(path.join(__dirname, 'mytest.txt'), 'yes OK', (e) =>
// fs.writeFile(path.join(__dirname, 'mytest.txt'), 'this is testing...', { flag: 'a+' }, (e) => {
// console.log(e, 777);
// });
//fs操作大文件常用方法:采用文件流方式操作
//创建可读文件流: fs.createReadStream()
//创建可写文件流: fs.createWriteStream()
let rs = fs.createReadStream(path.resolve(__dirname, 'shamo.mp3'));
let ws = fs.createWriteStream(path.resolve(__dirname, '123.mp3'));
let ws2 = fs.createWriteStream(path.resolve(__dirname, '456.mp3'));
rs.pipe(ws2); //管道流
rs.on('open', () => {
console.log('open...');
});
rs.on('ready', () => {
console.log('ready...');
});
var i = 0;
rs.on('data', (d) => {
// console.log(i++, 666);
// console.log(d, 8888);
ws.write(d);
});
2、fs操作目录:
创建目录:fs.mkdir()、fs.mkdirSync()
删除目录:fs.rmdir()、fs.rmdirSync() 注意:只能删除空目录
删除文件:fs.unlink()、fs.unlinkSync()
给目录或文件重命名:fs.rename()、fs.renameSync()
读取目录:fs.readdir()、fs.readdirSync()
获取文件状态:fs.stat()、fs.statSync()
判断是否为文件:isFile();
判断是否为目录:isDirectory()
const fs = require('fs');
const path = require('path');
//创建目录:fs.mkdir()、fs.mkdirSync()
if (!fs.existsSync(path.resolve(__dirname, 'mydemo'))) {
fs.mkdirSync(path.resolve(__dirname, 'mydemo'));
}
//删除目录:fs.rmdir()、fs.rmdirSync():
//注意: 只能删除空目录
// fs.rmdirSync(path.resolve(__dirname, 'mydemo'));
//删除文件:fs.unlink()、fs.unlinkSync()
//给目录或文件重命名:fs.rename()、fs.renameSync()
// fs.renameSync(path.resolve(__dirname, 'mydemo'), path.resolve(__dirname, 'mydemo222'));
//读取目录:fs.readdir()、fs.readdirSync()
let arr = fs.readdirSync(__dirname);
// console.log(arr);
//遍历内容
arr.forEach((item) => {
//console.log(item, 333);
//读取文件状态:fs.stat()、fs.statSync();
let obj = fs.statSync(path.resolve(__dirname, item));
// console.log(obj);
//判断是否为文件:obj.isFile();
//判断是否为目录:obj.isDirectory()
if (obj.isFile()) { //为文件
console.log(`文件:${item}`);
} else { //为目录
console.log(`目录:${item}`);
}
});
**作业:**封装一个函数:读取某个目录及其所有子目录中的文件
const fs = require('fs');
const path = require('path');
function showFile(paths){
let arr = fs.readdirSync(paths);
// console.log(arr);
// let nowDir =
arr.forEach((item)=>{
//读取文件状态:fs.stat()、fs.statSync();path.resolve(nowdir, item)
let obj = fs.statSync(path.resolve(paths,item))
//判断是否为目录:obj.isDirectory()
if(obj.isDirectory()){
// console.log(`${item}是目录`);
showFile(path.resolve(paths,item));
}else{
console.log(`${item}是文件`);
}
})
}
showFile(path.resolve(__dirname,'mypath'));//传入要访问的目录地址
nodejs自定义模块:
1、在nodejs中每个.js文件都是一个封闭的空间:
在nodejs中每个.js文件都是一个封闭的空间,因为每个js文件代码外层被一个匿名函数所包裹,代码如下:
// function(exports, require, module, __filename, __dirname) { //定义了公共的变量及函数:
// let exports = module.exports;
// var usr = 'Tom';
// var age = 20;
// var host = "www.baidu.com";
// function demo() {
// console.log('demo在2-module.js文件中');
// }
// console.log(arguments.callee.toString());
// return module.exports;
// }
2、nodejs自定义模块语法(commonjs):【重点】
1)、单个暴露:
(1)使用 exports:
exports.属性 = 属性值;
exports.方法 = 函数;
(2)使用module.exports:
module.exports.属性 = 属性值;
module.exports.方法 = 函数;
2)、批量暴露:
module.exports = {}
自定义模块文件(2-module.js)的代码如下:
//使用单个暴露:
exports.usr = 'Tom';
exports.age = 20;
module.exports.host = 'www.baidu.com';
module.exports.demo = function() {
console.log('demo在2-module.js文件中');
}
//使用批量暴露:
// var usr = 'Tom';
// var age = 20;
// function demo() {
// console.log('demo...');
// }
// module.exports = { usr, age, demo, 'host': 'www.baidu.com', fn: function() { console.log('fn...'); } };
使用上面自定义的模块文件(2-module.js)的代码如下:
//注意:
// 1)在nodejs中引入自定义模块文件时路径要以./或../开头
// 2)如果省略自定义模块文件的扩展名时,则按.js、.json、.node这样的顺序来查找对应的文件
const m1 = require('./2-module.js');
console.log(m1, 9999);
console.log(m1.usr, m1.host);
m1.demo();
m1.fn();
注意:在使用自定义模块文件时要以./或…/开头
3、注意:单个暴露与批量暴露不能一起使用【重点】
单个暴露与批量暴露不能一起使用,因为exports是module.exports的引用,而module.exports是真实存在的,最终返回的是module.exports,演示代码如下:
var module = { exports: {} };
var exports = module.exports;
exports.age = 20;
console.log(exports, module.exports);
module.exports = {};
console.log(exports, module.exports);
// let obj = {};
// let obj2 = obj;
// obj2.tst = 1;
// console.log(obj, obj2);
// obj = {};
// console.log(obj, obj2);
4、自定义模块应用:
自定义模块文件(4-compurter.js)的代码如下:
class Computer {
//方法
constructor(bd, pr) {
this.brand = bd;
this.price = pr;
}
output() {
console.log(`品牌为:${this.brand}的电脑价格是:${this.price}`);
}
}
module.exports = Computer;
使用上面的自定义模块文件(4-compurter.js)的代码如下:
//如果省略自定义模块文件的扩展名时,则按.js、.json、.node这样的顺序来查找对应的文件
let pc = require('./4-compurter');
// console.log(pc);
// return;
let computer1 = new pc('华为', 5000);
computer1.output();
作业:自定义一个计算器模块并使用
nodejs第三方模块(包)
1、要使用第三方包则需要先安装
安装第三方包:npm i/install 包名
注意:将npm服务器切到国内淘宝服务器(镜像服务器),在dos小黑窗中分别执行下面的命令*:
npm config set registry https://registry.npm.taobao.org --global
npm config set disturl https://npm.taobao.org/dist --global
2、创建项目自己的package.json文件:
1)在项目根目录中执行下面的命令来创建项目自己的package.json文件:
npm init 或 npm init -y(注意:如果项目目录名称含有中文则不能使用 -y)
2)为什么要创建项目自己的package.json文件?【重点】
package.json文件中配置项”dependencies”会记录我们依赖的所有第三方模块,当我们要把项目发给别人或要上传到服务器时,可以把我们项目安装的所有第三方模块删除掉,然后再发给别人或上传到服务器,当别人拿到项目或上传到服务后我们再使用npm install就可以把项目所有依赖的第三方模块再安装上
3、最好将第三方包安装在项目根目录中:【重点】
将第三方模块安装在项目根目录下可以在项目的任何目录都使用该第三方模块,因为当我们使用require(‘包名’)引入第三方模块时会在当前目录中查找访模块,如果找不到则返回到上一级目录中查找,一直到某个盘符的根目录中还是找不到则报错。
4、常用的npm命令:【重点】
npm -v 查看npm的版本
npm version 查看所有模块的版本
npm init 初始化项目(创建package.json),创建package.json文件作用:记录我们当前node项目中依赖哪些第三方的包,当我们把node项目发给别人或发布时,就可以删除node项目中已安装的第三包文件。
npm i/install 包名 安装指定的包 @版本号,不加版本默认为最新
npm i/install 包名 --save 安装指定的包并添加依赖
--save-dev的功能: 开发依赖(开发阶段需要,上线不需要[因为已转换好了])
--save的功能:之前旧的npm命令如果不带–save参数,则在.json文件中不产生依赖项(dependencies)
npm i/install 包名 -g 全局安装(一般都是一些工具)
npm i/install 安装当前项目所依赖的包
npm s/search 包名 搜索包
npm r/remove 包名 删除一个包
npm uninstall 包名 删除
注意:(1)、npm 老的版本(2,3版本在)安装包的时候,默认不加自动添加的denpendcies里面npm install 包名 --save 才会保存到依赖里面,但是现在npm升级好多次了,自动会回到package.json项目依赖当中。
5、使用第三方包(mime):
1)、在当前项目根目录中安装mime包:npm i mime
2)、使用mime包:
const mime = require('mime');
//根据文件扩展名获取对应的文件类型
console.log(mime.getType('txt'));
console.log(mime.getType('js'));
console.log(mime.getType('jpeg'));
//根据文件类型获取对应的文件扩展名
console.log(mime.getExtension('text/plain'));
console.log(mime.getExtension('text/html'));
console.log(mime.getExtension('image/gif'));
6、什么是MIME?【重点】
MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型,在http协议中用来标识返回数据类型,客户根据不同的数据类型会启动对应的应用程序来处理。
常用用的MIMIE类型有:
text/html html数据
text/css css数据
application/javascript javascript数据
image/png png图片数据
image/gif gif图片数据
image/jpg jpg图片数据
image/jpeg jpeg图片数据
buffer缓冲器:
1、buffer缓冲器简介:
buffer类似于数组,但buffer中可以存储二进制数据,nodejs在处理文件流、网络数据流这些数据时都是二进制的,因此需要使用buffer。
2、buffer使用:
注意:
1)buffer在输出时是以16进制来显示的;
2)buffer中存储最大数值为255,当数值超过255是只存储该数值转换成二进制的后8位
3)buffer的存储单位为bit(位)
8bit = 1byte(字节)
1024byte = 1KB
1024KB= 1M
书写格式:
Buffer.alloc (aize[,fill[,encoding]]),返回一个指定大小的Buffer实例,如果没有设置fill,则默认填满0
Buffer.from(aize[,fill[,encoding]]),返回一个被string初始化的新的BUffer实例
//创建buffer:
//注意:
// 1)buffer在输出时是以16进制来显示的;
// 2)buffer中存储最大数值为255,当数值超过255是只存储该数值转换成二进制的后8位
// 3)buffer的存储单位为bit(位)
// 8bit = 1byte(字节)
// 1024byte = 1KB
// 1024KB= 1M
let buf = Buffer.alloc(9);
console.log(buf);//<Buffer 00 00 00 00 00 00 00 00 00>
buf[0] = 6;
buf[10] = 8; //注意:buffer一旦创建其长度不能改变
buf[2] = 15;
buf[3] = 255;
buf[4] = 346;
console.log(buf);//<Buffer 06 00 0f ff 5a 00 00 00 00>
let buf2 = Buffer.allocUnsafe(8); //创建buffer时不会初始化内存
console.log(buf2);//<Buffer 01 00 00 00 ff ff ff ff>
let buf3 = Buffer.from('Hello');
console.log(buf3);//<Buffer 48 65 6c 6c 6f>
let obj = { x: 1, y: 2 };
let buf4 = Buffer.from(JSON.stringify(obj));
console.log(buf4);//<Buffer 7b 22 78 22 3a 31 2c 22 79 22 3a 32 7d>
let buf5 = Buffer.from([11, 3, 8, 9]);
console.log(buf5);//<Buffer 0b 03 08 09>
3、buffer应用:
const fs = require('fs');
const path = require('path');
let buf = Buffer.from('Hello...');
// fs.writeFile(path.resolve(__dirname, 'yesok.txt'), buf, (e) => {
// console.log(e, 888);
// });
let buf6 = fs.readFileSync(path.resolve(__dirname, 'yesok.txt'));
console.log(buf6, buf6.toString('latin1'), buf6.toString('utf-8'), 3333);
let str = "Hi web";
// let str64 = Buffer.from(str, 'base64');
// let str3 = Buffer.from('7468697320697320612074c3a97374', 'hex');
// console.log(str64, str3.toString(), 999);
//base64转换:
let usr = 'lisi';
let usrbase64 = Buffer.from(usr).toString('base64');
console.log(usrbase64, 667);
let usr2 = Buffer.from(usrbase64, 'base64').toString('utf-8');
console.log(usr2);
express
1、express简介:
基于 Node.js平台,快速、开放、极简的Web开发框架[后端]
2、安装express: 【重点】
****在当前项目根目录中****执行下面的命令: npm i express
3、使用express搭建web服务器:【重点】
//引入express
const express = require('express');
//创建应用
const app = express();
//监听端口
app.listen(3000, () => {
console.log('at port 3000');
});
4、接收get方式发送的参数:【重点】
1)、get方式发送参数的写法有两种:查询字符串方式、path路径方式
查询字符串方式发送参数格式如下:
http://localhost:4000/login?usr=lisi&age=20
接收get方式以查询字符串方式发送的参数:req.query
2)、 接收get方式以查询字符串方式发送的参数的例子:[重点]
用户登录界面(login.html)代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>用户登录</title>
</head>
<body>
<form action="/login" method="get">
<!-- 注意:表单项的name属性给后台使用,而id属性通常给前端【js或jquery】使用 -->
帐号:<input type="text" id="usr" name="usr"><br> 密码:
<input type="password" name="pwd"><br>
<input type="submit" value="登录"><br>
</form>
</body>
</html>
用户登录及处理登录的后端代码如下:
//引入express
const express = require('express');
const path = require('path');
//创建应用
const app = express();
//监听端口
app.listen(3000, () => {
console.log('3000');
});
//get方式发送参数的写法有两种:查询字符串方式、path路径方式
//查询字符串方式如下:
//http://localhost:4000/login?usr=lisi&age=20
//显示用户登录界面
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, 'login.html'));//读取当前文件夹下的‘login.html’,并渲染页面
});
//处理登录:当点击提交按钮时,相当于表单提交了‘/login’,对结果判断做出相应的响应
app.get('/login', (req, res) => {
//接收get查询字符串方式发送的参数:req.query
// console.log(req.query);
let { usr, pwd } = req.query;
// res.send(`${usr} ${pwd}`);
if (usr == 'demo' && pwd == 1234) { //登录成功
res.send(`登录成功`);
} else { //登录失败
res.send(`登录失败`);
}
});
express中路由写法分为两种:app级别、router级别 【重点】
1、app级别路由语法:app.get/post(‘路径’,回调函数)
app.get(‘路径’,回调函数)
app.post(‘路径’,回调函数)
app.all(’*’,回调函数) //all()能匹配所有请求方式
express是中间件:
1、什么是中间件?【重点】
就是在接收请求之后返回响应之前要执行的函数,而这些函数有一定的业务处理能力。
**中间件分为:**内置中间件、自定义中件、第三方中间件。
2、使用中间件语法:【重点】
app.use([路径,]中间件函数);
注意:
1)、使用中间件的代码通常放在所有路由的最前面;
2)、next()方法查找并执行后面能匹配上的路由
3)、当给next()方法传参时会自动查找含有err、req、res、next四个参数的中间件(错误处理中间件);
//引入express
const express = require('express');
//创建应用
const app = express();
//监听端口
app.listen(3000, () => {
console.log('at port 3000');
});
//设计路由:
//定义中间件:
function demo(req, res, next) {
res.setHeader('content-type', 'text/html;charset=utf-8');
// next(); //查找并执行后面能匹配上的路由
//注意:当给next()方法传参时会自动查找含有err、req、res、next四个参数的中间件(错误处理中间件).
if (0) {
next();
} else { //错误了
next('error message...');
}
}
//使用中间件:
// app.use(demo);
// app.use((req, res, next) => {
// res.setHeader('content-type', 'text/html;charset=utf-8');
// console.log('Hello...');
// next(); //查找并执行后面能匹配上的路由
// });
app.get('/teacher', (req, res) => {
res.end('这是老师相关信息');
});
//使用中间件:
app.use(demo);
app.get('/student', (req, res) => {
// res.setHeader('content-type', 'text/html;charset=utf-8');
res.end('这是学生相关信息....');
});
//错误处理中间件
app.use((err, req, res, next) => {
console.log(err, 888);
res.send(`错误原因:${err}`);
});
express托管静态资源:
让用户通过我们搭建的web服务器能访问到静态资源(如:图片、css文件、js文件等)。
1、使用express内置中间件函数express.static()实现托管静态资源
注意:将某个目录托管成功后在访问时不需要带上该目录名称
//引入express
const express = require('express');
const path = require('path');
//创建应用
const app = express();
//监听端口
app.listen(3000, () => {
console.log('at port 3000');
});
//使用express内置中间件函数express.static()实现托管静态资源:
//注意:将某个目录托管成功后在访问时不需要带上该目录名称
//app.use(express.static(path.resolve(__dirname, 'img')))
//app.use('/img', express.static(path.resolve(__dirname, 'img')))
app.use(express.static(path.resolve(__dirname, 'public')))
//设计路由
//显示用户登录界面的
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, 'userlogin.html'));
});
userlogin.html文件代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/index.js"></script>
</head>
<body>
<div><img src="img/3333.jpg"></div>
</body>
</html>
cookie与session:
1、为什么要使用cookie、session?
因为http协议是无状态协议,使用cookie或session技术后可以让我们的系统有记忆功能。
2、使用cookie:【重点】
1)、设置cookie: res.cookie(name, value [, options])
常用的选项有:
maxAge:用来设置cookie有效时间,时间单位为毫秒
httpOnly:为true则只能服务器访问cookie、客户端不能访问
path:设置cookie只能在某个路径中使用
domain:设置cookie只能在某个域名中使用
2)、获取cookie: 使用第三方中间件cookie-parser来获取cookie
中文文档:https://www.expressjs.com.cn/en/resources/middleware/cookie-parser.html
(1)安装中间件: 在项目根目录中执行命令:npm i cookie-parser
(2)使用第三方中间件cookie-parser来获取cookie:
var cookieParser = require('cookie-parser')
var app = express()
app.use(cookieParser())
3)、express操作cookie的例子:
//引入express
const express = require('express');
var cookieParser = require('cookie-parser');
//创建应用
const app = express();
//监听端口
app.listen(3000, () => {
console.log('at port 3000');
});
//使用第三方中间件:cookie-parser
app.use(cookieParser());
//设计路由
//设置cookie:
app.get('/setcookie', (req, res) => {
res.cookie('USR', ['lisi', 21], { maxAge: 10 * 1000 });
res.cookie('EMAIL', 'tom@163.com', { path: '/mycookie' });
res.cookie('TEL', '110', { domain: 'www.qq.com' });
res.send("<script>alert('cookie设置成功');location.href='/getcookie';</script>");
});
//获取cookie:需要使用第三方中间件:cookie-parser
app.get('/getcookie', (req, res) => {
console.log(req.cookies);
res.send('OK');
});
app.get('/cookietest', (req, res) => {
res.send(req.cookies);
});
app.get('/mycookie', (req, res) => {
res.send(req.cookies);
});
3、session的工作原理:【重点】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u6iyQzmd-1615858479909)(D:\beijing1009\day07\笔记\session原理.png)]
4、express操作session: 【重点】
express操作session要使用第三方中间件cookie-session:
中文文档: https://www.expressjs.com.cn/en/resources/middleware/cookie-session.html
1)、安装cookie-session: npm i cookie-session
2)、使用cookie-session:
const cookieSession = require('cookie-session');
//使用中间件cookie-session操作session:
app.use(cookieSession({
name: 'cursession', //cookie名称
keys: ['123^%$abd', '*(&^%#876'] //密钥
}));
3)、express操作session的例子:
//引入express
const express = require('express');
var cookieParser = require('cookie-parser');
//创建应用
const app = express();
//监听端口
app.listen(3000, () => {
console.log('at port 3000');
});
//使用第三方中间件:cookie-parser
app.use(cookieParser());
//设计路由
//设置cookie:
app.get('/setcookie', (req, res) => {
res.cookie('TST', 12345, { httpOnly: true });
res.cookie('USR', ['lisi', 21], { maxAge: 10 * 1000 });
res.cookie('EMAIL', 'tom@163.com', { path: '/mycookie' });
res.cookie('TEL', '110', { domain: 'www.qq.com' });
res.send("<script>alert('cookie设置成功');location.href='/getcookie';</script>");
});
//获取cookie:需要使用第三方中间件:cookie-parser
app.get('/getcookie', (req, res) => {
console.log(req.cookies);
res.send('OK');
});
app.get('/cookietest', (req, res) => {
res.send(req.cookies);
});
app.get('/mycookie', (req, res) => {
res.send(req.cookies);
});
5、cookie与session的区别: 【重点】
1)、cookie保存在客户端、相对不安全,session保存在服务端,相对安全;
2)、cookie默认有效时间为整个有效会话期间(有效会话期间是指打开某系统之后到关闭整个浏览器之前),cookie理论上可以永久有效,session不能设置有效时间,session默认有效时间为整个有效会话期间;
3)、cookie有大小限制(4KB左右)及每个域名存放cookie个数在20至50个左右,session没有这方面的限制;
4)、cookie在客户端可以被禁用,session则不能;
6、cookie与session的联系: 【重点】
session依赖cookie,因为seession id存放在客户端的cookie中;
热更新(nodemon):【重点】
1、安装nodemon:npm i -g nodemon
注意:使用-g参数要注意的地方有两点:
**第一点:**使用-g参数安装的包默认存放位置为: C:\Users\当前用户名\AppData\Roaming\npm\node_modules;
**第二点:**使用-g参数安装某个包时可以dow小黑窗的任何目录执行该命令,同一台电脑只需要执行一次即可;
2、将nodemon配置文件(nodemon.json)放到当前项目根目录中【可以忽略该步骤】;
3、使用nodemon启动项目或某个.js文件: nodemon ./bin/www 或 nodemon ./mytest.js
接收post方式发送的参数 【重点】
1、get与post区别:
get是显式提交、post是隐式提交,get有大小限制、post没有限制,post比get相对安全
2、接收post方式发送的参数:
1)、 使用express内置中间件:express.urlencoded({extended:false});
2)、使用req.body即可接收post发送的参数:
//引入express
const express = require('express');
//创建应用
const app = express();
//监听端口
app.listen(3000, () => {
console.log('at port 3000');
});
//使用内置中间件express.urlencoded()来接收post方式发送的参数:
app.use(express.urlencoded({ extended: false }));
//设计路由
app.post('/login', (req, res) => {
//接收post方式发送的参数
console.log(req.body, 999);
res.send(req.body);
});
express的Router级别路由 【重点】
如果使用express的app级别路由来设计项目路由时会把所有路由都放在一起,这样不便于项目的后期维护。
1、Router级别路由语法:
const express = require('express');
const router = express.Router();
//设计router级别的路由:
// router.get/post/all('路径',回调函数)
//暴露router
module.exports = router;
2、使用Router级别路由:
1)、引入某个router级别路由文件;
2)、app.use(router级别路由)
3、Router级别例子:
自定义router级别路由的文件(qiantai.js)代码如下:
const express = require('express');
const router = express.Router();
//设计router级别的路由:
// router.get/post/all('路径',回调函数)
//首页页面
router.get('/', (req, res) => {
res.send('这是项目的首页面');
});
//列表页面
router.get('/list', (req, res) => {
res.send('这是列表页面');
});
//处理用户登录
router.post('/loginact', (req, res) => {
res.send(req.body);
})
//暴露router
module.exports = router;
使用上面定义的router级别路由的文件(qiantai.js)代码如下:
//引入express
const express = require('express');
//创建应用
const app = express();
//监听端口
app.listen(3000, () => {
console.log('at port 3000');
});
//使用内置中间件express.urlencoded()来接收post参数
app.use(express.urlencoded({ extended: false }))
//使用router级别路由:
const qtRouter = require('./qiantai.js');
app.use(qtRouter);
ejs模板引擎: 【重点】
1、ejs模板引擎简介:
ejs模板引擎可以界面与数据分离,主要用来渲染页面(后端渲染)。
页面渲染分为前端渲染、后端渲染:
前端渲染使用ajax技术;
后端渲染[后端渲染是指在服务器端把数据渲染完成后作为响应直接发送给客户端面来展示]使用ejs、pug模板引擎;
2、使用ejs模板引擎:
1、安装ejs模板引擎: npm i ejs
2、设置ejs模板引擎: app.set(‘配置项’,‘值’)
//设置模板引擎为ejs
app.set(‘view engine’, ‘ejs’);
//设置模板文件存放位置
app.set(‘views’, [path.resolve(__dirname, ‘moban’), path.resolve(__dirname, ‘views’)]);
//告诉express: 将.html文件作为模板文件来解析
app.engine(‘html’, require(‘ejs’).__express);
3、渲染模板文件:
res.render(‘模板文件’,{模板变量1,模板变量2})
注意:默认模板文件扩展名为.ejs,则可以省略扩展名
4、在ejs模板文件中使用模板变量:
3.1)输出模板变量: <%=模板变量 %>
3.2)遍历模板变量: <% for() %>
3.3)判断模板变量:<% if() %>
3.4)引入公共的模板文件:<%- include(‘公共模板文件名’) %>
3.5)ejs模板文件注释: <%# 注释内容 %>
//引入express
const express = require('express');
const path = require('path');
const fs = require('fs');
//创建应用
const app = express();
//监听端口
app.listen(3000, () => {
console.log('at port 3000');
});
//设置模板引擎
//设置模板引擎为ejs
app.set('view engine', 'ejs');
//设置模板文件存放位置
app.set('views', [path.resolve(__dirname, 'moban'), path.resolve(__dirname, 'views')]);
//告诉express: 将.html文件作为模板文件来解析
app.engine('html', require('ejs').__express);
//设计路由:app级别的路由
//列表页面
app.get('/list', (req, res) => {
res.render('list.html');
});
//显示用户登录界面
app.get('/', (req, res) => {
// let user = req.cookies.USR ? req.cookies.USR : 'zhangsan';
// let user = 'zhangsan';
// let content = fs.readFileSync(path.resolve(__dirname, './moban/login.ejs'));
// content = content.toString();
// //字符串替换
// content = content.replace('$USER$', user);
// res.send(content);
// res.sendFile(path.resolve(__dirname,'./moban/login.ejs'));
let email = 'admin@163.com';
//分数
let score = [78, 90, 86, 69, 58];
let uarr = [{ 'uname': 'lisi', 'email': 'lisi@qq.com' }, { 'uname': 'tom', 'email': 'tom@163.com' }, { 'uname': 'zhangsan', 'email': 'zhangsan@sohu.com' }];
//渲染页面
res.render('login', { uarr, email, score });
});
模板文件(login.ejs)文件内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<%- include('login') %>
帐号:<input type="text" value="$USER$"><br> 密码:
<input type="password"><br>
<input type="submit" value="登录"><br>
<p>
<%=email %>
</p>
<p>
<%=uarr[0].uname %>
</p>
<div>
<table width="60%">
<tr>
<td>序号</td>
<td>帐号</td>
<td>邮箱</td>
</tr>
<% for(let i = 0;i<uarr.length;i++){ %>
<tr>
<td>
<%=i+1 %>
</td>
<td>
<%=uarr[i].uname %>
</td>
<td>
<%=uarr[i].email %>
</td>
</tr>
<% } %>
</table>
</div>
<% for(let s = 0;s<score.length;s++){ %>
<div>分数为:
<%=score[s] %>
</div>
<% if(score[s] >= 80) { %>
<div>优秀</div>
<% }else if(score[s] >= 60){ %>
<div>一般</div>
<% }else{ %>
<div>不及格</div>
<% } } %>
</body>
</html>
关于package.json文件中的”scripts”配置项的使用: 【重点】
如果在package.json文件中的”scripts”配置项中增加了下面的配置:
"scripts": {
"testejs": "node day09/1-ejs模板引擎.js",
"start": "node day09/1-ejs模板引擎2.js",
}
那么我们可以使用npm run testejs来运行对应的.js文件,当配置项名称为”start”时则可以使用省略run,即使用npm start 来运行对应的.js文件。
Express的生成器: 【重点】
1、express的生成器用途: 可以快速创建项目骨架。
2、express生成器用法:
1)、安装express生成器:npm i -g express-generator
2)、使用express生成器创建项目骨架:
express --view=模板引擎 项目名称
注意:创建项目骨架时要注意当前所在目录。
比如:
d:> express --view=ejs myoa
3)、切换到myoa目录中并安装项目所有依赖包:
d:>cd myoa
d:\myoa>npm install
4)、 启动项目:
d:>npm start
一、restful风格的api:
如:获取正在热映的电影接口:
https://api.douban.com/v2/movie/in_theaters
restful风格的api是指接口地址中要用专门的接口域名、版本号、动词与名称分开等一些约定。
二、windows常用快捷键:
1、win + r :打开windows的运行框
2、win + d:快速回到桌面
3、win + e:打开windows资源管理器
4、win + l:锁屏
三、数据库介绍:
1、什么是数据库?
按照一定数据结构组织、存放、使用数据的仓库。
2、为什么使用数据库?
使用数据库便于存储、使用、分享数据,同时能保证数据相对安全。
3、数据库分为关系型数据库、非关系型数据库:
关系型数据库:mysql、sqlserver、oracle等
非关系型数据库:mongodb、redis、memcached等
4、数据库基本概念:【重点】
1)、mysql数据库: 数据库—>表—>记录(数据)
2)、记录:表中每一行数据称为记录;
3)、字段:表中每一列称为字段;
4)、主键:能唯一代表表中某条记录的字段称为主键;
5)、外键:表中某个字段的值是另外一张表中主键的值,那么该字段称为外键
5、mysql常用管理命令:【重点】
1)、show databases:显示当前所有数据库
2)、use 数据库名:打开(切换)数据库
3)、show tables: 显示当前数据库中所有表
4)、create database 要创建的数据库名:创建数据库
5)、drop database 要删除的数据库名:删除数据库 慎重使用
6、windows下启动/停止mysql服务:
1)、在dos小黑窗中使用下面命令:
d:> net start mysql //启动mysql服务
d:> net stop mysql //停止mysql服务
2)、在windows服务管理器中启动/停止mysql服务:
1)右单击桌面”计算机”图标–>”管理”,打开”windows服务管理器”,如下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6u0jembO-1615858479911)(C:\Users\Shinelon\Desktop\笔记\windows服务管理器.png)]
2)、右单击上图中的mysql服务即可停止/启动mysql服务。
7、连接mysql数据库的两种方式:【重点】
1)、使用mysql自带的客户端应用程序(mysql.exe)连接mysql服务器,如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GyRbrlb0-1615858479913)(C:\Users\Shinelon\Desktop\笔记\mysql自带客户端.png)]
****注****: -h表示要连接的mysql主机 -u表示使用的mysql用户 -p表示用户密码
2、使用可视化客户端工具(Navicat )连接mysql数据库: 【重点】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7q118cDD-1615858479915)(C:\Users\Shinelon\Desktop\笔记\navicat.png)]
8、mysql常用的表类型[表引擎]: 【重点】
mysql常用的表类型有:myisam、innodb
myisam的特点:强调速度,不支持外键和事务;
innodb的特点:强调稳定性,支持外键和事务;
****事务****:比如给你朋友转2000元,那么要执行两个关键动作:你朋友帐户加2000、你自己帐户减2000,这个两个关键动作要么都成功、要么都失败。
设置外键时必须需求下面的要求:
1)、两张表的类型都是innodb;
2)、要设置外键的字段类型必须一样;
3)、要设置外键的字段值必须是另外一张表中主键的值;
9、mysql常用的字段类型:
定义表结构时字段类型根据实际存储值的类型来选择,其字段类型定义时既要满足当前需求、又要考虑将来扩展性;
1)、数值类型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TMtfxugM-1615858479916)(C:\Users\Shinelon\Desktop\笔记\数值类型.png)]
2)、字符类型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G6y0OyRV-1615858479920)(C:\Users\Shinelon\Desktop\笔记\字符类型.png)]
char:通常用来存储某个字段的值的长度是相对固定的,如果char类型中实际值的长度没达到定义时的长度则mysql会自动使用空格来填充;
varchar:通常用来存储某个字段的值的长度是可变的,varchar类型是字段值的实际长度来存储的;
添加数据:insert into 表名[(字段名1,字段名2…)]values(值1,值2…)
– 添加班级:
– insert into class(class-name
,teacher)values(‘java开发’,‘李老师’)
– insert into class(class-name
,teacher)values(‘张老师’,‘软测’)
– 添加学生:
insert into student(xingming,tel,age,classid,sex)values(‘Tom’,‘12345678’,20,‘3’,‘女’)
注意:只有给表中每个字段都添加值、并且每个字段值的顺序和表中字段顺序一一对应时可以省略字段名,如下:
– insert into class(classid,class-name
,teacher)values(4,‘python开发’,‘王老师’)
insert into class values(5,‘python开发2’,‘王老师3’)
修改数据: update 表名 set 要修改的字段名1=值1,要修改的字段名2=值2… [where 条件]
– 修改班号为3的班级名称为软件、老师为张老师
– update class set class-name
=‘web开发’,teacher=‘王老师’ where classid=3
– 修改学号为5的学生姓名为jack、性别为男:
update student set xingming=‘jack’,sex=‘男’ where xuehao=5
删除数据:delete from 表名 [where 条件]
– 删除班号为5的班级信息:
delete from class where classid=5
通过navicat工具导入、导出mysql数据:
1、导出数据:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZNXtgT3J-1615858479921)(C:\Users\Shinelon\Desktop\笔记\导出.png)]
2、导入数据:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ijrD1GWC-1615858479928)(C:\Users\Shinelon\Desktop\笔记\导入.png)]
单表查询: select */字段名/函数 from 表名 [where 条件 group by 字段名 order by 字段名 asc/desc having 条件 limit m,n]
– 查询所有学生信息:
– select * from student
– 查询每个学生的学号、姓名、年龄:
– select xuehao,xingming,age from student
– **注意:**可以在select关键词后面添加字符串当作固
– select ‘学号是:’,xuehao,‘姓名为:’,xingming,age from student
– 查询所有男生的学号、姓名、年龄、性别:
– select xuehao,xingming,age,sex from student where sex=‘男’
– 查询数学系、计算机系的学生姓名、学号、年龄、所在系:
– select xh,xm,age,szx from xsb where szx=‘计算机系’ or szx=‘数学系’
– [not] in()等价于上面的条件:
– select xh,xm,age,szx from xsb where szx in(‘计算机系’,‘数学系’)
– 查询分数大于等于80分、小于等于100的成绩信息:
– select * from cjb where cj>=80 and cj<=100
– ** [not] between…and等价于上面的条件**:
– select * from cjb where cj not between 80 and 100
– 模糊查询:
– %匹配零或n个任意字符 _匹配任意一个字符
– 查询姓王并且姓名为两个字的学生信息
select * from xsb where xm like ‘王_’
– 查询姓王并且姓名为多个字的学生信息
select * from xsb where xm like ‘王%’
– 查询姓名中含有王这个字的学生信息
select * from xsb where xm like ‘%王%’
– 不等于:<>或!=
– 查询不是计算机系的学生信息:
– select * from xsb where szx!=‘计算机系’
– 为 is [not] null值:
– 查询成绩为null的分数信息:
– select * from cjb where cj is null
– 去重:distinct
select distinct sex from xsb where szx=‘计算机系’
– 不等于:<>或!=
– 查询不是计算机系的学生信息:
– select * from xsb where szx!=‘计算机系’
– 为null值:
– 查询成绩为null的分数信息:
– select * from cjb where cj is null
– 去重:distinct
– select distinct sex from xsb where szx=‘计算机系’
– 排序:order by 默认按升序(asc)排序
– asc(升序)/desc(降序)
– 查询c02这个门课程的成绩信息,并按分数降序排序
– select * from cjb where kch=‘c02’ order by cj desc
– 查询除表演系外的学生学号、姓名、年龄、所在系,并按所在系升序排序、如果属于同一个的则按年龄降序排序
– select xh,xm,age,szx from xsb where szx<>‘表演系’ order by szx asc,age desc
– 随机排序:order by rand()
– 查询选修了c02、c05课程的分数信息,并随机排序
– select * from cjb where kch in(‘c02’,‘c05’) order by rand()
– as:起别名
– select xh as x,xm as m from xsb
– 查询个数:count()
– 查询学生总人数:
– select count(*) from xsb
– select count(age) as n from xsb
– 分组查询: group by
– 查询这个学校中的男生、女生分别有多少人?
– select count(*) as num,sex from xsb group by sex
– 查询成绩不为null的每门课程的选修人数,并按人数升序排序
– select count(xh) as n,kch from cjb where cj is not null group by kch order by n asc
– max()、min()、sum()、avg() 这些函数通常与group by 一起使用
– sum():求和
– max():最大值
– min():最小值
– avg():平均值
– 查询每门课程的最高分:
– select max(cj),kch from cjb group by kch
– 查询每个学生的总分数:
select sum(cj) as score,xh from cjb group by xh
– having:对查询结果进行二次筛选
– where:对表中存在的数据进行筛选
– 查询除表演系外每个系的人数,只显示人数在3人及3人以上的数据,并按所在系降序排序:
– select count(xh) as n,szx from xsb where szx<>‘表演系’ group by szx having n>=3 order by szx desc
– 查询分数在80分及80分以上的每门课程总分数,只显示总分数在200分及以上的数据,并按总分数降序排序:
– select sum(cj) as c,kch from cjb where cj>=80 group by kch having c>=200 order by c desc
– 限制查询条数:limit m,n
– m:位置编号[游标位置]
– n:每次要显示的条数
– 查询分数最高的前三条成绩信息:
– select * from cjb order by cj desc limit 3
– select * from cjb order by cj desc limit 0,3
– 位置编号默认从零开始:
– select * from xsb
– select * from xsb limit 1,4
– 计算总页面:向上取整函数(总记录个数/每页要显示的个数)
– 每页显示4个学生信息,第一页要显示的内容为:
– select * from xsb limit 0,4
– 每页显示4个学生信息,第二页要显示的内容为:
– select * from xsb limit 4,4
– 每页显示4个学生信息,第三页要显示的内容为:
– select * from xsb limit 8,4
– *游标位置=(第几页-1)每页要显示的条数
– 查询成绩不为null的每门课程总分数,只显示总分数最高的前三条:
select sum(cj) as n,kch from cjb where cj is not null group by kch order by n desc limit 3
express操作mysql数据库:
1、在项目根目录安装mysql包: npm i mysql
2、Express操作mysql:
1)、引入mysql包:
const mysql = require('mysql');
2)、创建连接:
const mysql = require('mysql');
//创建连接
let sqlObj = mysql.createConnection({
host: '主机名',
user: '用户名',
password: '密码',
port: 端口号,
database: '数据库名'
});
3)、连接mysql数据库: sqlObj.connect();
const mysql = require('mysql');
//创建连接
let sqlObj = mysql.createConnection({
host: '主机名',
user: '用户名',
password: '密码',
port: 端口号,
database: '数据库名'
});
//开始连接
sqlObj.connect();
4)、执行sql语句:sqlObj.query(‘sql语句’[,参数],(err,result)=>{});
注意:query()方法是异步方法
3、express操作mysql的例子:
//引入mysql包
const mysql = require('mysql');
const express = require('express');
const path = require('path');
const app = express();
// console.log(mysql);
app.listen(3000, () => {
console.log('port at 3000');
});
//使用内置中间件接收post参数
app.use(express.urlencoded({ extended: false }));
//设置ejs:
app.set('view engine', 'ejs');
app.set('views', [path.resolve(__dirname, 'views')]);
app.engine('html', require('ejs').__express);
//创建连接
let dbObj = mysql.createConnection({ host: 'localhost', user: 'root', password: '123456', port: '3306', database: 'myweb1020' });
// console.log(dbObj);
//连接数据库
dbObj.connect();
//操作数据库:dbObj.query('sql语句'[,参数],回调方法);
// $sql = "select * from student";
// dbObj.query($sql, (err, result) => {
// // console.log(err, result);
// result.forEach((item) => {
// // console.log(item, ind);
// console.log(item.xingming, item.sex);
// });
// });
//设计路由
app.get('/', (req, res) => {
res.render('searchuser.html');
})
//处理查询:
app.post('/search', (req, res) => {
// console.log(req.body);
//接参:
let uname = req.body.usr;
//用户输入的帐号
let usr = "";
//usr=demo
//usr=\' or 1=1\'
//用户输入的密码
let pwd = ""; //pwd=1234
//sql注入:利用sql语法漏洞攻击数据库
// sql = `select * from where usr='${usr}' and pwd='${pwd}'`;
// return;
//查询sql:
// sql = `select * from student where xingming like '%${uname}%'`;
sql = `select * from student where xingming like '%?%'`;
//执行sql:
dbObj.query(sql, [uname], (err, result) => {
console.log(err, result);
res.render('showuser.html', { result });
});
});
//添加用户
app.get('/adduser', (req, res) => {
//接参:
let { xingming, age, tel, sex, classid } = req.query;
let sql = `insert into student(xingming,age,tel,sex,classid)values(?,?,?,?,?)`;
dbObj.query(sql, [xingming, age, tel, sex, classid], (err, rt) => {
// console.log(err, rt);
if (err) { //失败
res.send("添加失败");
} else { //成功
res.send("添加成功");
}
})
});