(十二) 我的项目性能的实现之文章评论和退出性能
- 创立评论汇合
- 判断用户是否登录,如果用户登录,再容许用户提交评论表单
- 在服务器端创立文章评论性能对应的路由
- 在路由申请处理函数中接管客户端传递过去的评论信息
- 将评论信息存储在评论汇合中
- 将页面重定向回文章详情页面
-
在文章详情页面路由中获取文章评论信息并展现在页面中
BLOG -- 源码目录 └── config -- 配置文件 └── middleware └── loginGuard.js └── model -- 数据库操作 └── comment.js ├── public -- 动态资源 └── route -- 路由 └── admin ├── login.js 登录 └── logout.js 退出 └── home ├── article.js 博客文章 └──comment.js 博客评论 └── home.js 博客 └── views -- 模板 └── home └── common └──header.art 公共头部模板 └── article.art 文章内容模板 └── app.js -- 创立网站服务
comment.js
- 引入 mongoose 模块,创立汇合规定
- 增加存储每篇文章的 aid,关联文章汇合
- 存储 uid 评论的用户名,关联用户汇合
- 存储评论工夫,内容 time content
- 创立评论联合并作为模块成员进行导出
// 将评论汇合构造函数进行导入
const {Comment} = require('../../model/comment');
module.exports = async (req, res) => {
// 接管客户端传递过去的申请参数
const {content, uid, aid} = req.body;
// 将评论信息存储到评论汇合中
await Comment.create({
content: content,
uid: uid,
aid: aid,
time: new Date()});
// 将页面重定向回文章详情页面
res.redirect('/home/article?id='+ aid);
}
login.js
- 对用户进行权限治理,治理能够去后盾,一般的跳转到博客首页
- userinfo 示意用户是否登录
// 导入用户汇合构造函数
const {User} = require('../../model/user');
const bcrypt = require('bcrypt');
module.exports = async (req, res) => {
// 接管申请参数
const {email, password} = req.body;
// 如果用户没有输出邮件地址
// if (email.trim().length == 0 || password.trim().length == 0) return res.status(400).send('<h4> 邮件地址或者明码谬误 </h4>');
if (email.trim().length == 0 || password.trim().length == 0) return res.status(400).render('admin/error', {msg: '邮件地址或者明码谬误'});
// 依据邮箱地址查问用户信息
// 如果查问到了用户 user 变量的值是对象类型 对象中存储的是用户信息
// 如果没有查问到用户 user 变量为空
let user = await User.findOne({email});
// 查问到了用户
if (user) {
// 将客户端传递过去的明码和用户信息中的明码进行比对
// true 比对胜利
// false 比照失败
let isValid = await bcrypt.compare(password, user.password);
// 如果明码比对胜利
if (isValid) {
// 登录胜利
// 将用户名存储在申请对象中
req.session.username = user.username;
// 将用户角色存储在 session 对象中
req.session.role = user.role;
// res.send('登录胜利');
req.app.locals.userInfo = user;
// 对用户的角色进行判断
if (user.role == 'admin') {
// 重定向到用户列表页面
res.redirect('/admin/user');
} else {
// 重定向到博客首页
res.redirect('/home/');
}
} else {
// 没有查问到用户
res.status(400).render('admin/error', {msg: '邮箱地址或者明码谬误'})
}
} else {
// 没有查问到用户
res.status(400).render('admin/error', {msg: '邮箱地址或者明码谬误'})
}
}
loginGuard.js
- 把用户角色也存储在 session 中,如果用户是登录状态就让它跳转到博客首页,这样间接在 url 进行批改也不能够
const guard = (req, res, next) => {
// 判断用户拜访的是否是登录页面
// 判断用户的登录状态
// 如果用户是登录的 将申请放行
// 如果用户不是登录的 将申请重定向到登录页面
if (req.url != '/login' && !req.session.username) {res.redirect('/admin/login');
} else {
// 如果用户是登录状态 并且是一个普通用户
if (req.session.role == 'normal') {
// 让它跳转到博客首页 阻止程序向下执行
return res.redirect('/home/')
}
// 用户是登录状态 将申请放行
next();}
}
module.exports = guard;
article.art
- 在文章评论处模板语法如果是登录状态则显示
- 如果不是则暗藏评论表单
- 为评论表单增加申请地址 action 和申请形式 method 和 name 属性暗藏域 hidden, 一个蕴含登录用户的 id 值 uid,一个是文章的 id 值 aid,进行原文输入
- 对于评论人的信息进行循环动静输入,工夫格局的解决 dateFormate
{{extend './common/layout.art'}}
{{block 'link'}}
<link rel="stylesheet" href="/home/css/article.css">
{{/block}}
{{block 'main'}}
{{include './common/header.art'}}
<!-- 文章框架开始 -->
<div class="article">
<div class="w1100">
<div class="container">
<div class="article-header">
<h3 class="article-title">{{article.title}}</h3>
<div class="article-info">
<span class="author">{{article.author.username}}</span>
<span>{{dateFormat(article.publishDate, 'yyyy-mm-dd')}}</span>
</div>
</div>
<div class="article-content">
{{@article.content}}
</div>
<div class="article-comment">
{{if userInfo}}
<h4> 评论 </h4>
<form class="comment-form" action="/home/comment" method="post">
<textarea class="comment" name="content"></textarea>
<input type="hidden" name="uid" value="{{@userInfo._id}}">
<input type="hidden" name="aid" value="{{@article._id}}">
<div class="items">
<input type="submit" value="提交">
</div>
</form>
{{else}}
<div><h2> 先进行登录,再对文章进行评论 </h2></div>
{{/if}}
<div class="comment-list">
{{each comments}}
<div class="mb10">
<div class="article-info">
<span class="author">{{$value.uid.username}}</span>
<span>{{dateFormat($value.time, 'yyyy-mm-dd')}}</span>
<span>{{$value.uid.email}}</span>
</div>
<div class="comment-content">
{{$value.content}}
</div>
</div>
{{/each}}
</div>
</div>
</div>
</div>
</div>
<!-- 文章框架完结 -->
{{/block}}
logout.js
- 对用户 userinfo 进行革除,否则退出之后只是删除了 cookie 和 session,userinfo 还是存在的
- 实现退出性能,删除 session 和 cookie clearCookie(
- 并且重定向到用户登录页面
module.exports = (req, res) => {
// 删除 session
req.session.destroy(function () {
// 删除 cookie
res.clearCookie('connect.sid');
// 重定向到用户登录页面
res.redirect('/admin/login');
// 革除模板中的用户信息
req.app.locals.userInfo = null;
});
}
home.js
- 增加评论性能路由
// 援用 expess 框架
const express = require('express');
// 创立博客展现页面路由
const home = express.Router();
// 博客前台首页的展现页面
home.get('/', require('./home/index'));
// 博客前台文章详情展现页面
home.get('/article', require('./home/article'));
// 创立评论性能路由
home.post('/comment', require('./home/comment'));
// 将路由对象做为模块成员进行导出
module.exports = home;
comment.js
- 承受到客户端传过来的申请信息
- 通过对象解构的模式获取
- 将评论汇合构造函数进行导入
- 将评论信息存储到评论汇合中,异步
- 将页面重定向回文章详情页面
// 将评论汇合构造函数进行导入
const {Comment} = require('../../model/comment');
module.exports = async (req, res) => {
// 接管客户端传递过去的申请参数
const {content, uid, aid} = req.body;
// 将评论信息存储到评论汇合中
await Comment.create({
content: content,
uid: uid,
aid: aid,
time: new Date()});
// 将页面重定向回文章详情页面
res.redirect('/home/article?id='+ aid);
}
article.js
- 导入评论汇合构造函数
- 查问以后文章所对应的评论信息,用户名要多集联结查问 populate
- 对文章和评论进行渲染
// 导入文章汇合构造函数
const {Article} = require('../../model/article');
// 导入评论汇合构造函数
const {Comment} = require('../../model/comment');
module.exports = async (req, res) => {
// 接管客户端传递过去的文章 id 值
const id = req.query.id;
// 依据 id 查问文章详细信息
let article = await Article.findOne({_id: id}).populate('author');
// 查问以后文章所对应的评论信息
let comments = await Comment.find({aid: id}).populate('uid')
// res.send('欢送来到博客文章详情页面')
res.render('home/article.art', { article, comments});
header.art
- 对于退出登录增加 href
<!-- 头部 -->
<div class="header">
<!-- 网站标记 -->
<div class="logo fl">
黑马程序员 <i>ITHEIMA</i>
</div>
<!-- / 网站标记 -->
<!-- 用户信息 -->
<div class="info">
<div class="profile dropdown fr">
<span class="btn dropdown-toggle" data-toggle="dropdown">
{{userInfo && userInfo.username}}
<span class="caret"></span>
</span>
<ul class="dropdown-menu">
<li><a href="user-edit.html"> 个人资料 </a></li>
<li><a href="/admin/logout"> 退出登录 </a></li>
</ul>
</div>
</div>
<!-- / 用户信息 -->
</div>
<!-- / 头部 -->
app.js
- 在用户未登录状况下,不会初始化一个 cookie,saveUninitialized: false
- 给 cookie 设置一个主动过期的工夫
// 援用 expess 框架
const express = require('express');
// 解决门路
const path = require('path');
// 引入 body-parser 模块 用来解决 post 申请参数
const bodyPaser = require('body-parser');
// 导入 express-session 模块
const session = require('express-session');
// 导入 art-tempate 模板引擎
const template = require('art-template');
// 导入 dateformat 第三方模块
const dateFormat = require('dateformat');
// 导入 morgan 这个第三方模块
const morgan = require('morgan');
// 导入 config 模块
const config = require('config');
// 创立网站服务器
const app = express();
// 数据库连贯
require('./model/connect');
// 解决 post 申请参数
app.use(bodyPaser.urlencoded({extended: false}));
// 配置 session
app.use(session({
secret: 'secret key',
saveUninitialized: false,
cookie: {maxAge: 24 * 60 * 60 * 1000}
}));
// 通知 express 框架模板所在的地位
app.set('views', path.join(__dirname, 'views'));
// 通知 express 框架模板的默认后缀是什么
app.set('view engine', 'art');
// 当渲染后缀为 art 的模板时 所应用的模板引擎是什么
app.engine('art', require('express-art-template'));
// 向模板外部导入 dateFormate 变量
template.defaults.imports.dateFormat = dateFormat;
// 凋谢动态资源文件
app.use(express.static(path.join(__dirname, 'public')));
console.log(config.get('title'))
// 获取零碎环境变量 返回值是对象
if (process.env.NODE_ENV == 'development') {
// 以后是开发环境
console.log('以后是开发环境')
// 在开发环境中 将客户端发送到服务器端的申请信息打印到控制台中
app.use(morgan('dev'))
} else {
// 以后是生产环境
console.log('以后是生产环境')
}
// 引入路由模块
const home = require('./route/home');
const admin = require('./route/admin');
// 拦挡申请 判断用户登录状态
app.use('/admin', require('./middleware/loginGuard'));
// 为路由匹配申请门路
app.use('/home', home);
app.use('/admin', admin);
app.use((err, req, res, next) => {
// 将字符串对象转换为对象类型
// JSON.parse()
const result = JSON.parse(err);
// {path: '/admin/user-edit', message: '明码比对失败, 不能进行用户信息的批改', id: id}
let params = [];
for (let attr in result) {if (attr != 'path') {params.push(attr + '=' + result[attr]);
}
}
res.redirect(`${result.path}?${params.join('&')}`);
})
// 监听端口
app.listen(80);
console.log('网站服务器启动胜利, 请拜访 localhost')