黑马博客管理系统MySql + Express + art-template项目搭建(源码)

前言

关于搭建本系统要用到:mysql数据库exprss框架,art-template模板引擎,session会话,joi验证(由于博主垃圾电脑无法装载bcrypt,所以不作加密处理),有疑惑或有问题欢迎提问和指出(可以私信)。

多人博客管理系统:博客内容展示,博客管理功能

项目所需文件和插件

插件
文件

js源码部分(带注释)

主路由
sever.js
const express = require("express");
const session = require("express-session");
const dateFormat = require("dateformat");
const template = require("art-template");
const home = require("./route/home");
const admin = require("./route/admin");
const bodyParser = require("body-parser");
const path = require("path");
const app = express();
app.use(express.static(path.join(__dirname, "public")));
app.use(bodyParser.urlencoded({ extended: false }));
// 配置 session
app.use(session({secret: "secret key",saveUninitialized: false,//cookie存在时间为一天cookie: {maxAge: 24 * 60 * 60 * 1000,},})
);
// 拦截请求,判断用户登录状态
app.use("/admin", require("./middleware/loginGuard"));
// 前台路由
app.use("/home", home);
// 后台路由
app.use("/admin", admin);
//集中处理错误请求
app.use((err, req, res, next) => {const result = JSON.parse(err);let params = [];for (const attr in result) {if (attr != "path") {params.push(attr + "=" + result[attr]);}}res.redirect(`${result.path}?${params.join("&")}`);
});
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "art");
app.engine("art", require("express-art-template"));
// 向模板内部导入dateFormate变量
template.defaults.imports.dateFormat = dateFormat;app.listen("3000", () => {console.log("服务器启动成功");
});

common.js数据库连接
const mysql = require("mysql");const connect = mysql.createConnection({host: "localhost",port: 3306,user: "这里填自己MySQL的用户",password: "这里填自己MySQL的密码",database: "数据库名字",
});
connect.connect();
/***@function 获取MySQL数据库中的数函*@param  sql一条MySQL语句*@return Promise对象,异步函数@example await {result} = db("select * from user").then((result) => {return result;});**/
function db(sql) {return new Promise((resolve, reject) => {connect.query(sql, (err, result) => {if (err) {reject(err);} else {resolve(result);}});});
}module.exports = { db };
loginGuard.js
const guard = (req, res, next) => {// 判断用户访问的是否是登录页面// 判断用户的登录状态// 如果用户是登录的,将请求放行,向下执行;如果用户不是登录的,则将请求重定向到登录页if (req.url != "/login" && !req.session.username) {// 重定向到登录页return res.redirect("/admin/login");} else {//判断用户是否是管理员if (req.session.role == "normal") {return res.redirect("/home/");}// 用户是登录的,将请求放行,向下执行next();}
};module.exports = guard;

admin后台js

admin.js
const express = require("express");
const common = require("../model/common");const admin = express.Router();
//渲染登录页面
admin.get("/login", require("./admin/loginup"));
// 实现登录功能
admin.post("/login", require("./admin/login"));//渲染用户页面
admin.get("/user", require("./admin/userPage"));
// 实现退出功能
admin.get("/logout", require("./admin/logout"));
// 渲染创建用户列表路由
admin.get("/user-edit", require("./admin/userEdit"));
// 创建实现添加用户功能
admin.post("/user-edit", require("./admin/user-edit-fn"));
// 创建实现修改用户功能
admin.post("/user-modify", require("./admin/user-modify"));
// 创建实现删除用户功能
admin.get("/delete", require("./admin/user-delete"));//文章列表界面
admin.get("/article", require("./admin/article"));
//文章编辑界面
admin.get("/article-edit", require("./admin/article-edit"));// 实现文章添加功能的路由
admin.post("/article-add", require("./admin/article-add"));
module.exports = admin;
home.js
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;
登录
login.js
const express = require("express");
const common = require("../../model/common");
const login = express.Router();login.post("/login", (req, res) => {const { email, password } = req.body;let sql = `select * from user where email='${email}'`;//判断邮件和密码是否为空if (email.trim().length == 0) {res.status(400).render("admin/error.art", { msg: "邮件地址或密码错误" });}//实现登录common.db(sql).then((result) => {if (result.length > 0) {result.forEach((v) => {if (password == v.password) {//将用户名存储到req请求中req.session.username = v.username;req.session.role = v.role;req.app.locals.userInfo = v;//判断用户是否是管理员,是就可以进入后台if (v.role == "admin") {res.redirect("/admin/user");} else {res.redirect("/home/");}} else {res.status(400).render("admin/error.art", { msg: "邮件地址或密码错误" });}});} else {// 没有查询到用户res.status(400).render("admin/error.art", { msg: "邮件地址或密码错误" });}});
});module.exports = login;
loginup.js
module.exports = (req, res) => {res.render("admin/login.art");
};
logout.js
module.exports = (req, res) => {// 删除 sessionreq.session.destroy(function () {// 删除 cookieres.clearCookie("connect.sid");// 清除模板中的用户信息req.app.locals.userInfo = null;// 重定向到登陆页面res.redirect("/admin/login");});
};
用户
user-delete.js
const common = require("../../model/common");
module.exports = (req, res) => {common.db(`delete from user where _id='${req.query.id}'`);res.redirect("/admin/user");
};
user-edit-fn.js
// 引入 joi 模块
const Joi = require("joi");
const common = require("../../model/common");module.exports = (req, res, next) => {common.db(`select * from user where email='${req.body.email}'`).then(async (result) => {if (result.length > 0) {return res.redirect(`/admin/user-edit?message=邮箱地址已经被占用`);} else {// 定义对象的验证规则const schema = {username: Joi.string().alphanum().min(2).max(12).required().error(new Error("用户名不符合验证规则")),email: Joi.string().email().required().error(new Error("邮箱格式不符合验证规则")),password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/).required().error(new Error("密码格式不符合验证规则")),role: Joi.string().valid("normal", "admin").required().error(new Error("角色值非法")),state: Joi.number().valid(0, 1).required().error(new Error("状态值非法")),};try {// 实施验证await Joi.validate(req.body, schema);} catch (err) {// 验证没有通过// 重定向回用户添加页面,可以将这一类错误用一个中间件集中处理// res.redirect('/admin/user-edit?message=' + err.message);let obj = { path: "/admin/user-edit", message: err.message };next(JSON.stringify(obj));return;}// 将新用户信息添加到数据库中common.db(`insert into user values(null,'${req.body.username}','${req.body.email}','${req.body.password}','${req.body.role}','${req.body.state}')`);// 将页面重定向到用户列表页res.redirect("/admin/user");}});
};
user-modify.js
const common = require("../../model/common");module.exports = (req, res, next) => {const body = req.body;const id = req.query.id;common.db(`select * from user where _id=${id}`).then((result) => {result.forEach((v) => {if (v.password == body.password) {let sql = `update user set _id=${id},username='${body.username}',email='${body.email}',password='${body.password}',role='${body.role}',state='${body.state}' where _id=${id};`;common.db(sql);res.redirect("/admin/user");} else {let obj = {path: "/admin/user-edit",message: "密码错误,不能修改用户数据",id: id,};next(JSON.stringify(obj));}});});
};
userEdit.js
const common = require("../../model/common");
module.exports = (req, res) => {// 标识 标识当前访问的是用户管理页面,req.app.locals.currentLink = "user";const { message, id } = req.query;if (id) {common.db(`select * from user where _id=${id}`).then((user) => {user.forEach((v) => {//修改return res.render("admin/user-edit.art", {message: message,user: v,link: `/admin/user-modify?id=${id}`,button: "修改",});});});} else {//添加return res.render("admin/user-edit.art", {message: message,link: "/admin/user-edit",button: "添加",});}
};
userPage.js
const common = require("../../model/common");module.exports = async (req, res) => {// 标识 标识当前访问的是用户管理页面,req.app.locals.currentLink = "user";let page = req.query.page || 1;//每一页的数据条数let pagesize = 10;common.db("select * from user").then((result) => {let count = result.length;//总页数let total = Math.ceil(count / pagesize);let start = (page - 1) * pagesize;let sql = `select * from user limit ${start},${pagesize}`;common.db(sql).then((users) => {res.render("admin/user.art", {msg: req.session.username,users: users,page: page,total: total,});});});
};
文章
article.js
const common = require("../../model/common");
module.exports = async (req, res) => {// 标识 标识当前访问的是文章页面,req.app.locals.currentLink = "article";//当前页数let page = req.query.page || 1;//每一页的数据条数let pagesize = 10;let { total, start } = await common.db("select * from article").then((result) => {if (result.length <= 0)return res.render("./admin/article.art", { articles: {} });//数据库中数据个数let count = result.length;//总页数let total = Math.ceil(count / pagesize);let start = (page - 1) * pagesize;return { total: total, start: start };});//从MySQL数据库中限制获取到的数据,限制查询,需要多少查多少let sql = `select * from article limit ${start},${pagesize}`;//从数据库中拿到分页数据let articles = await common.db(sql).then((articles) => {return articles;});res.render("./admin/article.art", {articles: articles,page: page,total: total,});
};
article-add.js
const formidable = require("formidable");
const path = require("path");
const common = require("../../model/common");
module.exports = (req, res) => {// 创建表单解析对象const form = new formidable.IncomingForm();// 配置上传文件的存放位置form.uploadDir = path.join(__dirname, "../", "../", "public", "uploads");// 保留上传文件的后缀form.options.keepExtensions = true;form.parse(req, (err, fields, files) => {//对文件名进行处理,因为'\'会杯MySQL数据库吞掉let str = files.cover._writeStream.path.split("public")[1];let newStr = str.slice(0, 8) + "/" + str.slice(8);//日期如果没有填就默认CURRENT_TIMESTAMP,数据库会自动处理let publishDate =fields.publishDate == "" ? "CURRENT_TIMESTAMP" : fields.publishDate;//写入if (publishDate == "CURRENT_TIMESTAMP") {common.db(`insert into article values(null,'${fields.title}','${fields.author}',${publishDate},'${newStr}','${fields.content}')`);} else {common.db(`insert into article values(null,'${fields.title}','${fields.author}','${publishDate}','${newStr}','${fields.content}')`);}// 将页面重定向到文章列表页面res.redirect("/admin/article");});
};
article-edit.js
module.exports = (req, res) => {// 标识 标识当前访问的是文章页面req.app.locals.currentLink = "article";res.render("./admin/article-edit.art");
};

home前台js

article.js
const common = require("../../model/common");module.exports = async (req, res) => {let id = req.query.id;if (id == undefined) {return res.redirect("./");}//查找对应文章let article = await common.db(`select * from article where _id=${id}`).then((article) => {return article;});//查找对应文章下的评论let comments = await common.db(`select * from comment where aid=${id}`).then((comments) => {return comments;});for (let i = 0; i < comments.length; i++) {//通过评论的uid查找用户let user = await common.db(`select * from user where _id=${comments[i].uid}`).then((user) => {return user;});for (let j = 0; j < user.length; j++) {comments[i].uid = user[j];}}res.render("home/article.art", {article: article[0],comments: comments,});
};
comment.js
const comment = require("../../model/common");module.exports = (req, res) => {const { content, uid, aid } = req.body;if (content == "") return res.redirect("/home/article?id=" + aid);let date = new Date(); //返回当前的时间let time = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}`;comment.db(`insert into comment values('${aid}','${uid}','${time}','${content}',null)`);//重定向到文章页面res.redirect("/home/article?id=" + aid);
};
index.js
const common = require("../../model/common");module.exports = async (req, res) => {let page = req.query.page || 1;//每一页的数据条数let pagesize = 4;let { total = 0, start = 0 } = await common.db("select * from article").then((result) => {if (result.length <= 0)return res.render("./admin/article.art", { articles: {} });let count = result.length;//总页数let total = Math.ceil(count / pagesize);let start = (page - 1) * pagesize;return { total: total, start: start };});let sql = `select * from article limit ${start},${pagesize}`;//从数据库中拿到分页数据let result = await common.db(sql).then((result) => {return result;});res.render("home/default.art", {result: result,page: page,total: total,});
};

html源码部分

admin后台html

common 公共部分

aside

Powered by 黑马程序员

header

博客后台{{userInfo && userInfo.username}}

layout

Blog - Content Manager{{block 'link'}}{{/block}}
{{block 'main'}} {{/block}}{{block 'script'}} {{/block}}

article-edit

{{extend './common/layout.art'}}{{block 'main'}}{{include './common/header.art'}}{{include './common/aside.art'}}

文章编辑

{{/block}}{{block 'script'}} {{/block}}

article

{{extend './common/layout.art'}}{{block 'main'}}
{{include './common/header.art'}}

{{include './common/aside.art'}}

文章

找到1篇文章发布新文章{{each articles}}{{/each}}
ID标题发布时间作者操作
{{@$value._id}}{{ $value.title }}{{ dateFormat($value.publishDate, "yyyy-mm-dd") }}{{ $value.author }}
  • «
  • <% for (var i = 1; i <= total; i++) { %>
  • {{ i }}
  • <% } %>
  • »

error

{{extend './common/layout.art'}}{{block 'main'}}

{{msg}}

{{/block}}{{block 'script'}} {{/block}}

login


用户登录

登录

记住密码忘记密码?

user-edit

{{extend './common/layout.art'}}{{block 'main'}}{{include './common/header.art'}}{{include './common/aside.art'}}

{{@user && user._id}}

{{message}}

{{/block}}

user

{{extend './common/layout.art'}}{{block 'main'}}{{include './common/header.art'}}{{include './common/aside.art'}}

用户

找到{{users.length}}个用户新增用户{{each users}}{{/each}}
ID用户名邮箱角色状态操作
{{@$value._id}}{{$value.username}}{{$value.email}}{{$value.role == 'admin' ? '超级管理员': '普通用户'}}{{$value.state == 0 ? '启用': '禁用'}}
  • «
  • <% for (var i = 1; i <= total; i++) { %>
  • {{i}}
  • <% } %>
  • »
{{/block}}{{block 'script'}} {{/block}}

home前台html

common 公共部分

header

博客前台

layout


首页{{block 'link'}}{{/block}}

{{block 'main'}}{{/block}}

article

{{extend './common/layout.art'}}{{block 'link'}}
{{/block}}{{block 'main'}}{{include './common/header.art'}}

{{article.title}}

{{article.author}}{{dateFormat(article.publishDate, 'yyyy-mm-dd')}}{{@article.content}}{{if userInfo}}

评论

{{else}}

先进行登录,再对文章进行评论

{{/if}}{{each comments}}{{$value.uid.username}}{{dateFormat($value.time, 'yyyy-mm-dd')}}{{$value.uid.email}}{{$value.content}}{{/each}} {{/block}}

default

{{extend './common/layout.art'}}{{block 'link'}}
{{/block}}{{block 'main'}}{{include './common/header.art'}}
    {{each result}}
  • {{$value.title}}{{$value.author}}{{dateFormat($value.publishDate, 'yyyy-mm-dd')}}{{@$value.content.replace(/<[^>]+>/g, '').substr(0, 90) + '...'}}
  • {{/each}}
{{if page > 1}}上一页 {{/if}}<% for (var i = 1; i <= total; i++) { %>{{i}} <% } %>{{if page < total}}<23>{{/if}}// {{if result.page > 1}}// 上一页// {{/if}}// {{each result.display}}// {{$value}}// {{/each}}// {{if result.page < result.pages}}// <26>// {{/if}} {{/block}}

mysql源码部分

article.sql
DROP TABLE IF EXISTS `article`;
CREATE TABLE `article`  (`_id` int NOT NULL AUTO_INCREMENT,`title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,`author` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,`publishDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,`cover` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,`content` varchar(10000) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,PRIMARY KEY (`_id`) USING BTREE,INDEX `author`(`author`) USING BTREE,CONSTRAINT `author` FOREIGN KEY (`author`) REFERENCES `user` (`username`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;
comment.sql
DROP TABLE IF EXISTS `comment`;
CREATE TABLE `comment`  (`aid` int NOT NULL,`uid` int NOT NULL,`time` datetime NOT NULL,`content` varchar(10000) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,`_id` int NOT NULL AUTO_INCREMENT,PRIMARY KEY (`_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;
user.sql
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (`_id` int NOT NULL AUTO_INCREMENT,`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,`email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,`role` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,`state` int NOT NULL,PRIMARY KEY (`_id`) USING BTREE,INDEX `username`(`username`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 26 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部