项目参考:
N-blog: github.com/nswbmw/N-bl…
感谢作者大大详尽的指导,后端基本用的作者原始的架构
关于 fetchAPI, express 的原理没有深入了解,总体做了点搬砖的活
项目地址:
SimpleBlog: github.com/ShiroCheng/…
该项目已布在公网服务器上,demo地址:http://120.78.134.26
页面演示:
- 主页:
- 特定文章页:
- 发布文章页:
- 电影页:
使用方法:
环境配置:预装 MongoDB, Node.js
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:3000
项目目录结构:
-
lib
: 定义实体的数据结构 -
models
: 操作数据库的文件 -
public
: 静态文件,如样式、图片,包括用户上传的头像等 -
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 日志中间件
主要功能
- 多用户注册登录
- 发表、修改、删除文章
- 发表、删除评论
- 添加视频
实现方法
- 服务器后端框架:express,使用express 控制路由,动态渲染特定界面
- 数据库驱动:Mongolass,服务器与数据库交互的中间件
- 模板引擎:ejs,动态渲染前端页面
以登陆后的用户创建 movies 为实例:
定义 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
复制代码
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
// views/movies.ejs
<%- include('header') %>
<% movies.forEach(function (movie) { %>
<%- include('components/movie-content', { movie: movie }) %>
<% }) %>
<%- include('footer') %>
复制代码
这样,就完成了一个简单的 用户提交表单 -> 服务端存储数据到数据库 -> 服务端重渲染视图 的前后端交互流程 。
项目的设计还涉及到用户密码的hash加密,时间日期的格式化,日志的保存等,配置文件的更改及代码风格等,但简单的流程就如上所示。
TO DO
- 增加用户文章的分类与标签功能
- 增加文章的分页显示功能
- 增加用户的文章收藏功能
- 增加电影的分类与标签功能
- 增加用户的电影收藏功能