1. 程式人生 > 其它 >萬字Node.js學習筆記

萬字Node.js學習筆記

Node.js學習筆記

Node.js 可以解析JS程式碼(沒有瀏覽器安全級別的限制)提供很多系統級別的API,如:

  • 檔案的讀寫 (File System)
  • 程序的管理 (Process)
  • 網路通訊 (HTTP/HTTPS)
  • ……

1、基本用法

1、第一個node.js程式

// 引入http模組
//  程式碼塊: node-http-server
var http = require('http');
/* 建立一個web伺服器
request  獲取url傳過來的資訊
response 給瀏覽器響應資訊
*/
http.createServer(function (request, response) {
  // 設定響應頭
  response.writeHead(200, {'Content-Type': 'text/plain'});
  // 表示輸出一句話並且結束響應
  response.end('Hello World1111');
}).listen(8081); //埠號

console.log('Server running at http://127.0.0.1:8081/');

建立web服務

const http =require('http');

http.createServer((req,res)=>{

    console.log(req.url); //獲取url
    
    //設定響應頭
    //狀態碼是200, 檔案型別是html, 字符集是utf-8 
    res.writeHead(200,{ 'Content-type':"text/html;charset=utf-8" });
	res .write(" <meta charset="UTF-8">"); //解決亂碼
    res.write('小老弟');

    res.end(); //結束響應

}).listen(3000);

url模組

const http =require('http');
const url =require('url');

var api='http://www.baidu.com?name=zhangsan&age=19';

var getvalue=url.parse(api,true).query;

console.log(getvalue);

安裝superviaor

cnpm install -g superviaor

執行

supervisor app.js

2、CommonJs

模組

核心模組:HTTP模組、URL模組、Fs模組都是nodejs內建的核心模組,可以直接引入使用。

自定義模組:自己寫的模組

  1. 我們可以把公共的功能抽離成為一個單獨的js檔案作為一個模組,
    預設情況下面這個模組裡面的方法或者屬性,外面是沒法訪問的。
    如果要讓外部可以訪問模組裡面的方法或者屬性,
    就必須在模組裡面通過exports 或者module. exports暴露屬性或者方法。
  2. 在需要使用這些模組的檔案中,通過require 的方式引入這個模組。
    這個時候就可以使用模組裡面暴露的屬性和方法。

三種暴露模組方法

// var obj={

//     get:function(){
//         console.log('獲取資料')
//     },
//     post:function(){
//         console.log('提交資料')
//     }
// }
// exports.xxx=obj;

// module.exports=obj;

exports.get=function () {
    console.log('獲取資料')
}
exports.post=function () {
    console.log('提交資料')
}
 var request=require('./module/request');

console.log(request);    { xxx: { get: [Function: get], post: [Function: post] } }

console.log(request);    { get: [Function: get], post: [Function: post] }

console.log(request);   { get: [Function (anonymous)], post: [Function (anonymous)] }

自定義模組位置

路徑可以省寫

var axios=require('axios/index');

var axios=require('axios'); //也可以,預設啟用index

console.log(axios);

完全符合CommonJs規範的包目錄一般包含如下這些檔案。

  • package.json :包描述檔案。
  • lbin :用於存放可執行二進位制檔案的目錄。
  • lib :用於存放JavaScript程式碼的目錄。
  • doc:用於存放文件的目錄。

在NodeJs中通過NPM命令來下載第三方的模組(包)

NPM

1、可以在npm網站下載包

2、安裝

npm install md5 --save


3、引用

var md5=require('md5');
npm i

可以找回所依賴的包

4、看文件使用

5、指定包的版本(非常重要)

npm install node - [email protected] --savenpm install [email protected]

常用命令

  • npm init(生成package.json說明書檔案)
    • npm init -y(可以跳過嚮導,快速生成)
  • npm install
    • 一次性把dependencies選項中的依賴項全部安裝
    • 簡寫(npm i)
  • npm install 包名
    • 只下載
    • 簡寫(npm i 包名)
  • npm install --save 包名
    • 下載並且儲存依賴項(package.json檔案中的dependencies選項)
    • 簡寫(npm i 包名)
  • npm uninstall 包名
    • 只刪除,如果有依賴項會依然儲存
    • 簡寫(npm un 包名)
  • npm uninstall --save 包名
    • 刪除的同時也會把依賴資訊全部刪除
    • 簡寫(npm un 包名)
  • npm help
    • 檢視使用幫助
  • npm 命令 --help
    • 檢視具體命令的使用幫助(npm uninstall --help)

package.json

每一個專案都要有一個package.json檔案(包描述檔案,就像產品的說明書一樣)

這個檔案可以通過npm init自動初始化出來

npm init生成package.json

npm init --yes

生成 package.json

{  "name": "db",  "version": "1.0.0",  "description": "",  "main": "db.js", //預設啟動bd.js  "scripts": {    "test": "echo \"Error: no test specified\" && exit 1"  },  "keywords": [],  "author": "",  "license": "ISC"}

對於目前來講,最有用的是dependencies選項,可以用來幫助我們儲存第三方包的依賴資訊。

如果node_modules刪除了也不用擔心,只需要在控制面板中npm install就會自動把package.json中的dependencies中所有的依賴項全部都下載回來。

  • 建議每個專案的根目錄下都有一個package.json檔案

  • 建議執行npm install 包名的時候都加上--save選項,目的是用來儲存依賴資訊

3、fs的使用

引入

const fs=require('fs');

1. fs.stat 檢測是檔案還是目錄

fs.stat('./html',(err,date)=>{    if(err){        console.log(err);        return;    }    console.log(`是檔案;${date.isFile()}`);    console.log(`是目錄;${date.isDirectory()}`);})

2. fs.mkdir 建立目錄

fs.mkdir('./css',(err)=>{    if(err){        console.log(err);        return;    }    console.log('建立成功');})path        將建立的目錄路徑mode        目錄許可權(讀寫許可權),預設777callback    回撥,傳遞異常引數err

3. fs.writeFile 建立寫入檔案

fs.writeFile('./html/index.html','你好node.js',(err)=>{    if(err){        console.log(err);        return;    }    console.log('寫入成功');})filename    (String)             檔名稱data        (String| Buffer)    將要寫入的內容,可以使字串或buffer資料。options     (object)            option陣列物件,包含:    .encoding    (string)    可選值,預設'utf8'    .mode        (Number)    檔案讀寫許可權,預設值438    .flag        (String )       預設值“w'callback    {Function}   回撥, 傳遞一個異常引數err。

4. fs.appendFile 追加檔案

fs.appendFile('./html/index.html','\n你好node.js',(err)=>{    if(err){        console.log(err);        return;    }    console.log('追加成功');})

5. fs.readFile 讀取檔案

fs.readFile('./html/index.html',(err,date)=>{    if(err){        console.log(err);        return;    }    console.log(date.toString());})

6. fs.readdir 讀取目錄

fs.readdir('./html',(err,date)=>{    if(err){        console.log(err);        return;    }    console.log(date);})

7. fs.rename 重新命名 功能:重新命名&移動檔案

fs.rename('./html/new.html','./html/dd.html',(err)=>{    if(err){        console.log(err);        return;    }    console.log('重新命名成功');})

8. fs.rmdir 刪除目錄

fs.rmdir('./css',(err)=>{    if(err){        console.log(err);        return;    }    console.log('刪除目錄成功');})
fs.unlink('./html/dd.html',(err)=>{    if(err){        console.log(err);        return;    }    console.log('刪除檔案成功');})

10、流

讀取檔案

const fs=require('fs');var readStream=fs.createReadStream('./data/1.txt');var count=0;var str='';readStream.on('data',(data)=>{    str+=data;    count++;})readStream.on('end',()=>{    console.log(str);    console.log(count);})readStream.on('err',()=>{    console.log(err);})

寫入檔案

const fs=require('fs');var str='';for(var i=0;i<500;i++){    str+='你是dd嗎?\n';}var  WriteStream=fs.createWriteStream('./data/1.txt');WriteStream.write(str);// 標記檔案末尾WriteStream.end();WriteStream.on('finish',()=>{    console.log('寫入完成');})

管道流

const fs=require('fs');var readStream=fs.createReadStream('./1.jpg');var  WriteStream=fs.createWriteStream('./data/1.jpg');readStream.pipe(WriteStream);

題目:

1.判斷伺服器上面有沒有upload目錄。如果沒有建立這個目錄,如果有的話不做操作。

const fs=require('fs');var path='./upload';fs.stat(path,(err,date)=>{    if(err){        mkdir(path);    }    if(date.isDirectory()){        console.log('upload目錄存在');    }else{        // 首先刪除檔案,建立目錄        fs.unlink(path,(err)=>{            if(!err){                mkdir(path);            }else{                console.log('請檢查傳入資料是否正確');            }        })            }})function mkdir(dir){    fs.mkdir(dir,(err)=>{        if(err){            console.log(err);        }    });}

2.找出xxx資料夾下面的所有目錄,把資料夾加放在一個數組裡

因為非同步,導致先console.log輸出了,而陣列還沒有執行,最好用遞迴解決

ES6新特性

1. let const

let塊作用域

2.箭頭函式

run(function(){    console.log('執行');})//等於run(()=>{    console.log('執行');})

3.物件、屬性的簡寫

var name='張三';var app={    name,    //屬性名和變數一樣可以簡寫    run(){        console.log(`${name}在跑步`);    }}app.run();console.log(app.name)

4.模板字串

var name='張三';var age=20;console.log(`${name}的年齡是${age}`);

5.Promise

Promise來處理非同步 resolve 成功的回撥函式 reject失敗的回撥函式

var p=new Promise(function(resolve,reject){    setTimeout(function(){        var name='張三';        resolve(name);        },1000);})p.then((date)=>{    console.log(date);})

回撥本質

function getData(ca11bck){    //ajax    setTimeout(function(){    var name='張三';    ca11bck(name);    },1000);}getData((aaa)=>{    console.log(aaa);})

6.await

await在等待async方法執行完畢,其實await等待的只是-一個表示式,這個表示式在官方文件裡說的是Promise物件,但是它也可以接受普通值。

注意:await必須在async方法中才可以使用因為await問本身就會造成程式停正堵塞,所以必須在非同步方法中才可以使用。

async function test(){    return new Promise((resolve,reject)=>{        setTimeout(()=>{            var name='張三 222';            resolve(name);        },1000);    })}async function main(){    var date=await test();  //獲取非同步方法裡面的資料    console.log(date);      //await必須用在async非同步方法裡}main();

4、用node.js建立一個靜態web伺服器

1、建立伺服器

Web 伺服器一般指網站伺服器,是指駐留於因特網上某種型別計算機的程式,可以向瀏覽器等 Web 客戶端提供文件,也可以放置網站檔案讓全世界瀏覽,還可以放置資料檔案,讓全世界下載。目前最主流的 Web 伺服器有 Apache 、Nginx 、 IIS 等

接下來我們使用 http.createServer() 方法建立伺服器,並使用 listen 方法繫結 3000 埠。函式通過 request, response 引數來接收和響應數

app.js

const http = require('http');const fs = require('fs');const common=require('./module/common.js');const path=require('path');const url=require('url');http.createServer(function (req, res) {    // 1、獲取地址    let pathname=url.parse(req.url).pathname;    pathname=pathname=='/'?'/index.html':pathname;    // 後去字尾名path.extname()    let extname=path.extname(pathname);    // 2、通過fs模組讀取檔案    if(pathname!='/favicon.ico'){        fs.readFile('./static'+pathname,async(err,data)=>{ //非同步方法            if(err){                res.writeHead(404, {                    'Content-Type': 'text/html;charset="utf-8"'                });                res.end('404');            }            let mime = await common.getFilename(extname);            res.writeHead(200, {            'Content-Type': ''+mime+';charset="utf-8"'            });            res.end(data);        })    }    }).listen(3000);console.log('Server running at http://127.0.0.1:3000/');

common.js

var fs = require('fs')exports.getMime=(extname)=>{    switch(extname){        case '.html':            return 'text/html';        case '.css':            return 'text/css';        case '.js':            return 'text/javascript';        default:            return 'text/html';                }}exports.getFilename = function(extname){	//讀取mime.json裡的字尾    return new Promise((resolve,reject)=>{        fs.readFile('./data/mime.json',(err,data)=>{	//目錄是相對於app.js            if(err){                console.log(err);                reject(err);                return;            }            let mimeObj=JSON.parse(data.toString());            resolve(mimeObj[extname]);        })    })}

由於讀取mime.json檔案是非同步的,所以需要用readFileSync()把它變成同步。
由於data是檔案,所以要先把內容轉換成字串再變成JSON格式

也可以使用同步方法(必須要等待讀取完才能進行下一步)

exports.getFilename = function(extname){     var data = fs.readFile('./data/mime.json'); //同步方法    let mimeObj=JSON.parse(data.toString());    resolve(mimeObj[extname]);}

2、 Nodejs 封裝靜態 web

const http = require('http');const routes = require('./module/routes');http.createServer(function (req, res) {    // 建立web服務    routes.static(req,res,'static');}).listen(3000);
const fs = require('fs');const path=require('path');const url=require('url');//封裝成私有方法let getFilename = function(extname){     var data = fs.readFileSync('./data/mime.json'); //同步方法    let mimeObj=JSON.parse(data.toString());    return mimeObj[extname];}exports.static = function(req,res,staticPath){     let pathname=url.parse(req.url).pathname;    pathname=pathname=='/'?'/index.html':pathname;    // 後去字尾名path.extname()    let extname=path.extname(pathname);    // 通過fs模組讀取檔案    if(pathname!='/favicon.ico'){        fs.readFile('./'+staticPath+pathname,(err,data)=>{            if(err){                res.writeHead(404, {                    'Content-Type': 'text/html;charset="utf-8"'                });                res.end('404');            }            let mime = getFilename(extname);            res.writeHead(200, {            'Content-Type': ''+mime+';charset="utf-8"'            });            res.end(data);        })    }}

2、 路由

官方解釋:
路由(Routing)是由一個 URI(或者叫路徑)和一個特定的 HTTP 方法(GET、POST 等)組成的,涉及到應用如何響應客戶端對某個網站節點的訪問。
通俗的說:
路由指的就是針對不同請求的 URL,處理不同的業務邏輯。

Get 請求路由示

//路由    let pathname=url.parse(req.url).pathname;    let extname = path.extname(pathname);    if(!extname){ //如果有請求地址有後綴名的話讓靜態web服務去處理         if(pathname=='/login'){            res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });            res.end("執行登入");        }else if(pathname=='/register'){            res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });            res.end("執行註冊");        }else if(pathname=='/admin'){            res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });            res.end("處理後的業務邏輯");        }else{            res.writeHead(404, { 'Content-Type': 'text/html;charset="utf-8"' });            res.end("404");        }    }
exports.static = function (req, res, staticPath) {    //1、獲取地址    let pathname = url.parse(req.url).pathname;    let extname = path.extname(pathname);    if (extname) {  //如果有後綴名讓靜態web處理 否則路由處理        //2、通過fs模組讀取檔案        if (pathname != '/favicon.ico') {            try {                let data = fs.readFileSync('./' + staticPath + pathname);                if (data) {                    let mime = getFileMime(extname);                    res.writeHead(200, { 'Content-Type': '' + mime + ';charset="utf-8"' });                    res.end(data);                }            } catch (error) {                console.log(error)            }        }    }}

3、 初識 EJS 模組引擎

我們學的 EJS 是後臺模板,可以把我們資料庫和檔案讀取的資料顯示到 Html 頁面上面。它是一個第三方模組,需要通過 npm 安裝
https://www.npmjs.com/package/ejs

EJS 常用標籤

  • <% %>流程控制標籤(寫js的程式碼)
  • <%= %>輸出標籤(原文輸出 HTML 標籤)
  • <%- %>輸出標籤(HTML 會被瀏覽器解
const ejs = require('ejs');		//要先下載好ejs和引入if(pathname=='/login'){            let msg = "資料庫裡面獲得的資料";            let list = [                {                    title: '新聞111'                },                {                    title: '新聞222'                },                {                    title: '新聞3333'                },                {                    title: '新聞4444'                }, {                    title: '新聞5555'                }            ]			            //(渲染到什麼地方,渲染的資料,返回的資料)            ejs.renderFile('./views/login.ejs',{                msg:msg,                list:list            },(err,data)=>{                res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });                res.end(data);            })        }

ejs

<h2>登入頁面</h2>    <h3><%=msg%></h3>    <br>    <ul>        <%for(var i=0;i<list.length;i++){%>        <li><%=list[i].title%></li>        <%}%>    </list.length;i++){%></ul>

4、 Get、Post

超文字傳輸協議(HTTP)的設計目的是保證客戶端機器與伺服器之間的通訊。在客戶端和伺服器之間進行請求-響應時,兩種最常被用到的方法是:GET 和 POST。GET - 從指定的資源請求資料。(一般用於獲取資料)POST - 向指定的資源提交要被處理的資料。(一般用於提交資料)

路由:

  • 請求方法

  • 請求路徑

  • 請求處理函式

get:

//當你以get方法請求/的時候,執行對應的處理函式app.get('/',function(req,res){    res.send('hello world');})

post:

//當你以post方法請求/的時候,執行對應的處理函式app.post('/',function(req,res){    res.send('hello world');})
	// 獲取請求型別    console.log(req.method);    if(!extname){ //如果有請求地址有後綴名的話讓靜態web服務去處理         if(pathname=='/news'){            // 獲得get傳值            var query = url.parse(req.url,true).query;            console.log(query);            res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });            res.end('get傳值成功');        }else if (pathname == '/login') {            //post演示            ejs.renderFile("./views/form.ejs", {}, (err, data) => {                res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });                res.end(data)            })        }else if(pathname=='/doLogin'){            // 獲得post傳值            let postData = '';            req.on('data',(chunk)=>{                postData+=chunk;            })            req.on('end',()=>{                console.log(postData);                res.end(postData);            })        }else{            res.writeHead(404, { 'Content-Type': 'text/html;charset="utf-8"' });            res.end("404");        }    }

5、模組化的方式封裝

let app = {    static: (req, res, staticPath) => {        //1、獲取地址        let pathname = url.parse(req.url).pathname;        let extname = path.extname(pathname);        if (extname) { //如果有後綴名讓靜態web處理 否則路由處理            //2、通過fs模組讀取檔案            if (pathname != '/favicon.ico') {                try {                    let data = fs.readFileSync('./' + staticPath + pathname);                    if (data) {                        let mime = getFileMime(extname);                        res.writeHead(200, {                            'Content-Type': '' + mime + ';charset="utf-8"'                        });                        res.end(data);                    }                } catch (error) {                    console.log(error)                }            }        }    },    login: (req, res) => {        ejs.renderFile('./views/form.ejs', {}, (err, data) => {            res.writeHead(200, {                'Content-Type': 'text/html;charset="utf-8"'            });            res.end(data)        })    },    news: (req, res) => {        res.end('news');    },    doLogin: (req, res) => {        //獲取post傳值                let postData = '';        req.on('data', (chunk) => {            postData += chunk;        })        req.on('end', () => {            console.log(postData);            res.end(postData);        })    },    error: (req, res) => {        res.end('404');    }}module.exports = app;
	//路由    let pathname=url.parse(req.url).pathname.replace("/","");//去掉'/new'的'/'    // 獲取請求型別    try {        routes[pathname](req, res);    } catch (error) {        routes['error'](req, res);    }

6、封裝一個類似 express 框架的路由

路由設計

路由 方法 get引數 post引數 是否需要登入 備註
/ get 渲染首頁
/register(登入) get 渲染註冊頁面
/register post email,nickname,password 處理註冊請求
/login get 渲染登陸介面
/login post email,password 處理登入請求
/loginout get 處理退出請求

route.js

//封裝get方法const url= require("url");let G={};let app=function(req,res){    let pathname=url.parse(req.url).pathname;    if(G[pathname]){        G[pathname](req,res);  //執行方法    }else{        res.writeHead(404, { 'Content-Type': 'text/html;charset="utf-8"' });        res.end('頁面不存在');    }}app.get=function(str,cb){   //封裝get方法    //註冊方法    G[str]=cb;  }module.exports=app;

expreess_router

const http = require("http");const app=require('./module/route')//註冊web服務http.createServer(app).listen(3000);//配置路由app.get('/',function(req,res){    res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });    res.end('首頁');})//配置路由app.get('/login',function(req,res){    res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });    res.end('執行登入操作');})//配置路由app.get('/news',function(req,res){    res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });    res.end('新聞頁面');})

get和post的封裝

app.js

const http = require("http");const app=require('./module/route');const ejs = require("ejs");//註冊web服務http.createServer(app).listen(3000);//配置路由app.get('/',function(req,res){    res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });    res.end('首頁');})//配置路由app.get('/login',function(req,res){    // res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });    // res.end('執行登入操作');    ejs.renderFile("./views/form.ejs",{},(err,data)=>{        res.send(data)    })})app.post('/doLogin',function(req,res){    console.log(req.body);    res.send(req.body)})

route.js

const url = require("url");function changeRes(res) {   //封裝res方法    res.send = (data) => {        res.writeHead(200, {            'Content-Type': 'text/html;charset="utf-8"'        });        res.end(data);    }}let server = () => {    let G = {};    //把get 和 post分開    G._get = {};    G._post = {};    let app = function (req, res) {        //擴充套件res的方法        changeRes(res);        let pathname = url.parse(req.url).pathname;        //獲取請求型別        let method = req.method.toLowerCase();        console.log(method)        if (G['_' + method][pathname]) {            if (method == "get") {                G['_' + method][pathname](req, res); //執行方法            } else {                //post  獲取post的資料 把它繫結到req.body                let postData = '';                req.on('data', (chunk) => {                    postData += chunk;                })                req.on('end', () => {                    req.body = postData;                    G['_' + method][pathname](req, res); //執行方法                })            }        } else {            res.writeHead(404, {                'Content-Type': 'text/html;charset="utf-8"'            });            res.end('頁面不存在');        }    }    app.get = function (str, cb) {        //註冊方法        G._get[str] = cb;    }    app.post = function (str, cb) {        //註冊方法        G._post[str] = cb;    }    return app;}module.exports = server(); 

靜態web服務

app.js

const http = require("http");const app=require('./module/route');const ejs = require("ejs");//註冊web服務http.createServer(app).listen(3000);app.static("static");    //修改預設靜態web目錄//配置路由app.get('/',function(req,res){    res.send("首頁")})//配置路由app.get('/login',function(req,res){    // res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });    // res.end('執行登入操作');    ejs.renderFile("./views/form.ejs",{},(err,data)=>{        res.send(data)    })})app.post('/doLogin',function(req,res){    console.log(req.body);    res.send(req.body)})

route.js

const fs = require('fs');const path = require('path');const url = require('url');//擴充套件resfunction changeRes(res) {    res.send = (data) => {        res.writeHead(200, {            'Content-Type': 'text/html;charset="utf-8"'        });        res.end(data);    }}//根據字尾名獲取檔案型別function getFileMime(extname) {    var data = fs.readFileSync('./data/mime.json'); //同步方法    let mimeObj = JSON.parse(data.toString());    return mimeObj[extname];}//靜態web服務的方法function initStatic(req, res, staticPath) {    //1、獲取地址    let pathname = url.parse(req.url).pathname;    // pathname = pathname == '/' ? '/index.html' : pathname;    let extname = path.extname(pathname);    //2、通過fs模組讀取檔案    if (extname) { //如果有後綴名用靜態web服務處理        try {            let data = fs.readFileSync('./' + staticPath + pathname);            if (data) {                let mime = getFileMime(extname);                res.writeHead(200, {                    'Content-Type': '' + mime + ';charset="utf-8"'                });                res.end(data);            }        } catch (error) {            console.log(error);        }    }}let server = () => {    let G = {        _get: {},        _post: {},        staticPath: 'static' //,預設靜態web目錄    };    let app = function (req, res) {        //擴充套件res的方法        changeRes(res);        //配置靜態web服務        initStatic(req, res, G.staticPath);        let pathname = url.parse(req.url).pathname;        //獲取請求型別        let method = req.method.toLowerCase();        console.log(method);        let extname = path.extname(pathname);        if (!extname) { //如果有後綴名用靜態web處理            if (G['_' + method][pathname]) {                if (method == "get") {                    G['_' + method][pathname](req, res); //執行方法                } else {                    //post  獲取post的資料 把它繫結到req.body                    let postData = '';                    req.on('data', (chunk) => {                        postData += chunk;                    })                    req.on('end', () => {                        req.body = postData;                        G['_' + method][pathname](req, res); //執行方法                    })                }            } else {                res.writeHead(404, {                    'Content-Type': 'text/html;charset="utf-8"'                });                res.end('頁面不存在');            }        }    }    //get請求    app.get = function (str, cb) {        //註冊方法        G._get[str] = cb;    }    //post請求    app.post = function (str, cb) {        //註冊方法        G._post[str] = cb;    }    //配置靜態web服務目錄    app.static = function (staticPath) {        G.staticPath = staticPath;    }    return app;}module.exports = server();

5、MongoDB資料庫

關係型和非關係型資料庫

關係型資料庫(表就是關係,或者說表與表之間存在關係)。

  • 所有的關係型資料庫都需要通過sql語言來操作
  • 所有的關係型資料庫在操作之前都需要設計表結構
  • 而且資料表還支援約束
    • 唯一的
    • 主鍵
    • 預設值
    • 非空

非關係型資料庫

  • 非關係型資料庫非常的靈活
  • 有的關係型資料庫就是key-value對兒
  • 但MongDB是長得最像關係型資料庫的非關係型資料庫
    • 資料庫 -》 資料庫
    • 資料表 -》 集合(陣列)
    • 表記錄 -》文件物件

一個數據庫中可以有多個數據庫,一個數據庫中可以有多個集合(陣列),一個集合中可以有多個文件(表記錄)

{    qq:{       user:[           {},{},{}...       ]    }}
  • 也就是說你可以任意的往裡面存資料,沒有結構性這麼一說

NoSQL 資料庫在以下的這幾種情況下比較適用:

  1. 資料模型比較簡單;

  2. 需要靈活性更強的 IT 系統;

  3. 對資料庫效能要求較;

  4. 不需要高度的資料一致性;

  5. 對於給定 key,比較容易映射覆雜值的環境

NoSql 和傳統資料庫簡單對比

1、MongoDb 介紹

MongoDB 是一個介於關係資料庫和非關係資料庫之間的產品,是非關係資料庫當中功能最豐富,最像
關係資料庫的 NoSql 資料庫。他支援的資料結構非常鬆散,是類似 json 的 bson 格式,因此可以儲存比較復
雜的資料型別。Mongodb 最大的特點是他支援的查詢語言非常強大,其語法有點類似於面向物件的查詢語
言,幾乎可以實現類似關係資料庫單表查詢的絕大部分功能,而且還支援對資料建立索引。它的特點是高
效能、易部署、易使用,儲存資料非常方便

2、資料庫基本操作

啟動mongodb服務

mongod --dbpath C:\MongoDB\data\db
  1. 清屏

    cls
    
  2. 檢視所有資料庫列表

    show dbs
    
  3. 使用(建立)資料庫

    use itying
    

    如果真的想把這個資料庫建立成功,那麼必須插入一個數據。
    資料庫中不能直接插入資料,只能往集合(collections)中插入資料。下面命令表示給 itying 數
    據庫的 user 表中插入資料。

  4. 檢視當前連線的資料庫

    db
    
  5. 顯示當前的資料集合(mysql 中叫表)

    show collections
    
  6. 刪除集合,刪除指定的集合 刪除表

    db.user.drop()	//刪除user這個集合
    
  7. 刪除資料庫,刪除當前所在的資料庫

    db.dropDatabase();
    
  8. 插入(增加)資料

    db.表名.insert({"name":"zhangsan","age":20,status:1})
    
  9. 查詢當前資料庫的所有資料集合

    db.user.find();
    
  10. 查詢去掉後的當前聚集集合中的某列的重複資料

    db.user.distinct("name");
    
  11. 查詢指定條件的資料

    db.user.find({"age":22});	//查詢年齡為22歲的資料
    
  12. 查詢大於小於等於的資料

    db.user.find({age:{$gt:22}});	//大於db.user.find({age:{$lt:22}});	//小於db.user.find({age:{$gte:22}});	//大於等於db.user.find({age:{$lte:22}});	//小於等於
    
  13. 查詢多個條件的資料

    db.user.find({age: {$gte: 23, $lte: 26}};
    
  14. 簡單模糊搜尋

    db.user.find({name:/mongo/};
    
  15. 查詢表中以 xx 開頭或者結尾的

    db.user.find({name: /^mongo/}	//開頭db.user.find({name: /mongo$/}	//結尾         
    
  16. 查詢指定列資料

    db.user.find({},{name: 1, age: 1});	//查詢所有行的名字和年齡
    
  17. 排序

    db.user.find().sort({age: 1});	//升序db.user.find().sort({age: -1});	//降序
    
  18. 顯示列資料限制

    db.user.find().limit(5);	//前5個數db.user.find().skip(10);	//跳過10個數
    

    可用於分頁,limit 是 pageSize,skip 是(page-1)*pageSize

  19. 查詢某個結果集的記錄條數 統計數量

    db.user.find({age: {$gte: 25}}).count();
    
  20. or 與 查詢

    db.user.find({$or: [{age: 22}, {age: 25}]});
    
  21. 修改資料

     db.student.update({"name":"小明"},{$set:{"age":16}});	//前面查詢資料,後面修改資料 db.student.update({"name":"小明"},{"age":16});			//完整替換,不出現$set 關鍵字了: db.student.update({"sex":"男"},{$set:{"age":33}},{multi: true});	//修改符合條件的多條資料
    
  22. 刪除資料

    如刪除集合下全部文件:

    db.inventory.deleteMany({})
    

    刪除 status 等於 A 的全部文件:

    db.inventory.deleteMany({ status : "A" })
    

    刪除 status 等於 D 的一個文件:

    db.inventory.deleteOne( { status: "D" } )
    

3、索引

一、索引基礎

​ 索引是對資料庫表中一列或多列的值進行排序的一種結構,可以讓我們查詢資料庫變得更快。MongoDB 的索引幾乎與傳統的關係型資料庫一模一樣,這其中也包括一些基本的查詢優化技巧。

  • 建立索引命令:

    數字 1 表示 username 鍵的索引按升序儲存,-1 表示 age 鍵的索引按照降序方式存

    db.user.ensureIndex({"userame":1});
    
  • 獲得當前索引命令:

    db.user.getIndexes()
    
  • 刪除索引命令:

    db.user.dropIndex({"username":1})
    

複合索引

該索引被建立後,基於 username 和 age 的查詢將會用到該索引,或者是基於 username的查詢也會用到該索引,但是隻是基於 age 的查詢將不會用到該複合索引。因此可以說,如果想用到複合索引,必須在查詢條件中包含複合索引中的前 N 個索引列。然而如果查詢條件中的鍵值順序和複合索引中的建立順序不一致的話,MongoDB 可以智慧的幫助我們調整該順序,以便使複合索引可以為查詢所用。

db.user.ensureIndex({"username":1, "age":-1})

可以在建立索引時為其指定索引名

db.user.ensureIndex({"username":1},{"name":"userindex"})

二、唯一索引

建立唯一索引

如果再次插入 userid 重複的文件時,MongoDB 將報錯,以提示插入重複鍵;

如果插入的文件中不包含 userid 鍵,那麼該文件中該鍵的值為 null,如果多次插入類似的文件,MongoDB 將會報出同樣的錯誤。

db.user.ensureIndex({"userid":1},{"unique":true})

4、管理員許可權

1、建立超級管理使用者

use admindb.createUser({user:'admin', pwd:'123456', roles:[{role:'root',db:'admin'}]})

2、修改 Mongodb 資料庫配置檔案

security:    authorization: enabled

3、重啟 mongodb 服務

4、用超級管理員賬戶連線資料庫

mongo admin -u 使用者名稱 -p 密碼mongo 192.168.1.200:27017/test -u user -p password

5、給 eggcms 資料庫建立一個使用者 只能訪問 eggcms 不能訪問其他資料庫

use eggcmsdb.createUser({user: "eggadmin", pwd: "123456", roles: [ { role: "dbOwner", db: "eggcms" } ]})

Mongodb 賬戶許可權配置中常用的命令

show users;			#檢視當前庫下的使用者db.dropUser("eggadmin") 	#刪除使用者db.updateUser( "admin",{pwd:"password"}); #修改使用者db.auth("admin","password"); #密碼認證

Mongodb 資料庫角色
1.資料庫使用者角色:read、readWrite;
2.資料庫管理角色:dbAdmin、dbOwner、userAdmin;
3.叢集管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;
4.備份恢復角色:backup、restore;
5.所有資料庫角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、
dbAdminAnyDatabase
6.超級使用者角色:root

連線資料庫的時候需要配置賬戶密碼

const url = 'mongodb://admin:123456@localhost:27017/';

簡述關係資料庫中表與表的 3 種關係

1)一對一的關係例如:一個人對應一個唯一的身份證號,即為一對一的關係。

2)一對多關係例如:一個班級對應多名學生,一個學生只能屬於一個班級,即為一對多關

3)多對多關係例如:一個學生可以選多門課程,而同一門課程可以被多個學生選修,彼此的對應關即是多對多

MongoDB 的高階查詢 aggregate 聚合管道

一、MongoDB 聚合管道(Aggregation Pipeline)

使用聚合管道可以對集合中的文件進行變換和組合。實際專案:表關聯查詢、資料的統計。MongoDB 中使用 db.COLLECTION_NAME.aggregate([{},...]) 方法來構建和使用聚合管道。先看下官網給的例項,感受一下聚合管道的用法

二、MongoDB Aggregation 管道操作符與表示式

管道操作符 Descripti
$project 增加、刪除、重新命名欄位
$project 條件匹配。只滿足條件的文件才能進入下一階段
$limit 限制結果的數量
$skip 跳過文件的數量
$sort 條件排序
$group 條件組合結果 統計
$lookup $lookup 操作符 用以引入其它集合的資料 (表關聯查詢)

管道表示式:

管道操作符作為“鍵”,所對應的“值”叫做管道表示式。
例如如{$match:{status:"A"}},$match稱為管道操作符,而 status:"A"稱為管道表示式,是管道操作符的運算元(Operand)。
每個管道表示式是一個文件結構,它是由欄位名、欄位值、和一些表示式操作符組成的。

$project

修改文件的結構,可以用來重新命名、增加或刪除文件中的欄位。

db.order.aggregate([{$project:{ trade_no:1, all_price:1 }}])
$match

用於過濾文件。用法類似於 find() 方法中的引數

db.order.aggregate([{$project:{ trade_no:1, all_price:1 }}, {$match:{"all_price":{$gte:90}}}])
$group

將集合中的文件進行分組,可用於統計結果。
統計每個訂單的訂單數量,按照訂單號分組

db.order_item.aggregate([{$group: {_id: "$order_id", total: {$sum: "$num"}}}])
$sort

將集合中的文件進行排序

db.order.aggregate([{$project:{ trade_no:1, all_price:1 }}, {$match:{"all_price":{$gte:90}}}, {$sort:{"all_price":-1}}])
$limit

限制資料數目

db.order.aggregate([{$project:{ trade_no:1, all_price:1 }}, {$match:{"all_price":{$gte:90}}}, {$sort:{"all_price":-1}}, {$limit:1}])
$skip

跳過資料

db.order.aggregate([{$project:{ trade_no:1, all_price:1 }}, {$match:{"all_price":{$gte:90}}}, {$sort:{"all_price":-1}},{$skip:1}])
$lookup

表關聯

db.order.aggregate([{$lookup:{from: "order_item",		//連線哪一個表localField: "order_id", foreignField: "order_id", as: "items"	//			當前的連線列					要連線表的連線列	放到什麼地方(名字)}}])

結果:

{	"_id": ObjectId("5b743d8c2c327f8d1b360540"),	"order_id": "1",	"uid": 10,	"trade_no": "111",	"all_price": 100,	"all_num": 2,	"items": [{		"_id": ObjectId("5b743d9c2c327f8d1b360543"),		"order_id": "1",		"title": "商品滑鼠1",		"price": 50,		"num": 1	}, {		"_id": ObjectId("5b743da12c327f8d1b360544"),		"order_id": "1",		"title": "商品鍵盤2",		"price": 50,		"num": 1	}, {		"_id": ObjectId("5b74f457089f78dc8f0a4f3b"),		"order_id": "1",		"title": "商品鍵盤3",		"price": 0,		"num": 1	}]} {	"_id": ObjectId("5b743d902c327f8d1b360541"),	"order_id": "2",	"uid": 7,	"trade_no": "222",	"all_price": 90,	"all_num": 2,	"items": [{		"_id": ObjectId("5b743da52c327f8d1b360545"),		"order_id": "2",		"title": "牛奶",		"price": 50,		"num": 1	}, {		"_id": ObjectId("5b743da92c327f8d1b360546"),		"order_id": "2",		"title": "酸奶",		"price": 40,		"num": 1	}]} {	"_id": ObjectId("5b743d962c327f8d1b360542"),	"order_id": "3",	"uid": 9,	"trade_no": "333",	"all_price": 20,	"all_num": 6,	"items": [{		"_id": ObjectId("5b743dad2c327f8d1b360547"),		"order_id": "3",		"title": "礦泉水",		"price": 2,		"num": 5	}, {		"_id": ObjectId("5b743dff2c327f8d1b360548"),		"order_id": "3",		"title": "毛巾",		"price": 10,		"num": 1	}]}

MongoDB 備份(mongodump)與恢復(mongorestore)

>mongodump -h dbhost -d dbname -o dbdirectory
  • -h:

    MongoDB 所在伺服器地址,例如:127.0.0.1,當然也可以指定埠號:127.0.0.1:27017

  • -d:

    需要備份的資料庫例項,例如:test

  • -o:

    備份的資料存放位置,例如:c:\data\dump,當然該目錄需要提前建立,在備份完成後,系統自動在dump目錄下建立一個test目錄,這個目錄裡面存放該資料庫例項的備份資料。

>mongorestore -h <hostname><:port> -d dbname <path>
  • --host <:port>, -h <:port>:

    MongoDB所在伺服器地址,預設為: localhost:27017

  • --db , -d :

    需要恢復的資料庫例項,例如:test,當然這個名稱也可以和備份時候的不一樣,比如test2

  • --drop:

    恢復的時候,先刪除當前資料,然後恢復備份的資料。就是說,恢復後,備份後新增修改的資料都會被刪除,慎用哦!

  • mongorestore 最後的一個引數,設定備份資料所在位置,例如:c:\data\dump\test。

    你不能同時指定 和 --dir 選項,--dir也可以設定備份目錄。

  • --dir:

    指定備份的目錄

    你不能同時指定 和 --dir 選項。

node.js操作mongodb資料庫

1、查詢資料

db.collection("user").find({}).toArray((err,data)=>{        console.log(data);        // 關閉資料庫        client.close();    })

2、增加資料

db.collection("user").insertOne({"username":"nodejs操作mongodb","age":10},(err,result)=>{        if(err){            console.log(err);            return;        }        console.log("增加成功");        console.log(result);        client.close();    })

3、修改資料

db.collection("user").updateOne({"username":"zhangsan"},{$set:{"age":10}},(err,result)=>{        if(err){            console.log(err);            return;        }        console.log("修改成功");        console.log(result);        client.close();    })

4、刪除一條資料

 db.collection("user").deleteOne({"username":"zhangsan"},(err)=>{        if(err){            console.log(err);            return;        }        console.log("刪除一條成功");        client.close();    })

5、刪除多條資料

b.collection("user").deleteMany({"username":"zhangsan"},(err)=>{        if(err){            console.log(err);            return;        }        console.log("刪除多條成功");        client.close();    })

6、通過ejs顯示列表,和表單增加資料庫資料

const http = require("http");const app = require('./module/route');const ejs = require("ejs");const querystring = require('querystring');//引用querystring處理string成物件,方便加入資料庫const { MongoClient } = require('mongodb');const url = 'mongodb://localhost:27017';const dbName = 'itying';// const client = new MongoClient(url,{ useUnifiedTopology: true });//註冊web服務http.createServer(app).listen(3000);// app.static("public");    //修改預設靜態web目錄//配置路由app.get('/', function (req, res) {    MongoClient.connect(url,{ useUnifiedTopology: true }, (err, client) => {	//分離資料庫,方便執行一個命令關閉資料庫後再執行另一個命令                if (err) {            console.log(err);            return;        }        let db = client.db(dbName);        //查詢資料        db.collection("user").find({}).toArray((err, result) => {            if (err) {                console.log(err);                return;            }                        client.close();            ejs.renderFile("./views/index.ejs", {                list: result            }, (err, data) => {                res.send(data);            })        })    })})app.get('/register', function (req, res) {    ejs.renderFile("./views/register.ejs",{},(err,data)=>{	//渲染ejs        res.send(data);    })})app.post('/doRegister', function (req, res) {    // name=zhangsan&age=13    // {    //     "name":"zhangsan",    //     "age":13    // }        let body=querystring.parse(req.body);    MongoClient.connect(url,{ useUnifiedTopology: true },(err,client)=>{        if(err){            console.log(err);            return;        }        let db=client.db(dbName);        db.collection("user").insertOne(body,(err,result)=>{            if(err){                console.log(err);                return;            }            console.log("增加資料成功");            res.send("增加資料成功");        })    })})

6、Express

基本使用

  1. npm安裝express

    cnpm install express
    
  2. 引入express

    const express = require('express');const app = express();
    
  3. 多種路由

    app.get('/', function (req, res) {      //顯示資料    res.send('Hello World')})app.post('/post', function (req, res) {     //增加資料    console.log("增加資料");    res.send("增加資料");})app.put('/put', function (req, res) {  //修改資料    console.log("修改資料");    res.send("修改資料");})app.delete('/delete', function (req, res) {  //刪除資料    console.log("刪除資料");       res.send('刪除資料');})  // 配置路由多級目錄app.get('/news/user', function (req, res) {          res.send('Hello World')})
    
  4. 動態路由

    // 動態路由,注意順序app.get('/news/:id', function (req, res) {        var id =req.params["id"];       //獲取動態路由    res.send('動態路由'+id);})
    
  5. get傳值

    // get 傳值app.get('/product', function (req, res) {        var query = req.query;      //獲取get傳值    console.log(query)    res.send(query.id);})
    

Express中ejs的使用

app.js

const express = require('express');const app = express();//配置模板引擎app.set("view engine","ejs")//配置靜態web目錄		利用 Express. static 託管靜態檔案	引用cssapp.use(express.static("static"))app.get("/",(req,res)=>{    let title = "你好ejs";    res.render("index",{	//渲染ejs        title:title    })})app.get("/news",(req,res)=>{    let userinfo={        username:"張三",        age:20    }    let article="<h3>我是一個h3</h3>"    let list=["1111","22222","3333333"]    let newsList=[        {            title:"新聞1111",                  },        {            title:"新聞122222",                  },        {            title:"新聞33331",                  },        {            title:"新聞44444",                  }    ]    res.render("news",{        userinfo:userinfo,        article:article,        flag:true,        score:60,        list:list,        newsList:newsList    })})//監聽埠  埠號建議寫成3000以上app.listen(3000)

index.ejs

    <h2>我是一個ejs模板引擎</h2>    <p><%=title%></p>				//調取app.js裡的title    <%- include('footer.ejs') %>	//引用另一個ejs

news.ejs

    <h2>繫結資料</h2>    <p><%=userinfo.username%>---<%=userinfo.age%></p>    <p><%=article%></p>    <p><%-article%></p>        <h2>條件判斷</h2>    <%if(flag==true){%>    <strong>flag=true</strong>    <%}%>    <%if(score>=60){%>    <p>及格</p>    <%}else{%>    不及格    <%}%>        <h2>迴圈遍歷</h2>    <ul>        <%for(let i=0;i<list.length;i++){%>    <li><%=list[i]%></li>    <%}%>            </list.length;i++){%></ul>    <br>    <ul>        <%for(let i=0;i<newslist.length;i++){%>    <li><%=newsList[i].title%></li>    <%}%>               <h2>引入模組</h2>    </newslist.length;i++){%></ul>    <%- include('footer.ejs') %>

Express 中介軟體

中介軟體:把很複雜的事情分割成單個,然後依次有條理的執行。就是一箇中間處理環節,有輸入,有輸出。

說的通俗易懂點兒,中介軟體就是一個(從請求到響應呼叫的方法)方法。

把資料從請求到響應分步驟來處理,每一個步驟都是一箇中間處理環節。

中介軟體中如果想往下匹配的話,那麼需要寫 next()

中介軟體的功能包括:

  • 執行任何程式碼。
  • 修改請求和響應物件。
  • 終結請求-響應迴圈。
  • 呼叫堆疊中的下一個中介軟體。

Express 應用可使用如下幾種中介軟體:

  • 應用級中介軟體

    // 應用級中介軟體 (用於許可權判斷)app.use((req,res,next)=>{    console.log(new Date())    next();})
    
  • 路由級中介軟體

    // 路由級中介軟體 (用的比較較少)app.get('/news/add', function (req, res,next) {      //顯示資料    console.log("ddd");    next()})app.get('/news/:id', function (req, res) {      //顯示資料    res.send('新聞動態路由')})
    
  • 錯誤處理中介軟體

    // 錯誤處理中介軟體(放在最後面)app.use((req,res,next)=>{    res.status(404).send(404);})
    
  • 內建中介軟體

    // 內建中介軟體	app.use(express.static("static"));
    
  • 第三方中介軟體

    /*獲取post傳過來的資料1、cnpm install body-parser --save2、var bodyParser = require('body-parser')3、配置中介軟體    app.use(bodyParser.urlencoded({ extended: false }))    app.use(bodyParser.json())    4、接收post資料    req.body*/const express = require("express");const bodyParser = require('body-parser')const ejs = require("ejs");const app = express()//配置模板引擎app.engine("html",ejs.__express)app.set("view engine","html")//配置靜態web目錄app.use(express.static("static"))//配置第三方中介軟體app.use(bodyParser.urlencoded({ extended: false }))app.use(bodyParser.json())app.get("/",(req,res)=>{    res.send("首頁")})app.get("/login",(req,res)=>{   // req.query 獲取get傳值   res.render("login",{})})app.post("/doLogin",(req,res)=>{   // req.body 獲取post傳值   var body = req.body;   console.log(body)   res.send("執行提交"+body.username)})//監聽埠  埠號建議寫成3000以上app.listen(3000)
    

一、Cookie 簡介

  • cookie 是儲存於訪問者的計算機中的變數。可以讓我們用同一個瀏覽器訪問同一個域名的時候共享資料。
  • HTTP 是無狀態協議。簡單地說,當你瀏覽了一個頁面,然後轉到同一個網站的另一個頁面,伺服器無法認識到這是同一個瀏覽器在訪問同一個網站。每一次的訪問,都是沒有任何關係的。
  • Cookie 是一個簡單到爆的想法:當訪問一個頁面的時候,伺服器在下行 HTTP 報文中,命令瀏覽器儲存一個字串; 瀏覽器再訪問同一個域的時候,將把這個字串攜帶到上行HTTP 請求中。第一次訪問一個伺服器,不可能攜帶 cookie。 必須是伺服器得到這次請求,在下行響應報頭中,攜帶 cookie 資訊,此後每一次瀏覽器往這個伺服器發出的請求,都會攜帶這個 cookie。

二、Cookie 特點

  • cookie 儲存在瀏覽器本地
  • 正常設定的 cookie 是不加密的,使用者可以自由看到;
  • 使用者可以刪除 cookie,或者禁用它
  • cookie 可以被篡改
  • cookie 可以用於攻擊
  • cookie 儲存量很小。未來實際上要被 localStorage 替代,但是後者 IE9 相容。
1.安裝 cnpm instlal cookie-parser --save2.引入 var cookieParser = require('cookie-parser');3.設定中介軟體app.use(cookieParser());4.設定 cookieres.cookie("name",'zhangsan',{maxAge: 900000});5. 獲取 cookiereq.cookies.name

Cookie 屬性說明:

domain 正常情況不要設定預設就是當前域下面的所有頁面都可以方法
http0nly true表示這個cookie只有伺服器端可以訪問,false表示客戶端(js) ,伺服器端都可以訪問
singed 表示是否簽名 cookie, 設為 true 會對這個 cookie 簽名,這樣就需要用res.signedCookies 而不是 res.cookies 訪問它。被篡改的簽名 cookie 會被伺服器拒絕,並且 cookie 值會重置為它的原始值
maxAge 最大失效時間(毫秒),設定在多少後失效
Path 表示 cookie 影響到的路路徑,如 path=/。如果路徑不能匹配時,瀏覽器則不傳送這個 Cookie
const express = require('express');var cookieParser = require('cookie-parser')const app = express();// 配置cookieParser中介軟體app.use(cookieParser("itying"))app.get('/', function (req, res) {      //顯示資料    // 設定cookie   如果cookie沒有過期的話,關閉瀏覽器後重新開啟cookie, cookie不會銷燬    // cookie的名字     cookie的value值     過期時間    設定那一些路由可以訪問   	res.cookie("username","zhansan",{maxAge:1000*60*60,path:"/news"})        // 多域名共享cookie  僅限相同的一級域名   aaa.itying.com  bbb.itying.com    res.cookie("username","zhansan",{maxAge:1000*60*60,domain:"itying.com"})        // 中文cookie    res.cookie("username","張三",{maxAge:1000*60*60})        /*    	cookie加密        1、配置中介軟體的時候需要傳入加密的引數        app.use(cookieParser("itying"))        2、res.cookie("username","張三",{maxAge:1000*60*60,signed:true})        3、req.signedCookies    */     res.cookie("username","張三",{maxAge:1000*60*60,signed:true})    res.send('Hello World')})app.get('/news', function (req, res) {    // 獲取cookie    let username = req.cookies.username;    res.send('news--'+username)})app.get('/user', function (req, res) {      //顯示資料    let username = req.cookies.username;    res.send('user--'+username)}) app.get('/product', function (req, res) {      //顯示資料    let username = req.signedCookies.username;    res.send('user--'+username)})     app.listen(80)

Express Session 的基本使用

一、 Session 簡單介紹

session 是另一種記錄客戶狀態的機制,不同的是 Cookie 儲存在客戶端瀏覽器中,而session 儲存在伺服器上。Cookie 資料存放在客戶的瀏覽器上,Session 資料放在伺服器上。Session 相比 Cookie 要更安全一些。由於 Session 儲存到伺服器上,所以當訪問量增多的時候,會比較佔用伺服器的效能。單個 cookie 儲存的資料大小不能超過 4K,很多瀏覽器都限制一個站點最多儲存 20個 cookie。Session 沒有這方面的限制。Session 是基於 Cookie 進行工作的。

二、 Session 的工作流程

當瀏覽器訪問伺服器併發送第一次請求時,伺服器端會建立一個 session 物件,生成一個類似於 key,value 的鍵值對, 然後將 key(cookie)返回到瀏覽器(客戶)端,瀏覽器下次再訪問時,攜帶 key(cookie),找到對應的 session(value)。

三、 express-session 的使用

const express = require('express');const app = express();const session = require('express-session')		//引用session// 配置session的中介軟體app.use(session({    secret: 'keyboard cat',     //伺服器端生成session 的簽名    name:"lyc",         //修改session對應cookie的名稱    resave: false,      //'強制儲存session 即使它並沒有變化    saveUninitialized: true,    //強制將未初始化的session 儲存    cookie: {        maxAge:1000*60,             secure: false       //true表示只有https協議才能訪問cookie    },    rolling:true    //在每次請求時強行設定cookie, 這將重置cookie 過期時間(預設:false)        }))app.get('/', function (req, res) { //顯示資料    // 獲取session    if(req.session.username){        res.send(req.session.username+"-已登入")    }else{        res.send('Hello World')    }})app.get('/login', function (req, res) { //顯示資料    // 設定session    req.session.username="張三"    res.send("登入")})app.get('/loginOut', function (req, res) { //顯示資料    // 1、設定session過期時間為0    (他會把所有的cookie都銷燬)    req.session.cookie.maxAge=0;    // 2、指定銷燬session    req.session.username="";    // 3、銷燬session destroy    req.session.destroy();    res.send("退出登入");       })app.listen(3000)

四、負載均衡配置 Session,把 Session 儲存到資料庫裡面

  1. 配置express-session

  2. 安裝connect-mongo

  3. 引入

    const MongoStore = require('connect-mongo');
    
  4. 配置中介軟體

    // 配置session的中介軟體app.use(session({    secret: 'keyboard cat', //伺服器端生成session 的簽名    name: "lyc", //修改session對應cookie的名稱    resave: false, //'強制儲存session 即使它並沒有變化    saveUninitialized: true, //強制將未初始化的session 儲存    cookie: {        maxAge: 1000 * 60,        secure: false //true表示只有https協議才能訪問cookie    },    rolling: true, //在每次請求時強行設定cookie, 這將重置cookie 過期時間(預設:false)            store: MongoStore.create({        mongoUrl: 'mongodb://127.0.0.1:27017/shop',        touchAfter: 24*3600 	//不管發出了多少請求在24小時內只更新一次session,除非改變了這個session    })}))
    

Express 路由模組化以及 Express 應用程式生成器

一、 Express 路由模組化

https://expressjs.com/en/guide/routing.html
Express 中允許我們通過 express.Router 建立模組化的、可掛載的路由處理程式

app.js

const express = require('express');// 引入外部模組const app = express();const index = require("./routes/index");const api = require("./routes/api");const admin = require("./routes/admin");// 掛載login模組app.use("/admin",admin);app.use("/api",api);app.use("/",index);    app.listen(3000)

admin.js

const express = require('express');var router = express.Router();// 引入下一級模組const user = require("./admin/user")router.get("/",(req,res)=>{    res.send("後臺頁面");})// 掛載下一級路由router.use("/user",user);module.exports = router;

admin/user.js

const express = require('express');var router = express.Router();router.get("/admin/user",(req,res)=>{    res.send("後臺使用者頁面");})module.exports = router;

二、Express 應用生成器

通過應用生成器工具 express-generator 可以快速建立一個應用的骨架。

你可以通過 npx (包含在 Node.js 8.2.0 及更高版本中)命令來執行 Express 應用程式生成器。

npx express-generator或者cnpm install -g express-generator
express --view=ejs express09

Express 結合 multer 上傳圖片

一、 Multer 模組介紹

Multer 是一個 node.js 中介軟體,用於處理 multipart/form-data 型別的表單資料,它主要用於上傳檔案。它是寫在 busboy 之上非常高效。
注意: Multer 不會處理任何非 multipart/form-data 型別的表單資料。

二、 Express 上傳檔案模組 multer 的使用

  1. 安裝multer

  2. 引用

    const multer = require('multer');const path = require("path");
    
  3. 配置和封裝

    let tools = {    multer() {        // var upload = multer({ dest: 'static/upload' })      //上傳之前目錄必須存在        var storage = multer.diskStorage({            // 配置上傳的目錄            destination: function (req, file, cb) {                cb(null, 'static/upload')            },            // 修改上傳後的檔名            filename: function (req, file, cb) {                // 1、獲取字尾名                let extname = path.extname(file.originalname);                // 2、根據時間戳來生成檔名                cb(null, Date.now() + extname);            }        })        var upload = multer({            storage: storage        })        return upload;    },    md5(){    }}module.exports = tools;
    
  4. 使用

    router.get("/add", (req, res) => {    res.render("admin/nav/add")})router.post("/doAdd",tools.multer().single("pic"), (req, res) => {    // 獲取表單傳來的資料    res.send({        body: req.body,        file: req.file    });})
    
  5. 按照日期生成上傳檔案目錄

    const multer = require('multer');const path = require("path");var sd = require('silly-datetime');const mkdirp = require('mkdirp');let tools = {    multer() {        // var upload = multer({ dest: 'static/upload' })      //上傳之前目錄必須存在        var storage = multer.diskStorage({            // 配置上傳的墓目錄            destination: async (req, file, cb) => {                // 1、獲取當前日期                let day = sd.format(new Date(), 'YYYYMMDD');                // static/upload/20210404                let dir = path.join("static/upload", day); //拼接目錄                // 2、按照日期生成圖片儲存目錄  mkdirp是一個非同步方法                await mkdirp(dir)                cb(null, dir) //目錄必須存在            },            // 修改上傳後的檔名            filename: function (req, file, cb) {                // 1、獲取字尾名                let extname = path.extname(file.originalname);                // 2、根據時間戳來生成檔名                cb(null, Date.now() + extname);            }        })        var upload = multer({            storage: storage        })        return upload;    },    md5() {}}module.exports = tools;
    
  6. 多檔案上傳

    let cpUpload = tools.multer().fields([{name:'pic1',maxCount:1},{name:'pic2',maxCount:1}]);router.post("/doAdd",cpUpload, (req, res) => {    res.send({        body: req.body,        file: req.files    })})
    

Mongoose的使用

一、mongoose 介紹

Mongoose 是在 node.js 非同步環境下對 mongodb 進行便捷操作的物件模型工具。Mongoose是 NodeJS 的驅動,不能作為其他語言的驅動

1、通過關係型資料庫的思想來設計非關係型資料庫
2、基於 mongodb 驅動,簡化操作

  • 基本使用
//1.引入mongooseconst mongoose = require('mongoose');//2、建立連線  mongoose.connect('mongodb://127.0.0.1:27017/eggcms');//3、操作users表(集合)   定義一個Schema   Schema裡面的物件和資料庫表裡面的欄位需要一一對應var UserSchema = mongoose.Schema({    name: String,    age: Number,    status: Number})//4、定義資料庫模型  操作資料庫// model裡面的第一個引數 要注意:1首字母大寫  2、要和資料庫表(集合 )名稱對應  這個模型會和模型名稱相同的複數的資料庫表建立連線// var User=mongoose.model('User',UserSchema);    // 預設會操作 users表(集合)var User = mongoose.model('User', UserSchema, 'user'); //預設會操作第三個引數配置的表  user表(集合)//5、查詢users表的資料User.find({},function(err,doc){     if(err){        console.log(err);        return;    }    console.log(doc);})  
  • 增刪改查
//1.引入mongooseconst mongoose = require('mongoose');//2、建立連線  mongoose.connect('mongodb://127.0.0.1:27017/eggcms');//3、定義一個Schema var NewsSchema = mongoose.Schema({    title: "string",    author: String,    pic: String,    content: String,    status: Number})//4、定義操作資料庫的Modelvar News = mongoose.model('News', NewsSchema, 'news');//5、增加資料//通過例項化 Model 建立增加的資料var news = new News({    title: "我是一個新聞11111",    author: '張三1',    content: '我是新聞的內容',    status: 1});news.save(function (err) {    if (err) {        return console.log(err);    }    console.log('成功')});//6、修改資料News.updateOne({        "_id": "5b7563e2ba3c6747d0612204"    }, {        "title": "我是一個新聞2222"    },    function (err, doc) {        if (err) {            return console.log(err);        }        console.log(doc)    })//刪除資料News.deleteOne({    "_id": "5b7563e2ba3c6747d0612204"}, (err, result) => {    if (err) {        return console.log(err);    }    console.log(result)})
  • 預設操作
// 定義資料表(集合的)對映注意:欄位名稱必須和資料庫保持一 致var UserSchema = mongoes.Schema({    name: String,    age: Number,    status: {        type:Number,        default:1       //如果沒有資料 預設引數    }})//增加資料var u = new UserModel({    name:"張三",    age:19,    status:1,    sex:"男"        //和model不同 --無效})u.save((err)=>{    if(err){        console.log(err);        return;    }    console.log('成功增加資料');})
  • 模組化

app.js

var UserModel = require('./model/user.js');var user = new UserModel({    name: "李四666",    age: 40})user.save(function (err) {    if (err) {        console.log(err);        return;    }    //獲取user表的資料    UserModel.find({}, function (err, docs) {        if (err) {            console.log(err);            return;        }        console.log(docs);    })})

user.js

var mongoose=require('./db.js');var UserSchema=mongoose.Schema({    name:String,    age:Number,    status:{        type:Number,        default:1       }})module.exports=mongoose.model('User',UserSchema,'user');

db.js

//連線資料庫var mongoose=require('mongoose');//useNewUrlParser這個屬性會在url裡識別驗證使用者所需的db,未升級前是不需要指定的,升級到一定要指定。mongoose.connect('mongodb://127.0.0.1:27017/eggcms',{ useNewUrlParser: true },function(err){        if(err){            console.log(err);            return;        }        console.log('資料庫連線成功')});module.exports=mongoose;

預定義模式修飾符

var NewsSchema=mongoose.Schema({    title:{        type:String,        trim:true    //定義 mongoose模式修飾符 去掉空格    },    author:String,    pic:String,        content:String,    status:{        type:Number,        default:1    }})

Getters 與 Setters 自定義修飾符

除了 mongoose 內建的修飾符以外,我們還可以通過 set(建議使用) 修飾符在增加資料的時候對資料進行格式化。也可以通過 get(不建議使用)在例項獲取資料的時候對資料進行格式化。

set方法

var FocusSchema = mongoose.Schema({    title: {        type: String,        trim: true //定義 mongoose模式修飾符 去掉空格    },    pic: String,    redirect: {        type: String,        set(parmas) { //增加資料的時候對redirect欄位進行處理            // parmas可以獲取redirect的值 、    返回的資料就是redirect在資料庫實際儲存的值            /*            www.baidu.com              http://www.baidu.com            http://www.baidu.com       http://www.baidu.com            */            if (!parmas) {                return ''            } else {                if (parmas.indexOf('http://') != 0 && parmas.indexOf('https://') != 0) {                    return 'http://' + parmas;                }                return parmas            }        }    },    status: {        type: Number,        default: 1    }})

get方法

var UserSchema=mongoose.Schema({        name:{        type:String,        get(params){   //不建議使用            return "a001"+params        }       },    age:Number,           status:{        type:Number,        default:1     }})

Mongoose 索引擴充套件和Mongoose Model 的靜態方法和例項方法

Mongoose 索引

索引是對資料庫表中一列或多列的值進行排序的一種結構,可以讓我們查詢資料庫變得更快。MongoDB 的索引幾乎與傳統的關係型資料庫一模一樣,這其中也包括一些基本的查詢優化技巧。

mongoose 中除了以前建立索引的方式,我們也可以在定義 Schema 的時候指定建立索引。

var UserSchema=mongoose.Schema({        name:{        type:String,        unique: true    //唯一索引       },    sn:{        type:String,        index:true      // 普通索引    },    age:Number,           status:{        type:Number,        default:1    }})

Mongoose Model 的靜態方法和例項方法

//靜態方法 UserSchema.statics.findBySn=function(sn,cb){    //通過 find方法獲取 sn的資料    this 關鍵字獲取當前的model    this.find({"sn":sn},function(err,docs){        cb(err,docs)    })   }// 例項方法   (基本不用)UserSchema.methods.print=function(){    console.log('我是一個例項方法')    console.log(this.name)}

Mongoose 資料校驗

  • required : 表示這個資料必須傳入
  • max: 用於 Number 型別資料,最大值
  • min: 用於 Number 型別資料,最小值
  • enum:列舉型別,要求資料必須滿足列舉值 enum: ['0', '1', '2']
  • match:增加的資料必須符合 match(正則)的規則
  • maxlength:最大值
  • minlength:最小值
var mongoose=require('./db.js');//mongoose資料校驗:使用者通過mongoose給mongodb資料庫增加資料的時候,對資料的合法性進行的驗證//mongoose裡面定義Schema:欄位型別,修飾符、預設引數 、資料校驗都是為了資料庫資料的一致性//Schema,為資料庫物件的集合,每個schema會對映到mongodb中的一個collection,定義Schema可以理解為表結構的定義var UserSchema=mongoose.Schema({    name:{        type:String,//指定型別        trim:true,   //修飾符                 required:true          },    sn:{        type:String,        index:true,  //索引.        set(val){  //自定義修飾符            return val;        },        // maxlength:20,        // minlength:10        // match:/^sn(.*)/ ,        validate: function(sn) {            return sn.length >= 10;        }            },       age:{        type:Number,        min:0,    //用在number型別上面        max:150    },           status:{        type:String,         default:'success', //預設值        enum:['success','error']   //status的值必須在 對應的數組裡面  注意列舉是用在String    }})module.exports=mongoose.model('User',UserSchema,'user');

Mongoose 中使用 aggregate 聚合管道

使用聚合管道可以對集合中的文件進行變換和組合。
實際專案:表關聯查詢、資料的統計

/*mongodb資料庫使用 聚合管道db.order.aggregate([    {      $lookup:        {          from: "order_item",          localField: "order_id",          foreignField: "order_id",          as: "items"        }  },{    $match:{"all_price":{$gte:90}}}])*/var OrderModel = require('./model/order.js');//查詢order 表的資料/*    OrderModel.find({},function(err,docs){        console.log(docs);    })*///order表關聯order_itemOrderModel.aggregate([  {    $lookup: {      from: "order_item",      localField: "order_id",      foreignField: "order_id",      as: "items"    }  },  {    $match: {      "all_price": {        $gte: 90      }    }  }], function (err, docs) {  if (err) {    console.log(err);    return;  }  console.log(JSON.stringify(docs))})

查詢order_item,找出商品名稱是酸奶的商品,酸奶這個商品對應的訂單的訂單號以及訂單的總價格

var OrderItemModel = require('./model/order_item.js');
var OrderModel = require('./model/order.js');
var mongoose = require('mongoose');

//第一種實現方式

    OrderItemModel.find({"_id":"5b743da92c327f8d1b360546"},function(err,docs){
        // console.log(docs);
        var order_item=JSON.parse(JSON.stringify(docs));
        var order_id=order_item[0].order_id;
        OrderModel.find({"order_id":order_id},function(err,order){
            //    console.log(order);
            order_item[0].order_info=order[0];
            console.log(order_item)
        })
    })


//第二種方式 
//mongoose中獲取ObjectId           mongoose.Types.ObjectId

OrderItemModel.aggregate([{
    $lookup: {
      from: "order",
      localField: "order_id",
      foreignField: "order_id",
      as: "order_info"
    }
  }, {
    $match: {
      _id: mongoose.Types.ObjectId('5b743da92c327f8d1b360546')
    }
  }
], function (err, docs) {
  if (err) {
    console.log(err)
    return;
  }
  console.log(JSON.stringify(docs))
})

7、Koa

Koa 是基於 Node.js 平臺的下一代 web 開發框架。

Koa是由 Express 原班人馬打造的,致力於成為一個更小、更富有表現力、更健壯的 Web 框架。 使用 Koa 編寫 web 應用,可以免除重複繁瑣的回撥函式巢狀, 並極大地提升錯誤處理的效率。Koa不在核心方法中繫結任何中介軟體, 它僅僅提供了一個輕量優雅的函式庫,使得編寫 Web 應用變得得心應手,開發思路和 Express 差不多,最大的特點就是可以避免非同步巢狀

1、koa的基本使用

// 引入Koa
var koa = require('koa');
// 例項化Koa
var app = new koa();
 
app.use( async(ctx)=>{
    ctx.body = "hello,koa"
});
 
// 監聽埠
app.listen(3000);

koa路由的使用

// 1.引入路由並例項化
var router = require('koa-router')();
// 兩種寫法
var Koa = require('koa');
var app = new Koa();


// 路由路徑字首設定
router.prefix('/api')

// 3.配置路由
//ctx 上下文context,包含了request和response等資訊
router.get('/', async (ctx) => { // 路徑: /api/get
    // 返回資料給前端
    ctx.body = "你好";
}).get('/news',async (ctx)=>{
    console.log(ctx.query);     //獲取的是物件
    console.log(ctx.querystring);  //獲取的是字串

    ctx.body = "你好";
})
// 動態路由 可以傳入多個值
.get('/news/:aid/:cid',async (ctx)=>{
    // 獲取動態路由的傳值
    console.log(ctx.params);
    ctx.body="新聞"
})

// 4.啟動路由(來自於官方文件);
// router.allowedMethods()可以配置也可以不配置。
// 如果之前的沒有設定響應頭,配置此選項以後可以自動設定響應頭。
app
    .use(router.routes())
    .use(router.allowedMethods());

// 監聽埠
app.listen(3000);

Koa中介軟體

中介軟體是配合路由匹配完成做的一系列的操作,我們就可以把它叫做中介軟體。Koa中運用中介軟體可以實現以下一些功能:

(1).新增應用。主要通過app.use()這個函式新增或是啟動一些應用,如常見的一些第三方中介軟體的使用。
(2)匹配路由。主要通過next()這個函式完成多級路由匹配。
(3)錯誤處理。如果當前訪問的路由一直向下匹配沒有匹配到,可以通過中介軟體給出錯誤響應。

var Koa = require('koa');
var Router = require('koa-router');
var app = new Koa();
var router = new Router();
// Koa 錯誤處理中介軟體
// 無論app.use放到路由前面還是後面
// 都是先執行app.use再去執行路由
app.use(async (ctx, next) => {
    console.log('這是一箇中間件'); // 執行順序1
    
    await next();

    if (ctx.status == 404) { // 執行順序3
        ctx.body = '這是一個404頁面';
    } else {
        console.log(ctx.url);
    }
});

// 配置新聞頁                            // 執行順序2
router.get('/news', async (ctx, next) => {  //匹配到news後繼續向下執行
    console.log('這是新聞路由');
    await next();
});
router.get('/news',async (ctx)=>{
    ctx.body = '這是新聞路由';
})


app.use(router.routes());
app.use(router.allowedMethods());

app.listen(3000);

Koa非同步處理Async、Await 和Promise的使用(重點)

  • async是讓方法變成非同步
  • await是等待非同步方法執行完成。

await在等待async方法執行完畢,其實await等待的只是-一個表示式,這個表示式在官方文件裡說的是Promise物件,但是它也可以接受普通值。

注意:await必須在async方法中才可以使用因為await問本身就會造成程式停正堵塞,所以必須在非同步方法中才可以使用。

async function test(){    return new Promise((resolve,reject)=>{        setTimeout(()=>{            var name='張三 222';            resolve(name);        },1000);    })}async function main(){    var date=await test();  //獲取非同步方法裡面的資料    console.log(date);      //await必須用在async非同步方法裡}main();

ejs模板使用

同express一樣使用ejs

var router = require('koa-router')(),    views = require('koa-views'),    Koa = require('koa');app = new Koa();//配置模板引擎中介軟體 --第三方中介軟體//app. use(views('views', { map: (html: 'ejs' })); //這樣配置也可以 注意如果這樣配置的話模板的字尾名是. htmlapp.use(views('views',{    extension:'ejs'}))// 寫一箇中間件配置公共的資訊	在任何一個ejs中都可以呼叫app.use(async(ctx,next)=>{    ctx.state.userinfo='張三';    await next();})router.get('/', async (ctx) => {     let title = "你好";    await ctx.render('index',{        title:title    });});app    .use(router.routes())    .use(router.allowedMethods());// 監聽埠app.listen(3000);
<h2><%=title%>-----<%=userinfo%></h2>

post提交資料

原生node.js,在koa中獲取表單提交的資料

最新node中獲取post資料

Koa中koa-bodyparser中介軟體獲取表單提交的資料

/*    Koa中koa-bodyparser中介軟體獲取表單提交的資料        1.cnpm install --save koa -bodyparser    2.引入var bodyParser = require( koa-bodyparser' ) ;    3. app.use(bodyParser();    4. ctx.request.body;  獲取表單提交的資料*/ var router = require('koa-router')(),    views = require('koa-views'),    Koa = require('koa'),    bodyParser = require('koa-bodyparser');var app = new Koa();app.use(views('views',{    extension:'ejs'}))//配置bodyParser中介軟體app.use(bodyParser());router.get('/', async (ctx) => {     await ctx.render('index');});router.post('/doAdd',async (ctx)=>{    console.log(ctx.request.body);    ctx.body = ctx.request.body;})app.use(router.routes());app.use(router.allowedMethods());// 監聽埠app.listen(3000);

ejs

<form action="/doAdd" method="post">    使用者名稱:<input type="text" name="username">    <br>    <br>    密  碼:<input type="password" name="username">    <br>    <br>    <button type="submit">提交</button>    </form>

koa-static靜態web中介軟體

/*1. cnpm install koa-static --save2. const static = require('koa-static' )3.配置中介軟體  app. use(static(' static' )*/var router = require('koa-router')(),    views = require('koa-views'),    Koa = require('koa'),    bodyParser = require('koa-bodyparser'),    static = require('koa-static');var app = new Koa();app.use(views('views',{    extension:'ejs'}))// 配置靜態web中介軟體    首先去static中找,如果能找到返回對應的檔案,找不到next()app.use(static('static'));  //koa中介軟體可以配置多個app.use(bodyParser());router.get('/', async (ctx) => {     await ctx.render('index');});router.post('/doAdd',async (ctx)=>{    console.log(ctx.request.body);    ctx.body = ctx.request.body;})app.use(router.routes());app.use(router.allowedMethods());// 監聽埠app.listen(3000);

art-template的使用

介紹

art-template 是一個簡約、超快的模板引擎。

它採用作用域預宣告的技術來優化模板渲染速度,從而獲得接近 JavaScript 極限的執行效能,並且同時支援 NodeJS 和瀏覽器。

特性

  1. 擁有接近 JavaScript 渲染極限的的效能
  2. 除錯友好:語法、執行時錯誤日誌精確到模板所在行;支援在模板檔案上打斷點(Webpack Loader)
  3. 支援 Express、Koa、Webpack
  4. 支援模板繼承與子模板
  5. 瀏覽器版本僅 6KB 大小

語法

art-template 支援標準語法與原始語法。標準語法可以讓模板易讀寫,而原始語法擁有強大的邏輯表達能力。

標準語法支援基本模板語法以及基本 JavaScript 表示式;原始語法支援任意 JavaScript 語句,這和 EJS 一樣。

    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>Document</title>    {{list.name}}    <br>    {{@list.h}}    <br>    {{if num>20}} 大於 {{else}} 小於 {{/if}}    <br>    <ul>    {{each list.data}}        <li> {{$index}} --- {{$value}} </li>    {{/each}}    </ul>    <br>    {{include 'public/footer.html'}}

Koa中的cookie

使用同express中的cookie

var router = require('koa-router')(),    Koa = require('koa'),    render = require('koa-art-template'),    path = require('path');var app = new Koa();// 配置 koa-art-template 模板引擎render(app, {    root: path.join(__dirname, 'views'), //檢視的位置    extname: '.html',    //字尾名    debug: process.env.NODE_ENV !== 'production'    //是否開啟除錯模式});router.get('/', async (ctx) => {    // 在koa中無法直接設定中文cookie    var userinfo = new Buffer('張三').toString('base64');    ctx.cookies.set('userinfo',userinfo,{        maxAge:60*1000*60    });    await ctx.render('index');});router.get('/news', async (ctx) => {    var data = ctx.cookies.get('userinfo');    var userinfo = new Buffer(data,'base64').toString();    console.log(userinfo);    let app={        name:'張三'    };    await ctx.render('news',{        list:app    });});app    .use(router.routes())    .use(router.allowedMethods());// 監聽埠app.listen(3000);

Koa中的cookie

var router = require('koa-router')(),    Koa = require('koa'),    render = require('koa-art-template'),    path = require('path'),    session = require('koa-session');	//安裝並且引用koa-sessionvar app = new Koa();render(app, {    root: path.join(__dirname, 'views'),     extname: '.html',     debug: process.env.NODE_ENV !== 'production' //是否開啟除錯模式});// 配置session中介軟體app.keys = ['some secret hurr'];    //cookie的簽名const CONFIG = {    key: 'koa:sess', //cookie is key	maxAge: 86400000, // cookie 的過期時間 預設一天 ms	overwrite: true, //是否可以 overwrite 	httpOnly: true, //cookie 是否只有伺服器端可以訪問 	signed: true, //簽名預設 true 	rolling: false, //在每次請求時強行設定 cookie,這將重置 cookie 過期時間(預設:false) 	renew: true, //快過期的時候配置過期時間 需要修改 預設false};app.use(session(CONFIG, app));router.get('/', async (ctx) => {    // 設定session    ctx.session.userinfo='張三';    await ctx.render('index');});router.get('/news', async (ctx) => {    // 獲取session    console.log(ctx.session.userinfo);    let app = {        name: '張三'    };    await ctx.render('news', {        list: app    });});app    .use(router.routes())    .use(router.allowedMethods());// 監聽埠app.listen(3000);

js中面向物件繼承

1.1 原型鏈繼承

原型鏈繼承 :子類的原型物件 = 父類的例項物件

//1.父類建構函式function Student(name,age,sex){    this.name = name;    this.age = age;    this.sex = sex;    this.arr = [1,2,3];}Student.prototype.classId = "1116"Student.prototype.study = function(){    console.log("good good study , day day sleep!");}//2.子類建構函式function MiniStudent(){    this.play = function(){        console.log("玩王者榮耀");    }}//3.繼承的操作  原型鏈繼承 子類的原型物件 = 父類的例項物件MiniStudent.prototype = new Student("小夏",6,"男");//4.例項化物件var mS = new MiniStudent();

原型鏈:屬性或方法的查詢方式

//原型鏈:例項本身----》__proto__(prototype)---->父類的例項物件---->父類的__proto__(prototype)....... undefined        console.log(mS.name);        console.log(mS.classId);

原型鏈繼承問題:

//缺點1:不能傳參,每次創建出來都是一樣的var ms1 = new MiniStudent();console.log(ms1.arr);ms1.arr.push(4)console.log(ms1.arr);//缺點2:繼承了引用資料型別一改全改var ms2 = new MiniStudent();console.log(ms2.arr);

1.2 物件冒充繼承

//2.子類建構函式function MiniStudent(name,age,sex){    //3.物件冒充繼承    Student.call(this,name,age,sex);    this.play = function(){        console.log("玩王者榮耀");    }}//4.例項化物件var s1 = new MiniStudent("如花","6","女");console.log(s1);s1.arr.push(4);//[1,2,3,4]

優點:可以傳參,引用資料型別不會再一改全改

缺點:不能繼承原型中的屬性和方法

1.3 混合繼承

混合繼承:物件冒充繼承+原型鏈繼承

//1.父類建構函式function Student(name,age,sex){    this.name = name;    this.age = age;    this.sex = sex;    this.arr = [1,2,3];}Student.prototype.classId = "1116"Student.prototype.study = function(){    console.log("good good study , day day sleep!");}//2.子類建構函式function MiniStudent(name,age,sex){    //3.物件冒充繼承    Student.call(this,name,age,sex)    this.play = function(){        console.log("玩王者榮耀");    }}//混合繼承  物件冒充(建構函式中屬性和方法)+原型鏈繼承(繼承原型物件中屬性和方法)//4.原型鏈繼承 MiniStudent.prototype = new Student("小明",3,"男");//5.例項化物件var ms1 = new MiniStudent("小郝",10,"女");console.log(ms1);

優點:可以傳參,引用資料型別不會再一改全改,可以繼承父類原型中的屬性和方法

缺點:建立了一個多餘的父類例項

1.4 寄生式組合繼承

//2.子類建構函式function MiniStudent(name,age,sex){    //3.物件冒充繼承    Student.call(this,name,age,sex)    this.play = function(){        console.log("玩王者榮耀");    }}//混合繼承  物件冒充(建構函式中屬性和方法)+原型鏈繼承(繼承原型物件中屬性和方法)//4.原型鏈繼承    Object.create():以原型為基礎建立物件MiniStudent.prototype = Object.create(Student.prototype);MiniStudent.prototype.constructor = MiniStudent;//5.例項化物件var ms1 = new MiniStudent("小郝",10,"女");console.log(ms1);

優點:可以傳參,引用資料型別不會再一改全改,可以繼承父類原型中的屬性和方法,不會建立多餘的父類例項。

1.5 ES6中的繼承方法

    // 繼承是 兩個父子級關係的建構函式之間的應用    // 如何定義一個建構函式    // ES5語法    function Fun1(name, age) {    // 定義屬性    this.name = name;    this.age = age;		}		//定義方法		Fun1.prototype.f1 = function () {	    console.log(this.name, this.age);	}    // ES6語法    class Fun2{        // 構造器中定義屬性        constructor(name,age){            this.name = name;            this.age = age;        }        // 定義方法        f2(){            console.log(this.name,this.age);        }    }    // ES6的繼承語法    // 先定義父級建構函式 Father    // 通過 extends 來指定 繼承的父級的建構函式名稱    // 在構造器 constructor 中 通過 super 來 指定,哪個屬性來自於父級建構函式    // extends 關鍵詞 指定父級建構函式    // super 指定 屬性來源父級    // 繼承屬性,如果父級中有多個屬性    // 在 super 中, 只繼承一部分,並且只設定一部分,沒有設定的,執行結果是 undefined    // 父級的屬性 可以 只繼承部分    // 其他的屬性 如果沒有操作, 是 undefined    // 也可以在子級中,定義父級屬性的資料數值    // 子級中也可以定義新的屬性和屬性值    // 定義父級建構函式    function Father(name,age){        this.name = name;        this.age = age;    }    Father.prototype.f1 = function(){        console.log(this.name,this.age);    }    // extends 指定從 Father 建構函式中,執行繼承操作    class Son extends Father{        constructor(name,age,sex){            // 在構造其中,通過 super 來指定,從父級繼承來的屬性            // 繼承父級的name            super(name);            // 自行定義父級的age            this.age = age;            // 自定義屬性sex和sex的數值            this.sex = sex;        }        // 自定義方法        f2(){            console.log('我是自定義的子級方法');        }    }    const obj1 = new Father('張三' , 18);    console.log(obj1);    // 屬性是直接繼承父級中,定義的屬性的形式    // 方法是呼叫父級中定義的方法    const obj2 = new Son('李四' , 20 , '男');    console.log(obj2);    /*    總結  ES6的繼承語法    1,繼承語法是為了,簡化程式碼,防止重複程式碼的出現    2,繼承是兩個建構函式之間的應用    3,ES6語法,預設是繼承父級建構函式的所有的屬性和所有方法        屬性如果沒有指定資料,執行結果是undefined        方法是通過原型鏈,找到父級建構函式中,定義的方法    4,語法形式:      class 子級 extends 父級{          constructor(屬性引數...){              先寫繼承的屬性,再寫自定義的屬性              super(繼承父級的屬性);              自定義屬性          }          自定義的方法          自定義方法(){          }      }    */

1.6單例

單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。

這種模式涉及到一個單一的類,該類負責建立自己的物件,同時確保只有單個物件被建立。這個類提供了一種訪問其唯一的物件的方式,可以直接訪問,不需要例項化該類的物件。

注意:

  • 1、單例類只能有一個例項。
  • 2、單例類必須自己建立自己的唯一例項。
  • 3、單例類必須給所有其他物件提供這一例項。
class Db{    static getInstance(){   //單例        if(!Db.Instance){            Db.Instance = new Db();        }        return Db.Instance;    }    constructor(){        console.log('例項化');        this.connect();    }    connect(){        console.log('連線資料庫')    }}var myDB = Db.getInstance();var myDB2 = Db.getInstance();

kao中的mongodb資料庫

var MongoClient = require('mongodb').MongoClient;var dbUrl = 'mongodb://127.0.0.1:27017/';var dbName = 'koa';// 連線資料庫 MongoClient.connect(dbUrl, (err, client) => {    if (err) {        console.log(err);        return;    }    var db = client.db(dbName);    // 增加資料    db.collection('user').insertOne({'username':"dd",'age':29,'sex':"男","status":"1"},(err,res)=>{        if(!err){            console.log("連線成功");            client.close();        }    })    // 查詢資料    var result = db.collection('user').find({});    result.toArray((err,docs)=>{        console.log(docs);    })})

封裝 MongoDB 類

在專案的根目錄建立一個 mongodb 目錄,然後在該目錄下新建 config.js,用來儲存一些資料庫常量配置

// /mongodb/config.jsconst dbUrl = 'mongodb://127.0.0.1:27017'; // 資料庫地址const dbName = 'Movie'; //資料庫名稱module.exports = {  dbUrl,  dbName}

在 mongodb 目錄下建立一個 index.js,使用中介軟體連線 MongoDB 資料庫

// /mongodb/index.jsconst { MongoClient, ObjectID } = require("mongodb");const Config = require("./config");class Db {  static getInstance() {    // 單例模式 解決多次例項化 例項不共享的問題    if (!Db.instance) {      Db.instance = new Db();    }    return Db.instance;  }  constructor() {    this.dbClient = ""; //db物件    this.connect(); // 例項化的時候就連線資料庫  }  connect() {    // 連線資料庫    return new Promise((resolve, reject) => {      if (!this.dbClient) {        //解決資料庫多次連線的問題        MongoClient.connect(Config.dbUrl, { useUnifiedTopology: true }, (err, client) => {          if (err) {            reject(err);            return;          }          this.dbClient = client.db(Config.dbName);          resolve(this.dbClient);        });      } else {        resolve(this.dbClient);      }    });  }  //查詢操作 collection:表名 json:查詢條件  find(collection, json) {    return new Promise((resolve, reject) => {      this.connect().then((db) => {        let result = db.collection(collection).find(json);        result.toArray((err, docs) => {          if (!err) {            resolve(docs);          } else {            reject(err);          }        });      });    });  }  //新增操作  insert(collection, json) {    return new Promise((resolve, reject) => {      this.connect().then((db) => {        db.collection(collection).insertOne(json, (err, result) => {          if (!err) {            resolve(result);          } else {            reject(err);          }        });      });    });  }  //修改操作  update(collection, json1, json2) {    return new Promise((resolve, reject) => {      this.connect().then((db) => {        db.collection(collection).updateOne(          json1,          {            $set: json2,          },          (err, result) => {            if (!err) {              resolve(result);            } else {              reject(err);            }          }        );      });    });  }  //刪除操作  delete(collection, json) {    return new Promise((resolve, reject) => {      this.connect().then((db) => {        db.collection(collection).removeOne(json, (err, result) => {          if (!err) {            resolve(result);          } else {            reject(err);          }        });      });    });  }  //在進行查詢或者刪除操作的時候,我們一般都會通過id去進行操作,但是我們直接使用傳遞過來的id是不起作用的,需要使用mongodb提供的ObjectID方法,生成一個新的id去查詢。  getObjectID(id) {    return new ObjectID(id);  }}module.exports = Db.getInstance();

app.js

var Koa=require('koa'),    router = require('koa-router')(),    render = require('koa-art-template'),    path=require('path'),    bodyParser=require('koa-bodyparser'),    DB=require('./module/db.js');var app=new Koa();//配置post提交資料的中介軟體app.use(bodyParser());//配置 koa-art-template模板引擎render(app, {    root: path.join(__dirname, 'views'),   // 檢視的位置    extname: '.html',  // 字尾名    debug: process.env.NODE_ENV !== 'production'  //是否開啟除錯模式});//顯示學員資訊router.get('/',async (ctx)=>{    var result=await DB.find('user',{});    console.log(result);    await ctx.render('index',{        list:result    });})//增加學員router.get('/add',async (ctx)=>{    await ctx.render('add');})//執行增加學員的操作router.post('/doAdd',async (ctx)=>{    //獲取表單提交的資料   // console.log(ctx.request.body);  //{ username: '王麻子', age: '12', sex: '1' }    let data=await DB.insert('user',ctx.request.body);    //console.log(data);    try{        if(data.result.ok){            ctx.redirect('/')        }    }catch(err){        console.log(err);        return;        ctx.redirect('/add');    }})//編輯學員router.get('/edit',async (ctx)=>{    //通過get傳過來的id來獲取使用者資訊    let id=ctx.query.id;    let data=await DB.find('user',{"_id":DB.getObjectId(id)});    //獲取使用者資訊    await ctx.render('edit',{        list:data[0]    });})router.post('/doEdit',async (ctx)=>{    //通過get傳過來的id來獲取使用者資訊    //console.log(ctx.request.body);    var id=ctx.request.body.id;    var username=ctx.request.body.username;    var age=ctx.request.body.age;    var sex=ctx.request.body.sex;    let data=await DB.update('user',{"_id":DB.getObjectId(id)},{        username,age,sex    })    try{        if(data.result.ok){            ctx.redirect('/')        }    }catch(err){        console.log(err);        return;        ctx.redirect('/');    }})//刪除學員router.get('/delete',async (ctx)=>{    let id=ctx.query.id;    var data=await DB.remove('user',{"_id":DB.getObjectId(id)});    console.log(data);    if(data){        ctx.redirect('/')    }})app.use(router.routes());   /*啟動路由*/app.use(router.allowedMethods());app.listen(3000);