Node.Js_Express_Part2.配置註冊登入介面與功能實作與MySQL資料庫配置
Step1.新增配置頁面路由與連結
新增兩個ejs檔案
views\user\login.ejs
views\user\register.ejs
app.js程式調整新增路由
const express = require('express') //const path = require('path'); const app = express() app.set('view engine','ejs') //設置默認採用模板引擎名稱 app.set('views','./views') //設置模板頁面存放路徑 //將node_modules資料夾,託管為靜態資源目錄 app.use('/node_modules',express.static('./node_modules')) //app.use('/node_modules', express.static(path.join(__dirname, 'node_modules'))); app.get('/', (req,res) => { //使用render函數之前,必須確保已經安裝和配置好ejs模板引擎 res.render('index.ejs',{name:'王曉明' , age:25}) }) app.get('/register' , (req,res) => { res.render('./user/register.ejs',{}) }) app.get('/login' , (req,res) => { res.render('./user/login.ejs',{}) }) app.listen(80, () => { console.log('server running at http://127.0.0.1') })
./views/index.ejs
更改為a標籤設置指向跳轉的程式請求網址
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap-theme.min.css"> <script src="/node_modules/jquery/dist/jquery.min.js"></script> <!-- 叮嚀:bootstrap的js是有依賴jquery文件的,要在之前先配置jquery。 --> <script src="/node_modules/bootstrap/dist/js/bootstrap.min.js"></script> </head> <body> <!-- 導覽列區塊 --> <nav class="navbar navbar-default"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="/">論壇</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <div class="nav navbar-nav navbar-right navbar-form"> <a class="btn btn-success" href="/register">註冊</a> <a class="btn btn-primary" href="/login">登入</a> </div> <div class="nav navbar-nav navbar-right navbar-form"> <button class="btn btn-warning">歡迎</button> <button class="btn btn-danger">註銷</button> </div> <ul class="nav navbar-nav navbar-right"> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">發表 <span class="caret"></span> </a> <ul class="dropdown-menu"> <li> <a href="#">文章</a> </li> <li> <a href="#">問題</a> </li> </ul> </li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <h1>貼文列表</h1> <!-- 版權聲明區塊 --> <div class="text-center text-muted"> AAA © BBB 2025 </div> </body> </html>
Step2.註冊畫面的內容
views\user\register.ejs
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap-theme.min.css"> <style> #form { width: 400px; margin: 0 auto; margin-top: 100px; } h1 { text-align: center; } input[type='submit']{ width: 100%; } </style> </head> <body> <form id="form"> <h1>註冊畫面</h1> <div class="form-group"> <input type="text" name="username" id="username" class="form-control input-lg" placeholder="帳號名" required> </div> <div class="form-group"> <input type="password" name="password" id="password" class="form-control input-lg" placeholder="密碼" required> </div> <div class="form-group"> <input type="text" name="nickname" id="nickname" class="form-control input-lg" placeholder="暱稱" required> </div> <div class="form-group"> <input type="submit" value="註冊新用戶" class="btn btn-primary btn-lg"> </div> </form> <script src="/node_modules/jquery/dist/jquery.min.js"></script> <script> $(function(){ $('#form').on('submit' , function(e){ e.preventDefault() $.ajax({ url: '/register', data: $('#form').serialize(), type: 'POST', dataType: 'json', success: function (result){ console.log(result) } }) }) }) </script> </body> </html>
views\user\login.ejs
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap-theme.min.css"> <style> #form { width: 400px; margin: 0 auto; margin-top: 100px; } h1 { text-align: center; } input[type='submit']{ width: 100%; } </style> </head> <body> <form id="form"> <h1>登入畫面</h1> <div class="form-group"> <input type="text" name="username" id="username" class="form-control input-lg" placeholder="帳號名" required value="王某某"> </div> <div class="form-group"> <input type="password" name="password" id="password" class="form-control input-lg" placeholder="密碼" required value="1234"> </div> <div class="form-group"> <a href="/register" class="pull-right">去註冊</a> </div> <div class="form-group"> <input type="submit" value="登入" class="btn btn-primary btn-lg"> </div> </form> <script src="/node_modules/jquery/dist/jquery.min.js"></script> <script> $(function(){ $('#form').on('submit' , function(e){ e.preventDefault() $.ajax({ url: '/login', data: $('#form').serialize(), type: 'POST', dataType: 'json', success: function (result){ console.log(result) } }) }) }) </script> </body> </html>
body-parser 是Express 常搭配的中介軟體,用來解析body請求資料。
比方POST 一筆JSON 格式的資料上傳至Express後端應用,就可透過body-parser 解析這筆資料。
Step5.配置bodyParser並測試套件功能
./app.js
const express = require('express') //const path = require('path'); const app = express() const bodyParser = require('body-parser') app.set('view engine','ejs') //設置默認採用模板引擎名稱 app.set('views','./views') //設置模板頁面存放路徑 app.use(bodyParser.urlencoded({extended:false})) //將node_modules資料夾,託管為靜態資源目錄 app.use('/node_modules',express.static('./node_modules')) //app.use('/node_modules', express.static(path.join(__dirname, 'node_modules'))); app.get('/', (req,res) => { //使用render函數之前,必須確保已經安裝和配置好ejs模板引擎 res.render('index.ejs',{name:'王曉明' , age:25}) }) app.get('/register' , (req,res) => { res.render('./user/register.ejs',{}) }) app.post('/register' , (req,res) => { const body = req.body console.log(body) res.send({msg:'ok' , status:200}) }) app.get('/login' , (req,res) => { res.render('./user/login.ejs',{}) }) app.listen(80, () => { console.log('server running at http://127.0.0.1') })
Step6.註冊流程梳理與配置MySQL套件與創建資料庫與表
下載mysql套件
npm i mysql -S
phpmyadmin 設置資料庫帳號密碼
預設的帳號是 root ,沒有密碼
http://localhost:8090/phpmyadmin
會看到一個使用者名稱叫「任何」,且主機名稱為「%」的帳號
代表讓所有人都不用輸入密碼即可進入到資料庫管理後台。
先將其勾選並底下也勾起【刪除與使用者同名的資料庫。】再按執行
127.0.0.1
::1
localhost
三個都要設定相同密碼
當返回使用者帳號頁面,即可發覺密碼欄位更新為「是」
再往下分別是
第20行表示你預設phpmyadmin資料庫登入帳號為root
第21行表示剛剛設定的三組相同密碼
可自行維護上去
再次輸入剛剛設置的帳密即可
下載時間戳格式化套件moment(),把時間格式化成標準格式或其他格式
https://momentjs.com/
npm install moment --save
app.js程式碼(增加註冊流程)
const express = require('express') //const path = require('path'); const app = express() const bodyParser = require('body-parser') const mysql = require('mysql') const moment = require('moment') //獲取當前時間戳 const conn = mysql.createConnection({ port:3306, host: '127.0.0.1', database: 'blog_db', user: 'root', password: 'root' }) app.set('view engine','ejs') //設置默認採用模板引擎名稱 app.set('views','./views') //設置模板頁面存放路徑 app.use(bodyParser.urlencoded({extended:false})) //將node_modules資料夾,託管為靜態資源目錄 app.use('/node_modules',express.static('./node_modules')) //app.use('/node_modules', express.static(path.join(__dirname, 'node_modules'))); app.get('/', (req,res) => { //使用render函數之前,必須確保已經安裝和配置好ejs模板引擎 res.render('index.ejs',{name:'王曉明' , age:25}) }) app.get('/register' , (req,res) => { res.render('./user/register.ejs',{}) }) app.post('/register' , (req,res) => { const body = req.body console.log(body) if(body.username.trim().length <= 0 || body.password.trim().length <=0 || body.nickname.trim().length <=0){ return res.send({msg: '請填寫完整表單欄位,再註冊帳號!',status:501}) } //確認是否帳號名有重複 const sql_str = 'select count(*) as count from blog_users where username=?' conn.query(sql_str,body.username,(err,result) => { console.log(err) console.log('result1:') console.log(result) if(err) return res.send({msg:'帳號名查重異常!',status:502}) if(result[0].count !==0) return res.send({msg:'請改用其他帳號名重新註冊!',status:503}) body.ctime = moment().format('YYYY-MM-DD HH:mm:ss') const sql_str2 = 'insert into blog_users set ?' console.log(body) conn.query(sql_str2 , body , (err,result) => { console.log('result2:') console.log(result) if(err || result.affectedRows !== 1) { console.log(err) return res.send({msg:'註冊新帳號失敗!',status:504}) } res.send({msg:'註冊新帳號成功' , status:200}) }) }) }) app.get('/login' , (req,res) => { res.render('./user/login.ejs',{}) }) app.listen(80, () => { console.log('server running at http://127.0.0.1') })
在預設配置的資料庫連接對象指向要吻合phpmyadmin的資料庫名稱
這裡的 insert into blog_users set ? 是 MySQL 的一個語法簡化。
它的作用是將 body 中的每個屬性當作欄位與對應的值插入到 blog_users 表中。
以下是其具體運作機制:
- set ? 的語法:MySQL 可以將一個物件直接傳給 ?,以替代傳統 insert into table (col1, col2, ...) values (?, ?, ...) 的寫法。
- 自動映射屬性:body 物件的屬性名稱會自動映射到資料庫的欄位名稱,例如,如果 body 物件中有 username、password 和 nickname 屬性,它們會自動對應到 blog_users 表中相應的欄位。
- 安全性:這種寫法也幫助防止 SQL 注入攻擊,因為 conn.query 會使用預處理語句(parameterized queries)將值進行轉義。
- SQL 簡化:insert into blog_users set ? 的語法比傳統插入語句更加簡潔,不必顯示列出每個欄位,適合在插入許多欄位的情況下快速編寫。
views\user\register.ejs
畫面部分的html程式碼。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap-theme.min.css"> <style> #form { width: 400px; margin: 0 auto; margin-top: 100px; } h1 { text-align: center; } input[type='submit']{ width: 100%; } </style> </head> <body> <form id="form"> <h1>註冊畫面</h1> <div class="form-group"> <input type="text" name="username" id="username" class="form-control input-lg" placeholder="帳號名" required> </div> <div class="form-group"> <input type="password" name="password" id="password" class="form-control input-lg" placeholder="密碼" required> </div> <div class="form-group"> <input type="text" name="nickname" id="nickname" class="form-control input-lg" placeholder="暱稱" required> </div> <div class="form-group"> <input type="submit" value="註冊新用戶" class="btn btn-primary btn-lg"> </div> </form> <script src="/node_modules/jquery/dist/jquery.min.js"></script> <script> $(function(){ $('#form').on('submit' , function(e){ e.preventDefault() $.ajax({ url: '/register', data: $('#form').serialize(), type: 'POST', dataType: 'json', success: function (result){ console.log(result) if(result.status !== 200){ return alert(result.msg) } location.href = '/login' } }) }) }) </script> </body> </html>
起初示範成功註冊後,資料庫有成功增加一筆帳號資料。
Step8.登入流程梳理
app.js程式碼(增加登入流程)
const express = require('express') //const path = require('path'); const app = express() const bodyParser = require('body-parser') const mysql = require('mysql') const moment = require('moment') //獲取當前時間戳 const conn = mysql.createConnection({ port:3306, host: '127.0.0.1', database: 'blog_db', user: 'root', password: 'root' }) app.set('view engine','ejs') //設置默認採用模板引擎名稱 app.set('views','./views') //設置模板頁面存放路徑 app.use(bodyParser.urlencoded({extended:false})) //將node_modules資料夾,託管為靜態資源目錄 app.use('/node_modules',express.static('./node_modules')) //app.use('/node_modules', express.static(path.join(__dirname, 'node_modules'))); app.get('/', (req,res) => { //使用render函數之前,必須確保已經安裝和配置好ejs模板引擎 res.render('index.ejs',{name:'王曉明' , age:25}) }) app.get('/register' , (req,res) => { res.render('./user/register.ejs',{}) }) app.post('/register' , (req,res) => { const body = req.body console.log(body) if(body.username.trim().length <= 0 || body.password.trim().length <=0 || body.nickname.trim().length <=0){ return res.send({msg: '請填寫完整表單欄位,再註冊帳號!',status:501}) } //確認是否帳號名有重複 const sql_str = 'select count(*) as count from blog_users where username=?' conn.query(sql_str,body.username,(err,result) => { console.log(err) console.log('result1:') console.log(result) if(err) return res.send({msg:'帳號名查重異常!',status:502}) if(result[0].count !==0) return res.send({msg:'請改用其他帳號名重新註冊!',status:503}) body.ctime = moment().format('YYYY-MM-DD HH:mm:ss') const sql_str2 = 'insert into blog_users set ?' console.log(body) conn.query(sql_str2 , body , (err,result) => { console.log('result2:') console.log(result) if(err || result.affectedRows !== 1) { console.log(err) return res.send({msg:'註冊新帳號失敗!',status:504}) } res.send({msg:'註冊新帳號成功' , status:200}) }) }) }) app.get('/login' , (req,res) => { res.render('./user/login.ejs',{}) }) app.post('/login' , (req,res) => { const body = req.body const sql_str = 'select * from blog_users where username = ? and password=?' conn.query(sql_str , [body.username,body.password] , (err,result) => { if(err || result.length !== 1) return res.send({msg:'帳號登入失敗' , status:501}) res.send({msg:'ok',status:200}) }) }) app.listen(80, () => { console.log('server running at http://127.0.0.1') })
views\user\login.ejs
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap-theme.min.css"> <style> #form { width: 400px; margin: 0 auto; margin-top: 100px; } h1 { text-align: center; } input[type='submit']{ width: 100%; } </style> </head> <body> <form id="form"> <h1>登入畫面</h1> <div class="form-group"> <input type="text" name="username" id="username" class="form-control input-lg" placeholder="帳號名" required value="王某某"> </div> <div class="form-group"> <input type="password" name="password" id="password" class="form-control input-lg" placeholder="密碼" required value="1234"> </div> <div class="form-group"> <a href="/register" class="pull-right">去註冊</a> </div> <div class="form-group"> <input type="submit" value="登入" class="btn btn-primary btn-lg"> </div> </form> <script src="/node_modules/jquery/dist/jquery.min.js"></script> <script> $(function(){ $('#form').on('submit' , function(e){ e.preventDefault() $.ajax({ url: '/login', data: $('#form').serialize(), type: 'POST', dataType: 'json', success: function (result){ console.log(result) if(result.status !== 200){ return alert(result.msg) } location.href = '/' } }) }) }) </script> </body> </html>
測試效果
留言
張貼留言