文章管理系统 -- Express学习
文章管理系统 – Express学习
仓库:https://gitee.com/aeipyuan/articles_manage
1.项目搭建
生成express
项目
express -e article_managemet 创建项目 -e 表示使用ejs模板引擎
mongodb
创建数据库
mongo - 开启mongodb
use articles_db - 创建/使用数据库
db.createCollection('users') - 创建users集合
db.createCollection('articles') - 创建article集合
show collections - 查询是否创建成功测试:
db.users.insertOne({username:'admin',passsword:'000'})
db.users.find()
创建连接mongodb
连接的模块
文件位置:model > index.jsconst MongoClient = require('mongodb').MongoClient;/* 连接数据库的url,在mongo命令下可以找到 */let url = 'mongodb://localhost:27017';/* 连接的数据库名字 */let dbName = 'articles_db';/* 封装数据库连接方法 */function connect(callback) {MongoClient.connect(url, (err, client) => {if (err) {console.log('数据库连接错误!', err);} else {/* 根据数据库名获取数据库返回给callback处理 */let db = client.db(dbName);callback && callback(db);client.close();}})}module.exports = { connect };/* 测试 */connect(db => {db.collection('users').findOne({ username: 'admin' }, (err, docs) => {if (err)console.log(err)elseconsole.log(docs); });});//{ _id: 5ea442dbbc0dfbff14afd728, username: 'admin', passsword: '000'
2.注册页
注册路由
//位置:routes > index.js
router.get('/regist', (req, res, next) => {res.render('regist');
})
页面结构
<div class='form-box'><form action="/users/regist" method="post"><input type="text" name="username" placeholder="请输入用户名"><input type="password" name="password" placeholder="请输入密码"><input type="password" name="password2" placeholder="请确认密码"><input type="submit" value="注册"></form><div>已有帐户,<a href="/login">立即登录</a></div>
</div>
提交处理
//位置 routes > user.js
router.post('/regist', (req, res, next) => {/* 取出提交数据 */let { username, password, password2 } = req.body;let data = { username, password, password2 };/* 校验数据 */if (password !== password2) {console.log("两次输入的密码不一致");res.redirect('/regist');} else {model.connect(db => {/* 写入数据库 */db.collection('users').insertOne(data, (err, docs) => {if (err) {console.log('注册失败');res.redirect('/regist');//返回注册页} else {console.log('注册成功');res.redirect('/login');//返回登陆页}})})}
})
3.登录页
页面结构
<div class="form-box"><form action="/users/login" method="post"><input type="text" name="username" placeholder="请输入用户名"><input type="password" name="password" placeholder="请输入密码"><input type="submit" value="登录"></form><div>没有帐号,<a href="/regist">立即注册</a>!</div>
</div>
提交处理
(1)安装express-session
拦截登录状态
安装
npm i express-session -S /* -------------app.js配置------------- */
/* 配置session */
app.use(session({secret: 'qf project',resave: false,saveUninitialized: true,cookie: { maxAge: 1000 * 60 * 10 } // 指定登录会话的有效时长
}))
/* 拦截登陆状态 */
app.get('*', (req, res, next) => {let username = req.session.username;let path = req.path;console.log("session-" + username);if (path != '/login' && path != '/regist') {if (!username)res.redirect('/login');}next();
})
(2)从数据库查询信息并存入session
/* 登录提交 */
router.post('/login', (req, res, next) => {let data = {username: req.body.username,password: req.body.password}/* 连接数据库 */model.connect(db => {db.collection('users').findOne(data, (err, docs) => {if (err) {console.log(err);res.redirect('/login');} else {req.session.username = data.username;res.redirect('/');}})})
})
4. 通用顶部组件
结构
<!-- bar.ejs -->
<div class='bar'><span><%- username %></span><a href='/write'>写文章</a><a href='/users/logout'>退出</a><a href='/' class='home'><img src="/images/home.png" alt="首页"></a>
</div>
处理退出请求
router.get('/logout', (req, res, next) => {req.session.username = null;res.redirect('/login');
})
5. 写文章
页面结构
<%- include('bar',{username:username}) %>
<form class="article" action="/article/add" method="post"><input type="text" name="title" placeholder="请输入文章标题"><textarea name="content" class="xheditor" cols="30" rows="10"></textarea><input type="submit" value="发布">
</form>
<!-- xheditor富文本编辑器 -->
<script type="text/javascript" src="/xheditor/jquery/jquery-1.4.4.min.js"></script>
<script type="text/javascript" src="/xheditor/xheditor-1.2.2.min.js"></script>
<script type="text/javascript" src="/xheditor/xheditor_lang/zh-cn.js"></script>
<script>$('.xheditor').xheditor({tools: 'full',skin: 'default',upImgUrl: '/article/upload',html5Upload: false,upMultiple: 1});
</script>
数据提交
(1)创建article
路由处理文件
/* app.js配置 */
var articleRouter=require('./routes/article');
app.use('/article', articleRouter);
(2)处理提交请求
/* routes > article.js */
router.post('/add', (req, res, next) => {/* 获取数据 */let username = req.session.username;let data = {title: req.body.title,content: req.body.content,id: Date.now(),username: username}/* 写入数据库 */model.connect(db => {db.collection('articles').insertOne(data, (err, docs) => {if (err) {console.log('提交失败', err);res.redirect('/write');} else {console.log('提交成功');res.redirect('/');}})})
})
6. 首页
页面结构
<%- include('bar',{username}) %>
<div class='list'><% data.list.map((item,index)=>{ %><div class='row'><span><%- index+1 %></span><!-- 序号 --><span><%- item.username %></span><!-- 作者 --><span><a href="/detail?id=<%- item.id %>&pageIndex=<%- data.pageIndex %> "> <%- item.title %></a><!-- 标题 --></span><span><%- item.time %></span><!-- 时间 --><div><a href=" /write?id=<%- item.id %>&pageIndex=<%- data.pageIndex %>">编辑</a><a href="/article/delete?id=<%- item.id %>&pageIndex=<%- data.pageIndex %>">删除</a></div></div><% }) %><!-- 显示页码 --><div class="pages"><% for(let i=1;i<=data.total;i++){ %><a href="/?pageIndex=<%- i %>"><%- i %></a><!-- 根据页码重新请求数据 --><% } %></div>
</div>
<!--
data数据结构:
{total: 1,pageIndex: 1,list: [{_id: 5ea5538ad8c2e22d908155eb,title: '1dxsxx',content: 'dccfwvfr',id: 1587893130840,username: 'a',time: '2020-04-26 05:25:30'}]
} -->
数据请求实现分页
通过url
将当前页码pageIndex
传入,然后第一次查询总的数量处理pageSize
获得总页数total
,第二次查询添加限制条件获取页面需要显示的数据列表,针对不是第一页时页面数据为空的问题,将pageIndex-1
重新加载
/* http://localhost:8888/?pageIndex=1 */
router.get('/', async (req, res, next) => {/* 页面数据 */let pageIndex = req.query.pageIndex || 1;let pageInfo = {total: 0,/* 总共页数 */pageIndex,/* 当前页 */list: []/* 页面数据 */}let pageSize = 3;model.connect(db => {/* 查询所有数据 */db.collection('articles').find().toArray((err, docs) => {if (err) {console.log('首页数据查询错误');res.render('index', { username, pageInfo });} else {pageInfo.total = Math.ceil(docs.length / pageSize);//获取总的页面数model.connect(db => {/* 限制条件查询 */db.collection('articles').find()/* 查找所有 */.sort({ id: -1 })/* 按时间倒序 */.limit(pageSize)/* 限制数量 */.skip((pageIndex - 1) * pageSize)/* 跳过数量 */.toArray((err2, list) => {if (err2) {console.log('首页数据查询错误', err2);} else {/* 除第一页若页面数据条数为0则请求前一页 */if (pageIndex != 1 && !list.length) {res.redirect('/?pageIndex=' + (pageIndex - 1));} else {/* 格式化时间 */list.forEach(v => v.time = moment(v.id).format('YYYY-MM-DD hh:mm:ss'))pageInfo.list = list;}/* 将数据传给页面 */res.render('index', {username: req.session.username,data: pageInfo});}})})}})})
})
7.文章详情
页面结构
<!-- index.ejs入口 -->
<a href="/detail?id=<%- item.id %>&pageIndex=<%- data.pageIndex %> "><%- item.title %>
</a><!-- 标题 --><!-- detail.ejs -->
<%- include('bar',{username}) %>
<div class='detail'><div class='title'><%- data.title %></div><div class="desc"><span>作者:<%- data.title %></span> <span> 发布时间:<%- data.time %></span></div><div class="content"><%- data.content %></div>
</div>
<!--
data格式:
{_id: 5ea5538ad8c2e22d908155eb,title: '1dxsxx',content: 'dccfwvfr',id: 1587893130840,username: 'a',time: '2020-04-26 05:25:30'
}-->
数据处理
/* 文章详情 http://localhost:8888/detail?id=1587900351782&pageIndex=1 */
router.get('/detail', (req, res, next) => {let id = parseInt(req.query.id);let pageIndex = req.query.pageIndex;model.connect(db => {db.collection('articles').findOne({ id }, (err, docs) => {if (err) {console.log('详情获取失败' + err);res.redirect('/?=' + pageIndex);//返回主页} else {/* 时间格式化 */docs.time = moment(docs.id).format('YYYY-MM-DD hh:mm:ss');console.log(docs)res.render('detail', {username: req.session.username,data: docs})}})})
})
8.文章编辑
页面结构
编辑与添加文章结构相同,区别在于数据id
和pageIndex
记录,修改write
页结构即可
<!-- index.ejs的入口 -->
<a href=" /write?id=<%- item.id %>&pageIndex=<%- data.pageIndex %>">编辑</a>
<!-- write.ejs -->
<form class="article" action="/article/add" method="post"><!-- 传递参数使用hidden --><input type="hidden" name="id" value="<%- data.id %>"><input type="hidden" name="pageIndex" value="<%- data.pageIndex %>"><input type="text" name="title" placeholder="请输入文章标题" value="<%- data.title %>"><textarea class="xheditor" name="content" cols="30" rows="10"><%- data.content %></textarea><input type="submit" value="<%- data.id?'修改':'发布' %>">
</form>
<!-- data数据结构{id: 1587893123696,title: 'qqqqq',content: 'qcdxcdxcxzczx',pageIndex: '1'}
-->
数据处理
1.进入write
页面数据获取
写文章进入write
页时没有id
和pageIndex
传入,修改文章时可以通过id
查询到文章title
和content
,通过pageIndex
可以标识修改完成后要返回的页面
/* 文章 http://localhost:8888/write?id=1587900351782&pageIndex=1*/
router.get('/write', (req, res, next) => {/* 获取数据 */let id = parseInt(req.query.id) || null;let pageIndex = req.query.pageIndex || 1;let data = {id,title: '',content: '',pageIndex}/* 查询数据 */model.connect(db => {db.collection('articles').findOne({ id: id }, (err, docs) => {if (err) {console.log('获取文章数据失败', err);res.redirect('/?pageIndex=' + pageIndex);} else {if (docs) {/* 查询结果为空是新增文章 */data.title = docs.title;data.content = docs.content;}res.render('write', {username: req.session.username,data})}})})
})
2.点击修改按钮更新数据
通过是否含有id
来判断是更新操作还是插入操作,操作失败返回当前页,成功则返回主页
/* 文章发布/修改 req.body => id pageIndex title content*/
router.post('/add', (req, res, next) => {/* 获取数据 */let username = req.session.username;let id = parseInt(req.body.id);let pageIndex = req.body.pageIndex;let data = {title: req.body.title,content: req.body.content,id: id || Date.now(),/* 修改是id,添加是Date.now() */username: username,}model.connect(db => {if (id) {/* 修改 */db.collection('articles').updateOne({ id }, { $set: data }, (err, docs) => {if (err) {console.log('修改失败', err);res.redirect(`/write?id=${id}&pageIndex=${pageIndex}`);/* 重新操作 */} else {res.redirect(`/?pageIndex=${pageIndex}`);//回主页}})} else {/* 添加 */db.collection('articles').insertOne(data, (err, docs) => {if (err) {console.log('发布失败', err);res.redirect('/write');/* 重新操作 */} else {console.log('发布成功');res.redirect('/');/* 回主页 */}})}})
})
9.删除文章
<a href="/article/delete?id=<%- item.id %>&pageIndex=<%- data.pageIndex %>">删除</a>
在主页加入删除文章选项,id
用于找到指定文章,pageIndex
确定删除后返回的页面
/* 文章删除 http://localhost:8888/?id=1587874300950&pageIndex=1 */
router.get('/delete', (req, res, next) => {/* 获取id和当前页码 */let id = parseInt(req.query.id);let pageIndex = req.query.pageIndex;/* 删除数据 */model.connect(db => {db.collection('articles').deleteOne({ id }, (err, ret) => {if (err) {console.log('删除失败', err);res.redirect(`/?pageIndex=${pageIndex}`);} else {console.log('删除成功', ret);res.redirect(`/?pageIndex=${pageIndex}`);}})})
})
10.实现图片上传
安装multiparty
插件解析请求
npm i multiparty -S
配置xheditor
富文本编辑器
$('.xheditor').xheditor({tools: 'full',skin: 'default',upImgUrl: '/article/upload',/* 上传路由 */html5Upload: false,upMultiple: 1
});
配置上传路由
/* 图片上传 */
router.post('/upload', (req, res, next) => {var form = new multiparty.Form();form.parse(req, (err, fields, files) => {if (err) {console.log('上传失败', err);} else {let file = files.filedata[0];/* 创建读写流 */let rs = fs.createReadStream(file.path);/* 存图片的路径为public下的/uploads/ */let newPath = '/uploads/' + file.originalFilename;let ws = fs.createWriteStream('./public' + newPath);/* 边读边写 */rs.pipe(ws);ws.on('close', () => {console.log('文件上传成功');res.send({ err: '', msg: newPath });})}})
})
/*
files {filedata: [{fieldName: 'filedata',originalFilename: 'Snipaste_2019-09-23_00-10-40.png',path: 'C:\\Users\\14329\\AppData\\Local\\Temp\\qWOzXsQRXhVyqiO57W3qjMgC.png',headers: [Object],size: 146188}]
}
*/
文章管理系统 -- Express学习相关推荐
- 基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET - 文章汇总及学习指南...
一.AgileEAS.NET平台简介 AgileEAS.NET平台是一套应用系统快速开发平台,用于帮助中小软件开发商快速构建自己的企业信息管理类开发团队,以达到节省开发成本.缩短开发时间,快速适应市场 ...
- 基于SSM框架的文章管理系统(增加留言回复功能)
一个简单的文章管理系统(增加留言回复功能) 简单使用百度富文本实现了文章管理的功能,增加了留言回复功能,其实这个小项目只是为了测试怎样实现留言回复功能而提取出来的,并不是很完善,主要实现了对文章的增删 ...
- Java Web 文章管理系统(Jsp+Ajax+JDBC+MySql实现)
本示例是使用JavaWeb技术实现一个简单的文章管理系统(新闻管理系统)其中主要功能如下: 用户和管理员登录 用户发布新文章.文章详情查看.文章修改.文章删除与恢复 用户查看他人对自己授权的文章及其文 ...
- java留言并后台回复_基于SSM的文章管理系统(增加留言回复功能)
食用说明 这是本人初学SSM的时候写的,旨在学习SSM框架使用,在达到学习目的的前提下实现部分功能,项目本身大体没有问题,如果细节部分你遇到了问题还请自行完善下 本人不会再维护此项目 本人不会再维护此 ...
- php申请系统,PHP+MYSQL的文章管理系统(一)_php
此篇文章属原创,如有引用,请标明作者信息. Email: leo_cdp@yeah.net http://www.cfeng.net/ 本文代码任意转载,使用请保留此声明 ############## ...
- 小孔子文章管理系统V2.0发布测试
小孔子文章管理系统V2.0 [感谢] 本系统是仿照nbArticle开发,在此表示感谢nb联盟的作品. [版权声明] ...
- 简易php access文章管理系统,PHP+ACCESS 文章管理程序代码
代码如下: session_start(); //========================== //作者:biyuan //时间:2006.07 //联系:QQ6010707 //====== ...
- express学习 - (3)express 路由
express学习 (3) express 路由 李俊才 的 CSDN 博客 邮箱 :291148484@163.com CSDN 主页:https://blog.csdn.net/qq_285502 ...
- express学习 - (1)环境配置与第一个express项目
express学习 (1) 环境配置与第一个express项目 CSDN主页:jcLee95 邮箱:291148484@163.com [任务]: 安装express: 创建第一个express项目: ...
最新文章
- AI时代,如何缓解CMO的决策焦虑?
- iOS11 UITableViewCell滑动事件改动
- MySQL表结构设计之范式化和反范式化对比
- 《2017微信春节数据报告》出炉 初一到初五微信红包收发总量达到460亿个
- Redis初识、设计思想与一些学习资源推荐
- Ae:Roto 笔刷工具和调整边缘工具
- python职位要求_python 开发工程师职位描述与岗位职责任职要求
- 寒霜系列引擎技术解析
- Java 时间相关 获取某月的某一天
- Tomcat与JDK版本对应关系,Tomcat各版本特性,鸟哥linux视频教程
- 三星海外远程真机调试使用教程
- 【004】国家企业信用信息公示系统-官方渠道查询企业信息
- redis实现坐标附近查询
- 本地win10安装的MySQL8.0.12用navicat12报错 2509 -Authentication plugin ' caching_sha2_password' cannot be :
- JavaScript基础知识总结复习(一)
- 抖音企业号建议做吗?有什么好处?
- linux高手知乎,配置一个简洁高效的 Zsh | Linux 中国
- SAPトランザクション一覧(メモ)
- 可控硅过零导通程序--可控硅驱动程序
- 3 基于matplotlib的python数据可视化——导入Excel数据绘制组合图表