项目说明
需求功能分析
开发步骤
1.快速生成一个项目
①npm install -g express-generator (打开cmd在NPM中安装Express项目生成器)
② express -e blog(生成ejs模板的Express博客项目)
③npm install (安装项目依赖)
其中public中存放静态资源,routes中存放路由文件;view中存放ejs模板文件;在app.js文件中的内容有引入项目模块,使用中间件,使用路由以及处理404错误
④在app.js中添加监听器listen
// 监听器
app.listen(3000,function(){
console.log('listening port 3000');
});
⑤使用NPM安装normalize.css库 用于同一各个浏览器的默认样式
npm install normalize.css
⑥通过node app 开启项目
设计和实现登录页面
前端部分
登录页面由表单组成,核心思想是利用用户提交的用户名和密码等信息与后端数据库中的信息进行对比,根据对比结果反馈给用户,信息匹配一致,将用户页面重定向至用户需要进入的页面,若信息匹配不一致,将错误信息反馈给用户;
①实现一个前端页面
1.在routes文件夹下的index.js 文件中添加登录页的路由(请求一个get方式的路由,并渲染模板引擎文件夹下login视图模板)
// 登录页
router.get('/login',(req,res,next)=>{
res.render('login');//请求一个get方式的路由,并渲染模板引擎文件夹下login视图模板
});
2.重构登录页面(在views文件夹下新建login.ejs文件)
3.对这个页面进行样式开发(main.css 文件中写整个项目的文件)
②后端部分
核心:将用户提交信息和数据库中的信息进行比较,从而得出结果
1: 在项目的根目录下新建一个config.js文件 进行数据库的配置
// 数据库的相关信息
const DB={
host:"localhost",
port:3306,
user:'root',
password:'',
database:'blog'
};
module.exports=DB;
2:在项目的根目录下新建一个database.js 的文件 用于连接mysql
// 加载数据库驱动
const mysql=require('mysql');
const config=require('./config.js');
// 连接数据库
const database=mysql.createConnection({
host:config.host,
user:config.user,
port:config.port,
password:config.password,
database:config.database
});
// 执行连接操作
database.connect();
module.exports=database;
3.由于在设计数据库时 用户的密码是通过md5加密后存储的,所以用户提交的数据也需要通过md5加密后才能对比
注:md5是一种不可逆的加密算法,只能用穷举枚举等暴力方法破解,如:e10adc3949ba59abbe56e057f20f883e 原密码是123456
在Node.js提供了crypto模块 crypto模块的目的是为了提供通用的加密和哈希算法
在route文件夹下的index.js中引入cypto 和database模块
const crypto=require('crypto');
const mysql=require('./../database');
// 登录信息验证
router.post('/login', (req, res, next)=> {
var name = req.body.name;
var password = req.body.password;
var hash = crypto.createHash('md5');
hash.update(password);
password = hash.digest('hex');
var query = 'SELECT * FROM author WHERE authorName=' + mysql.escape(name) + ' AND authorPassword=' + mysql.escape(password);
mysql.query(query, (err, rows, fields)=>{
if(err) {
console.log(err);
return;
}
var user = rows[0];
if(!user) {
res.render('login', {
message:'用户名或者密码错误'});
// 当输入错误的时候提示用户
return;
}
req.session.userSign=true,
req.session.userID= user.authorID;
//正确时返回到首页
res.redirect('/');
});
});
需要注意的是mysql.escape()方法,可防止SQL注入攻击,对用户提交的进行处理
实现博客首页
用户登录博客之后自动跳转到首页
①在route文件夹下的index.js中更改首页的路由请求
`
router.get('/',(req, res, next)=> {
let query='SELECT * FROM article';
mysql.query(query,(err,rows,fields)=>{
var acticles=rows;
res.render("index",{
articles:articles}); //get请求渲染的模板
})
});
②编写登录页面(在views文件夹下新建index.ejs文件)
<section class="main-articles">
<ul>
<% for(var i = 0, max = articles.length; i < max; i++) {
%>
<li class="main-articles-item">
<h2><a href=""><%=articles[i].articleTitle%></a></h2>
<section class="main-articles-items-des">
<p>
<span>作者:<%=articles[i].articleAuthor %></span>
<span>发布时间:<%=articles[i].articleTime %></span>
<span>浏览量:<%=articles[i].articleClick %></span>
</p>
</section>
</li>
<% } %>
</ul>
</section>
③对这个页面进行样式开发(main.css 文件中写整个项目的文件)
④在数据库article表中插入信息
刷新浏览器
注意:整个项目有前端页面许多重复的地方,可以将这些代码分离出来进行重用。可以在view文件夹中新建一个public文件夹 用来放置这些代码文件,如head.ejs 其中写入head标签的内容,在header.ejs中写入博客网站的头部
利用ejs的include方法可以将外部的ejs文件引入 <%-include(文件路径)%>
//如:
<!DOCTYPE html>
<html>
<%- include('./public/head.ejs') %>
<body>
<%- include('./public/header.ejs') %>
<section class="main floatfix">
<%- include('./public/aside.ejs') %>
播客文章内容页的实现
由于当一个播客的文章量很大时,不能为每篇文章的内容都单独设计一个路由。可通过express提供的一种路由配置方式,在路由路径中使用一个占位符,通过这个占位符来判断不同的路由。在整个项目中,由于每篇文章的ID是不同的,所以可以用来做占位符
连接数据库
router.get('/articles/:articleID', (req, res, next)=> {
//占位符 :
let articleID = req.params.articleID;//这个对象用于存储请求路由配置中占位符的真实内容
let query = 'SELECT * FROM article WHERE articleID=' + mysql.escape(articleID);
mysql.query(query,(err, rows, fields)=> {
if(err) {
console.log(err);
return;
}
// 增加点击率
var query = 'UPDATE article SET articleClick=articleClick+1 WHERE articleID=' + mysql.escape(articleID);
var article = rows[0];
mysql.query(query, (err, rows, fields)=>{
if(err) {
console.log(err)
return;
}
var year = article.articleTime.getFullYear();
var month = article.articleTime.getMonth() + 1 > 10 ? article.articleTime.getMonth() : '0' + (article.articleTime.getMonth() + 1);
var date = article.articleTime.getDate() > 10 ? article.articleTime.getDate() : '0' + article.articleTime.getDate();
article.articleTime = year + '-' + month + '-' + date;
res.render('article', {
article:article,user:req.session.user});
});
});
});
①添加写文章页面的路由
router.get('/edit',(req,res,next)=>{
res.render('edit');
});
②实现页面的视图层 edit.ejs文件
③需要将添加的进去的数据加到数据库MySql中,在index.js中添加用户发布文章的post请求处理
// 用户发布文章
router.post('/edit',(req,res,next)=>{
let title=req.body.title;
let content=req.body.content;
let author=req.session.user.authorName; //用户登录后用户信息会存在session中
let query='INSERT article SET articleTitle=' + mysql.escape(title) + ',articleAuthor=' + mysql.escape(author) + ',articleContent=' + mysql.escape(content) + ',articleTime=CURDATE()';
mysql.query(query, (err, rows, fields)=>{
if(err) {
console.log(err);
return;
}
res.redirect('/');
});
});
let data='SELECT * FROM article ORDER BY authorID DESC';
2.用户在发表文章时通过session判断,如果不是用户将重定向到登录页
router.get('/edit', function(req, res, next) {
var user = req.session.user;
if(!user) {
res.redirect('/login');
return;
}
res.render('edit');
});
router.get('/modify/:articleID',(req,res,next)=>{
let user=req.session.user;
let articleID=req.params.articleID;
let query='SELECT * FROM article WHERE articleID='+mysql.escape(articleID);
if(!user){
res.redirect('/login');
return;
}
mysql.query(query,(err,rows,fields)=>{
if(err) throw err;
let article=rows[0];
let title=article.articleTitle;
let content=article.articleContent;
console.log(title,content);
res.render('modify',{
user:user,title:title,content:content});
});
});
添加文章修改后的数据库(更新)
router.post('/modify/:articleID',(req,res,next)=>{
let user=req.session.user;
let articleID=req.params.articleID;
let query="UPDATE article SET articleTitle=' +mysql.escape(title)',articleContent='+mysql.escape(content) + 'WHERE articleID='+mysql.escape(articleID)";
mysql.query(query,(err,rows,fields)=>{
if(err) throw err;
res.redirect('/');
});
});
在首页添加编辑页面的链接并添加样式
点击编辑之后就可以进行修改了
// 删除文章
router.get('delete/:articleID',(req.res,next)=>{
let articleID=req.params.articleID;
let user=req.session.user;
let query='DELETE FROM article WHERE articleID'+mysql.escape(articleID);
if(!user){
res.redirect('/login');
return
}
mysql.query(query,(err,rows,fields)=>{
if(err) throw err;
res.redirect('/');
});
});
在博客首页添加每篇文章删除时的链接
在首页添加删除页面的链接并添加样式
<span class="delete"><a href="/delete/<%= articles[i].articleID %>">删除</a></span>
文章分页 可利用url中的query字符串来实现。数据库中的sql查询可以通过LIMIT语句限制文章的篇数,通过查询当前数据库中文章的总篇数来判断是否需要分页
修改index.js中对首页的路由处理