1. 程式人生 > >【nodeJS】從nodejs原生的部落格網站搭建到 koa框架實現個人部落格網站搭建

【nodeJS】從nodejs原生的部落格網站搭建到 koa框架實現個人部落格網站搭建

nodejs實現搭建部落格網站

前言:原java後端渣渣一枚,因專案需要轉學了nodejs進行開發,正式進行專案開發之前,師傅安排了一些專案訓練,先熟悉js語法,然後熟悉nodejs,再慢慢重構向框架的使用。

    寫這一篇文章的目的在於記錄自己學習的歷程,同時也是給其他的nodejs學習者一點參考,如果有修正之處,請給予意見,感謝各位,希望對你有用~

開發環境

系統:可以的話建議使用Linux系統,推薦Ubuntu,筆者習慣了Windows開發,暫時使用的是win7

開發工具:Visual Studio Code

語言:node 5.6.0

npm 5.6.0(其他的依賴模組靠npm去安裝)

語法基礎

1.熟悉js的基本語法,把nodejs的req、res以及其他相關的api熟悉起來;

2.mysql的使用,熟悉的sql指令碼的編寫

專案開發

目標功能(主要功能還是比較簡單的幾個需求,要求一天內完成)

1.網站顯示圖片、文字、有簡潔的樣式

2.網站返回伺服器時間

3.網站支援使用者留言以及顯示當前最新10條留言

4.網站顯示當前訪問的客戶的客戶端資訊

5.底部顯示當前網站的訪問量(日訪問量以及總訪問量)

——————————————————————coding———————————————————————————

選定某個資料夾路徑,先新建一個index.js檔案,作為專案入口,然後,在命令提示符環境下執行以下命令

npm init

之後就按照提示,輸入對應的專案資訊,初始化專案工程,完成之後,就可以開始coding啦~

開啟index.js檔案,先把對應模組引入(經由師傅提醒,為專案匯入的時候應同時建立依賴檔案的記錄,這樣能保證工程在其他機器執行的前能夠安裝所有的依賴模組)

npm install 模組名 --save

好了,這麼一來,依賴的模組也搞定了,剩下的只剩下部落格的後臺處理邏輯以及前端展示的頁面了。

var http = require('http');
var util = require('util');
var url = require('url');
var fs = require('fs');
var path = require('path');
var querystring = require('querystring');

目前模組引入如上,關於搭建伺服器的基本語法,菜鳥教程上講的非常詳細,我們就不贅述了

在入口index.js檔案裡面,我們搭建了伺服器,監聽對應的埠,並對相應的介面地址進行邏輯處理:

const http = require('http');
const util = require('util');
const url = require('url');
const fs = require('fs');
const path = require('path');
const querystring = require('querystring');
//連線資料庫
const mysql = require('mysql');
const connection = mysql.createConnection({     
  host     : 'localhost',       
  user     : 'root',              
  password : '1234',       
  port: '3306',                   
  database: 'mysql', 
}); 
connection.connect();


//留言功能
let message = [];
let mesLength = 0;
let messageShow = '';

let sql = 'SELECT message FROM MyOwnPage_messageBox';

const uriName = ['html','css','jsp','jpg','png'];

console.log("專案已經啟動……127.0.0.1:3000監聽當中")

var app = http.createServer(function (req, res) {
    let body = "";
    req.on('data', function (chunk) {
        body += chunk;
    });

    req.on('end',function(){
        body = querystring.parse(body);
        let pathName = url.parse(req.url).pathname;
        //static resource
            if(req.method == 'GET' && pathName == '/' ){
                fs.readFile(__dirname+"\\LoginPage.html", function (err, data){
                    if(err){
                        res.writeHead(404, {'Content-Type': 'text/html'});
                    }else{
                        res.writeHead(200,{'Content-Type': 'text/html'});
                        res.write(data);
                        res.end();
                    }
                })
            }
            if(req.method == 'GET' && uriName.indexOf(path.extname(pathName).substring(1)) != -1){
                if(pathName ==='/HomePage.html'){
                    let addsql = 'INSERT INTO login_log (page,ip,login_time) value (?,?,?)';
                    let ip = req.socket["remoteAddress"];
                    let date = new Date();
                    let day = date.getDate();
                    let month = date.getMonth()+1;
                    let year = date.getFullYear();
                    let login_time = year+'-'+month+'-'+day;
                    let sqlParams = [pathName,ip,login_time];
                    connection.query(addsql,sqlParams,function(err,result){
                        if(err){
                        return;
                        }        
                    })
                }
                fs.readFile(__dirname+"\\"+pathName.substring(1), function (err, data){
                    if(err){
                        res.writeHead(404, {'Content-Type': 'text/html'});
                    }else{
                        if(path.extname(pathName).substring(1) === 'css'){
                            res.writeHead(200,{'Content-Type': 'text/css'});
                        }else if(path.extname(pathName).substring(1) === 'html'){
                            res.writeHead(200,{'Content-Type': 'text/html'});
                        }else if(path.extname(pathName).substring(1) === 'jpg'){
                            res.writeHead(200,{'Content-Type': 'image/jpeg'});
                        }
                        res.write(data);
                        res.end();
                    }
                })
            }
        //獲取系統時間
            if(req.method == 'GET'  && pathName == '/sysTime_wenzhiqun'){
                    let time = new Date();
                    let year = time.getFullYear();
                    let month = time.getMonth()+1;
                    let date= time.getDate();
                    let hour = time.getHours();
                    let minutes = time.getMinutes();
                    let seconds = time.getSeconds();
                    if(month<10){
                    month = "0"+month; 
                    }
                    if(date<10){
                    date = "0"+date; 
                    }
                    if(hour<10){
                    hour = "0"+hour; 
                    }
                    if(minutes<10){
                    minutes = "0"+minutes; 
                    }
                    if(seconds<10){
                    seconds = "0"+seconds; 
                    }
                    let currentTime = "當前伺服器時間為:"+year+"年"+month+"月"+date+"日"+hour+":"+minutes+":"+seconds;
                res.write(currentTime); 
                res.end();
            }
            
            //提交留言資訊
            if(req.method == 'POST' && pathName == '/message'){
                // 新增留言欄中的留言
                let addsql = 'INSERT INTO MyOwnPage_messageBox (messageCount,message) value (?,?)'
                let userMes = body['message'];
                let sqlParams = [mesLength+1,userMes];
                connection.query(addsql,sqlParams,function(err,result){
                    if(err){
                    res.write("提交失敗,請重試");
                    res.end();
                    return;
                    }        
                    res.write("提交成功");
                    res.end();        
                  })
            }
            //獲取留言欄
            if(req.method == 'GET' && pathName == '/message/list'){
                let sql = 'SELECT message FROM MyOwnPage_messageBox';
                //查詢目前的留言欄
                connection.query(sql,function (err, result) {
                        if(err){
                        return;
                        }
                    message = [];
                    mesLength = 0;
                    for(i of result){
                        message[mesLength]=i.message;
                        mesLength++;
                    } 
                });
                let messageShow = '留言欄:';
                if(message.length<=10){
                    for(let i = message.length,j=1;i>0;i--){
                        messageShow = messageShow+'<br>'+'('+j+')'+message[i-1];
                        j++;
                    }
                }else if(message.length>10){
                    for(let i = message.length,j=1;i>(message.length-10);i--){
                        messageShow = messageShow+'<br>'+'('+j+')'+message[i-1];
                        j++;
                    }
                }
                res.write(messageShow);
                res.end();
            }
            //獲取客戶端資訊
            if(req.method == 'GET' && pathName == '/sysinfo'){
                let ob = req.headers["user-agent"].split(" ");
                let system = ob[1].substring(1);
                let chrome = ob[9].split('/')[0];
                let ip = req.socket["remoteAddress"];
                let iptype = req.socket["remoteFamily"];
                res.write("<b>作業系統:</b>"+system+"  <b>瀏覽器:</b> "+chrome+"<b>ip地址:</b> "+ip+"     <b>ip型別:</b> "+iptype);
                res.end();
            }

            //獲取訪客量
            if(req.method == 'GET' && pathName == '/visit'){
                let sql = 'SELECT login_time FROM login_log';
                //查詢目前的總訪客量和日訪客量
                connection.query(sql,function (err, result) {
                        if(err){
                        return;
                        }
                    let arr = [];
                    //日訪問量
                    let date = new Date();
                    let day = date.getDate();
                    let month = date.getMonth()+1;
                    let year = date.getFullYear();
                    let login_date = year+'-'+month+'-'+day;
                    let day_vi = 0;
                    for(i of result){
                        arr.push(i.login_time);
                    }
                    // 訪問總量
                    let vi = arr.length;
                    for (let i = 0; i<arr.length;i++){
                        if(arr[i] == login_date){
                            day_vi++;
                        }
                    }
                    console.log("總訪問量為:"+vi+"\n今日訪問量為:"+day_vi);
                    res.write("當前頁面總訪問量為:"+vi+"次"+"\n今日訪客量為:"+day_vi+"次");
                    res.end();  
                });
            }
    })
});

app.listen(3000);

以上是一個非常簡單的實現,由於是很久很久以前寫的了,所以會有很多不足的地方,包括:

1)資料庫沒有使用連線池去管理,沒有考慮每條資料庫連線之後的處理

2)有較多的模組沒有抽象出來寫成公共的工具類(其實也是想要一次性完成,畢竟只用一天的時間……比較粗糙)

3)聽說沒有error處理的程式碼不是好程式碼

另外關於具體的程式碼實現有幾點是需要補充說明的:

1)讀取靜態檔案,像html、css、jpg等檔案時,需要判斷請求檔案的型別,並對其做出相應的處理,而不只是單純的針對html字尾的檔案進行返回(畢竟也是自己踩過的坑,對於html的基礎沒有學好,導致漏處理)

2)熟練的應用node的原生模組,可以使用querysthing、url等模組對http請求進行解析,以便於我們對於訪問資源的處理以及請求的響應

3)依據restful風格,get請求與post請求歸類之後針對其uri進行操作

4)由於當時對於整塊html不算熟悉,用了最原生態的返回html原始碼去寫頁面,⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄

主要的程式碼如上,其實邏輯很簡單,API也很簡單,完成之後點選一波F5,或者在命令提示符窗口裡,輸入node index.js 執行工程…(其實我大部分的時間還是花在這個渣渣的前端頁面編寫上)

跑起來的工程大概就是這樣了——


在瀏覽器輸入localhost:3000/HomePage.html,前端顯示如下——


至此,原生的部落格網站搭建完成了,勉強完成以上的需求(頁面有點醜…勿噴~)

——————————————————————我是分割線—————————————————————————

經過一番koa框架的學習,終於我要邁出從渣渣原生到美膩的框架實現的蛻變了!

學習資料參考:

1.koa官網:https://koa.bootcss.com/

2.ejs模板引擎學習

開始之前重新澄清一下需求,這一次,我們的需求更新了一些細節上的東西

目標功能

包含之前的五個功能

6.增加登入、註冊功能

7.增加登入後的角色許可權,並分配給管理員角色操作留言欄的功能

8.在頁面中新增顯示登入的角色的使用者名稱

9.網站的樣式定時更換

10.優化後臺的資料持久化方式(使用連線池)

——————————————————————coding———————————————————————————

一、專案建立

選定資料夾作為工程存放位置,之後還是在cmd環境下使用

npm init
先對工程進行初始化,之後使用以下指令建立koa工程結構
npm koa

好了,接下來還是需要我們手動建立一個index.js檔案,開始敲我們的程式碼——

二、工程目錄結構


三、開始書寫我們的主程式碼:

主目錄下的index.js(入口檔案)

const koa = require('koa');
const app = new koa();
const static = require('koa-static');
const index = require('./routes/index');
const views = require('koa-views');
const bodyParser = require('koa-bodyparser');
var MysqlStore = require('koa-mysql-session');
const session = require('koa-session-minimal');
const config = require('./config/default.js');
const ejs = require('ejs');
const path = require('path');

//靜態資源載入
app.use(static(__dirname+'/public'));
//檢視呼叫
// app.use(views(__dirname+'/views'));
app.use(views(path.join(__dirname, './views'), {
    extension: 'ejs'
}))

// session儲存配置
const sessionMysqlConfig= {
    user: config.database.USERNAME,
    password: config.database.PASSWORD,
    database: config.database.DATABASE,
    host: config.database.HOST,
}
  
  // 配置session中介軟體
app.use(session({
    key: 'USER_SID',
    store: new MysqlStore(sessionMysqlConfig)
}))

app.use(bodyParser());

//這裡的 allowedMethods 用於校驗請求的方法,如果用 post 請求訪問 get 介面,就會直接返回失敗
app.use(index.routes(),index.allowedMethods());


app.listen(3000,function(){
    console.log("專案已經啟動");
});

這裡面,我們引入了本次工程依賴的模組,和原生的工程不同,我們這次加入了很多的“新面孔”,包括有處理靜態資源的public、views模組,session模組(對於角色的控制)、ejs模組(模板引擎)以及資料庫連線池配置等等

關於koa我有幾點想說的:

1)koa框架將req和res封裝到了ctx當中,方便我們直接使用ctx呼叫原來res和req的方法

2)koa中引入了中介軟體的概念,我們使用.use()的方法去呼叫我們需要使用的中介軟體,按照從上往下的順序,中介軟體的使用是有順序區分的

3)採用MVC的思想,我們會將整個工程目錄去做分層,如同工程結構截圖所示,views裡存放的是我們返回的檢視,routes存放的是控制器和我們的業務處理(核心所在)…

routes目錄下的index.js

const fs = require('fs');
const router = require('koa-router')();
const timeGetter = require('../utils/timeGetter');
const sqlUser = require('../lib/mysql');
const session = require('koa-session-minimal');
let mesLength2 ;

router.get('/HomePage',async (ctx)=>{
    //記錄訪客量
    let ip = ctx.request.socket["remoteAddress"];
    let currentTime = timeGetter.getServerDate();
    let path = '/HomePage.html' ;
    let value =[path,ip,currentTime]; 
    if(ctx.session){
        await  ctx.render('homePage',{
            session : ctx.session
        })
    }else{
        await ctx.render('homePage',{
            session : null
        })
    }
    sqlUser.addVisit(value);
    sqlUser.getAllMesCount().then(result=>{
        mesLength2 = result['count(message)'];
    })
})

//獲取伺服器時間
router.get('/sysTime_wenzhiqun', ctx => {
    ctx.body = (timeGetter.getServerTime()).toString();
})

//獲取留言欄
router.get('/message/list', async(ctx) => {
    let mesLength = 0;
    let message = [];
    await sqlUser.getAllMes().then(result =>{
        for(i of result){
            message[mesLength]=i.message;
            mesLength++;
        }
    })
    let messageShow = '留言欄:';
    //普通使用者
    if(ctx.session.role != 'admin'){
        if(message.length<=10){
            for(let i = message.length,j=1;i>0;i--){
                messageShow = messageShow+'<br>'+'('+j+')'+message[i-1];
                j++;
            }
        }else if(message.length>10){
            for(let i = message.length,j=1;i>(message.length-10);i--){
                messageShow = messageShow+'<br>'+'('+j+')'+message[i-1];
                j++;
            }
        }
    }else{
        if(message.length<=10){
            for(let i = message.length,j=1;i>0;i--){
                messageShow = '<table style="text-align: left"><tr><th>'+messageShow+'</th><th></th><th></th></tr>'+'<tr><td>('+j+')</td><td><p id="'+j+'">'+message[i-1]+'</p></td><td><button onclick = deleteMes('+j+')>刪除留言</button></td></tr>';
                j++;
            }
        }else if(message.length>10){
            for(let i = message.length,j=1;i>(message.length-10);i--){
                messageShow = '<table style="text-align: left"><tr><th>'+messageShow+'</th><th></th><th></th></tr>'+'<tr><td>('+j+')</td><td><p id="'+j+'">'+message[i-1]+'</p></td><td><button onclick = deleteMes('+j+')>刪除留言</button></td></tr>';
                j++;
            }
        }
        messageShow = messageShow +'</table>';
    }
    mesLength2 = mesLength;
    ctx.body = messageShow;
})

//獲取客戶端資訊
router.get('/sysinfo', ctx => {
    let ob = ctx.request.headers["user-agent"].split(" ");
    let system = ob[1].substring(1);
    let chrome = ob[9].split('/')[0];
    let ip = ctx.request.socket["remoteAddress"];
    let iptype = ctx.request.socket["remoteFamily"];
    ctx.body = "<b>作業系統:</b>"+system+"  <b>瀏覽器:</b> "+chrome+"<b>ip地址:</b> "+ip+" <b>ip型別:</b> "+iptype;
})

//獲取訪問量
router.get('/visit',async (ctx) => {
    await sqlUser.getVisitCount()
    .then(result =>{
        let arr = [];
        let day_vi = 0;
        let today_date = timeGetter.getServerDate(); 
        for(i of result){
            arr.push(i.login_time);
        }
        // 訪問總量
        let vi = arr.length;
        for (let i = 0; i<arr.length;i++){
            if(arr[i] == today_date){
                day_vi++;
            }
        }
        ctx.body = "當前頁面總訪問量為:"+vi+"次"+"\n今日訪客量為:"+day_vi+"次";
    });
})

// 提交留言
router.post('/message',async (ctx) =>{
    let userMes = ctx.request.body.message;
    let sqlParams = [mesLength2+1,userMes];
    await sqlUser.insertMes(sqlParams).then(result=>{
        ctx.body = "成功了!";
    });
});

//刪除留言
router.post('/deleteMes',async (ctx) =>{
    let userMes = ctx.request.body.message;
    let sqlParams = [userMes];
    await sqlUser.deleteMes(sqlParams).then(result=>{
        ctx.body = "刪除成功!";
    });
});


//登陸
router.post('/login',async (ctx) =>{
    let username = ctx.request.body.profile;
    let pwd = ctx.request.body.pwd;
    let user = {'username':username};
    await sqlUser.findDataByUser(username,pwd).then( result=>{
        if(result[0]){
            user['role'] = result[0].role;
            ctx.session = user;
            ctx.body = '2';
        }else{
            ctx.body = '1' ;
        }
    })
})

//登入引導頁
router.get('/',async ctx =>{
    if(JSON.stringify(ctx.session) =='{}'){
        await ctx.render('login');
    }else{
        await ctx.render('homePage',{
            session : ctx.session
        });
    }
})

//登出
router.get('/clearSession',async (ctx) =>{
    let clear = function(){
        ctx.session = null;
    }
    clear();
    await ctx.render('login');
})

//註冊
router.post('/register',async(ctx) =>{
    let profile = ctx.request.body.profile;
    let pwd = ctx.request.body.pwd;
    let username = ctx.request.body.username;
    let create_time = timeGetter.getServerDate();
    let role = 'normal_user';
    let value = [profile,pwd,username,role,create_time];
    await sqlUser.insertUser(value).then(result=>{
        if(result){
            let user = {username:username,role:role};
            ctx.session = user;
            ctx.body = "1";
        }else{
            ctx.body = '2';
        }
    })
})

module.exports = router;

值得注意的是,我們在這裡面開始應用上ES6、7標準的語法,async/await函式以及promise的語法:

1)在routes中的index檔案,我們應該在裝有非同步的事件中使用async函式,部分api是不需要使用到async函式,因為不存在非同步回撥的使用,如返回伺服器時間、獲取客戶端系統資訊等

2)使用了async函式,引數列表是否使用next取決於函式的內容,next()會直接進入下一個中介軟體,等待中介軟體處理完畢之後再回到當前函式繼續執行

3)我們在資料庫操作完成返回了一個promise物件,可以利用promise物件的.then()對await 裡獲得的返回物件進行下一步的操作,並且建議await後面的語句是一個非同步的事件,當然如果不是也沒關係,await會按照正常的語句去處理,相當於同步處理

關於使用的幾大模組:

1.session:直接對session的操作,依賴koa-session-minimal我們實現了對ctx.session非常簡便的操作,進行使用者角色和許可權的控制

2.sql:將sql的管理控制抽離出來,在工程結構裡整合管理

sql資料持久化操作

mysql.js

var mysql = require('mysql');
var config = require('../config/default.js')

var pool  = mysql.createPool({
  host     : config.database.HOST,
  user     : config.database.USERNAME,
  password : config.database.PASSWORD,
  database : config.database.DATABASE
});

let query = function( sql, values ) {

  return new Promise(( resolve, reject ) => {
    pool.getConnection(function(err, connection) {
      if (err) {
        resolve( err )
      } else {
        connection.query(sql, values, ( err, rows) => {

          if ( err ) {
            reject( err )
          } else {
            resolve( rows )
          }
          connection.release()
        })
      }
    })
  })

}

// 提交留言
let insertMes = function(value) {
  let _sql = "INSERT INTO MyOwnPage_messageBox (messageCount,message) value (?,?) "
  return query( _sql, value )
}
// 刪除留言
let deleteMes = function(value) {
  let _sql = "DELETE FROM MyOwnPage_messageBox WHERE message = ?"
  return query( _sql, value )
}

// 獲取所有的留言總量
let getAllMesCount = function() {
  let _sql = "SELECT count(message) FROM MyOwnPage_messageBox"
  return query( _sql)
}

// 獲取所有的留言
let getAllMes = function() {
  let _sql = "SELECT message FROM MyOwnPage_messageBox"
  return query( _sql)
}

// 查詢訪客量
let getVisitCount = function() {
  let _sql = "SELECT login_time FROM login_log"
  return query( _sql)
}

//增加訪客量
let addVisit = function(value) {
  let _sql = "INSERT INTO login_log (page,ip,login_time) value (?,?,?) ";
  return query( _sql, value);
}

//通過賬戶名密碼查詢登陸id及角色
let findDataByUser = function (profile,pwd) {
  let _sql = `SELECT username, role FROM USER_PROFILE WHERE email = "${profile}"`
  return query( _sql)
}

//新增(註冊)使用者
let insertUser = function(value) {
  let _sql = "INSERT INTO user_profile (email,pwd,username,role,create_time) value (?,?,?,?,?) ";
  return query( _sql, value );
}

module.exports={
    insertMes,
    deleteMes,
    getAllMes,
    findDataByUser,
    getVisitCount,
    addVisit,
    getAllMesCount,
    insertUser
}

登入頁面

login.ejs

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>IronMan 登陸頁面</title>
    <script src="https://cdn.bootcss.com/jquery/1.10.2/jquery.min.js"></script>
    <style>
        #header{
            background-color:black;
            color:white;
            text-align:center;
            padding:5px;
            height: 20px;
        }
    </style>
    <script>
        function login(){
            let profile = $("#profile").val() ;
            let pwd = $("#pwd").val();
            $.ajax({
                type:'POST',
                url:'/login',
                data:{profile : profile,
                    pwd : pwd
                },
                success: function(data){
                    if(data == '2'){
                        // alert(data);
                        red(data);
                    }else{
                        alert('賬號或密碼出錯了!');
                        }
                    }
                })
        }
        function red(data){
            // let dd = data.split(',');
            // let us = dd[0];
            // let ro = dd[1];
            let link = '/HomePage';
            window.location.href=link;
        }
        function register(){
            let profile = $("#profile2").val() ;
            let username = $("#username").val();
            let pwd = $("#pwd2").val();
            $.ajax({
                type:'POST',
                url:'/register',
                data:{profile : profile,
                    username : username,
                    pwd : pwd
                },
                success: function(data){
                    if(data == '1'){
                        alert("註冊成功,跳轉至首頁!");
                        red(data);
                    }else{
                        alert('賬號名或密碼已存在!');
                        }
                    }
                })
        }
        function changePwd(){
            let profile = $("#profile3").val() ;
            let old_pwd = $("#old_pwd").val();
            let new_pwd = $("#pwd3").val();
            let new_pwd2 = $("#pwd4").val();
            if(new_pwd != new_pwd2){
                alert("輸入的兩次密碼不一致,請重新輸入");
            }else{
                $.ajax({
                type:'POST',
                url:'/changePwd',
                data:{profile : profile,
                    pwd : old_pwd,
                    pwd2 : new_pwd
                },
                success: function(data){
                    if(data){
                        alert("修改成功");
                        red(data);
                    }else{
                        alert('賬號名或密碼已存在!');
                        }
                    }
                })
            }
        }
    </script>
</head>
<body>
        <p id="header">IronMan</p>
        <h2 style="text-align: center">
            <b style="color: rgb(255, 180, 180)">歡迎來到IronMan的個站</b>
        </h2>
        <table>
            <tr>
                <th>
                    <h3 style="color: rgb(145, 145, 253)" >登陸</h3>
                </th>
            </tr>
            <tr>
                <td>賬號:</td><td><input id="profile"></td>
            </tr>
            <tr>
                <td>密碼:</td><td><input id="pwd"></td>
            </tr>
            <tr>
                <td><input value="登陸" type="submit" onclick="login()"></td>
            </tr>
        </table>
        <br>

        <table style="text-align: left">
            <tr>
                <th><h3 style="color: rgb(145, 145, 253)" >註冊</h3></th>
            </tr>
            <tr>
                <td><b>請填寫以下資訊並完成註冊:</b></td>
            </tr>
            <tr>
                <td>賬號(郵箱):</td><td><input id="profile2"></td>
            </tr>
            <tr>
                <td>使用者名稱:</td><td><input id="username"></td>
            </tr>
            <tr>
                <td>密碼:</td><td><input id="pwd2"></td>
            </tr>
            <tr>
                <td><input value="註冊" type="submit" onclick="register()"></td>
            </tr>
        </table>
        <br>
        <table style="text-align: left">
            <tr>
                <th><h3 style="color: rgb(145, 145, 253)" >修改密碼</h3></th>
            </tr>
            <tr>
                <td>賬號</td><td><input id="profile3"></td>
            </tr>
            <tr>
                <td>請輸入舊密碼:</td><td><input id="old_pwd"></td>
            </tr>
            <tr>
                <td>新密碼:</td><td><input id="pwd3"></td>
            </tr>
            <tr>
                <td>確認密碼:</td><td><input id="pwd4"></td>
            </tr>
            <tr>
                <td><input value="確認修改" type="submit" onclick="changePwd()"></td>
            </tr>
        </table>
</body>
</html>

登入頁面是常規的操作了,很簡單,重點在於我們的主頁,使用模板引擎去把session的內容展示出來

主頁 homePage.ejs

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <link type="text/css" rel="styleSheet"  href="./iron.css" />
    <script src="https://cdn.bootcss.com/jquery/1.10.2/jquery.min.js"></script>
    <title>個人站點主頁</title>
    <script> 
        //獲取系統時間
        function getSystemTime(){
            $.ajax({
            type:'GET',
            url:'/sysTime_wenzhiqun',
            success: function(data){
                if(data){
                    document.getElementById('time').innerHTML= data;

                }else{
                    alert('失敗了!');
                    }
                }
            })
        }
        //獲取訪問次數
        function getVisit(){
            $.ajax({
            type:'GET',
            url:'/visit',
            success: function(data){
                if(data){
                    document.getElementById('foot').innerHTML= data;
                }else{
                    alert('失敗了!');
                    }
                }
            })
        }
        //獲取留言資訊
        function getMesBox(){
            $.ajax({
            type:'GET',
            url:'/message/list',
            success: function(data){
                if(data){
                    document.getElementById('messageBox').innerHTML= data;
                }else{
                    alert('失敗了!');
                    }
                }
            })
        }
        //提交留言
        function mesPost(){
            console.log($('.form').serialize())
            let mes = $("#message").val() ;
            alert(mes);
            if(mes == '' || mes.length >= 20){
                alert("留言不能為空或超過20個字元長度");
            }else{
                $.ajax({
            type:'POST',
            url:'/message',
            data:$('.form').serialize(),
            success: function(data){
                if(data){
                    getMesBox();
                }else{
                    alert('失敗了!');
                    }
                }
            })
            }
        }
        //獲取客戶端資訊
        function getClientMes(){
            $.ajax({
            type:'GET',
            url:'/sysinfo',
            success: function(data){
                if(data){
                    document.getElementById('xiugai').innerHTML= data;
                }else{
                    alert('失敗了!');
                    }
                }
            })
        }
        function choose(){
            let choose = parseInt(3*Math.random())+1;
            if(choose === 1 ){
                document.getElementById('body').style.backgroundColor = 'white';
            }if(choose === 2){
                document.getElementById('body').style.backgroundColor = 'rgb(212, 211, 211)';
            }if(choose ===3){
                document.getElementById('body').style.backgroundColor = 'rgb(251, 255, 188)';
            }
        }
        function changeStyle(){
            setInterval('choose()',3000); 
        }

        function deleteMes(j){
            let mes = document.getElementById(j).innerText;
                $.ajax({
                    type:'POST',
                    url:'/deleteMes',
                    data:{message : mes },
                    success: function(data){
                        if(data){
                            getMesBox();
                        }else{
                            alert('失敗了!');
                            }
                    }
                })
        }
    </script>

</head>
<body id="body"  onload="changeStyle()" style="background-color: rgb(248, 211, 211)"></body>
    <p id="header">IronMan</p>
    <h4 id="time" onclick="getSystemTime()">點我重新整理伺服器時間</h4>
    <div class="user_name" style="text-align: right">
        您好,
        <% if(session.username){ %>
             <%= session.username %>
             <a href="/clearSession">退出登入</a>
        <% } %>
        <% if(!session.username){ %>
            您還未登入
        <% } %>
        
    </div>
    <div>
        <div id="myimage">
            <img src="./iron2.jpg">
        </div>
        <div id="kongbai"></div>
        <div id="headDiv">
            <h3>個人介紹</h3>
            <h4>IronMan</h4>
            <h4>誕生地:Marvel</h4>
            <h4>詳細介紹:</h4>
            <p>託尼·史塔克(Tony Stark)即鋼鐵俠(Iron Man),
                是美國漫威漫畫旗下超級英雄,初次登場於《懸疑故事》(Tales of Suspense)第39期(1963年3月),
                由斯坦·李、賴瑞·理柏、唐·赫克以及傑克·科比聯合創造。全名安東尼·愛德華·“託尼”·斯塔克(Anthony Edward “Tony” Stark),
                是斯塔克工業(STARK INDUSTRIES)的董事長,因於一場陰謀綁架中,胸部遭彈片穿入,生命危在旦夕,為了挽救自己的生命,
                在同被綁架的物理學家殷森(Yin Sen)的協助下託尼造出了防止彈片侵入心臟的方舟反應爐從而逃過一劫,後又用方舟反應爐作為能量運轉的來源,
                暗中製造了一套高科技戰衣殺出重圍後逃脫,後參與創立復仇者聯盟。</p>
            </p>
        </div>
    </div>
    
    <form class="form create" method="post ">
        <div>
            <label>留言板 :</label> 
            <input placeholder="留言" type="text" name="message" id="message">
        </div>
        <div class="submit" onclick="mesPost()">提交</div>
    </form> 

    <div id="headDiv2">
        <h4 id="messageBox"  onclick="getMesBox()">點我顯示留言欄</h4>
        <h4 onclick="getClientMes()" >點我顯示當前訪問的客戶端資訊為:</h4><p id="xiugai"></p>
    </div>
   
       
    <div >
        <p id="foot" onclick="getVisit()">點我顯示訪問量</p>
    </div>
    
</body>
</html>

實現後,管理員登入的頁面如下圖:

1)在伺服器時間下多了登入的使用者名稱顯示

2)支援管理對留言欄的刪除處理

3)其實還有一個隱藏的頁面背景色的定時變化,截圖所以看不出來~但是程式碼裡面是可以發現的


結束語

到這裡,基本上整個網站就已經完成了~

這個部落格網站比較簡單,程式碼有很多改進的地方,希望對你們有幫助,如果有什麼建議可以和我聯絡,qq:657897294,有什麼不懂得也可以問我,有空就會回覆啦!

git地址:https://github.com/VeniesLoveJava/nodejs_Koa_BlogWeb.git

非常感謝你讀完這篇這麼長的文章!