• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • Node.js基礎

    Chapter01.簡介

    • NodeJS是讓JavaScript脫離瀏覽器運行在服務器的一個平臺,不是語言。
    • NodeJS采用的JS引擎來自GoogleChromeV8,運行在瀏覽器外不用考慮JS兼容性。
    • NodeJS采用單線程、異步IO、事件驅動的設計來實現高并發
    • NodeJS內建HTTP服務器

    安裝

    // 測試命令
    node -v
    npm -v
    

    NPM

    NPM(Node Package Modules)用于安裝豐富的NodeJs庫來完成開發需求。

    // 查看幫助
    npm help
    npm h
    // 安裝模塊
    npm install <module_name>
    // 全局安裝模塊
    npm install -g <module name>
    // 卸載模塊
    npm uninstall <module_name>
    // 已安裝模塊
    npm list
    

    Chapter02.事件模塊

    events事件是NodeJS重要模塊,events模塊提供events.EventEmitter對象用于事件發射和事件監聽。
    NodeJS大部分模塊都繼承自Events模塊。與DOM事件不同的是,Events不存在事件冒泡和逐層捕獲等行為。
    EventEmitter支持若干事件監聽器,當事件發射時注冊到此事件的事件監聽器被依次調用,事件參數作為回調函數參數傳遞。

    // 加載模塊
    require('events');
    

    Chapter03.模塊

    核心模塊

    NodeJS提供核心模塊編譯成二進制文件,是用require('module_name')去獲取,核心模塊具有最高的加載優先級。

    文件模塊

    NodeJS的文件模塊可以是JS代碼、JSON文件、C/C++編輯過的文件。

    文件模塊訪問是通過 require('dir/file.ext') 來訪問。

    NodeJS加載優先級是:js文件>json文件>node文件

    案例:自定義計數器模塊

    Chapter04.與MySQL交互

    NodeJS與MySQL交互操作有很多庫,暫時選擇 felixge/node-mysql

    // 安裝
    npm install mysql
    

    執行CURD

    //加載mysql庫
    var mysql = require('mysql');
    
    //創建連接
    var dbcfg = {
        host:'127.0.0.1',
        user:'root',
        password:'root',
        port:'3306',
        database:'test'
    };
    var link = mysql.createConnection(dbcfg);
    link.connect(function(err){
       if(err){
           console.log(err);
           return;
       }
       console.log('mysql create connect success!');
    });
    //執行sql語句
    var sql = 'SELECT 1+1 AS solution';
    link.query(sql,function(err,rows,fields){
       if(err){
           console.log(err);
           return;
       }
       var msg = 'The solution is '+rows[0].solution;
       console.log(msg);
    });
    
    //插入數據
    var sql = "INSERT INTO user(username,password) VALUES(?,?)";
    var para = ['alice','123456'];
    link.query(sql,para,function(err,ret){
       if(err){
           console.log(err.message);
           return;
       }
       console.log(ret);
    });
    
    
    //關閉連接
    link.end(function(err){
        if(err){
            return;
        }
        console.log('mysql connect end!');
    });
    
    //斷線重連
    function handleDisconnect(){
        link = mysql.createConnection(dbcfg);
        link.connect(function(err){
           if(err){
               console.log('數據庫斷線重連:'+new Date());
               setTimeout(handleDisconnect,2000);//定時2秒重連
               return;
           }
           console.log('數據庫連接成功:'+new Date());
        });
        //監聽數據庫連接是否斷掉
        link.on('error',function(err){
            console.log('數據庫連接斷線: ',err);
           if(err.code === 'PROTOCOL_CONNECTION_LOST'){
               handleDisconnect();
           } else{
               throw err;
           }
        });
    }
    handleDisconnect();
    

    執行事務

    關閉連接

    • end() 在執行query()后執行,end()接收一個回調函數,query()執行出錯仍結束連接,錯誤會返回給回調函數err參數可在回調函數中出力。
    • destory() 暴力關閉,無回調函數,立即執行不管query() 是否完成。

    斷線重連

    [錯誤代碼] error code: PROTOCOL_CONNECTION_LOST
    

    Chapter05.Express框架與EJS模板引擎

    NodeJS提供HTTP模塊,HTTP模塊提供底層接口但不便于開發。從Express框架著手去進行Web開發,Express實現更好更高層的接口,使Web開發更加便捷。
    Express是一個輕量級、簡潔、易用的NodeJS Web MVC開發框架,Express基于NodeJS原有模塊并對Web開發所需的功能封裝。

    安裝

    // -g 表示全局安裝
    npm install -g express-generator
    
    express -V
    

    案例:創建express的web應用

    express webapp
    

    下載依賴

    npm install
    

    添加端口監聽

    app.listen(8100,function(){
      console.log('server start');
    });
    

    安裝supervisor每次修改后自動重啟

    npm install -g supervisor
    supervisor app.js
    

    express默認實用模板引擎為jade

    模板引擎ejs

    創建express+ejs項目

    express -e webapp
    cd webapp && npm install 
    

    webapp/app.js 添加8100端口監聽

    app.listen(8100,function(){
        console.log('server start');
    });
    

    webapp/routes/index.js修改路由

    router.get('/', function(req, res, next) {
      res.render('index', { title: 'Express', list:[{username:'alice'},{username:'ben'},{username:'carl'}] });
    });
    

    webapp/view/index.ejs修改模板

    <!DOCTYPE html>
    <html>
      <head>
        <title><%= title %></title>
        <link rel='stylesheet' href='/stylesheets/style.css' />
      </head>
      <body>
        <h1><%= title %></h1>
        <% list.forEach(function(item){ %>
        <p><%=item.username%></p>
        <% }) %>
        <p>Welcome to <%= title %></p>
      </body>
    </html>
    

    瀏覽器查看結果

    http://localhost:8100
    

    Chapter06.構建網絡應用基礎

    案例1:接收GET提交

    創建應用

    cd workspace
    express -e webapp
    cd webappp && npm install
    

    添加路由

    # webapp/app.js
    var subform = require('./routes/subform');
    app.use('/subform', subform);
    

    監聽端口

    # webapp/app.js
    app.listen(8100,function(){
        console.log('server start');
    });
    

    創建路由文件

    # webapp/routes/subform.js
    var express = require('express');
    var router = express.Router();
    
    router.get('/',function(req,res){
        /*
       //接收GET參數并輸入控制臺
        var username = req.query.username;
        var password = req.query.password;
    
        var username = req.param('username');
        var password = req.param('password');
    
        console.log(username,password);
        */
    
        //渲染頁面
        res.render('subform',{title:'提交表單'});
    });
    
    module.exports = router;
    

    創建公共模板

    # webapp/views/nav.ejs
    
    <ul class="list-group">
        <li class="list-group-item"><a href="/">首頁</a></li>
        <li class="list-group-item"><a href="/subform">提交表單</a></li>
        <li class="list-group-item"><a href="/session">回話控制</a></li>
        <li class="list-group-item"><a href="/cookie">Cookie設置</a></li>
        <li class="list-group-item"><a href="/crypto">字符串加密</a></li>
    </ul>
    

    創建表單模樣

    # webapp/views/subform.ejs
    
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title><%=title%></title>
        <link rel="stylesheet" href="/stylesheets/bootstrap.css"/>
    </head>
    <body>
    <% include nav %>
    <form role="form">
        <p class="form-group">
            <label for="username">賬戶</label>
            <input type="text" class="form-control" id="username" name="username" placeholder="賬戶"/>
        </p>
        <p class="form-group">
            <label for="password">密碼</label>
            <input type="password" class="form-control" name="password" id="password" placeholder="密碼"/>
        </p>
        <p class="form-group">
            <label for="repassword">重復密碼</label>
            <input type="password" class="form-control" name="repassword" id="repassword" placeholder="重復密碼"/>
        </p>
        <button class="btn btn-primary" id="submit">注冊</button>
        <a href="/login" class="btn btn-default">登錄</a>
    </form>
    </body>
    </html>
    

    案例2:接收POST提交

    路由文件:webapp/routes/subform.js

    router.post('/',function(req,res){
       //接收參數
       //  var username = req.body.username;
       //  var password = req.body.password;
    
        var username = req.param('username');
        var password = req.param('password');
    
        console.log(username,password);
    
        res.render('subform',{title:'表單提交'});
    });
    

    小結

    GET和POST方式接收值,從直接效果上來看。

    • req.query 接收GET方式提交參數
    • req.body 接收POST方式提交參數
    • req.params 接收GET和POST提交參數

    關于req.body
    Express出力post請求是通過中間件bodyParser來完成的,從app.js文件可發現:

    var bodyParser = require('body-parser');
    ...
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: false }));
    

    bodyParser中間件分析 application/x-www-form-urlencodedapplication/json請求,并將變量存入 req.body后才能獲取。

    案例3:字符串加密

    表單提交后比如密碼等敏感信息需進行加密出力,NodeJS提交加密模塊crypto

    入口文件添加路由
    webapp/app.js

    var crypto = require('./routes/crypto');
    app.use('/crypto', crypto);
    

    創建路由
    webapp/routes/crypto.js

    var express = require('express');
    var router = express.Router();
    
    var crypto = require('crypto');//載入加密模塊
    
    // 獲取GET參數
    router.get('/',function(req,res){
       res.render('crypto', {title:'字符串加密'});
    });
    
    //處理POST提交
    router.post('/',function(req,res){
        //獲取參數
        var username = req.body.username;
        var password = req.body.password;
    
        //生成口令的散列值
        var md5 = crypto.createHash('md5');
        var md5pwd = md5.update(password).digest('hex');
    
        console.log(username,password,md5pwd);
    
        res.render('crypto',{title:'加密處理'});
    });
    
    //暴露接口
    module.exports = router;
    

    創建視圖
    webapp/views/crypto.ejs

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title><%=title%></title>
        <link rel="stylesheet" href="/stylesheets/bootstrap.css"/>
    </head>
    <body>
    <% include nav %>
    <form method="post">
        <p class="form-group">
            <label for="username">賬戶</label>
            <input type="text" class="form-control" id="username" name="username" placeholder="賬戶"/>
        </p>
        <p class="form-group">
            <label for="password">密碼</label>
            <input type="password" class="form-control" name="password" id="password" placeholder="密碼"/>
        </p>
        <button class="btn btn-primary" type="submit">登錄</button>
    </form>
    </body>
    </html>
    

    小結:
    實用crypto提供的createHash(algorithm),采用給定算法生成hash對象。NodeJS的Hash算法提供了md5、sha1、sha264等。
    update(data,[input_encoding])通過指定的input_encoding和傳入的data數據更新hash對象,input_encoding為可選參數,無傳入則作為buffer處理。

    案例:會話控制

    Internet通訊協議分為stateful和stateless,http是stateless協議及客戶端發送請求到服務器建立連接,請求得到響應后立即終端,服務器不記錄狀態,服務器想確定是那個客戶端提交的請求,就必須借助于session和cookie。session存在于服務器端,需cookie協助才能完成,服務端和客戶端通過session_id來建立聯系。

    express可實用中間件express-session來實用session。

    思路:登錄判斷,不同頁面中判斷是否具有session,若有則表示登錄,無則表示未登錄。
    步驟1:npm安裝中間件
    webapp/package.json

      "dependencies": {
        "express-session":"latest",
      }
    

    執行并下載更新

    npm install
    

    步驟2:入口文件添加session模塊
    webapp/app.js

    //加載回話模塊
    var session = require('express-session');
    //傳入秘鑰加session_id
    app.use(cookieParser('junchow'));
    //實用中間件
    app.use(session({secret:'junchow'}));
    

    步驟3:入口添加登錄控制路由
    webapp/app.js

    var login = require('./routes/login');//表單提交
    app.use('/login',login);
    

    步驟4:創建登錄路由控制
    webapp/routes/login.js

    var express = require('express');
    var router = express.Router();
    
    var title = '登錄';
    router.get('/',function(req,res){
        //清除session
        //req.session.destroy();
        //判斷session中是否具有登錄標識符isLogin
        if(req.session.isLogin){
            //控制臺輸出
            console.log('session isLogin : '+req.session.isLogin);
            //頁面分配變量
            res.locals.isLogin = req.session.isLogin;
        }
        //頁面渲染
        res.render('login',{title:title});
    });
    router.post('/',function(req,res){
        //提交成功并寫入session
        req.session.isLogin = true;
        req.locals.isLogin = req.session.isLogin;
    
        res.render('login',{title:title});
    });
    module.exports = router;
    

    步驟5:創建登錄視圖
    webapp/views/login.ejs

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title><%=title%></title>
        <link rel="stylesheet" href="/stylesheets/bootstrap.css"/>
    </head>
    <body>
        <% include nav %>
        <% if(locals.isLogin){ %>
            <p class="alert alert-success">用戶已登錄</p>
        <% }else{ %>
            <form method="post">
                <input type="submit" value="登錄" class="btn btn-primary">
            </form>
        <% } %>
    </body>
    </html>
    

    出現問題:

    Cannot set property 'isLogin' of undefined
    

    案例:Cookies

    cookies保存在客戶端安全性比較低,一般要存入加密后的信息,建議要設置實用過期時間或不使用時刪除。cookies使用場景例如登錄中“記錄密碼”或“自動登錄”。
    步驟1:webapp/app.js

    var cookie = require('./routes/cookie');
    app.use('/cookie',cookie);
    

    步驟2:webapp/routes/cookie.js

    var express = require('express');
    var router = express.Router();
    
    var title = 'cookies';
    router.get('/',function(req,res){
        if(req.cookies.isLogin){
            console.log('cookies isLogin: '+req.cookies.isLogin);
            req.session.isLogin = req.cookies.isLogin;
        }
        if(req.session.isLogin){
            console.log('cookies isLogin: ' + req.session.isLogin);
            res.locals.isLogin = req.session.isLogin;
        }
       res.render('cookie',{title:title});
    });
    router.post('/',function(req,res){
        req.session.isLogin = true;
        res.locals.isLogin = req.session.isLogin;
        //設置cookie過期時長為60000毫秒(1分鐘)
        res.cookie('isLogin',true,{maxAge:60000});
        res.render('cookie',{title:title});
    });
    
    module.exports = router;
    

    步驟3:webapp/views/cookie.ejs

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title><%=title%></title>
        <link rel="stylesheet" href="/stylesheets/bootstrap.css"/>
    </head>
    <body>
    <% include nav %>
    <% if(locals.isLogin){ %>
    <p class="alert alert-warning">已登錄</p>
    <% }else{ %>
    <form method="post">
        <input type="submit" value="登錄" class="btn btn-primary">
    </form>
    <% } %>
    </body>
    </html>
    

    小結:清除session和cookie
    // 清除cookies
    res.clearCookie('isLogin');
    // 清除session
    req.session.destroy();

    Chatper07.構架網絡應用案例

    步驟1:創建項目

    cd workspace
    express -e webapp
    cd webapp && npm install
    

    步驟2:創建數據庫

    CREATE DATABASE IF NOT EXISTS `test` CHARSET utf8;
    USE test;
    SET FOREIGN_KEY_CHECKS=0;
    
    DROP TABLE IF EXISTS `user`;
    CREATE TABLE IF NOT EXISTS `user`(
        id int(11) unsigned NOT NULL PRIMARY KEY COMMENT '主鍵',
        username varchar(20) NOT NULL DEFAULT '' COMMENT '賬戶',
        password varchar(64) NOT NULL DEFAULT '' COMMENT '密碼'
    )ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶表';
    

    步驟3:安裝模塊
    修改package.json安裝session和mysql模塊

    {
      "name": "webapp",
      "version": "0.0.0",
      "private": true,
      "scripts": {
        "start": "node ./bin/www"
      },
      "dependencies": {
        "body-parser": "~1.17.1",
        "cookie-parser": "~1.4.3",
        "debug": "~2.6.3",
        "ejs": "~2.5.6",
        "express": "~4.15.2",
        "morgan": "~1.8.1",
        "serve-favicon": "~2.4.2",
        "express-session":"latest",
        "mysql":"latest"
      }
    }
    

    安裝模塊

    npm install
    

    webapp/app.js添加代碼

    //加載回話
    var session = require('express-session');
    //傳入秘鑰加session_id
    app.use(cookieParser('junchow'));
    //實用中間件
    app.use(session({secret:'junchow'}));
    

    步驟4:前端資源

    npm install bootstrap
    npm install jquery
    

    從webapp/node_module/中尋找bootstrap和jquery提取文件加入public目錄。

    步驟5.規劃路由
    首頁:/
    注冊:register

    routes/register.js
    views/register.ejs
    

    登錄:login

    routes/login.js
    views/login.ejs
    

    安全退出:logout

    routes/logout.js
    views/logout.ejs
    

    公共頁面:

    header.ejs
    

    步驟6:具體實現
    創建數據訪問方法
    webapp/models/user.js

    var mysql = require('mysql');
    var dbname = 'test';
    
    //創建連接
    var dbcfg = {host:'127.0.0.1', user:'root', password:'root'};
    var pool = mysql.createPool(dbcfg);
    pool.on('connection', function(connection){
       connection.query('SET SESSION auto_increment_increment = 1');
    });
    pool.getConnection(function(err,connection){
        //選擇數據庫
        var sql = "USE "+ dbname;
        connection.query(sql, function(err){
           if(err){
               console.log("USE ERROR: "+err.message);
               return;
           }
           console.log("USE SUCCESS");
        });
        //保存數據
        User.prototype.save = function save(callback){
            var obj = {username:this.username, password:this.password};
            var sql = "INSERT INTO user(username,password) VALUES(?,?)";
            connection.query(sql, [obj.username, obj.password], function(err,result){
                if(err){
                    console.log("save error: "+sql, err.message);
                    return;
                }
                connection.release();
                console.log("invoked save");
                callback(err,result);
            });
        };
        // 根據賬戶獲取用戶數目
        User.getUserNumByName = function getUserNumByName(username,callback){
            var sql = "SELECT COUNT(1) AS num FROM user WHERE username=?";
            connection.query(sql,[username],function(err,result){
                if(err){
                    console.log("getUserNumByName error:"+err.message);
                    return;
                }
                console.log("invoked getUserNumByName");
                callback(err,result);
            });
        };
        //根據賬戶獲取用戶信息
        User.getUserByUsername = function getUserByUsername(username,callback){
          var sql = "SELECT * FROM user WHERE 1=1 AND username=?";
          connection.query(sql, [username], function(err,result){
              if(err){
                  console.log("getUserByUsername error: "+err.message);
                  return;
              }
              connection.release();
              console.log("invoked getUserByUsername");
              callback(err,result);
          });
        };
    });
    //暴露接口
    function User(obj){
        this.username = obj.username;
        this.password = obj.password;
    }
    module.exports = User;
    
    4933701-28f61c63e4f9f0c4.png
    2017-04-18_17-08-15.png

    注冊模塊
    webapp/app.js

    var register = require('./routes/register');
    app.use('/register',register);
    

    webapp/routes/register.js

    var express = require('express');
    var router = express.Router();
    
    var User = require('../models/user.js');
    var crypto = require('crypto');
    
    var title = '注冊';
    router.get('/', function(req, res, next) {
        res.render('register', { title: title});
    });
    
    
    router.post('/', function(req,res){
        var username = req.body['username'];
        var password = req.body['password'];
        var repassword = req.body['repassword'];
    
        var md5 = crypto.createHash('md5');
        password = md5.update(password).digest('hex');
    
        var obj = new User({username:username, password:password});
    
        //檢查賬戶是否存在
        User.getUserNumByName(obj.username, function(err,result){
            if(result!=null && result[0]['num']>0){
                err = '賬戶已存在';
            }
            if(err){
                res.locals.error = err;
                res.render('register', {title:title});
                return;
            }
            obj.save(function(err,result){
                console.log(err,result);
               if(err){
                   res.locals.error = err;
                   res.render('register',{title:title});
                   return;
               }
               if(result.insertId > 0){
                   res.locals.success = '注冊成功,請<a class="btn btn-link" href="/login" role="button">登錄</a>!';
               }else{
                   res.locals.error = err;
               }
               res.render('register',{title:title});
            });
        });
    });
    
    module.exports = router;
    

    webapp/views/register.ejs

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title><%=title%></title>
        <link rel="stylesheet" href="/stylesheets/bootstrap.css"/>
    </head>
    <body>
    <div id="container" class="container">
        <h2 class="page-header"><%=title%></h2>
        <% if(locals.success){%>
        <div id="success" class="alert alert-success"><%-success%></div>
        <%}%>
        <% if(locals.error){ %>
        <div id="warning" class="alert alert-warning"><%=error%></div>
        <%}%>
        <form role="form" method="post">
            <p class="form-group">
                <label for="username">賬戶</label>
                <input type="text" class="form-control" id="username" name="username" placeholder="賬戶"/>
            </p>
            <p class="form-group">
                <label for="password">密碼</label>
                <input type="password" class="form-control" name="password" id="password" placeholder="密碼"/>
            </p>
            <p class="form-group">
                <label for="repassword">重復密碼</label>
                <input type="password" class="form-control" name="repassword" id="repassword" placeholder="重復密碼"/>
            </p>
            <button class="btn btn-primary" id="submit">注冊</button>
            <a href="/login" class="btn btn-default">登錄</a>
        </form>
    </div>
    <script src="/javascripts/jquery.js"></script>
    <script>
        String.prototype.format = function(args){
            var that = this;
            if(arguments.length > 0){
                if(arguments.length == 1 && typeof(args)=='object'){
                    for(var k in args){
                        if(args[k] != undefined){
                            var reg = new RegExp('({'+k+'})', 'g');
                            that = that.replace(reg, args[k]);
                        }
                    }
                }else{
                    for(var i=0; i<arguments.length; i++){
                        if(arguments[i] != undefined){
                            var reg = new RegExp('({)'+i+'(})','g');
                            that = that.replace(reg, arguments[i]);
                        }
                    }
                }
            }
            return that;
        }
        //表單驗證
        $(function(){
           $('#submit').on('click',function(){
               var username = $('#username');
               var usernameVal = $.trim(username.val());
    
               var password = $('#password');
               var passwordVal = $.trim(password.val());
    
               var repassword = $('#repassword');
               var repasswordVal = $.trim(repassword.val());
    
               var tip = '<div id="tip" class="alert alert-warning">{0}</div>';
    
               $('#success,#warning,#tip').remove();
    
               if(usernameVal.length == 0){
                   $('#container').prepend(tip.format('賬戶不能為空!'));
                   username.focus();
                   return false;
               }
               if(passwordVal.length == 0){
                   $('#container').prepend(tip.format('密碼不能為空!'));
                   password.focus();
                   return false;
               }
               if(repasswordVal.length == 0){
                   $('#container').prepend(tip.format('重復密碼不能為空!'));
                   repassword.focus();
                   return false;
               }
               if(passwordVal != repasswordVal){
                   $('#container').prepend(tip.format('兩次密碼不一致!'));
                   repassword.focus();
                   return false;
               }
    
               return true;
           });
        });
    </script>
    </body>
    </html>
    
    4933701-a07714b62b5dd8d7.png
    2017-04-18_17-24-29.png

    登錄模塊

    webapp/app.js

    var login = require('./routes/login');
    app.use('/login',login);
    

    webapp/routes/login.js

    var express = require('express');
    var router = express.Router();
    
    var crypto = require('crypto');
    var User = require('../models/user.js');
    var title = '登錄';
    
    router.get('/',function(req,res){
       res.render('login',{title:title});
    });
    router.post('/',function(req,res){
        var username = req.body['username'];
        var password = req.body['password'];
        var rem = req.body['rem'];
        var md5 = crypto.createHash('md5');
    
        User.getUserByUsername(username,function(err,ret){
           if(ret==''){
               res.locals.error = '賬戶不存在';
               res.render('login',{title:title});
               return;
           }
           password = md5.update(password).digest('hex');
           if(ret[0].username!=username || ret[0].password!=password){
               res.locals.error = '賬戶或密碼錯誤';
               res.render('login',{title:title});
               return;
           }else{
               if(rem){
                   res.cookie('isLogin', username, {maxAge:60000});
               }
               res.locals.username = username;
               req.session.username = res.locals.username;
               console.log(req.session.username);
    
               res.redirect('/home');
               return;
           }
        });
    });
    
    module.exports = router;
    

    webapp/views/login.ejs

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title><%=title%></title>
        <link rel="stylesheet" href="/stylesheets/bootstrap.css"/>
    </head>
    <body>
    <div id="container" class="container">
        <h2 class="page-header"><%=title%></h2>
        <% if(locals.success){%>
        <div id="success" class="alert alert-success"><%-success%></div>
        <%}%>
        <% if(locals.error){ %>
        <div id="warning" class="alert alert-warning"><%=error%></div>
        <%}%>
        <form role="form" method="post">
            <p class="form-group">
                <label for="username">賬戶</label>
                <input type="text" class="form-control" id="username" name="username" placeholder="賬戶"/>
            </p>
            <p class="form-group">
                <label for="password">密碼</label>
                <input type="password" class="form-control" name="password" id="password" placeholder="密碼"/>
            </p>
            <p class="form-group">
                <label class="checkbox"><input type="checkbox" name="rem" id="rem">自動登錄</label>
            </p>
            <button class="btn btn-primary" id="submit">登錄</button>
            <a href="/register" class="btn btn-default">注冊</a>
        </form>
    </div>
    <script src="/javascripts/jquery.js"></script>
    <script>
        String.prototype.format = function(args){
            var that = this;
            if(arguments.length > 0){
                if(arguments.length == 1 && typeof(args)=='object'){
                    for(var k in args){
                        if(args[k] != undefined){
                            var reg = new RegExp('({'+k+'})', 'g');
                            that = that.replace(reg, args[k]);
                        }
                    }
                }else{
                    for(var i=0; i<arguments.length; i++){
                        if(arguments[i] != undefined){
                            var reg = new RegExp('({)'+i+'(})','g');
                            that = that.replace(reg, arguments[i]);
                        }
                    }
                }
            }
            return that;
        }
        //表單驗證
        $(function(){
            $('#submit').on('click',function(){
                var username = $('#username');
                var usernameVal = $.trim(username.val());
    
                var password = $('#password');
                var passwordVal = $.trim(password.val());
    
                var tip = '<div id="tip" class="alert alert-warning">{0}</div>';
    
                $('#success,#warning,#tip').remove();
    
                if(usernameVal.length == 0){
                    $('#container').prepend(tip.format('賬戶不能為空!'));
                    username.focus();
                    return false;
                }
                if(passwordVal.length == 0){
                    $('#container').prepend(tip.format('密碼不能為空!'));
                    password.focus();
                    return false;
                }
    
                return true;
            });
        });
    </script>
    </body>
    </html>
    

    首頁模塊

    webapp/app.js

    var home = require('./routes/home');
    app.use('/home',home);
    

    webapp/routes/home.js

    var express = require('express');
    var router = express.Router();
    
    var title = '主頁';
    router.get('/',function(req,res){
        if(req.cookies.isLogin){
            console.log('cookies isLogin: '+req.cookies.isLogin);
            req.session.username = req.cookies.isLogin;
        }
        if(req.session.username){
            console.log('session username : '+req.session.username);
            res.locals.username = req.session.username;
        }else{
            res.redirect('/login');
            return;
        }
        res.render('home',{title:title});
    });
    
    module.exports = router;
    

    webapp/views/home.ejs

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title><%=title%></title>
        <link rel="stylesheet" href="/stylesheets/bootstrap.css"/>
    </head>
    <body>
    <% include header %>
    <div id="container" class="container">
    
    </div>
    <script src="/javascripts/jquery.js"></script>
    </body>
    </html>
    

    webapp/views/header.ejs

    <div class="navbar navbar-default navbar-static-top" role="navigation">
        <div class="container">
            <div class="navbar-header"><a href="/home" class="navbar-brand">home</a></div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav navbar-right">
                    <% if(locals.username){%><li><a href="#"><%=username%></a></li><%}%>
                    <li><a href="/logout">安全退出</a></li>
                </ul>
            </div>
        </div>
    </div>
    

    退出模塊

    webapp/app.js

    var logout = require('./routes/logout');
    app.use('/logout',logout);
    

    webapp/routes/logout.js

    var express = require('express');
    var router = express.Router();
    
    router.get('/',function(req,res){
        req.session.destroy();
        res.redirect('/home');
    });
    
    module.exports = router;
    

    Chatper08.文件上傳

    formidable的文件上傳模塊
    安裝模塊:webapp/package.json

    "formidable":"latest"
    

    安裝依賴

    npm install
    

    入口文件添加:webapp/app.js

    var upload = require('./routes/upload');
    app.use('/upload',upload);
    

    路由處理文件:web/routes/upload.js

    var express = require('express');
    var router = express.Router();
    
    //上傳處理類
    var formidable = require('formidable');
    var fs = require('fs');
    var UPLOAD_FOLDER = '/upload/';
    
    var title = '上傳';
    router.get('/',function(req,res){
        res.render('upload',{title:title});
    });
    
    router.post('/',function(req,res){
        //創建上傳表單
        var form = new formidable.IncomingForm();
        //設置字符集
        form.encoding = 'utf-8';
        //設置上傳陌路
        form.uploadDir = 'public'+UPLOAD_FOLDER;
        //是否保留文件后綴
        form.keepExtensions = true;
        //顯示上傳文件大小
        form.maxFieldsSize = 2*1024*1024;
    
        //上傳處理
        form.parse(req, function(err,fields,files){
           if(err){
               res.locals.error = true;
               res.render('upload', {title:title});
               return;
           }
    
           var ext = '';
           switch(files.type){
               case 'image/pjpeg': ext = 'jpg'; break;
               case 'image/jpeg': ext = 'jpg'; break;
               case 'image/png': ext = 'png'; break;
               case 'image/x-png': ext = 'png'; break;
           }
    
           if(ext.length == 0){
               res.locals.error = '僅支持png或jpg格式圖片';
               res.render('upload',{title:title});
               return;
           }
    
           var picname = Math.random()+'.'+ext;
           var picfile = form.uploadDir+picname;
    
           fs.renameSync(files.path, picfile);
        });
    
        res.locals.success = '上傳成功';
        res.render('upload', {title:title});
    });
    
    
    module.exports = router;
    

    模板文件:webapp/views/upload.ejs

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title><%=title%></title>
        <link rel="stylesheet" href="/stylesheets/bootstrap.css"/>
    </head>
    <body>
    <div id="container" class="container">
        <form class="form" role="form" method="post" enctype="multipart/form-data">
            <h2 class="page-header">文件上傳</h2>
            <p class="input-group">
                <input type="file" name="pid" id="pic" class="form-control"/>
                <span class="input-group-btn">
                    <button class="btn btn-primary" type="submit" id="submit">上傳</button>
                </span>
            </p>
        </form>
    </div>
    <script src="/javascripts/jquery.js"></script>
    <script>
        String.prototype.format = function(args){
            var that = this;
            if(arguments.length > 0){
                if(arguments.length == 1 && typeof(args) == 'object'){
                    for(var i in args){
                        if(args[i] != undefined){
                            var reg = new RegExp("({"+i+"})", "g");
                            that = that.replace(reg, args[i]);
                        }
                    }
                }else{
                    for(var i=0; i<arguments.length;i++){
                        if(arguments[i] != undefined){
                            var reg = new RegExp("({)"+i+"(})","g");
                            that = that.replace(reg,arguments[i]);
                        }
                    }
                }
            }
            return that;
        }
    
        $(function(){
           $('#submit').on('click',function(){
               var picVal = $('#pic').val();
               var tip = '<div id="tip" class="alert alert-warning">{0}</div>';
    
               if(picVal.length == 0){
                   $('#container').prepend(tip.format('請選擇上傳文件'));
                   return false;
               }
    
               var ext = picVal.substring(picVal.lastIndexOf('.'), picVal.length).toLowerCase();
               console.log(ext);
               if(ext!='.png' && ext!='.jpg'){
                   $('#container').prepend(tip.format('僅支持png或jpg格式圖片!'));
                   return false;
               }
    
               return true;
           });
        });
    </script>
    </body>
    </html>
    

    運行中錯誤

    Error: Can't set headers after they are sent.
        at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:357:11)
        at ServerResponse.header (D:\nodejs\webapp\node_modules\express\lib\response
    .js:725:10)
        at ServerResponse.send (D:\nodejs\webapp\node_modules\express\lib\response.j
    s:170:12)
        at done (D:\nodejs\webapp\node_modules\express\lib\response.js:962:10)
        at tryHandleCache (D:\nodejs\webapp\node_modules\ejs\lib\ejs.js:208:10)
        at View.exports.renderFile [as engine] (D:\nodejs\webapp\node_modules\ejs\li
    b\ejs.js:412:10)
        at View.render (D:\nodejs\webapp\node_modules\express\lib\view.js:128:8)
        at tryRender (D:\nodejs\webapp\node_modules\express\lib\application.js:640:1
    0)
        at EventEmitter.render (D:\nodejs\webapp\node_modules\express\lib\applicatio
    n.js:592:3)
        at ServerResponse.render (D:\nodejs\webapp\node_modules\express\lib\response
    .js:966:7)
    

    Chapter09.與Redis交互

    Redis簡介

    • 高性能key-value存儲
    • 可采用in-memory數據集的方式,也可采用磁盤存儲方式。
    • 支持主從同步、pub/sub等
      redis服務端
      redis客戶端

    在windows中下載redis服務端解壓后運行redis-server.exe,redis.conf作為配置文件。

    安裝node_redis

    npm install redis
    npm install hiredis redis
    

    區別:hiredis是非阻塞的,速度更快。node_redis默認以它作為解釋器,若沒安裝則會用純javascript解釋器。

    創建連接

    //連接到本地redis服務器
    var redis = require('redis');
    var client = redis.createClient();//返回RedisClient對象
    
    //連接到遠程redis服務器
    var redis = require('redis');
    var RDS_PORT = 6379;
    var RDS_HOST = '127.0.0.1';
    var RDS_OPTS = {};
    var client = redis.createClient(RDS_PORT,RDS_HOST,RDS_OPTS);//返回RedisClient對象
    

    設置遠程連接密碼
    在redis.conf配置文件打開requirepass foobared,其中foobared是密碼。

    密碼認證

    //連接到redis服務器并認證
    var redis = require('redis');
    var RDS_PORT = 6379;
    var RDS_HOST = '127.0.0.1';
    var RDS_PWD = 'foobared';
    var RDS_OPTS = {auth_pass:RDS_PWD};
    //返回RedisClient對象
    var client = redis.createClient(RDS_PORT,RDS_HOST,RDS_OPTS);
    
    //密碼認證
    client.auth(RDS_PWD,function(){
        console.log('通過認證');
    });
    

    觸發事件

    //當與redis服務器連接成功后觸發ready事件
    //表示已準備好接收命令,當此事件出發之前client命令會存在的隊列中,當一切準備就緒后調用。
    client.on('ready',function(err){
        console.log('ready',err);
    });
    
    //在不設置client.options.no_ready_check情況下,客戶端觸發connect同時會發出ready。
    //若設置了client.options.no_ready_check,當這個stream被連接時會觸發connect,此時就可以自由嘗試發命令。
    client.on('connect',function(){
        //單值設置
       client.set('author', 'junchow', redis.print);//設置單個key和value
       client.get('author',redis.print);//通過key獲取value
    
        //多值設置
        client.hmset('short',{'js':'javascript', 'C#':'C sharp'}, redis.print);
        client.hmset('short', 'SQL','Structured Query Language', 'HTML', 'HyperText Markup Language', redis.print);
        client.hgetall('short',function(err,res){
           if(err){
               console.log('Error:' + err);
               return;
           }
           console.dir(res);
       });
    });
    

    Chapter10.與MongoDB交互

    MongoDB高性能的NoSQL數據庫,支持索引、集群、復制、故障轉移、各種語言驅動程序,高伸縮性。
    MongoDB的NodeJS驅動:node-mongodb-native

    [下載MongoDB](http://www.mongodb.org/downloads

    安裝服務端
    步驟1:創建數據庫和日志存放目錄
    在MongoDB目錄下創建db和log兩個文件夾,并在log目錄下新建mongodb.log文件。
    步驟2:創建配置文件
    在MongoDB下的bin目錄下創建mongo.conf文件,添加配置

    ##數據庫目錄
    dbpath=D:\MongoDB\db
    ##日志輸出文件
    logpath=D:\MongoDB\log\mongodb.log
    

    步驟3:添加環境變量
    D:\MongoDB\bin添加到環境變量path中
    步驟4:安裝服務
    mongod --config "D:\MongoDB\bin\mongo.conf" --install
    步驟5:啟動服務
    net start mongodb
    步驟6:打開服務端
    mongo

    備注:MongoDB默認端口為27017

    庫操作
    //查看數據庫列表
    show dbs
    //檢查當前選擇的數據庫
    db
    //創建數據庫
    use test
    //use創建的數據庫需插入數據后才能顯示
    db.user.insert({"name":"alice"})
    //刪除當前數據庫
    db.dropDatabase()

    集合操作
    //創建集合
    db.createCollection(name,options)
    //查看集合列表
    show collections
    //刪除集合
    db.collection.drop()
    //向集合中插入數據
    db.user.insert({"name":"alice"})
    //獲取集合數據
    db.user.find()
    //獲取集合條數
    db.user.find().count()

    NodeJS操作MongoDB
    安裝
    npm install mongodb
    創建連接

    var MongoClient = require('mongodb').MongoClient;
    var MongoLink = 'mongodb://127.0.0.1:27017/test';
    //連接數據庫
    MongoClient.connect(MongoLink,function(err,db){
        console.log('連接成功');
    });
    

    插入數據

    var MongoClient = require('mongodb').MongoClient;
    var MongoLink = 'mongodb://127.0.0.1:27017/test';
    //插入數據
    var insertData = function(db,callback){
      //連接集合
        var collection = db.collection('user');
        //插入數據
        var data = [
            {"name":"alice","age":18},
            {"name":"ben","age":19},
            {"name":"carl","age":20}
        ];
        collection.insert(data,function(err,res){
           if(err){
               console.log(err);
               return;
           }
           callback(res);
        });
    };
    //連接數據庫
    MongoClient.connect(MongoLink,function(err,db){
        console.log('連接成功');
        //插入數據
        insertData(db,function(res){
           console.log(res);
           db.close();//關閉數據庫
        });
    });
    

    查詢數據

    var MongoClient = require('mongodb').MongoClient;
    var MongoLink = 'mongodb://127.0.0.1:27017/test';
    
    //查詢數據
    var findData = function(db,callback){
        //連接集合
        var collection = db.collection('user');
        //查詢條件
        var where = {"name":"alice"};
        //查詢數據
        collection.find(where).toArray(function(err,res){
           if(err){
               console.log(err);
               return;
           }
           callback(res);
        });
    };
    //連接數據庫
    MongoClient.connect(MongoLink,function(err,db){
        console.log('連接成功');
        //查詢數據
        findData(db,function(res){
           console.log(res);
           db.close();
        });
    });
    

    更新數據

    var MongoClient = require('mongodb').MongoClient;
    var MongoLink = 'mongodb://127.0.0.1:27017/test';
    //修改數據
    var updateData = function(db,callback){
      var collection = db.collection('user');
      var where = {"name":"alice"};
      var data = {$set:{"age":30}};
      collection.update(where, data, function(err,res){
          if(err){
              console.log(err);
              return;
          }
          callback(res);
      });
    };
    //連接數據庫
    MongoClient.connect(MongoLink,function(err,db){
        console.log('連接成功');
        //更新數據
        updateData(db,function(res){
            console.log(res);
            db.close();
        });
    });
    

    注意:以上更新發現僅更新一條

    刪除數據

    var MongoClient = require('mongodb').MongoClient;
    var MongoLink = 'mongodb://127.0.0.1:27017/test';
    //刪除數據
    var removeData = function(db,callback){
        var collection = db.collection('user');
        var where = {"name":"alice"};
        collection.remove(where,function(err,res){
            if(err){
                console.log(err);
                return;
            }
            callback(res);
        });
    };
    //連接數據庫
    MongoClient.connect(MongoLink,function(err,db){
        console.log('連接成功');
        //刪除數據
        removeData(db,function(res){
           console.log(res);
           db.close();
        });
    });
    

    Chapter11.數據采集器

    使用request和cheerio發送請求并實用正則解析數據來完成數據采集。

    • request 用于http請求
    • cheerio 用于提取request返回的html中所需數據

    步驟1:安裝
    webapp/package.json中依賴中添加

    "request":"*",
    "cheerio":"*"
    

    執行命令

    cd webapp && npm install
    

    采集代碼
    思路:實用request一個get請求,請求回調中返回body即html代碼,通過cherrio庫的jquery語法操作解析,獲取所需要的數據。

    /*數據采集*/
    var request = require('request');
    var cheerio = require('cheerio');
    var url = 'http://36kr.com';
    
    //開啟數據采集器
    function startup(){
        doRequest(url);
    }
    //請求數據
    function doRequest(url){
        request({url:url,method:'GET'},function(err,res,body){
           if(err){
               console.log(err,res,body);
               return;
           }
           //解析數據
            doParse(body);
        });
    }
    //解析數據
    function doParse(body){
        var $ = cheerio.load(body);
        
        var articles = $('article');
        for(var i=0; i=articles.length; i++){
            var article = articles[i];
            var desc = $(article).find('.desc');
            if(desc.length==0){
                continue;
            }
    
            var coverDom = $(article).children().first();
            var titleDom = $(desc).find('.info_flow_news_title');
            var timeagoDom = $(desc).find('.timeago');
    
            var titleVal = titleDom.text();
            var urlVal = titleDom.attr('href');
            var timeVal = timeDom.attr('title');
            var timeSecs = new Date(timeVal).getTime()/1000;
            var converUrl = converDom.attr('data-lazyload');
    
            if(urlVal!=undefined){
                console.info('----------------------------------');
                console.info('標題:'+titleVal);
                console.info('地址:'+urlVal);
                console.info('時間:'+timeSecs);
                console.info('封面:'+converUrl);
            }else{
                console.info('error');
            }
        }
    }
    startup();
    

    升級版本:加入代理
    若需長期實用為避免網站屏蔽,還需添加一個代理列表。

    /*數據采集*/
    var request = require('request');
    var cheerio = require('cheerio');
    var url = 'http://36kr.com';
    
    //長期采集為防止網站屏蔽加入代理列表
    var proxy = require('./proxylist.js');
    
    //開啟數據采集器
    function startup(){
        doRequest(url);
    }
    //請求數據
    function doRequest(url){
        //實用代理發送請求
        request({url:url,method:'GET',proxy:proxy.getProxy()},function(err,res,body){
           if(err){
               console.log(err,res,body);
               return;
           }
           //解析數據
            doParse(body);
        });
    }
    //解析數據
    function doParse(body){
        var $ = cheerio.load(body);
    
        var articles = $('article');
        for(var i=0; i=articles.length; i++){
            var article = articles[i];
            var desc = $(article).find('.desc');
            if(desc.length==0){
                continue;
            }
    
            var coverDom = $(article).children().first();
            var titleDom = $(desc).find('.info_flow_news_title');
            var timeagoDom = $(desc).find('.timeago');
    
            var titleVal = titleDom.text();
            var urlVal = titleDom.attr('href');
            var timeVal = timeDom.attr('title');
            var timeSecs = new Date(timeVal).getTime()/1000;
            var converUrl = converDom.attr('data-lazyload');
    
            if(urlVal!=undefined){
                console.info('----------------------------------');
                console.info('標題:'+titleVal);
                console.info('地址:'+urlVal);
                console.info('時間:'+timeSecs);
                console.info('封面:'+converUrl);
            }else{
                console.info('error');
            }
        }
    }
    startup();
    setInterval(startup,10000);//間隔執行
    

    升級版本:支持HTTPS

    //請求數據
    function doRequest(url){
        //支持HTTPS的header頭
        request({url:url,method:'GET',headers:{'User-Agent':'wilson'}},function(err,res,body){
           if(err){
               console.log(err,res,body);
               return;
           }
           //解析數據
            doParse(body);
        });
    }
    

    Chapter12.定時任務

    定時任務應用場景一般包括定時導出數據、定時發送消息、定時發送郵件給用戶、定時備份文件。
    目標:使用node-schedule來完成定時任務
    安裝:
    npm install node-schedule
    定時任務

    var schedule = require('node-schedule');
    function cron(){
       //每隔30秒觸發
        schedule.scheduleJob('30 * * * * *',function(){
            console.log(new Date());
        })
    }
    cron();
    

    遞歸定時器

    var schedule = require('node-schedule');
    function cron(){
        //遞歸定時器
        var rule = new schedule.RecurrenceRule();
        rule.second = 0;
    
        schedule.scheduleJob(rule,function(){
            console.log(new Date());
        });
    }
    cron();
    

    對象文本定時器

    var schedule = require('node-schedule');
    function cron(){
        var cfg = {hour:1, minute:1, dayOfWeek:1};
        schedule.scheduleJob(cfg,function(){
            console.log(new Date());
        });
    }
    cron();
    

    取消定時器

    var schedule = require('node-schedule');
    function cron(){
        var counter = 1;
        var i = schedule.scheduleJob('* * * * * *',function(){
           console.log(counter);
           counter++;
        });
        setTimeout(function(){
            console.log('cancel');
            i.cancel();
        },5000);
    }
    cron();
    
    版權聲明:本文為JunChow520原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/JunChow520/article/details/103030461

    智能推薦

    node.js基礎了解

    node.js的特點 單線程:只有一個線程執行任務 非堵塞I/O:在I/O耗時操作時,線程不堵塞 事件驅動:使用事件驅動程序往下繼續運行 node,js模塊化 規范:遵循common.js規范     加載模塊的時候同步。當遇到require() 語句時,會停下來等加載完成然后繼續往下執行。     暴露模塊的時候推薦...

    node.js基礎入門

    為什么學習node.js     node.js可以輔助前端開發,代替后端開發(但其還是不能和java比),node.js與php相比來說,他的優點是:性能高,開發效率高,應用范圍廣,其缺點是:新型語言,函數少,ide(開發環境,編譯器)不完善 什么是node.js?     node.js是基于chrome v8引擎的JavaScript運行環境。node...

    HTML中常用操作關于:頁面跳轉,空格

    1.頁面跳轉 2.空格的代替符...

    freemarker + ItextRender 根據模板生成PDF文件

    1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...

    電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!

    Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...

    猜你喜歡

    requests實現全自動PPT模板

    http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...

    Linux C系統編程-線程互斥鎖(四)

    互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...

    統計學習方法 - 樸素貝葉斯

    引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...

    styled-components —— React 中的 CSS 最佳實踐

    https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...

    精品国产乱码久久久久久蜜桃不卡