N-blog: github.com/nswbmw/N-bl…javascript
感謝做者大大詳盡的指導,後端基本用的做者原始的架構css
關於 fetchAPI, express 的原理沒有深刻了解,整體作了點搬磚的活前端
SimpleBlog: github.com/ShiroCheng/…java
該項目已布在公網服務器上,demo地址:http://120.78.134.26node
環境配置:預裝 MongoDB, Node.jsjquery
mkdir mongodb/data
mongod --dbpath=mongodb/data
git clone https://github.com/Ubilabs-NicholasCheng/SimpleBlog.git
cd SimpleBlog
npm i
vim config/default.js #修改端口 80->3000
node index.js
複製代碼
以後,訪問 localhost:3000git
lib
: 定義實體的數據結構github
models
: 操做數據庫的文件web
public
: 靜態文件,如樣式、圖片,包括用戶上傳的頭像等mongodb
routes
: 存放路由文件
views
: 用於渲染的視圖文件
index.js
: 程序主文件
package.json
: 項目名、描述、做者、依賴等等信息
config
: 項目的配置信息,服務器端口,鏈接的數據庫端口等
遵循 MVC 的開發模式
Materilazie + GoogleIcons
: Material Design 風格的組件庫與 Google 圖標github-markdown-css
: 添加 github markdown 風格樣式highlight.js
: 代碼語法高亮simpleMDE
: markdown 的樣式支持jquery
: 實現動畫等功能materialize.min.js
: materialize 組件的js庫express
: web 框架express-session
: session 中間件connect-mongo
: 將 session 存儲於 mongodb,結合 express-session 使用connect-flash
: 頁面通知的中間件,基於 session 實現ejs
: 模板express-formidable
: 接收表單及文件上傳的中間件config-lite
: 讀取配置文件marked
: markdown 解析moment
: 時間格式化mongolass
: mongodb 驅動objectid-to-timestamp
: 根據 ObjectId 生成時間戳sha1
: sha1 加密,用於密碼加密winston
: 日誌express-winston
: express 的 winston 日誌中間件定義 Movie 的 schema:
// lib/mongo.js
const Mongolass = require('mongolass')
const mongolass = new Mongolass()
/********* Movie Schema **********/
exports.Movie = mongolass.model('Movie', {
title:{
type: 'string',
required: true
},
src:{
type: 'string',
required: true
}
})
// 創建索引
exports.Movie.index({
postId:1,
_id: 1
}).exec()
複製代碼
Movie 這個 model 中定義的方法,加載全部電影,刪除與獲取特定的電影:
(Mongolass 這個驅動的方法與mongodb的數據庫api一致,使用起來很直觀)
// model/movies.js
const Movies = require('../lib/mongo').Movie
module.exports = {
create: function create (movie) {
return Movies.create(movie).exec()
},
// 經過電影 id 獲取一部電影
getMovieById: function getMovieById(movieId) {
return Movies.findOne({
_id: movieId
}).exec()
},
// 經過電影 id 刪除一部電影
delMovieById: function (movieId) {
return Movies.deleteOne({
_id: movieId
}).exec()
},
//找到全部的電影
getMovies: function () {
return Movies.find({
}).exec()
}
}
複製代碼
定義表單的方法爲 post,input 的 name 爲屬性名。
// views/createMovies.ejs
<form class="col s12 m12 " method="POST">
// more code here
<input name="title" id="title" type="text" class="validate">
<input name="src" id="src" type="text" class="validate" >
// more code here
</form>
複製代碼
express 的路由中提供了處理請求的方法,input 的 value 將掛載在 req.fileds.name 這一屬性下:
使用 MovieModel 的 create方法,在數據庫對應的表中插入這一條用戶新建立的數據,若該表不存在則會建立該表。
// routes/movies.js
// 建立電影頁
router.post('/create', function(req, res, next) {
const movieId = req.fields.movieId
const title = req.fields.title
const src = req.fields.src
// 校驗參數
try {
if (!src.length) {
throw new Error('Please write movie src!')
}
} catch (e) {
req.flash('error', e.message)
return res.redirect('back')
}
const movie = {
movieId: movieId,
title: title,
src: src
}
MovieModel.create(movie)
.then(function() {
req.flash('success', 'create movie successfully!')
// 建立成功後跳轉到上一頁
res.redirect('/movies')
})
.catch(next)
})
複製代碼
同時引入了 checkLogin 方法,判斷用戶是否登錄,登錄後的用戶纔有權限建立電影:
// middlewares/checkLogin.js
module.exports = {
checkLogin: function checkLogin(req, res, next) {
if (!req.session.user) {
//設置當前的錯誤爲未登陸
req.flash('error', '未登陸')
return res.redirect('/signIn')
}
next()
},
checkNotLogin: function checkNotLogin(req, res, next) {
if (req.session.user) {
req.flash('error', '已登陸')
return res.redirect('back') //若已登陸返回原頁面
}
next()
}
}
複製代碼
使用 MovieModel 中定義的 getMovies() 方法,查詢到 movies 表下的全部記錄,使用res.render() 方法渲染ejs模板,並傳入這些查詢到的記錄。
// routes/movies.js
// 顯示電影頁
router.get('/', function(req, res, next) {
MovieModel.getMovies()
.then(function (movies) {
res.render('movies', {
movies: movies
})
})
.catch(next)
})
複製代碼
前端的 ejs 模板獲取到服務器響應傳入的多條記錄,使用 forEach方法將其依次渲染:
(components/movies-content.ejs 做爲組件,movies.ejs 使用include方法渲染多個 movies-content.ejs組件 )
// views/components/movies-content.ejs
<label><h5 class="white-text center-align" style="margin-top: 230px;">
<%= movie.title %></h5></label>
<div class="responsive-video center-align" controls>
<iframe width="853" height="480" src="<%= movie.src %>" frameborder="0" allowfullscreen> </iframe>
</div>
// views/movies.ejs
<%- include('header') %>
<% movies.forEach(function (movie) { %>
<%- include('components/movie-content', { movie: movie }) %>
<% }) %>
<%- include('footer') %>
複製代碼
這樣,就完成了一個簡單的 用戶提交表單 -> 服務端存儲數據到數據庫 -> 服務端重渲染視圖 的先後端交互流程 。
項目的設計還涉及到用戶密碼的hash加密,時間日期的格式化,日誌的保存等,配置文件的更改及代碼風格等,但簡單的流程就如上所示。