zoukankan      html  css  js  c++  java
  • node.js mongodb笔记


    主模块:
    一个项目只允许有一个主模块,通常命名为:main.js index.js app.js package.json文件中的main声明
    主模块是整个项目的启动模块,主模块对整个项目的其它模块进行统筹调试

    Node.js的模块组成:
    所有用户编写的代码都放在模块中,模块就是文件(函数)
    所以用户编写的代码都自动封装在一个函数中,函数有五个参数:
    exports 暴露对象,可以将模块中的数据暴露给引入的地方
    require 引入模块的函数,用于在一个模块中引用另外一个模块,并且将子模块暴露的数据赋值给变量
    module 模块对象,包含了当前模块的所有信息
    _filename 当前模块的文件名
    _dirname 当前模块所在的路径(目录路径)

    require函数:
    作用:在当前模块中加载另外一个模块

    模块分类:
    1) 自定义模块
    我们自己编写的文件就是一个自定义模块
    require('');

    注意:
    a. 子模块没有暴露数据时,返回空对象
    b. 自定义模块必须加 ./ ,因为在node.js中查找模块默认在node_modules目录中查找

    2) 第三方模块
    第三方程序员或公司开发的模块,先安装再使用
    安装可以使用npm包管理工具
    npm install <包的名称>

    require('模块名');

    3) 系统模块
    node.js开发团队已经开发好的功能模块,直接引入即可使用,不需要安装也不需要自己写
    fs http url path ......

    require('模块名');

    require函数的注意事项:
    1) 当引入的模块有语法错误时,会报错
    2) 当引入的模块路径有错时,也会报错
    3) 当一个模块被多次引入时,只执行一次,将暴露对象直接写入缓存,以后就直接从缓存读取

    exports 导出对象:
    作用:将模块中需要共享给其它模块的数据暴露(导出)到引用处
    语法:
    exports.属性名 = 值;
    exports.方法名 = 函数;

    注意:
    1) exports 是module.exports对象的引用
    2) exports是module.exports的引用,不能改指向,只能添加属性和方法
    3) module.exports才是真正的暴露对象,指向哪里就暴露哪里

    module模块对象:
    module.exports 【重点】真正的暴露对象,exports对象只是对它的引用。
    module.exports.属性 = 值;
    module.exports.方法 = 函数;
    module.exports = 对象或函数;

    (了解)
    module.id 模块ID,模块名称
    module.parent 模块的父级
    module.filename 模块的文件名和路径
    module.children 子模块列表
    module.paths 模块查找路径,如果当前目录下找不到node_modules就去上一级目录查找,直到根目录...
    如果配置了NODE_PATH环境变量,则会再去环境变量指向的路径查找

    1. 什么是NPM ?
    npm(Node Package Manager)是基于nodejs的包管理工具

    1) 什么是包?
    包 === 项目
    模块 === 文件

    2. 什么是package.json ?
    package.json是node.js项目的包描述文件,以JSON格式的形式描述项目

    1) 如何创建package.json
    npm init
    npm init -y //自动以全部为yes的形式生成package.json文件

    2) package.json的常用属性
    name 项目名称
    version 版本号
    description 项目描述
    main 主模块
    dependencies 依赖列表
    devDependencies 开发时依赖
    scripts 脚本命令,可以使用npm命令进行执行
    license 开源协议

    3. npm 的常用命令
    //安装包
    npm install <包的名称> //安装指定的包
    npm i <包的名称> //效果同上,缩写形式
    npm i <包的名称>@版本号 //安装指定版本的包
    npm i <包的名称> -g //全局安装
    安装位置:C:UsersAdministratorAppDataRoaming pm ode_modules

    npm i <包的名称> --save //将安装包写入package.json依赖列表
    npm i <包的名称> --save-dev //将安装包写入package.json开发时依赖列表

    //其它命令
    npm search <包的名称> //搜索包
    npm view <包的名称> //查看包的信息
    npm uninstall <包的名称> //卸载包
    npm update <包的名称> //卸载包

    4. cnpm
    npm 就是一个文件下载工具,默认情况下去npmjs.com(github.com)下载资源
    cnpm 由于在国内下载npmjs.com的数据非常慢,所以淘宝制作了一个npmjs.com的镜像(可以下载,不能上传),直接访问国内的服务器

    安装cnpm:
    npm install -g cnpm --registry=https://registry.npm.taobao.org

    使用cnpm:
    与npm一模一样。

    控制台命令:
    console.log() 普通输出语句
    console.dir() ...
    console.error() 警告输出
    console.time(标识) 计时开始
    console.timeEnd(标识) 计时结束
    console.assert(表达式, 输出文字); //当表达式为假时,输出文字(抛出错误)

    注意:console.debug() 不能在node.js中使用

    //开启计时
    console.time('t1');
    for(var i=0; i<=9999999; i++){

    }
    console.timeEnd('t1');

    //断言
    console.assert(1>2, '表达式为假');

    node.js的作用域:
    由于node.js在执行里会将用户编写的所有代码都封装在函数中,所有用户定义的变量或函数都是局部的。
    要将数据共享给其它模块使用:
    1. 暴露对象
    module.exports

    2.全局对象
    global.属性或方法 = 值;

    注意:使用时global关键字可以省略不写

    示例:
    var username = '张三';

    //第一种:暴露对象
    module.exports.name = username;

    //第二种:使用全局对象
    global.name = username;

    回调函数:
    1) 什么是回调函数?
    回调函数又称为回调,将a函数作为参数传入b函数中,b函数在执行过程中根据时机或条件决定是否调用a函数,a函数就是回调函数

    2) 回调函数的机制
    a. 定义一个普通函数(可用做回调函数)
    b. 将函数作为参数传入另外一个函数(调用者)
    c. 调用者在执行过程中根据时机和条件来决定是否调用函数

    3) 回调函数的用途
    通常用于达到某个时机或条件时需要执行代码的情况,我们就会使用回调函数

    示例1:
    function show(){
    console.log('今天我学习了node.js');
    }

    setInterval(show, 1000);

    set Interval函数的定义:
    function setInterval(fn, time){
    //...计时...
    fn();
    }

    示例2:在html页面body里面写
    <script>
    ;(function(){
    $.fn.show = function(url, fn){
    var iframe = $('<iframe src="'+url+'" ></iframe>').appendTo('body');

    iframe.on('load',function(){
    data = $(this.contentDocument).find('body').text();
    data = JSON.parse(data);
    //data就是JSON数据
    fn(data);//回调函数的调用处,获取到数据以后才调用回调函数(回过头再调用你)
    });
    }
    })();

    //调用插件获取数据
    $('body').show('./data.json', function(a){
    console.log(a);
    });
    </script>


    异步的实现
    异步的三种实现方式:
    1. 回调函数
    回调函数不一定是异步,但是异步一定有回调函数
    2. 事件
    事件源.on('事件名称', 回调函数)
    3. promise 承诺对象
    1) 什么是promise
    promise是ES6中新增的承诺对象,用于对异步的操作进行消息的传递

    2) promise的状态
    Pending 等待中
    Resolved 成功
    Rejected 失败

    Pending => Resolved
    Pending => Rejected

    3) promise有什么用?
    promise可以用于传递异步消息

    示例1:
    //异步一定有回调函数
    setTimeout(function(){
    console.log('111');
    },1000); //时间在windows系统里面最小是15ms,即使设置为0ms也会自动修改为15ms

    //回调函数不一定是异步
    console.log('111');
    var arr = [1,2,3,4];
    arr.forEach(function(v,i){
    console.log(v);
    });
    console.log('222');

    示例2:
    var http = require('http');

    var server = http.createServer();
    server.on('request', function(req, res){
    res.writeHead(200, {"Content-Type":'text/html; charset=utf-8'});
    res.write('<h1>您下在访问node.js服务器</h1>');
    res.end();
    });

    server.listen(80, function(){
    console.log('服务器已运行');
    });

    示例3:
    var fs = require('fs');

    //将异步的数据交给p1进行处理
    var p1 = new Promise(function(resolve, reject){
    //读取file1.txt
    fs.readFile('./file1.txt', function(err, data){
    if(err){
    reject('数据找不到'); //从等待改变成失败
    }else{
    resolve(data.toString()); //从等待改变成成功
    }
    });
    });

    //调用p1对象,统一展示异步的数据
    p1.then(function(data){
    console.log('promise对象输出的数据:', data);
    },function(err){
    console.log('promise对象错误展现:', err);
    });

    //读取file2.txt
    var p2 = new Promise(function(resolve, reject){
    fs.readFile('./file2.txt', function(err, data){
    //file2的异步消息也交给promise对象进行控制
    if(err){
    reject('file2出错了');
    }else{
    resolve(data.toString());
    }
    });
    });

    //利用Promise对象的all方法可以实现手动调整输出的顺序,相当于把异步变成同步
    Promise.all([p1,p2]).then(function(datas){
    console.log(datas);
    },function(errs){
    console.log(errs);
    });

    缓存区
    1. 什么是缓存区?
    在内存中开辟一个临时区域用户存储需要运算的字节码

    2. 创建缓存区
    1) 创建指定长度的缓存区

    2) 按指定的数组(编码)创建缓存区
    var buf = new Buffer([10进制编码]);

    3) 按指定字符创建缓存区
    var buf = new Buffer('字符串');

    示例1:
    //创建指定长度的缓存区
    var buf = new Buffer(5); //创建5个字节的缓存区
    buf.write('张'); //在node.js中默认使用utf-8编码,一个中文字占3个字节

    console.log(buf);

    示例2:
    //按指定的数组(编码)创建缓存区
    var buf = new Buffer([97,98,99,65,66]);
    console.log(buf);

    示例3:
    //按指定字符创建缓存区
    var buf = new Buffer('张三');
    console.log(buf);
    console.log(buf.toString());

    3. 写入缓存区
    buf.write('字符串');

    4. 读取缓存区
    buf.toString();

    5. 缓存区复制
    buf1.copy(buf2); //把buf1的数据复制给buf2

    文件系统操作(文件模块fs)
    1. 读取文件
    由于node.js是服务器端程序,必须要有读写文件操作,在客户端没有这样的功能
    文字读写的两种方式:
    1) 直接读取
    将硬盘上的所有内容全部读入内存以后才触发回调函数
    两种写法:
    异步:定义一个回调函数,接收读取到的内容
    fs.readFile('文件路径', function(错误对象, 数据){
    });

    同步:几乎所有的fs函数都有同步版本,只需要在异步版本后面添加Sync即可
    var data = fs.readFileSync('文件路径');

    示例1:
    //如果要读取文件,必须使用文件系统模块(fs)
    var fs = require('fs');

    console.log('111');
    //直接读取文件--异步
    fs.readFile('./data.json', function(err, data){
    console.log(data.toString());
    });
    console.log('222');

    示例2:
    console.log('111');
    //同步读取文件
    var data = fs.readFileSync('./data.json');
    console.log(data.toString());
    console.log('222');

    2) 流式读取
    将数据从硬盘中读取一节就触发回调函数,实现大文件操作

    2. 写入文件
    1) 同步版本
    fs.writeFileSync('文件名', '数据');

    2) 异步版本
    fs.writeFile('文件名', '数据', function(err){
    //写完文件以后执行的代码
    });

    示例:
    var fs = require('fs');
    var hello = "<h1>Hello Node.js</h1>";
    fs.writeFile('index.html', hello, function(err){
    if(err){
    throw err;
    }else{
    console.log('文件写入成功');
    }
    });

    3. 读取文件信息:
    fs.stat('文件名', function(err, state){
    //state是文件的信息对象,包含了常用的文件信息
    size 文件大小(字节)
    mtime 文件修改时间
    birthtime 文件创建时间

    //方法
    .isFile() 判断当前查看的对象是不是一个文件
    .IsDirectory() 判断是不是一个目录
    });

    示例:
    var fs = require('fs');
    fs.stat('./data.json', function(err, state){
    console.log(state.isFile());
    console.log(state.isDrectory());
    });

    4. 删除文件
    fs.unlink('文件路径', function(err){
    //...
    });

    示例:
    var fs = require('fs');
    fs.unlink('./jquery.js', function(err){
    if(err)
    {
    throw err;
    }else{
    console.log('删除成功');
    }
    });

    5.递归删除非空目录
    需求:编写代码实现删除一个非空目录
    1) 读取目录中的文件及文件夹列表
    fs.readdir()
    2) 读取每一个文件的详细信息
    fs.stat()
    3) 判断如果是文件
    fs.unlink()
    4) 判断如果是目录
    递归调用自己
    5) 删除空目录
    fs.rmdir()

    示例:
    var fs = require('fs');
    //使用同步的方式实现
    function deldir(p){
    //读取文件夹的内容
    var list = fs.readdirSync(p);
    //遍历数组
    for(var i in list){
    //list[i] 是当前目录中每一个文件及文件夹的名称
    var path = p + '/' + list[i]; //拼接一个从(05.js)当前目录能查找到的路径

    var info = fs.statSync(path);
    if(info.isFile()){
    fs.unlinkSync(path); //如果是文件则删除
    }else{
    arguments.callee(path); //如果不是文件就是目录,则调用自己再删除该目录
    }
    }
    //删除空目录
    fs.rmdir(p);
    }

    deldir('./data');

    6.读取流和写入流
    1) 什么流?
    所有互联网传输的数据都以流的方式,流是一组有起点有终点的数据传输方式
    2) 流的操作
    a. 流式读取文件
    一节一节的读取数据,一节64kb ==> 65536字节

    b. 以流的方式写文件
    一节一节的写文件

    示例1:读取流
    var fs = require('fs');
    var data = ''; //存储每次读取的数据

    //创建一个可以读取的流
    var stream = fs.createReadStream('./file3.txt');
    //设置编码为utf8
    readerStream.setEncoding('UTF8');

    //绑定data事件,当读取到内容就执行
    stream.on('data', function(a){
    data += a;
    });

    //读取流的事件:end 完成事件
    stream.on('end', function(){
    console.log(data);
    });

    //读取流的事件:error 错误事件
    stream.on('error', function(err){
    console.log(err.stack);
    });

    示例2:写入流
    var fs = require('fs');
    var data = '今天我学习了node.js,真高兴';

    //创建一个可以写入的流
    var stream = fs.createWriteStream('./file4.txt');
    //使用 utf8 编码写入数据
    writerStream.write(data, 'UTF8');

    stream.end(); //以流的方式写数据必须显示的声明结束

    //写入流的事件:finish 完成事件
    stream.on('finish', function(){
    console.log('写完了');
    });

    //写入流的事件:error 错误事件
    stream.on('error', function(err){
    console.log(err.stack);
    });

    7. 管理pipe
    1) 什么是管道?
    管道是node.js中提供了一个输出流到输入流的机制。通常我们用于从一个流中获取数据并将数据传递到另外一个流中。

    2) 管道语法
    输出流.pipe(输入流)

    示例(实现大文件的复制):
    var fs = require('fs');

    var s1 = fs.createReadStream('./file3.txt');
    var s2 = fs.createWriteStream('./file6.txt');

    //1.以流的方式实现大文件复制,读取一节存一节
    s1.on('data', function(a){
    s2.write(a);
    });

    s1.on('end', function(){
    s2.end();
    console.log('文件复制已完成');
    });

    //2.使用管道实现大文件的复制
    s1.pipe(s2);

    8. 链式流
    将多个管道连接起来,实现链式处理。

    示例(使用链式流实现大文件压缩):
    var fs = require('fs');
    var zlib = require('zlib');

    var s1 = fs.createReadStream('./file3.txt');
    var s2 = fs.createWriteStream('.file3.txt.zip');

    s1.pipe(zlib.createGzip()).pipe(s2);

    常用模块
    1. path模块
    1) 什么是path模块?
    path 模块是node.js中提供的一个系统模块,用于格式化或拼接一个完整的路径

    2) path模块的常用方法
    path.join() //【重点】将多个字符串拼接成一个完整的路径
    path.dirname() //返回路径中的文件夹部分
    path.basename() //返回路径中的文件部分(文件名和扩展名)
    path.extname() //返回路径中的扩展部分
    path.parse() //【重点】解析路径:返回一个对象包含路径中的各个部分

    示例:
    var path = require('path');

    var p1 = "../../../path/../a./b/../c.html";
    console.log(path.normalize(p1)); //格式化路径

    var p2 = 'day02/hello/zs.html';
    console.log(path.join('code', p2));
    console.log(path.join(_dirname, p2)); //_dirname是模块的组成部分之一,代表当前模块所在的目录

    2. URL模块
    1) 什么是url?
    url 全球统一资源定位符,对网站资源的一种简洁表达形式,也称为网址。

    2) url的构成
    //完整结构
    协议://用户名:密码@主机名.名.域:端口号/目录名/文件名.扩展名?参数名=参数值&参数名2=参数值2#hash

    //http协议的url常见结构:
    协议://主机名.名.域/目录名/文件名.扩展名?参数名=参数值&参数名2=参数值2#hash

    3) node.js的url模块
    在node.js中提供了两套对于url进行处理的API功能。
    a. 老的node.js url模块
    b. 新的url模块(WHATWG URL标准模块)

    示例:
    var url = require('url');

    var u = 'http://music.163.com:8080/aaa/index.html?id=10#/discover/playlist';

    //老的node.js 的url模块
    console.log(url.parse(u));

    //新的url模块(符合WHATWG标准)
    var obj = new url.URL(u);
    console.log(obj);


    3. http模块
    1) 什么是网络?
    网络是一个共享、传输信息的虚拟平台

    2) 什么是网络协议?
    每天有大量的数据在网络上传输,都需要遵循相应的规则,规则就是网络协议

    3) 什么是http协议?
    http(hypertext transfer protocol)即超文本传输协议,传输超文本内容(文字、图片、视频、音频、动画...)

    4) http协议规定的细节
    http协议是一种请求应答形式的协议,一次请求,一次应答(响应).

    细节:
    定义了浏览器以什么格式向服务器发请求
    定义了服务器以什么格式解析浏览器发送过来的数据
    定义了服务以什么格式响应数据给浏览器
    定义了浏览器以什么格式解析服务器响应的数据

    5) get方法
    get方法用于模仿客户端从服务器获取数据

    var http = require('http');
    http.get('url', function(res){
    //res 是返回对象,接收到服务器响应的所有内容
    });

    node.js服务器
    1. 引入通信模块
    2. 创建服务器
    3. 监听request事件
    4. 监听端口

    代码:
    var http = require('http');
    //创建服务器
    var server = http.createServer();

    //监听request请求事件,当前请求事件发生时就返回数据
    server.on('request', function(req, res){
    //req:请求对象,包含了所有客户端请求的数据,请求头,请求主体
    //res:响应对象,包含了所有服务器端发送给客户端的数据,响应头、响应主体
    res.write('<h1>Hello Node.js</h1>');
    res.end();
    });

    //监听服务器的80端口
    server.listen(80, function(){
    console.log('服务器已运行');
    });

    5. http状态码
    1) 什么是状态码?
    http协议规定的服务器响应数据时的状态编码,就是状态码

    2) 常用的状态码
    1XX : 表示普通消息,没有特殊含义
    2XX : 表示服务器响应成功
    200 成功【掌握】

    3XX : 表示重定向
    301 永久重定向【掌握】
    302 临时重定向
    304 使用缓存(服务器没有更新过)

    4XX : 无法访问
    403 权限不足,无法访问
    404 资源找不到【掌握】

    5XX : 服务器有错
    500 服务器端代码有错【掌握】
    502 网关错误
    503 服务器已崩溃

    3) 状态码的使用
    res.writeHead(状态码, 响应头对象);

    示例:
    var http = require('http');
    var server = http.createServer();

    server.on('request', function(req, res){
    res.writeHead(200, {"Content-Type":"text/html; charset=utf-8"});
    res.write('<h1>今天星期二</h1>');
    res.end();
    });

    server.listen(80, function(){
    console.log('服务器已运行');
    });

    4) 响应头
    Content-Type 响应的文件类型
    text/html
    注意:未指定响应文件类型时,默认就是html,编码默认是系统编码

    Content-Length 响应内容的长度
    Access-Control-Allow-Origin 设置响应头可以跨域

    示例:
    var http = require('http');
    var server = http.createServer();

    server.on('request', function(req, res){
    res.writeHead(200, {"Content-Type":"text/html; charset=utf-8","Access-Control-Allow-Origin":"*"});
    res.write('<h1>今天星期二</h1>');
    res.end();
    });

    server.listen(80, function(){
    console.log('服务器已运行');
    });

    5) MIME类型
    1) 什么是MIME类型?
    MIME类型可以认为是文件类型的表述

    2) 常用的MIME类型
    .html text/html
    .css text/css
    .js text/javascript
    .json text/json application/json
    .xml text/xml
    .png image/png
    .jpg image/jpeg
    .gif image/gif
    .mp3 audio/mpeg
    .mp4 video/mpeg
    .pdf application/pdf
    .zip application/x-gzip
    ......

    express框架
    1. 什么是express?
    express是一个基于node.js的极简、灵活的web开发框架。可以实现非常强大的web服务器功能。

    2. express的特点
    可以设置中间件响应或过滤http请求
    可以使用路由实现动态网页,响应不同的http请求。
    内置支持ejs模板(默认是jade模块)实现模板渲染生成html

    3. express安装与使用
    1) 安装express-generator生成器
    cnpm i -g express-generator //安装完成后可以使用express命令

    2) 创建项目
    express -e 项目名称 //自动创建项目目录
    express -e //手动创建项目目录

    3) 安装依赖
    cnpm i

    4) 开启项目 (3种方式)
    node app //【推荐】需要手动添加监听端口的代码
    app.listen(80, function(){
    console.log('服务器已运行');
    });
    npm start //自动查找当前目录下的package.json文件,找到start对应的命令进行执行
    node ./bin/www

    5) 测试项目
    打开浏览器,输入 localhost

    4. express项目的目录说明
    1) 目录
    bin 可执行文件目录
    node_modules 依赖包的目录

    public 静态文件根目录
    所有的静态文件都应当放在这个目录下(静态html、css、js、图片、字体、视频等资源)

    routes 路由模块目录,动态文件的目录
    请求发生时,优先找静态文件,如果没有静态存在则找动态路由,如果动态路由也没有,就404

    views 视图目录,用于存储所有的ejs模板

    2) 文件
    app.js 项目的主文件,对整个项目的所有资源进行统筹的安排

    package.json 项目描述文件,声明项目的名称、版本、依赖等信息

    5. 路由的概念及基本用法
    1) 什么是路由?
    路由是指接收用户请求,处理用户数据,返回结果给用户的一套程序。可以理解为:动态网页的程序。
    后端路由的核心:URL

    2) express的路由
    express对象自带有一个Router类,可以实例化出路由对象,可以在该对象上挂载非常多的路由节点

    3) 路由的写法
    //挂载路由线路的写法
    router.请求方式('请求地址', function(req, res){
    res.send('数据');
    });

    6. 响应对象
    响应对象(res)的方法向客户端返回响应,终结请求响应的循环。如果在路由函数中一个方法也不调用,来自客户端的请求会一直挡土挂起。

    1) send 方法(重点中的重点)
    send(data) 可以返回任意类型的数据。

    res.send(new Buffer('whoop')); //流
    res.send({some:'json'}); //json数据
    res.send('<p>some html</p>'); //普通文本

    //设置状态码,并且返回内容
    res.status(404).send('Sorry,we cannot find that!');
    res.status(500).send({error:'something blew up'});

    2) json 方法
    json(data) 返回json对象,一般针对ajax应用。
    res.json(null);
    res.json({user:'Terry'});

    //设置状态码,并返回 json数据
    res.status(500).json({error:'message'});

    3) render 视图模板

    //将渲染视图发送给客户端
    res.render('index');

    //将视图和数据合并后发送给客户端
    res.render('index',{username:"二狗"});

    4) download 下载
    res.download('./xxx.doc'); //下载当前目录下面的xxx.doc文件
    res.download('./xxx.dox', 'yyy.doc'); //下载当前目录下面的xxx.doc文件,并且重命名为yyy.doc

    5) redirect 重定向
    重定向到从指定的URL路径(浏览器地址变为设置的地址)
    res.redirect('/login.html');
    res.redirect('http://www.baidu.com');

    6) 完整 api
    res.app : 同req.app一样
    res.append() : 追加指定HTTP头
    res.set() 在 res.append() 后将重置之前设置的头
    res.cookie(name, value[, option]) : 设置Cookie
    option : domain/expires/httpOnly/maxAge/path/secure/signed
    res.clearCookie() : 清除Cookie
    res.download() : 传送指定路径的文件
    res.get() : 返回指定的HTTP头
    res.json() : 传送JSON响应
    res.jsonp() : 传送JSONP响应
    res.location() : 只设置响应的Location HTTP头,不设置状态码或者close response
    res.redirect() : 设置响应Location HTTP头,并且设置状态码302
    res.send() : 传送HTTP响应
    res.sendFile(path[, option][, fn]) : 传送指定路径的文件 -会自动根据文件extension设定Content-Type
    res.set() : 设置HTTP头,传入object可以一次设置多个头
    res.status() : 设置HTTP状态码
    res.type() : 设置Content-Type的MIME类型

    7. 请求对象req(重点)
    1) 什么是请求对象?
    客户端向服务器发送数据的对象,包含请求头和请求主体

    2) 接收get方式传的值
    语法:req.query.参数名
    示例:req.query,id

    3) 接收post方式传的值
    语法:req.body.参数名

    4) 完整api
    req.app : 当callback为外部文件时,用req.app访问express的实例
    req.baseUrl : 获取路由当前安装的URL路径
    req.bodyr : 获得请求主体
    req.cookies : 获取Cookie
    req.fresh/req.stale : 判断请求是否还新鲜
    req.hostname : 获取主机名
    req.ip : 获取IP地址
    req.originalUrl : 获取原始请求URL
    req.params : 获取路由的parameters
    req.path : 获取请求路径
    req.protocol :获取协议类型
    req.query : 获取URL的查询参数串
    req.route : 获取当前匹配的路由
    req.subdomains : 获取子域名
    req.accepts() : 检查请求的Accept头的请求类型
    req.acceptsCharsets / req.acceptsEncodings / req.acceptsLanguages
    req.get() : 获取指定的HTTP请求头
    req.is() : 判断请求头Content-Type的MIME类型

    中间件
    Express 是一个自身功能极简,完全是由路由和中间件构成一个的web开发框架:从本质上来说,一个Express应用就是在调用各种中间件。

    1. 什么是中间件?
    中间件(Middleware)本质就是一个函数,它可以访问请求对象(request object(req)),响应对象(response object(res)),和web应用中处于请求-响应循环流程中的中间件,一般被命名为next的变量。(next 尾函数,执行下一个任务)

    中间件的功能包括:
    执行任何代码
    修改请求和响应对象
    终结请求-响应循环
    调用堆栈中的下一个中间件

    如果当前中间件没有终结请求-响应循环,则必须调用 next() 方法将控制权交给下一个中间件,否则请求就会挂起。

    2. 自定义中间件
    app.use(function(req, res, next){
    res.send('我是中间件');
    });

    3. 尾函数 next
    如果中间件不调用next函数,整个请求响应流程就中止不会再往后面执行
    调用尾函数相当于调用下一个中间件,执行完以后自己的函数继续执行

    4. 应用级中间件
    应用级中间件绑定到 app 对象使用 app.use() 和 app.METHOD(),其中,METHOD 是需要处理的HTTP请求方法,例如 GET,PUT,POST等等,全部小写。

    示例1://最简单的中间件
    var app = express();
    //应用的每个请求都会执行该中间件
    app.use(function(req, res, next){
    req.nowDate = Date.now();
    //继续执行下一个中间件或路由

    });

    示例2:
    var app = express();
    //应用的每个请求都会执行该中间件
    app.use(function(req, res, next){
    var accessToken = req.query.accessToken;

    //检查请求中是否含有“认证牌”,存在就继续执行
    if(accessToken){
    next();
    }else{
    res.send('请求必须包含 token');
    }
    });

    5. 内置中间件
    Express中只为我们提供了唯一一个中间件,其他的中间件需要安装

    6. 第三方中间件
    通过使用第三方中间件从而为 Express 应用增加更多功能。
    安装所需要的 node 模块,并在应用中加载,可以在应用级加载,也可以在路由级加载。
    下面的例子安装并加载了一个解析 cookie 的中间件: cookie-parser

    cnpm i multer --save

    var multer = require('multer');
    var app = express();

    //使用文件上传中间件
    app.use(multer({ dest:'./uploads/'}));

    中间件列表:https://github.com/senchalabs/connect#middleware

    7. 实例
    需求:写一个记录网站访问日志的中间件

    app.use(function(req, res, next){
    var fs = require('fs');
    var ip = req.ip;
    var time = new Date().toLocaleString();

    var data = fs.readFileSync('./2020-04-10.log');
    data += '访问时间:'+ time + ' IP:' + ip + ' ';
    fs.writeFileSync('./2020-04-10.log', data);

    next();
    });

    数据库的基本介绍
    1. 什么是数据库?
    数据库(database)是一个按照数据结构进行数据的组织、管理、存入数据的仓库。

    2. 关系型数据库
    按照关系模型存储数据的数据库,数据与数据之间的关联非常密切,可以实现跨数据表查询数据,占用更少的硬盘实现更多数据存储
    T-SQL标准的结构化查询语言是关系型数据库的通用查询语言。
    常见的关系型数据库:Mysql sql-server access sqlite oracle ...

    结构:一台服务器 => 数据库 => 数据表 => 数据行

    3. 非关系型数据库
    不按关系模型存储数据的数据库,统称为nosql。
    第一层含义:不是SQL,不是关系型数据库。
    第二层含义:Not Only SQL,不仅仅是SQL

    结构:一台服务器 => 数据库 => 集合 => 文档

    4. 非关系型数据库与关系型数据库区别

    非关系型数据库的优势:

    1) 性能
    NOSQL 是基于键值对的,可以想象成表中的主键和值的对应关系,而且不需要经过SQL层的解析,所以性能非常高。

    2) 可扩展性
    同样也是因为基于键值对,数据之间没有耦合性,所以非常容易水平扩展。

    关系型数据库的优势:

    1) 复杂查询
    可以用SQL语句方便的在多个表之间做非常复杂的数据查询

    2) 事务支持
    使得对于安全性能很高的数据访问要求得以实现

    总结:
    数据库功能是用来存储数据的
    数据库分为关系型数据库和非关系型数据库(nosql)
    关系型数据库是由表和表之间的关系组成的,nosql是由集合组成的,集合下面是很多的文档
    非关系型数据库文件存储格式为 BSON (一种JSON的扩展)


    5. MongoDB
    1) 安装 mongodb软件
    选择完全安装

    2) 设置环境变量
    找到安装目录,找到mongo命令所在位置:C:Program FilesMongoDBServer3.2in
    将命令位置添加到环境变量:
    我的电脑(计算机) 点击鼠标右键-> 属性 -> 高级系统设置 -> 高级 -> 环境变量 -> 修改PATH的值(添加一个分号,将数...)

    3) 创建文件夹
    在非系统盘(D盘)下创建一个文件夹mongodb,再创建两个子文件夹 db 和 log
    d:mongdb
    d:mongdbdb
    d:mongdblog

    4) 将mongodb挂载成windows服务
    使用命令挂载服务
    mongod --dbpath "d:开发区mongodbdb" --logpath "d:开发区mongodblogMongoDB.log" --install --serviceName "MongoDB"

    服务如何查看
    在“计算机”上点鼠标右键 -> 管理 ->服务与应用程序 -> 服务
    运行命令 services.msc

    补充说明服务的命令
    net start mongdb //开启服务
    net stop mongdb //关闭服务
    sc delete mongdb //卸载服务

    5) 常见问题
    32位操作系统的问题
    必须添加存储引擎设置: --storageEngine mmapv1
    mongod --storageEngine mmapv1 --dbpath "d:mongdbdb" --logpath "d:mongdb..."...

    win8或win10操作的权限问题
    必须以管理员身份运行cmd命令行,再执行挂载服务命令

    6. 数据库基础命令
    1) 进入数据库管理模式
    在命令行中运行:mongo 进入数据库管理模式
    在数据库管理模式中只能执行数据库命令,不能执行其它命令

    exit 退出数据库管理模式

    2) 常用的命令
    a. 数据库命令
    显示所有的数据库列表
    show dbs

    创建数据库/进入数据库
    use 数据库名
    如果数据库名不存在,则创建
    如果数据库已存在,则进入

    查看当前数据库是谁
    db

    删除数据库
    db.dropDatabase();

    b. 集合的命令
    显示当前数据库中的所有集合
    show collections

    创建集合
    db.集合名.insert({});
    通常,在创建数据时自动创建集合,不需要单独创建

    删除集合
    db.集合名.drop();

    3) 文档(数据)的操作【重点】
    a. 新增文档(数据)
    db.集合名.insert({JSON数据});
    db.集合名.save({JSON数据});

    insert 和 save 方法的区别:
    .insert() 向集合中插入一条数据【推荐使用】
    .save() 向集合中添加一条数据,如果集合中已经存在该数据则更新

    b. 查询文档(数据)
    db.集合名.find(); 【重点】//查找当前集合中的所有数据
    db.集合名.find({条件对象}); //符合条件的数据被查出来
    db.集合名.findOne(); //查找集合中的第一条数据
    db.集合名.find().pretty(); //将找到的数据以格式化的结果显示出来

    c. 修改数据
    db.集合名.update(查找对象, 修改结果);

    例如:
    db.user.update({"username":"张三"},{"age":18});

    d. 删除数据
    db.集合名.remove({}); //删除当前集合中的所有数据
    db.集合名.remove({条件对象});
    例如:
    db.user.remove({"age":18});
    db.user.remove({});

    7. 高级用法
    1) 按指定条件查询
    //查找到所有的女歌星
    db.singer.find({"sex":"女"});

    //SQL : select * from singer where sex = '女'

    //查找所有中国女歌星
    db.singer.find({"country":"中国","sex":"女"});

    2) 大于
    语法:db.集合名.find({字段名:{$gt:值}});

    //查找年龄大于50岁的所有数据
    db.singer.find({"age":{$gt:50}});

    //SQL : select * from singer where age > 50

    3) 大于等于
    语法:db.集合名.find({字段名:{$gte:值}});

    //查找年龄大于等于50岁的所有数据
    db.singer.find({"age":{$gte:50}});

    4) 小于
    语法:db.集合名.find({字段名:{$lt:值}});

    //查找年龄小于30岁的所有数据
    db.singer.find({"age":{$lt:30}});

    5) 小于等于
    语法:db.集合名.find({字段名:{$lte:值}});

    //查找年龄小于等于30岁的所有数据
    db.singer.find({"age":{$lte:30}});

    6) 查询指定范围的数据
    语法:db.集合名.find({字段名:{$gt:小值, $lt:大值}});

    //查找年龄30-0岁之间的所有数据
    db.singer.find({"age":{$gt:30,$lt:40}});

    //SQL : select * from singer where age>30 and age<40
    //SQL : select * from singer where age between 30 and 40

    7) $in 子句
    语法:db.集合名.find({"字段名":{$in:[数组值]}});

    //找出刘德华、张学友、郭富城
    db.singer.find({"namme":{$in:['刘德华','张学友','郭富城']}});

    //SQL : select * from singer where name in ('刘德华','张学友','郭富城')

    8) $nin 子句
    语法:db.集合名.find({"字段名":{$nin:[数组值]}});

    9) 按数组元素的个数查找
    语法:db.集合名.find({"字段名":{$size:数量}});

    //查找只有一个代表作的歌手
    db.singer.find({"works":{$size:1}});

    10) $or 子句
    查找多条件时,符合其中一个就找出来
    语法:db.集合名.find({$or:[{"字段名":值},{"字段名2":值2}]});

    某个活动必须要刘德化参加,另外需要团队的全部女歌手配合演出,领导安排你帮忙打印歌手资料
    db.singer.find({$or:[{"name":"刘德华"},{"sex":"女"}]});

    //SQL : select * from singer where name="刘德华" or sex="女"

    11) 不等于
    语法:db.集合名.find({"字段名":{$ne:值}});

    12) 取模运算,条件相当于 字段名%10==1 即字段名除以10余数为1的
    语法:db.集合名.find({"字段名":{$mod:[10,1]}});

    13) $exists
    语法:db.集合名.find({"key":{$exists:true|false}});

    $exists 字段存在,true返回存在字段key的数据,false返回不存在字段key的数据

    8.其它重要语句
    1) 排序 sort()
    语法:db.集合名.find({}).sort({"字段名":1, "字段名":-1});
    说明:1是升序(从小到大),-1是降序(从大到小)

    //对所有歌手按年龄进行降序排序
    db.singer.find().sort({"age":-1});
    db.singer.find().sort({"age":-1, "score":1});

    2) 限制输出 limit() skip()
    .limit(数字) //限定输出数据的条数
    .skip(数字) //跳过指定的数据条数

    //只查找年龄最大的三个人
    db.singer.find().sort({"age":-1}).limit(3);

    //查看年龄在第三、第四、第五的三个人
    db.singer.find().sort({"age":-1}).skip(2).limit(3);

    扩展:这两个限定输出的语句主要用于分页
    数据太多,在一个页面显示不完,可以分多个页面显示数据,就叫分页

    场景:现在有100条数据,每页显示10条,一共有多少页?10页
    如果当前在第2页上,应当显示哪些数据?11-20之间的数据

    3) 返回结果集的条数 count()
    语法:db.集合名.find().count();

    注意:在加入skip()和limit()这两个操作时,要获得实际返回的结果数,需要一个参数true,否则返回的是符合查询条件的结果总数
    db.集合名.find().skip(5).limit(5).count(true);

    3) 模糊查询
    语法:db.singer.find({"字段名":/值/});

    //需求:找出所有姓刘的人
    db.singer.find({"name":/刘/i});


    mongoose模块
    1. 什么是mongoose?
    mongoose是一个基于node.js的用于操作mongodb数据库的第三方模块

    2. mongoose的安装
    先配置一个express框架
    cnpm install mongoose

    3. mongoose的使用
    1) 连接数据库
    语法:mongoose.connect("mongodb://服务器:端口号/数据库名", 回调函数);

    示例:
    var mongoose = require('mongoose');
    mongoose.connect("mongodb://127.0.0.1:27017/数据库名", function(err){
    if(err){
    throw err;
    }else{
    console.log('数据库连接成功');
    }
    });

    2) 定义骨架 schema
    概述:schema骨架量一种数据结构声明,不具备数据库的操作能力

    语法:
    var schema = new mongoose.Schema({
    字段名:类型,
    字段名:类型
    });

    示例:
    var singerSchema = new mongoose.Schema({
    name:String,
    country:String,
    age:Number
    });

    骨架的类型:String Number Date Buffer ObjectId Array ...

    3) 创建模型 model
    概述:model模型是一种根据骨架创建出来的模型,具备数据库操作的能力,通常用于读取数据库
    语法:
    var singerModel = mongoose.model('模型名称', 骨架, '集合名称');

    示例:
    var singerModel = mongoose.model('singer', 'singerSchema', 'singer');

    4) 创建实体 Entity
    概述:Entity实体是根据模型创建出一个实例,具备数据库操作的能力,通常用于写数据(新增、修改、删除)
    var singer = new singerModel();
    singer.属性名 = 值;
    singer.save(); //将添加到实例上的属性保存到数据库中
    singer.remove(); //删除数据

    4. 数据操作(增删改查)
    1) 查询数据/读取数据
    //根据条件进行数据查询,可以找出多条数据
    模型.find({条件}, function(err,data){
    //data是从数据库中读取到的数据
    //find方法找出来的数据一定是一个数组,即使没有数据也是一个空数组
    });

    //通过ID查找一条数据
    模型.findById('id', function(err, data){
    //findById找出来的数据是一个对象
    });

    //另一种常用的写法(为了实现更好的链式调用)
    模型.find({}).skip().limit.sort().exec(function(err, data){

    });

    2) 新增数据
    var list = new listModel(); //根据模型创建实例
    list.name = '张三';
    list.age = 18;
    //将新增的数据保存到数据库中
    list.save(function(err){
    console.log('新增成功');
    });

    //注意:骨架中没有定义属性及类型,不能加进数据库


    3) 删除数据
    思想:
    第一步:找出要被删除的数据
    第二步:调用remove()方式删除数据

    实现:
    listModel.findById(id),exec(function(err, data){
    data.remove(function(err){
    console.log('删除成功');
    });
    });

    4) 修改数据
    思想:
    第一步:找出被修改的数据
    第二步:将数据修改以后保存回数据库

    实现:
    listModel.findById(id).exec(function(err, data){
    data.name = 新的值;
    data.age = 新的值;
    data.save(function(err){
    console.log('修改成功');
    });
    });

  • 相关阅读:
    leetcode319
    leetcode516
    leetcode46
    leetcode337
    leetcode287
    leetcode328
    leetcode241
    2018-6-30-dotnet-设计规范-·-抽象类
    2018-6-30-dotnet-设计规范-·-抽象类
    2018-8-10-WPF-如何画出1像素的线
  • 原文地址:https://www.cnblogs.com/sky6699/p/12675684.html
Copyright © 2011-2022 走看看