node+koa+Mysql 搭建博客(mini-blog
来源:互联网 发布:python 函数 符 编辑:程序博客网 时间:2024/06/06 01:46
如果你觉得这篇文章帮助到了你,那就赏脸给个star吧,https://github.com/Ningjunhua/mini-blog
开发环境
- nodejs
v8.1.0
- koa
v2.3.0
- mysql
v5.7.0
准备工作
文中用到了promise、async await等语法,所以你需要一点es6的语法,传送门当然是阮老师的教程了http://es6.ruanyifeng.com/
如果你已经配置好node和mysql可以跳过
1
$ node -v 查看你的node版本,如果过低则去nodejs官网下载替换之前的版本
下载mysql,并设置好用户名和密码,默认可以为用户名:root,密码:123456
1
进入到 bin 目录下 比如 cd C:\Program Files\MySQL\MySQL Server 5.7\bin
然后开启mysql
1
$ mysql -u root -p
输入密码之后创建database
(数据库),nodesql
是我们创建的数据库
1
$ create database nodesql;
记住sql语句后面一定要跟;
符号,接下来看看我们创建好的数据库列表
1
$ show databases;
启用创建的数据库
1
$ use nodesql;
查看数据库中的表
1
$ show tables;
显示Empty set (0.00 sec)
,因为我们还没有建表,稍后会用代码建表
注释:
这是后面建表之后的状态
目录结构
- config 存放默认文件
- lib 存放操作数据库文件
- middlewares 存放判断登录与否文件
- public 存放样式文件
- routes 存放路由文件
- views 存放模板文件
- index 程序主文件
- package.json 包括项目名、作者、依赖等等
首先我们创建koa2-blog文件夹,然后cd koa2-blog
1
接着使用 `npm init` 来创建package.json
接着安装包,安装之前我们使用cnpm安装
1
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
1
$ cnpm i koa koa-bodyparser koa-mysql-session koa-router koa-session-minimal koa-static koa-views md5 moment mysql ejs --save
各模块用处
koa node
框架koa-bodyparser
表单解析中间件koa-mysql-session
、koa-session-minimal
处理数据库的中间件koa-router
路由中间件koa-static
静态资源加载中间件ejs
模板引擎md5
密码加密moment
时间中间件mysql
数据库koa-views
模板呈现中间件
在文件夹里面新建所需文件
首先配置config
我们新建default.js
文件
123456789101112131415
const config = {// 启动端口port: 3000,// 数据库配置database: {DATABASE: 'nodesql',USERNAME: 'root',PASSWORD: '123456',PORT: '3306',HOST: 'localhost'}}module.exports = config
这是我们所需的一些字段,包括端口和数据库连接所需,最后我们把它exports暴露出去,以便可以在别的地方使用
配置index.js文件
index.js
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
var Koa=require('koa');var path=require('path')var bodyParser = require('koa-bodyparser');var ejs=require('ejs');var session = require('koa-session-minimal');var MysqlStore = require('koa-mysql-session');var config = require('./config/default.js');var router=require('koa-router')var views = require('koa-views')var koaStatic = require('koa-static')var app=new Koa()// session存储配置const sessionMysqlConfig= {user: config.database.USERNAME,password: config.database.PASSWORD,database: config.database.DATABASE,host: config.database.HOST,}// 配置session中间件app.use(session({key: 'USER_SID',store: new MysqlStore(sessionMysqlConfig)}))// 配置静态资源加载中间件app.use(koaStatic(path.join(__dirname , './public')))// 配置服务端模板渲染引擎中间件app.use(views(path.join(__dirname, './views'), {extension: 'ejs'}))// 使用表单解析中间件app.use(bodyParser())// 使用新建的路由文件// app.use(require('./routers/signin.js').routes())app.use(require('./routers/signup.js').routes())// app.use(require('./routers/posts.js').routes())// app.use(require('./routers/signout.js').routes())// 监听在3000端口app.listen(3000)console.log(`listening on port ${config.port}`)
我们使用koa-session-minimal``koa-mysql-session
来进行数据库的操作
使用koa-static
配置静态资源,目录设置为public
使用ejs
模板引擎
使用koa-bodyparser
来解析提交的表单信息
使用koa-router
做路由
之前我们配置了default.js,我们就可以在这里使用了
首先引入进来 var config = require(‘./config/default.js’);
然后在数据库的操作的时候,如config.database.USERNAME,得到的就是root。
如果你觉得这篇文章帮助到了你,那就赏脸给个star吧,https://github.com/wclimb/Koa2-blog
配置lib的mysql.js文件
关于数据库的使用这里介绍一下,首先我们建立了数据库的连接池,以便后面的操作都可以使用到,我们创建了一个函数query
,通过返回promise的方式以便可以方便用.then()
来获取数据库返回的数据,然后我们定义了三个表的字段,通过createTable
来创建我们后面所需的三个表,包括posts(存储文章),users(存储用户),comment(存储评论),create table if not exists users()表示如果users表不存在则创建该表,避免每次重复建表报错的情况。后面我们定义了一系列的方法,最后把他们exports暴露出去。
这里只介绍注册用户insertData,后续的可以自行查看,都差不多
12345
// 注册用户let insertData = function( value ) {let _sql = "insert into users(name,pass) values(?,?);"return query( _sql, value )}
我们写了一个_sql的sql语句,意思是插入到users的表中(在这之前我们已经建立了users表)然后要插入的数据分别是name和pass,就是用户名和密码,后面values(?,?)意思很简单,你有几个值就写几个问号,最后调用query
函数把sql语句传进去
lib/mysql.js
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
var mysql = require('mysql');var config = require('../config/default.js')var pool = mysql.createPool({host : config.database.HOST,user : config.database.USERNAME,password : config.database.PASSWORD,database : config.database.DATABASE});let query = function( sql, values ) {return new Promise(( resolve, reject ) => {pool.getConnection(function(err, connection) {if (err) {resolve( err )} else {connection.query(sql, values, ( err, rows) => {if ( err ) {reject( err )} else {resolve( rows )}connection.release()})}})})}users=`create table if not exists users(id INT NOT NULL AUTO_INCREMENT,name VARCHAR(100) NOT NULL,pass VARCHAR(40) NOT NULL,PRIMARY KEY ( id ));`posts=`create table if not exists posts(id INT NOT NULL AUTO_INCREMENT,name VARCHAR(100) NOT NULL,title VARCHAR(40) NOT NULL,content VARCHAR(40) NOT NULL,uid VARCHAR(40) NOT NULL,moment VARCHAR(40) NOT NULL,comments VARCHAR(40) NOT NULL DEFAULT '0',pv VARCHAR(40) NOT NULL DEFAULT '0',PRIMARY KEY ( id ));`comment=`create table if not exists comment(id INT NOT NULL AUTO_INCREMENT,name VARCHAR(100) NOT NULL,content VARCHAR(40) NOT NULL,postid VARCHAR(40) NOT NULL,PRIMARY KEY ( id ));`let createTable = function( sql ) {return query( sql, [] )}// 建表createTable(users)createTable(posts)createTable(comment)// 注册用户let insertData = function( value ) {let _sql = "insert into users(name,pass) values(?,?);"return query( _sql, value )}// 发表文章let insertPost = function( value ) {let _sql = "insert into posts(name,title,content,uid,moment) values(?,?,?,?,?);"return query( _sql, value )}// 更新文章评论数let updatePostComment = function( value ) {let _sql = "update posts set comments=? where id=?"return query( _sql, value )}// 更新浏览数let updatePostPv = function( value ) {let _sql = "update posts set pv=? where id=?"return query( _sql, value )}// 发表评论let insertComment = function( value ) {let _sql = "insert into comment(name,content,postid) values(?,?,?);"return query( _sql, value )}// 通过名字查找用户let findDataByName = function ( name ) {let _sql = `SELECT * from userswhere name="${name}"`return query( _sql)}// 通过文章的名字查找用户let findDataByUser = function ( name ) {let _sql = `SELECT * from postswhere name="${name}"`return query( _sql)}// 通过文章id查找let findDataById = function ( id ) {let _sql = `SELECT * from postswhere id="${id}"`return query( _sql)}// 通过评论id查找let findCommentById = function ( id ) {let _sql = `SELECT * FROM comment where postid="${id}"`return query( _sql)}// 查询所有文章let findAllPost = function ( ) {let _sql = `SELECT * FROM posts`return query( _sql)}// 更新修改文章let updatePost = function(values){let _sql=`update posts set title=?,content=? where id=?`return query(_sql,values)}// 删除文章let deletePost = function(id){let _sql=`delete from posts where id = ${id}`return query(_sql)}// 删除评论let deleteComment = function(id){let _sql=`delete from comment where id = ${id}`return query(_sql)}// 删除所有评论let deleteAllPostComment = function(id){let _sql=`delete from comment where postid = ${id}`return query(_sql)}// 查找let findCommentLength = function(id){let _sql=`select content from comment where postid in (select id from posts where id=${id})`return query(_sql)}module.exports={query,createTable,insertData,findDataByName,insertPost,findAllPost,findDataByUser,findDataById,insertComment,findCommentById,updatePost,deletePost,deleteComment,findCommentLength,updatePostComment,deleteAllPostComment,updatePostPv}
下面是我们建的表
- id主键递增
- name: 用户名
- pass:密码
- title:文章标题
- content:文章内容和评论
- uid:发表文章的用户id
- moment:创建时间
- comments:文章评论数
- pv:文章浏览数
- postid:文章id
现在感觉有点枯燥,那我们先来实现一下注册吧
实现注册页面
routers/singup.js
12345678910
var router=require('koa-router')();// GET '/signup' 注册页router.get('/signup',async (ctx,next)=>{await ctx.render('signup',{})})module.exports=router
使用get方式得到’/signup’页面,然后渲染signup模板,这里我们还没有在写signup.ejs
views/signup.ejs
1234567891011121314151617181920212223242526
<html lang="en"><head><meta charset="UTF-8"><title>Document</title></head><body><div class="container"><form class="form create" method="post"><div><label>用户名:</label><input placeholder="用户名" type="text" name="name"></div><div><label>密码:</label><input class="password" type="password" name="password"></div><div><label>重复密码:</label><input class="repeatpass" type="password" name="repeatpass"></div><div class="submit">注册</div></form></div></body></html>
我们先安装supervisor
1
$ cnpm i supervisor
supervisor的作用是会监听文件的变化,而我们修改文件之后不必去重启程序
1
supervisor --harmony index
现在访问 localhost:3000/signup 看看效果吧。注意数据库一定要是开启的状态,不能关闭
完善注册功能
首先我们来完善一下样式吧,稍微美化一下
public/index.css
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
body,header,ul,li,p,div,html,span,h3,a{margin: 0;padding: 0;color: #333;}body{margin-bottom: 20px;}a{text-decoration: none;}header{width: 60%;margin: 20px auto;display: -webkit-flex;display: -moz-flex;display: -ms-flex;display: -o-flex;display: flex;justify-content: space-between;}.user_name{font-size: 20px;}.has_user{}.has_user a,.has_user span,.none_user a{padding: 5px 15px;background: #5FB878;border-radius: 15px;color: #fff;cursor: pointer;}.posts{list-style: none;width: 60%;margin: 0 auto;}.posts li{margin-top: 10px;border: 1px solid #ccc;border-radius: 5px;position: relative;padding-bottom: 50px;}h3{display: inline-block;padding: 5px 10px;background: #1E9FFF;color: #fff;border-radius: 10px;}.post_title p,.post_content p{margin: 10px 0;background: #eee;padding: 10px 20px;border: 1px solid #ddd;border-radius: 4px;}.post_time{position: absolute;bottom: 5px;right: 10px;}.post_3{position: absolute;bottom: 5px;left: 10px;}.post_3 p{display: inline-block;margin-left: 5px;}.post_title{padding: 10px 20px;}.post_content{padding: 0 20px;}.spost{width: 60%;margin:0 auto;border: 1px solid #ddd;position: relative;padding-bottom: 40px;}.spost_user{position: absolute;left: 20px;bottom: 5px;}.edit{position: absolute;right: 20px;bottom: 5px;}.edit p{display: inline-block;margin-left: 10px;}.comment_wrap{width: 60%;margin:20px auto;}.submit{display: block;width: 90px;height: 35px;line-height: 35px;text-align: center;border-radius: 10px;background: #5FB878;cursor: pointer;color: #fff;float: right;margin-top: 20px;}.cmt_content{background: #eee;padding: 20px ;position: relative;}.cmt_name{position: absolute;right: 20px;bottom: 5px;}.cmt_name a{margin-left: 10px;}.cmt_content{margin-top: 10px;}.form{margin:0 auto;width: 50%;margin-top: 20px;}textarea{width: 100%;height: 200px;padding-left: 20px;font-size: 20px;}.container{width: 60%;margin: 0 auto;}input{display: block;width: 100%;height: 40px;padding-left: 20px;font-size: 20px;}.create label{display: block;margin: 10px 0;}.comment_wrap form{width: 100%;}.delete_comment,.delete_post{cursor: pointer;}.delete_comment:hover,.delete_post:hover{color: #f60;}a:hover{color: #f60;}
我们再把模板引擎的header和footer独立出来
/views/header.ejs
顺便引入index.css和jq
123456789
<html lang="en"><head><meta charset="UTF-8"><title>Document</title></head><link rel="stylesheet" href="/index.css"><script src="http://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script><body>
/views/footer.ejs
123
</body></html>
修改views/signup.ejs
12345678910111213141516171819
<% include header %><div class="container"><form class="form create" method="post"><div><label>用户名:</label><input placeholder="用户名" type="text" name="name"></div><div><label>密码:</label><input class="password" type="password" name="password"></div><div><label>重复密码:</label><input class="repeatpass" type="password" name="repeatpass"></div><div class="submit">注册</div></form></div><% include footer %>
修改routers/signup.js
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
var router=require('koa-router')();// 处理数据库(之前已经写好,在mysql.js)var userModel=require('../lib/mysql.js');// 加密var md5=require('md5')router.get('/signup',async (ctx,next)=>{await ctx.render('signup',{session:ctx.session,})})// POST '/signup' 注册页router.post('/signup',async (ctx,next)=>{console.log(ctx.request.body)var user={name:ctx.request.body.name,pass:ctx.request.body.password,repeatpass:ctx.request.body.repeatpass}await userModel.findDataByName(user.name).then(result=>{// var res=JSON.parse(JSON.stringify(reslut))console.log(result)if (result.length){try {throw Error('用户存在')}catch (error){//处理errconsole.log(error)}ctx.body={data:1};;}else if (user.pass!==user.repeatpass || user.pass==''){ctx.body={data:2};}else{ctx.body={data:3};console.log('注册成功')// ctx.session.user=ctx.request.body.nameuserModel.insertData([ctx.request.body.name,md5(ctx.request.body.password)])}})})module.exports=router
- 我们使用md5实现密码加密
- 使用我们之前说的
bodyParse
来解析提交的数据,通过ctx.request.body
得到 - 我们引入了数据库的操作 findDataByName和insertData,因为之前我们在/lib/mysql.js中已经把他们写好,并暴露出来了。意思是先从数据库里面查找注册的用户名,如果找到了证明该用户名已经被注册过了,如果没有找到则使用insertData增加到数据库中
- ctx.body 是我们通过ajax提交之后给页面返回的数据,比如提交ajax成功之后
msg.data=1
的时候就代表用户存在,msg.data
出现在后面的signup.ejs
模板ajax请求中
我们使用ajax来提交数据,方便来做成功错误的处理
模板引擎ejs
我们使用的是ejs,语法可以见ejs官网
之前我们写了这么一段代码
12345
router.get('/signup',async (ctx,next)=>{await ctx.render('signup',{session:ctx.session,})})
这里就用到了ejs所需的session 我们通过渲染signup.ejs模板,将值ctx.session赋值给session,之后我们就可以在signup.ejs中使用了
ejs的常用标签为:
<% code %>
:运行 JavaScript 代码,不输出<%= code %>
:显示转义后的 HTML内容<%- code %>
:显示原始 HTML 内容
<%= code %>
和<%- code %>
的区别在于,<%= code %>不管你写什么都会原样输出,比如code为<strong>hello</strong>
的时候 <%= code %>
会显示<strong>hello</strong>
而<%- code %>
则显示加粗的hello
修改/views/signup.ejs
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
<% include header %><div class="container"><form class="form create" method="post"><div><label>用户名:</label><input placeholder="用户名" type="text" name="name"></div><div><label>密码:</label><input class="password" type="password" name="password"></div><div><label>重复密码:</label><input class="repeatpass" type="password" name="repeatpass"></div><div class="submit">注册</div></form></div><script>$('.submit').click(()=>{console.log($('.form').serialize())$.ajax({url: "/signup",data: $('.form').serialize(),type: "POST",cache: false,dataType: 'json',success: function (msg) {if (msg.data == 1) {$('.error').text('用户名存在')$('input').val('')fade('.error')}else if (msg.data == 2){$('.error').text('请输入重复的密码')fade('.error')}else if(msg.data == 3){$('.success').text('注册成功')fade('.success')setTimeout(()=>{window.location.href="/signin"},1000)}//console.log($('.ui.error.message').text);},error: function () {alert('异常');}})})</script><% include footer %>
这里重点就在于ajax提交了,提交之后换回数据 1 2 3,然后分别做正确错误处理,把信息写在error和success中
修改/views/header.ejs
我们之前在/routers/signup.js get ‘/signup’ 中 向模板传递了session参数 session:ctx.session,存取的就是用户的信息,包括用户名、登录之后的id等,之所以可以通过ctx.session获取到,因为我们在后面登录的时候已经赋值 如ctx.session.user=res[0][‘name’]
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
<html lang="en"><head><meta charset="UTF-8"><title>koa-blog</title></head><body><link rel="stylesheet" href="/index.css"><script src="http://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script><header><div class="user_name">user:<% if(session.user){ %><%= session.user %><% } %><% if(!session.user){ %>未登录<% } %></div><div class="message"><div class="error"></div><div class="success"></div></div><div class="user_right"><% if(session.user){ %><div class="has_user"><a href="/posts">全部文章</a><a href="/create">发表文章</a><span class="signout">登出</span></div><% } %><% if(!session.user){ %><div class="none_user"><a href="/posts">全部文章</a><a href="/signup">注册</a><a href="/signin">登录</a></div><% } %></div></header><script>function fade(data){if ($(data).css('display')!=='none') {$(data).fadeOut(1500)}else{$(data).show()$(data).fadeOut(1500)}}</script>
我们可以看到,如果不存在用户,则只显示全部文章
注册
登录
,如果session.user存在则有登出的按钮
我们可以看到当状态data为 3 的时候window.location.href=”/signin”
为了方便跳转,我们先简单实现一下signin页面
修改 /routers/signin.js
123456789
var router=require('koa-router')();// get '/signin'登录页面router.get('/signin',async (ctx,next)=>{await ctx.render('signin',{session:ctx.session,})})module.exports=router
修改 /views/signin.ejs
123456789101112131415
<% include header %><div class="container"><form class="form create" method="post "><div><label>用户名:</label><input placeholder="用户名" type="text" name="name"></div><div><label>密码:</label><input placeholder="密码" type="password" name="password"></div><div class="submit">登录</div></form></div><% include footer %>
修改 index.js 文件 把下面这段代码注释去掉,之前注释是因为我们没有写signin的路由,以免报错,后面还有文章页和登出页的路由,大家记住一下
1
app.use(require('./routers/signin.js').routes())
现在注册一下来看看效果吧
1
$ supervisor --harmony index
我们怎么查看我们注册好的账号和密码呢?打开mysql控制台
1
$ select * from users;
这样刚刚我们注册的用户信息都出现了
如果你觉得这篇文章帮助到了你,那就赏脸给个star吧,https://github.com/wclimb/Koa2-blog
登录页面
修改signin
routers/signin.js
1234567891011121314151617181920212223242526272829303132333435363738394041
var router=require('koa-router')();// 处理数据库(之前已经写好,在mysql.js)var userModel=require('../lib/mysql.js')// 加密var md5=require('md5')// get '/signin'登录页面router.get('/signin',async (ctx,next)=>{await ctx.render('signin',{session:ctx.session,})})// post '/signin'登录页面router.post('/signin',async (ctx,next)=>{console.log(ctx.request.body)var name=ctx.request.body.name;var pass=ctx.request.body.password;// 这里先查找用户名存在与否,存在则判断密码正确与否,不存在就返回falseawait userModel.findDataByName(name).then(result =>{// console.log(reslut)var res=JSON.parse(JSON.stringify(result))if (name === res[0]['name'] && md5(pass) === res[0]['pass']) {ctx.body='true'// ctx.flash.success='登录成功!';ctx.session.user=res[0]['name']ctx.session.id=res[0]['id']console.log('ctx.session.id',ctx.session.id)// ctx.redirect('/posts')console.log('session',ctx.session)console.log('登录成功')}}).catch(err=>{ctx.body='false'console.log('用户名或密码错误!')// ctx.redirect('/signin')})})module.exports=router
我们进行登录操作,判断登录的用户名和密码是否有误,使用md5加密
我们可以看到登录成功返回的结果是result
然后处理一下 var res=JSON.parse(JSON.stringify(result))
为什么呢?
因为返回的结果是这样的一个数组:id:4 name:rrr pass:…
[ RowDataPacket { id: 4, name: ‘rrr’, pass: ‘44f437ced647ec3f40fa0841041871cd’ } ]
修改views/signin.ejs
signin.ejs
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
<% include header %><div class="container"><form class="form create" method="post "><div><label>用户名:</label><input placeholder="用户名" type="text" name="name"></div><div><label>密码:</label><input placeholder="密码" type="password" name="password"></div><div class="submit">登录</div></form></div><script>$('.submit').click(()=>{console.log($('.form').serialize())$.ajax({url: "/signin",data: $('.form').serialize(),type: "POST",cache: false,dataType: 'json',success: function (msg) {if (!msg) {$('.error').text('用户名或密码错误')$('input').val('')fade('.error')}else{$('.success').text('登录成功')fade('.success')setTimeout(()=>{window.location.href="/posts"},1000)}//console.log($('.ui.error.message').text);},error: function () {alert('异常');}})})</script><% include footer %>
我们增加了ajax请求,在routers/singin.js里,我们设置如果登录失败就返回false,登录成功返回true
12
ctx.body='false'ctx.body='true'
那我们登录成功后要做跳转,可以看到window.location.href="/posts"
跳转到posts页面
全部文章
修改routers/posts.js
posts.js
123456789101112131415161718
var router=require('koa-router')();// 处理数据库(之前已经写好,在mysql.js)var userModel=require('../lib/mysql.js')// 时间中间件var moment=require('moment')// get '/'页面router.get('/',async (ctx,next)=>{ctx.redirect('/posts')})// get '/posts'页面router.get('/posts',async (ctx,next)=>{await ctx.render('posts',{session:ctx.session})})module.exports=router
修改 index.js
app.use(require(‘./routers/posts.js’).routes())的注释去掉
修改 views/posts.ejs
12345
<% include header %>posts<% include footer %>
现在看看登录成功之后的页面吧
接下来我们事先登出页面
登出页面
修改 router/signout.js
signout.js
12345678910
var router=require('koa-router')();router.get('/signout',async (ctx,next)=>{ctx.session=null;console.log('登出成功')ctx.body='true'})module.exports=router
把session设置为null即可
修改 index.js
app.use(require(‘./routers/posts.js’).routes())的注释去掉,现在把注释的路由全部取消注释就对了
然后修改 views/header.ejs
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
<html lang="en"><head><meta charset="UTF-8"><title>koa-blog</title></head><body><link rel="stylesheet" href="/index.css"><script src="http://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script><header><div class="user_name">user:<% if(session.user){ %><%= session.user %><% } %><% if(!session.user){ %>未登录<% } %></div><div class="message"><div class="error"></div><div class="success"></div></div><div class="user_right"><% if(session.user){ %><div class="has_user"><a href="/posts">全部文章</a><a href="/create">发表文章</a><span class="signout">登出</span></div><% } %><% if(!session.user){ %><div class="none_user"><a href="/posts">全部文章</a><a href="/signup">注册</a><a href="/signin">登录</a></div><% } %></div></header><script>function fade(data){if ($(data).css('display')!=='none') {$(data).fadeOut(1500)}else{$(data).show()$(data).fadeOut(1500)}}$('.signout').click(()=>{$.ajax({url: "/signout",type: "GET",cache: false,dataType: 'json',success: function (msg) {if (msg) {$('.success').text('登出成功')fade('.success')setTimeout(()=>{window.location.href="/posts"},1000)}},error: function () {alert('异常');}})})</script>
增加点击登出后的ajax 的提交,成功之后回到posts页面
发表文章
修改router/posts
在后面增加
12345678910111213141516171819202122232425
// get '/create'router.get('/create',async (ctx,next)=>{await ctx.render('create',{session:ctx.session,})})// psot '/create'router.post('/create',async (ctx,next)=>{console.log(ctx.session.user)var title=ctx.request.body.titlevar content=ctx.request.body.contentvar id=ctx.session.idvar name=ctx.session.uservar time=moment().format('YYYY-MM-DD HH:mm')console.log([name,title,content,id,time])// 这里我们向数据库插入用户名、标题、内容、发表文章用户的id、时间,成功返回true,失败为falseawait userModel.insertPost([name,title,content,id,time]).then(()=>{ctx.body='true'}).catch(()=>{ctx.body='false'})})
修改 views/create.ejs
create.ejs
1234567891011121314151617181920212223242526272829303132333435363738394041424344
<% include header %><div class="container"><form method="post" class="form create"><div><label>标题:</label><input placeholder="" type="text" name="title"></div><div><label>内容:</label><textarea name="content" id="" cols="42" rows="10"></textarea></div><div class="submit">发表</div></form></div><script>$('.submit').click(()=>{$.ajax({url: "/create",data: $('.form').serialize(),type: "POST",cache: false,dataType: 'json',success: function (msg) {if (msg) {$('.success').text('发表成功')fade('.success')setTimeout(()=>{window.location.href="/posts"},1000)}else{$('.success').text('发表失败')fade('.success')setTimeout(()=>{window.location.reload()},1000)}},error: function () {alert('异常');}})})</script><% include footer %>
现在看看能不能发表吧
即使我们发表了文章,但是当前我们的posts的页面没有显示,因为还没有获取到数据
接下来
修改 routers/posts.js
修改 get ‘/posts’
12345678910111213141516171819202122232425262728
router.get('/posts',async (ctx,next)=>{// 这里我们先通过查找有没有类似/posts?author=XXX 的连接跳转,如果有就执行下面这句话,把用户名取下来,由于用户名存在中文,所以我们进行解码if (ctx.request.querystring) {console.log('ctx.request.querystring',decodeURIComponent(ctx.request.querystring.split('=')[1]))await userModel.findDataByUser(decodeURIComponent(ctx.request.querystring.split('=')[1])).then(result=>{res=JSON.parse(JSON.stringify(result))console.log(res)})await ctx.render('posts',{session:ctx.session,posts:res})}else{// 如果连接是正常的 如 /posts 则我们获取的是全部文章的列表,所以通过findAllPost查找全部文章并向模板传递数据posts, posts的值为resawait userModel.findAllPost().then(result=>{console.log(result)res=JSON.parse(JSON.stringify(result))console.log('post',res)})await ctx.render('posts',{session:ctx.session,posts:res})}})
if (ctx.request.querystring) {}这部分我们先不用管,后面会说。只需要看else后面的代码我们查找我们发表的全部文章然后将获取到的值定义为posts,传给模板posts.ejs,这样就可以渲染出来了
修改 Views/posts.ejs
posts.ejs
123456789101112131415161718192021222324
<% include header %><ul class="posts"><% posts.forEach(function(res){ %><li><div class="post_3"><p class="post_user"><a href="/posts?author=<%= res['name'] %>">作者: <%= res['name'] %></a></p><p class="post_comments">评论数:<%= res['comments'] %></p><p class="post_pv">浏览数:<%= res['pv'] %></p></div><a href="/posts/<%= res['id'] %>"><div class="post_title"><h3>title</h3><p><%= res['title'] %></p></div><div class="post_content"><h3>content</h3><p><%= res['content'] %></p></div></a><p class="post_time">发表时间:<%= res['moment'] %></p></li><% }) %></ul><% include footer %>
现在看看posts页面有没有文章出现了
我们看到是所有的文章,但是我需要点击单篇文章的时候,显示一篇文章怎么办呢?
修改 routers/posts.js
在posts.js后面增加
1234567891011121314151617
router.get('/posts/:postId',async (ctx,next)=>{console.log(ctx.params.postId)// 通过文章id查找返回数据,然后增加pv 浏览 +1await userModel.findDataById(ctx.params.postId).then(result=>{res=JSON.parse(JSON.stringify(result))res_pv=parseInt(JSON.parse(JSON.stringify(result))[0]['pv'])res_pv+=1console.log(res)})// 渲染模板,并传递三个数据await ctx.render('sPost',{session:ctx.session,posts:res})})
现在的设计是,我们点进去出现的url是 /posts/1 这类的 1代表该篇文章的id,我们在数据库建表的时候就处理了,让id为主键,然后递增
我们通过userModel.findDataById 文章的id来查找数据库
我们通过userModel.findCommentById 文章的id来查找文章的评论,因为单篇文章里面有评论的功能
单篇文章页
修改 views/sPost.ejs
sPost.ejs
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
<% include header %><div class="spost"><p class="spost_user">author: <a href="/posts?author=<%= posts[0]['name'] %>"><%= posts[0]['name'] %></a></p><div class="post_title"><h3>title</h3><p><a href="/posts/<%= posts[0]['id'] %>"><%= posts[0]['title'] %></a></p></div><div class="post_content"><h3>content</h3><p><%= posts[0]['content'] %></p></div><div class="edit"><% if(session && session.user=== posts[0]['name'] ){ %><p><a href="<%= posts[0]['id'] %>/edit">编辑</a></p><p><a class="delete_post" >删除</a></p><% } %><script>$('.delete_post').click(()=>{$.ajax({url:"<%= posts[0]['id'] %>/remove",type:'GET',cache: false,success:function(msg){if (msg.data==1) {$('.success').text('删除文章成功')fade('.success')setTimeout(()=>{window.location.href="/posts"},1000)}else if(msg.data==2){$('.error').text('删除文章失败')fade('.error');setTimeout(()=>{window.location.reload()},1000)}}})})</script></div></div><div class="comment_wrap"><h3>comment</h3><div class="comment_list"><% comments.forEach(function(res){ %><div class="cmt_lists"><p></p><p class="cmt_content">content: <%= res['content'] %><span class="cmt_name">By: <%= res['name'] %><% if(session && session.user === res['name'] ){ %><a class="delete_comment"> 删除</a><% } %></span></p></div><script>$('.delete_comment').click(()=>{$.ajax({url:"<%= posts[0]['id'] %>/comment/<%= res['id'] %>/remove",type:'GET',cache: false,success:function(msg){if (msg.data==1) {$('.success').text('删除留言成功')fade('.success')setTimeout(()=>{window.location.reload()},1000)}else if(msg.data==2){$('.error').text('删除留言失败')fade('.error');setTimeout(()=>{window.location.reload()},1000)}},error:function(){alert('异常')}})})</script><% }) %></div><% if(session.user){ %><form class="form" method="post" action="/<%= posts[0]['id'] %>"><textarea name="content" id=""></textarea><div class="submit">发表留言</div></form><% } %></div><script>$('.submit').click(function(){$.ajax({url: '/'+document.URL.slice(document.URL.lastIndexOf('/')+1),data:$('.form').serialize(),type: "POST",cache: false,dataType: 'json',success: function (msg) {if (msg) {$('.success').text('发表留言成功')fade('.success')setTimeout(()=>{window.location.reload()},1000)}},error: function () {alert('异常');}})})</script><% include footer %>
现在点击单篇文章试试,进入单篇文章页面,但是编辑、删除、评论都还没有做,点击无效,我们先不做,先实现每个用户发表的文章列表,我们之前在 get ‘/posts’ 里面说先忽略if (ctx.request.querystring) {}里面的代码,这里是做了应该处理,假如用户点击了某个用户,该用户发表了几篇文章,我们需要只显示该用户发表的文章,那么进入的url应该是 /posts?author=xxx ,这个处理在posts.ejs 就已经加上了,就在文章的左下角,作者:xxx就是一个链接。我们通过判断用户来查找文章,继而有了ctx.request.querystring
获取到的是:author=XXX
注:这里我们处理了,通过判断 session.user === res['name']
如果不是该用户发的文章,不能编辑和删除,评论也是。这里面也可以注意一下包裹的<a href=""></a>
标签
编辑文章、删除文章、评论、删除评论
评论
修改routers/posts.js
在post.js 后面增加
123456789101112131415161718192021
router.post('/:postId',async (ctx,next)=>{var name=ctx.session.uservar content=ctx.request.body.contentvar postId=ctx.params.postId// 插入评论的用户名,内容和文章idawait userModel.insertComment([name,content,postId])// 先通过文章id查找,然后评论数+1await userModel.findDataById(postId).then(result=>{res_comments=parseInt(JSON.parse(JSON.stringify(result))[0]['comments'])res_comments+=1})// 更新评论数 res_commentsawait userModel.updatePostComment([res_comments,postId]).then(()=>{ctx.body='true'}).catch(()=>{ctx.body='false'})})
现在试试发表评论的功能吧,之所以这样简单,因为我们之前就在sPost.ejs做了好几个ajax的处理,删除文章和评论也是如此
删除评论
修改routers/posts.js
继续在post.js 后面增加
1234567891011121314151617181920212223
router.get('/posts/:postId/comment/:commentId/remove',async (ctx,next)=>{var postId=ctx.params.postIdvar commentId=ctx.params.commentIdawait userModel.findDataById(postId).then(result=>{res_comments=parseInt(JSON.parse(JSON.stringify(result))[0]['comments'])console.log('res',res_comments)res_comments-=1console.log(res_comments)})await userModel.updatePostComment([res_comments,postId])await userModel.deleteComment(commentId).then(()=>{ctx.body={data:1}}).catch(()=>{ctx.body={data:2}})})
现在试试删除评论的功能吧
删除文章
只有自己发表的文字删除的文字才会显示出来,才能被删除,
修改routers/posts.js
继续在post.js 后面增加
1234567891011121314151617
router.get('/posts/:postId/remove',async (ctx,next)=>{var postId=ctx.params.postIdawait userModel.deleteAllPostComment(postId)await userModel.deletePost(postId).then(()=>{ctx.body={data:1}}).catch(()=>{ctx.body={data:2}})})
现在试试删除文章的功能吧
编辑文字
修改routers/posts.js
继续在post.js 后面增加
1234567891011121314151617181920212223242526272829
// get '/posts/:postId/edit'router.get('/posts/:postId/edit',async (ctx,next)=>{var name=ctx.session.uservar postId=ctx.params.postIdawait userModel.findDataById(postId).then(result=>{res=JSON.parse(JSON.stringify(result))console.log('修改文章',res)})await ctx.render('edit',{session:ctx.session,posts:res})})// post '/posts/:postId/edit'router.post('/posts/:postId/edit',async (ctx,next)=>{var title=ctx.request.body.titlevar content=ctx.request.body.contentvar id=ctx.session.idvar postId=ctx.params.postIdawait userModel.updatePost([title,content,postId]).then(()=>{ctx.body='true'}).catch(()=>{ctx.body='false'})})
修改views/edit.js
1234567891011121314151617181920212223242526272829303132333435363738394041
<% include header %><div class="container"><form class="form create" method="post"><div><label>标题:</label><input placeholder="标题" type="text" name="title" value="<%= posts[0]['title'] %>"></div><div><label>内容:</label><textarea name="content" id="" cols="42" rows="10"><%= posts[0]['content'] %></textarea></div><!-- <input type="submit" value="修改"> --><div class="submit">修改</div></form></div><script>$('.submit').click(()=>{$.ajax({url: document.URL,data: $('.form').serialize(),type: "POST",cache: false,dataType: 'json',success: function (msg) {if (msg) {$('.success').text('修改成功')fade('.success')setTimeout(()=>{window.location.href="/posts"},1000)}},error: function () {alert('异常');}})})</script><% include footer %>
现在试试编辑文字然后修改提交吧
- node+koa+Mysql 搭建博客(mini-blog
- 使用Node+Koa2+Mysql搭建简易博客
- Node博客hexo搭建
- node+express+mysql 搭建一个多人博客
- 个人博客Blog搭建
- Node.js18 Koa 框架
- Node.js-koa入门
- nodejs koa web搭建
- iKcamp团队制作|基于Koa2搭建Node.js实战(含视频)☞ 路由koa-router
- Node.js Web框架 - Koa
- node.js的koa框架
- 基于restful api规范下node.js-koa-mysql-mongodb操作
- pomeo , node 游戏环境搭建 (博客迁移)
- node+express+mongoDB搭建个人博客 ( 一 )
- node+express+mongoDB搭建个人博客 ( 二)
- node+express+mongoDB搭建个人博客 (三)
- node+express+mongoDB搭建个人博客 (四)
- node+express+mongoDB搭建个人博客 (五)
- CentOS下Nginx的安装和配置
- LNMP部署
- 四大组件之Activity
- 使用DOS命令无法插入中文数据到数据库的问题
- JAVA JDK1.5-1.9新特性
- node+koa+Mysql 搭建博客(mini-blog
- webstorm 给console.log设置快捷键
- 第2章 运算符&表达式&数据类型
- 创建一个数组, 实现函数init()初始化数组、 实现empty()清空数组、 实现reverse()函数完成数组元素的逆置。 要求:自己设计函数的参数,返回值。
- 初学者(一)Dictionary,ConcurrentDictionary,SortedDictionary
- 插入排序
- AngularJS输入内容到公告窗,敏感字以*代替
- 自定义可拖拽的父容器
- 数据库的基本构成和原理-2