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加密,时间日期的格式化,日志的保存等,配置文件的更改及代码风格等,但简单的流程就如上所示。