登录
首页 >  数据库 >  MySQL

Node+Koa2+Mysql 搭建简易博客

来源:SegmentFault

时间:2023-02-16 15:27:47 469浏览 收藏

亲爱的编程学习爱好者,如果你点开了这篇文章,说明你对《Node+Koa2+Mysql 搭建简易博客》很感兴趣。本篇文章就来给大家详细解析一下,主要介绍一下MySQL、Node.js、javascript、koa.js,希望所有认真读完的童鞋们,都有实质性的提高。

Koa2-blog

2018-1-5 更新教程(新增上传头像、新增分页、样式改版、发布文章和评论支持markdown语法)
现在GitHub的代码结构有变现在GitHub的代码结构有变,接口名也有变动。

Node+Koa2+Mysql 搭建简易博客

预览地址

http://blog.wclimb.site

写在前面

本篇教程一方面是为了自己在学习的过程加深记忆,也是总结的过程。另一方面给对这方面不太了解的同学以借鉴经验。如发现问题还望指正,
如果你觉得这篇文章帮助到了你,那就赏脸给个star吧,https://github.com/wclimb/Koa...
下一篇可能是 Node + express + mongoose 或 zepto源码系列
感谢您的阅读^_^
ps:关于markdown代码缩进问题,看起来不太舒服,但复制到编辑器是正常的哟!

演示效果

img

开发环境

  • nodejs
    const Koa = require('koa');
    const path = require('path')
    const bodyParser = require('koa-bodyparser');
    const ejs = require('ejs');
    const session = require('koa-session-minimal');
    const MysqlStore = require('koa-mysql-session');
    const config = require('./config/default.js');
    const router=require('koa-router')
    const views = require('koa-views')
    // const koaStatic = require('koa-static')
    const staticCache = require('koa-static-cache')
    const 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(staticCache(path.join(__dirname, './public'), { dynamic: true }, {
      maxAge: 365 * 24 * 60 * 60
    }))
    app.use(staticCache(path.join(__dirname, './images'), { dynamic: true }, {
      maxAge: 365 * 24 * 60 * 60
    }))
    
    // 配置服务端模板渲染引擎中间件
    app.use(views(path.join(__dirname, './views'), {
      extension: 'ejs'
    }))
    app.use(bodyParser({
      formLimit: '1mb'
    }))
    
    //  路由(我们先注释三个,等后面添加好了再取消注释,因为我们还没有定义路由,稍后会先实现注册)
    //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())
    
    
    app.listen(3000)
    
    console.log(`listening on port ${config.port}`)
    

    我们使用

    // 注册用户
    let insertData = function( value ) {
      let _sql = "insert into users set name=?,pass=?,avator=?,moment=?;"
      return query( _sql, value )
    }

    我们写了一个_sql的sql语句,意思是插入到users的表中(在这之前我们已经建立了users表)然后要插入的数据分别是name、pass、avator、moment,就是用户名、密码、头像、注册时间,最后调用

    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) {
            reject( err )
          } else {
            connection.query(sql, values, ( err, rows) => {
    
              if ( err ) {
                reject( err )
              } else {
                resolve( rows )
              }
              connection.release()
            })
          }
        })
      })
    
    }
    
    
    // let query = function( sql, values ) {
    // pool.getConnection(function(err, connection) {
    //   // 使用连接
    //   connection.query( sql,values, function(err, rows) {
    //     // 使用连接执行查询
    //     console.log(rows)
    //     connection.release();
    //     //连接不再使用,返回到连接池
    //   });
    // });
    // }
    
    let users =
        `create table if not exists users(
         id INT NOT NULL AUTO_INCREMENT,
         name VARCHAR(100) NOT NULL,
         pass VARCHAR(100) NOT NULL,
         avator VARCHAR(100) NOT NULL,
         moment VARCHAR(100) NOT NULL,
         PRIMARY KEY ( id )
        );`
    
    let posts =
        `create table if not exists posts(
         id INT NOT NULL AUTO_INCREMENT,
         name VARCHAR(100) NOT NULL,
         title TEXT(0) NOT NULL,
         content TEXT(0) NOT NULL,
         md TEXT(0) NOT NULL,
         uid VARCHAR(40) NOT NULL,
         moment VARCHAR(100) NOT NULL,
         comments VARCHAR(200) NOT NULL DEFAULT '0',
         pv VARCHAR(40) NOT NULL DEFAULT '0',
         avator VARCHAR(100) NOT NULL,
         PRIMARY KEY ( id )
        );`
    
    let comment =
        `create table if not exists comment(
         id INT NOT NULL AUTO_INCREMENT,
         name VARCHAR(100) NOT NULL,
         content TEXT(0) NOT NULL,
         moment VARCHAR(40) NOT NULL,
         postid VARCHAR(40) NOT NULL,
         avator VARCHAR(100) 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 set name=?,pass=?,avator=?,moment=?;"
      return query( _sql, value )
    }
    // 删除用户
    let deleteUserData = function( name ) {
      let _sql = `delete from users where name="${name}";`
      return query( _sql )
    }
    // 查找用户
    let findUserData = function( name ) {
      let _sql = `select * from users where name="${name}";`
      return query( _sql )
    }
    // 发表文章
    let insertPost = function( value ) {
      let _sql = "insert into posts set name=?,title=?,content=?,md=?,uid=?,moment=?,avator=?;"
      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 set name=?,content=?,moment=?,postid=?,avator=?;"
      return query( _sql, value )
    }
    // 通过名字查找用户
    let findDataByName = function ( name ) {
      let _sql = `select * from users where name="${name}";`
      return query( _sql)
    }
    // 通过文章的名字查找用户
    let findDataByUser = function ( name ) {
      let _sql = `select * from posts where name="${name}";`
      return query( _sql)
    }
    // 通过文章id查找
    let findDataById = function ( id ) {
      let _sql = `select * from posts where 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 findPostByPage = function (page) {
      let _sql = ` select * FROM posts limit ${(page-1)*10},10;`
      return query( _sql)
    }
    // 查询个人分页文章
    let findPostByUserPage = function (name,page) {
      let _sql = ` select * FROM posts where name="${name}" order by id desc limit ${(page-1)*10},10 ;`
      return query( _sql)
    }
    // 更新修改文章
    let updatePost = function(values){
      let _sql = `update posts set  title=?,content=?,md=? 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)
    }
    
    // 滚动无限加载数据
    let findPageById = function(page){
      let _sql = `select * from posts limit ${(page-1)*5},5;`
      return query(_sql)
    }
    // 评论分页
    let findCommentByPage = function(page,postId){
      let _sql = `select * from comment where postid=${postId} order by id desc limit ${(page-1)*10},10;`
      return query(_sql)
    }
    
    module.exports = {
        query,
        createTable,
        insertData,
          deleteUserData,
          findUserData,
        findDataByName,
          insertPost,
          findAllPost,
          findPostByPage,
        findPostByUserPage,
        findDataByUser,
        findDataById,
        insertComment,
        findCommentById,
        updatePost,
        deletePost,
        deleteComment,
        findCommentLength,
        updatePostComment,
        deleteAllPostComment,
        updatePostPv,
        findPageById,
        findCommentByPage
    }
    
    

    下面是我们建的表

    users   posts   comment
      id     id     id  
      name     name     name  
      pass     title     content  
     avator    content       moment  
      moment    md       postid 
       -   uid       avator  
       -   moment       - 
        -  comments       -     
        -  pv       -      
        -   avator        -   
    • id主键递增
    • name: 用户名
    • pass:密码
    • avator:头像
    • title:文章标题
    • content:文章内容和评论
    • md:markdown语法
    • uid:发表文章的用户id
    • moment:创建时间
    • comments:文章评论数
    • pv:文章浏览数
    • postid:文章id

    现在感觉有点枯燥,那我们先来实现一下注册吧

    实现注册页面

    routers/singup.js

    const router = require('koa-router')();
    const userModel = require('../lib/mysql.js');
    const md5 = require('md5')
    const checkNotLogin = require('../middlewares/check.js').checkNotLogin
    const checkLogin = require('../middlewares/check.js').checkLogin
    const moment = require('moment');
    const fs = require('fs')
    // 注册页面
    router.get('/signup', async(ctx, next) => {
        await checkNotLogin(ctx)
        await ctx.render('signup', {
            session: ctx.session,
        })
    })
        
    module.exports = router

    使用get方式得到'/signup'页面,然后渲染signup模板,这里我们还没有在写signup.ejs

    views/signup.ejs

    
    
        注册
    预览头像
    注册

    我们先安装supervisor

    body,
    header,
    ul,
    li,
    p,
    div,
    html,
    span,
    h3,
    a,
    blockquote {
        margin: 0;
        padding: 0;
        color: #333;
    }
    
    body {
        margin-bottom: 20px;
    }
    ul,li{
        list-style-type: none;
    }
    a {
        text-decoration: none;
    }
    
    header {
        width: 60%;
        margin: 20px auto;
    }
    header:after{
        content: '';
        clear: both;
        display: table;
    }
    header .user_right{
        float: right
    }
    header .user_right .active{
        color: #5FB878;
        background: #fff;
        border: 1px solid #5FB878;
        box-shadow: 0 5px 5px #ccc;
    }
    header .user_name {
        float: left
    }
    .user_name {
        font-size: 20px;
    }
    
    .has_user a,
    .has_user span,
    .none_user a {
        padding: 5px 15px;
        background: #5FB878;
        border-radius: 15px;
        color: #fff;
        cursor: pointer;
        border: 1px solid #fff;
        transition: all 0.3s;
    }
    
    .has_user a:hover,.has_user span:hover{
        color: #5FB878;
        background: #fff;
        border: 1px solid #5FB878;
        box-shadow: 0 5px 5px #ccc;
    }
    
    .posts{
        border-radius: 4px; 
        border: 1px solid #ddd;
    }
    .posts > li{
        padding: 10px;
        position: relative;
        padding-bottom: 40px;
    }
    .posts .comment_pv{
        position: absolute;
        bottom: 5px;
        right: 10px;
    }
    .posts .author{
        position: absolute;
        left: 10px;
        bottom: 5px;
    }
    .posts .author span{
        margin-right: 5px;
    }
    .posts > li:hover {
        background: #f2f2f2;
    }
    .posts > li:hover pre{
        border: 1px solid #666;
    }
    .posts > li:hover .content{
        border-top: 1px solid #fff;
        border-bottom: 1px solid #fff;
    }
    .posts > li + li{
        border-top: 1px solid #ddd;
    }
    .posts li .title span{
        position: absolute;
        left: 10px;
        top: 10px;
        color: #5FB878;
        font-size: 14px;
    }
    .posts li .title{
         margin-left: 40px;
         font-size: 20px;
         color: #222;
    }
    .posts .userAvator{
        position: absolute;
        left: 3px;
        top: 3px;
        width: 40px;
        height: 40px;
        border-radius: 5px;
    }
    .posts .content{
        border-top: 1px solid #f2f2f2;
        border-bottom: 1px solid #f2f2f2;
        margin: 10px 0 0 0 ;
        padding: 10px 0;
        margin-left: 40px;
    }
    .userMsg img{
        width: 40px;
        height: 40px;
        border-radius: 5px;
        margin-right: 10px;
        vertical-align: middle;
        display: inline-block;
    }
    .userMsg span{
        font-size: 18px;
        color:#333;
        position: relative;
        top: 2px;
    }
    .posts li img{
        max-width: 100%;
    }
    .spost .comment_pv{
        position: absolute;
        top: 10px;
    }
    .spost .edit {
        position: absolute;
        right: 20px;
        bottom: 5px;
    }
    
    .spost .edit p {
        display: inline-block;
        margin-left: 10px;
    }
    
    .comment_wrap {
        width: 60%;
        margin: 20px auto;
    }
    
    .submit {
        display: block;
        width: 100px;
        height: 40px;
        line-height: 40px;
        text-align: center;
        border-radius: 4px;
        background: #5FB878;
        cursor: pointer;
        color: #fff;
        float: left;
        margin-top: 20px ;
        border:1px solid #fff;
    }
    .submit:hover{
        background: #fff;
        color: #5FB878;
        border:1px solid #5FB878;
    }
    .comment_list{
        border: 1px solid #ddd;
        border-radius: 4px;
    }
    .cmt_lists:hover{
        background: #f2f2f2;
    }
    .cmt_lists + .cmt_lists{
        border-top: 1px solid #ddd;
    }
    .cmt_content {
        padding: 10px;
        position: relative;
        border-radius: 4px;
        word-break: break-all;
    }
    .cmt_detail{
        margin-left: 48px;
    }
    .cmt_content img{
        max-width: 100%;
    }
    /* .cmt_content:after {
        content: '#content';
        position: absolute;
        top: 5px;
        right: 5px;
        color: #aaa;
        font-size: 13px;
    }
     */
    .cmt_name {
        position: absolute;
        right: 8px;
        bottom: 5px;
        color: #333;
    }
    
    .cmt_name a {
        margin-left: 5px;
        color: #1E9FFF;
    }
    .cmt_time{
        position: absolute;
        font-size: 12px;
        right: 5px;
        top: 5px;
        color: #aaa
    }
    .form {
        margin: 0 auto;
        width: 50%;
        margin-top: 20px;
    }
    
    textarea {
        width: 100%;
        height: 150px;
        padding:10px 0 0 10px;
        font-size: 20px;
        border-radius: 4px;   
        border: 1px solid #d7dde4;
        -webkit-appearance: none;
        resize: none;
    }
    
    textarea#spContent{
        width: 98%;
    }
    
    .tips {
        margin: 20px 0;
        color: #ec5051;
        text-align: center;
    }
    
    .container {
        width: 60%;
        margin: 0 auto;
    }
    .form img.preview {
        width:100px;
        height:100px;
        border-radius: 50%;
        display: none;
        margin-top:10px;
    }
    input {
        display: block;
        width: 100%;
        height: 35px;
        font-size: 18px;
        padding: 6px 7px;    
        border-radius: 4px;   
        border: 1px solid #d7dde4;
        -webkit-appearance: none;
    }
    
    input:focus,textarea:focus{
        outline: 0;
        box-shadow: 0 0 0 2px rgba(51,153,255,.2);
        border-color: #5cadff;
    }
    
    input:hover,input:active,textarea:hover,textarea:active{
        border-color: #5cadff;
    }
    
    .create label {
        display: block;
        margin: 10px 0;
    }
    
    .comment_wrap form {
        width: 100%;
        margin-bottom: 85px;
    }
    
    .delete_comment,
    .delete_post {
        cursor: pointer;
    }
    
    .delete_comment:hover,
    .delete_post:hover,
    a:hover {
        color: #ec5051;
    }
    .disabled{
        user-select: none;
        cursor: not-allowed !important;
    }
    .error{
        color: #ec5051;
    }
    .success{
        color: #1E9FFF;
    }
    .container{
        width: 60%;
        margin:0 auto;
    }
    .message{
        position: fixed;
        top: -100%;
        left: 50%;
        transform: translateX(-50%);
        padding: 10px 20px;
        background: rgba(0, 0, 0, 0.7);
        color: #fff;
        border-bottom-left-radius: 15px;
        border-bottom-right-radius: 15px;
        z-index: 99999;
    }
    .markdown pre{
        display: block;
        overflow-x: auto;
        padding: 0.5em;
        background: #F0F0F0;
        border-radius: 3px;
        border: 1px solid #fff;
    }
    .markdown blockquote{
        padding: 0 1em;
        color: #6a737d;
        border-left: 0.25em solid #dfe2e5;
        margin: 10px 0;
    }
    .markdown ul li{
        list-style: circle;
        margin-top: 5px;
    }

    我们再把模板引擎的header和footer独立出来

    /views/header.ejs
    顺便引入index.css和jq

    
    
        koa2-blog
    Hello, 欢迎注册登录^_^
    登录成功

    首先我们看到用到了session.user,这个值从哪来呢?请看下面的代码

    // 注册页面
    router.get('/signup', async(ctx, next) => {
        await checkNotLogin(ctx)
        await ctx.render('signup', {
            session: ctx.session,
        })
    })

    我们可以看到我们向模板传了一个session值,session:ctx.session,这个值存取的就是用户的信息,包括用户名、登录之后的id等,session一般是你关闭浏览器就过期了,等于下次打开浏览器的时候就得重新登录了,用if判断他存不存在,就可以知道用户是否需要登录,如果不存在用户,则只显示

        
    
    

    修改views/signup.ejs

        
    预览头像
    注册

    先看我们请求的url地址,是'/signup',为什么是这个呢?我们看下面这段代码(后面有完整的)

    router.post('/signup', async(ctx, next) => {
        //console.log(ctx.request.body)
        let user = {
            name: ctx.request.body.name,
            pass: ctx.request.body.password,
            repeatpass: ctx.request.body.repeatpass,
            avator: ctx.request.body.avator
        }
        ....
    }

    我们的请求方式是post,地址是

    const router = require('koa-router')();
    const userModel = require('../lib/mysql.js');
    const md5 = require('md5')
    const checkNotLogin = require('../middlewares/check.js').checkNotLogin
    const checkLogin = require('../middlewares/check.js').checkLogin
    const moment = require('moment');
    const fs = require('fs')
    // 注册页面
    router.get('/signup', async(ctx, next) => {
        await checkNotLogin(ctx)
        await ctx.render('signup', {
            session: ctx.session,
        })
    })
    // post 注册
    router.post('/signup', async(ctx, next) => {
        //console.log(ctx.request.body)
        let user = {
            name: ctx.request.body.name,
            pass: ctx.request.body.password,
            repeatpass: ctx.request.body.repeatpass,
            avator: ctx.request.body.avator
        }
        await userModel.findDataByName(user.name)
            .then(async (result) => {
                console.log(result)
                if (result.length) {
                    try {
                        throw Error('用户已经存在')
                    } catch (error) {
                        //处理err
                        console.log(error)
                    }
                    // 用户存在
                    ctx.body = {
                        data: 1
                    };;
                    
                } else if (user.pass !== user.repeatpass || user.pass === '') {
                    ctx.body = {
                        data: 2
                    };
                } else {
                    // ctx.session.user=ctx.request.body.name   
                    let base64Data = user.avator.replace(/^data:image\/\w+;base64,/, "");
                    let dataBuffer = new Buffer(base64Data, 'base64');
                    let getName = Number(Math.random().toString().substr(3)).toString(36) + Date.now()
                    await fs.writeFile('./public/images/' + getName + '.png', dataBuffer, err => { 
                        if (err) throw err;
                        console.log('头像上传成功') 
                    });            
                    await userModel.insertData([user.name, md5(user.pass), getName, moment().format('YYYY-MM-DD HH:mm:ss')])
                        .then(res=>{
                            console.log('注册成功',res)
                            //注册成功
                            ctx.body = {
                                data: 3
                            };
                        })
                }
            })
    })
    module.exports = router
    • 我们使用md5实现密码加密,长度是32位的
    • 使用我们之前说的
      router.get('/signup',async (ctx,next)=>{
          await ctx.render('signup',{
              session:ctx.session,
          })
      })

      这里就用到了ejs所需的session 我们通过渲染signup.ejs模板,将值ctx.session赋值给session,之后我们就可以在signup.ejs中使用了
      ejs的常用标签为:

      • const router = require('koa-router')();
        const userModel = require('../lib/mysql.js')
        const md5 = require('md5')
        const checkNotLogin = require('../middlewares/check.js').checkNotLogin
        const checkLogin = require('../middlewares/check.js').checkLogin
        
        router.get('/signin', async(ctx, next) => {
            await checkNotLogin(ctx)
            await ctx.render('signin', {
                session: ctx.session,
            })
        })
        module.exports=router

        修改 /views/signin.ejs

            
        登录

        修改 index.js 文件 把下面这段代码注释去掉,之前注释是因为我们没有写signin的路由,以免报错,后面还有文章页和登出页的路由,大家记住一下

        app.use(require('./routers/signin.js').routes())
        

        现在注册一下来看看效果吧

        const router = require('koa-router')();
        const userModel = require('../lib/mysql.js')
        const md5 = require('md5')
        const checkNotLogin = require('../middlewares/check.js').checkNotLogin
        const checkLogin = require('../middlewares/check.js').checkLogin
        
        router.get('/signin', async(ctx, next) => {
            await checkNotLogin(ctx)
            await ctx.render('signin', {
                session: ctx.session,
            })
        })
        
        router.post('/signin', async(ctx, next) => {
            console.log(ctx.request.body)
            let name = ctx.request.body.name;
            let pass = ctx.request.body.password;
        
            await userModel.findDataByName(name)
                .then(result => {
                    let res = result
                    if (name === res[0]['name'] && md5(pass) === res[0]['pass']) {
                        ctx.body = true
                        ctx.session.user = res[0]['name']
                        ctx.session.id = res[0]['id']
                        console.log('ctx.session.id', ctx.session.id)
                        console.log('session', ctx.session)
                        console.log('登录成功')
                    }else{
                        ctx.body = false
                        console.log('用户名或密码错误!')
                    }
                }).catch(err => {
                    console.log(err)
                })
        
        })
        
        module.exports = router

        我们进行登录操作,判断登录的用户名和密码是否有误,使用md5加密
        我们可以看到登录成功返回的结果是

            
        登录

        我们增加了ajax请求,在routers/signin.js里,我们设置如果登录失败就返回false,登录成功返回true

        const router = require('koa-router')();
        const userModel = require('../lib/mysql.js')
        const moment = require('moment')
        const checkNotLogin = require('../middlewares/check.js').checkNotLogin
        const checkLogin = require('../middlewares/check.js').checkLogin;
        const md = require('markdown-it')();  
        // 重置到文章页
        router.get('/', async(ctx, next) => {
            ctx.redirect('/posts')
        })
        // 文章页
        router.get('/posts', async(ctx, next) => {
            let res,
                postsLength,
                name = decodeURIComponent(ctx.request.querystring.split('=')[1]);
            if (ctx.request.querystring) {
                console.log('ctx.request.querystring', name)
                await userModel.findDataByUser(name)
                    .then(result => {
                        postsLength = result.length
                    })
                await userModel.findPostByUserPage(name,1)
                    .then(result => {
                        res = result
                    })
                await ctx.render('selfPosts', {
                    session: ctx.session,
                    posts: res,
                    postsPageLength:Math.ceil(postsLength / 10),
                })
            } else {
                await userModel.findPostByPage(1)
                    .then(result => {
                        //console.log(result)
                        res = result
                    })
                await userModel.findAllPost()
                    .then(result=>{
                        postsLength = result.length
                    })    
                await ctx.render('posts', {
                    session: ctx.session,
                    posts: res,
                    postsLength: postsLength,
                    postsPageLength: Math.ceil(postsLength / 10),
                    
                })
            }
        })
        // 首页分页,每次输出10条
        router.post('/posts/page', async(ctx, next) => {
            let page = ctx.request.body.page;
            await userModel.findPostByPage(page)
                    .then(result=>{
                        //console.log(result)
                        ctx.body = result   
                    }).catch(()=>{
                    ctx.body = 'error'
                })  
        })
        // 个人文章分页,每次输出10条
        router.post('/posts/self/page', async(ctx, next) => {
            let data = ctx.request.body
            await userModel.findPostByUserPage(data.name,data.page)
                    .then(result=>{
                        //console.log(result)
                        ctx.body = result   
                    }).catch(()=>{
                    ctx.body = 'error'
                })  
        })
        module.exports = router

        修改 index.js

        app.use(require('./routers/posts.js').routes())的注释去掉

        修改 views/posts.ejs

        const 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())的注释去掉,现在把注释的路由全部取消注释就对了

        然后我们看看

        // 发表文章页面
        router.get('/create', async(ctx, next) => {
            await ctx.render('create', {
                session: ctx.session,
            })
        })
        
        // post 发表文章
        router.post('/create', async(ctx, next) => {
            let title = ctx.request.body.title,
                content = ctx.request.body.content,
                id = ctx.session.id,
                name = ctx.session.user,
                time = moment().format('YYYY-MM-DD HH:mm:ss'),
                avator,
                // 现在使用markdown不需要单独转义
                newContent = content.replace(/[']/g, (target) => { 
                    return {
                        '': '>',
                        "'": '''
                    }[target]
                }),
                newTitle = title.replace(/[']/g, (target) => {
                    return {
                        '': '>',
                        "'": '''
                    }[target]
                });
        
            //console.log([name, newTitle, content, id, time])
            await userModel.findUserData(ctx.session.user)
                .then(res => {
                    console.log(res[0]['avator'])
                    avator = res[0]['avator']       
                })
            await userModel.insertPost([name, newTitle, md.render(content), content, id, time,avator])
                    .then(() => {
                        ctx.body = true
                    }).catch(() => {
                        ctx.body = false
                    })
        
        })

        修改 views/create.ejs

        create.ejs

        img

        发表

        现在看看能不能发表吧

        即使我们发表了文章,但是当前我们的posts的页面没有显示,因为还没有获取到数据

        我们可以看我们之前写的代码

        if (ctx.request.querystring) {
            ...
        }else {
                await userModel.findPostByPage(1)
                    .then(result => {
                        //console.log(result)
                        res = result
                    })
                await userModel.findAllPost()
                    .then(result=>{
                        postsLength = result.length
                    })    
                await ctx.render('posts', {
                    session: ctx.session,
                    posts: res,
                    postsLength: postsLength,
                    postsPageLength: Math.ceil(postsLength / 10),
                    
                })
            }

        if前面这部分我们先不用管,后面会说。只需要看else后面的代码我们通过

            

        现在点击单篇文章试试,进入单篇文章页面,但是编辑、删除、评论都还没有做,点击无效,我们先不做,先实现每个用户自己发表的文章列表,我们之前在 get '/posts' 里面说先忽略if (ctx.request.querystring) {}里面的代码,这里是做了一个处理,假如用户点击了某个用户,该用户发表了几篇文章,我们需要只显示该用户发表的文章,那么进入的url应该是 /posts?author=xxx ,这个处理在posts.ejs 就已经加上了,就在文章的左下角,作者:xxx就是一个链接。我们通过判断用户来查找文章,继而有了

        if (ctx.request.querystring) {
                console.log('ctx.request.querystring', name)
                await userModel.findDataByUser(name)
                    .then(result => {
                        postsLength = result.length
                    })
                await userModel.findPostByUserPage(name,1)
                    .then(result => {
                        res = result
                    })
                await ctx.render('selfPosts', {
                    session: ctx.session,
                    posts: res,
                    postsPageLength:Math.ceil(postsLength / 10),
                })
            }

        修改 selfPost.ejs

            
      • ' ) }) }else{ alert('分页不存在') } } }) })

        编辑文章、删除文章、评论、删除评论

        评论

        修改routers/posts.js

        在post.js 后面增加

      // 发表评论
      router.post('/:postId', async(ctx, next) => {
          let name = ctx.session.user,
              content = ctx.request.body.content,
              postId = ctx.params.postId,
              res_comments,
              time = moment().format('YYYY-MM-DD HH:mm:ss'),
              avator;
          await userModel.findUserData(ctx.session.user)
              .then(res => {
                  console.log(res[0]['avator'])
                  avator = res[0]['avator']
              })   
          await userModel.insertComment([name, md.render(content),time, postId,avator])
          await userModel.findDataById(postId)
              .then(result => {
                  res_comments = parseInt(result[0]['comments'])
                  res_comments += 1
              })
          await userModel.updatePostComment([res_comments, postId])
              .then(() => {
                  ctx.body = true
              }).catch(() => {
                  ctx.body = false
              })
      })
      // 评论分页
      router.post('/posts/:postId/commentPage', async function(ctx){
          let postId = ctx.params.postId,
              page = ctx.request.body.page;
          await userModel.findCommentByPage(page,postId)
              .then(res=>{
                  ctx.body = res
              }).catch(()=>{
                  ctx.body = 'error'
              })  
      })

      现在试试发表评论的功能吧,之所以这样简单,因为我们之前就在sPost.ejs做了好几个ajax的处理,删除文章和评论也是如此
      评论我们也做了分页,所以后面会有一个评论的分页的接口,我们已经在sPost.ejs里面写好了ajax请求

      删除评论

      修改routers/posts.js

      继续在post.js 后面增加

      // 删除评论
      router.post('/posts/:postId/comment/:commentId/remove', async(ctx, next) => {
          let postId = ctx.params.postId,
              commentId = ctx.params.commentId,
              res_comments;
          await userModel.findDataById(postId)
              .then(result => {
                  res_comments = parseInt(result[0]['comments'])
                  //console.log('res', res_comments)
                  res_comments -= 1
                  //console.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 后面增加

      // 删除单篇文章
      router.post('/posts/:postId/remove', async(ctx, next) => {
          let postId = ctx.params.postId
          await userModel.deleteAllPostComment(postId)
          await userModel.deletePost(postId)
              .then(() => {
                  ctx.body = {
                      data: 1
                  }
              }).catch(() => {
                  ctx.body = {
                      data: 2
                  }
              })
      })

      现在试试删除文章的功能吧

      编辑文章

      修改routers/posts.js

      继续在post.js 后面增加

      // 编辑单篇文章页面
      router.get('/posts/:postId/edit', async(ctx, next) => {
          let name = ctx.session.user,
              postId = ctx.params.postId,
              res;
          await userModel.findDataById(postId)
              .then(result => {
                  res = result[0]
                  //console.log('修改文章', res)
              })
          await ctx.render('edit', {
              session: ctx.session,
              postsContent: res.md,
              postsTitle: res.title
          })
      
      })
      
      // post 编辑单篇文章
      router.post('/posts/:postId/edit', async(ctx, next) => {
          let title = ctx.request.body.title,
              content = ctx.request.body.content,
              id = ctx.session.id,
              postId = ctx.params.postId,
               // 现在使用markdown不需要单独转义
              newTitle = title.replace(/[']/g, (target) => {
                  return {
                      '': '>',
                      "'": '''
                  }[target]
              }),
              newContent = content.replace(/[']/g, (target) => {
                  return {
                      '': '>',
                      "'": '''
                  }[target]
              });
          await userModel.updatePost([newTitle, md.render(content), content, postId])
              .then(() => {
                  ctx.body = true
              }).catch(() => {
                  ctx.body = false
              })
      })
      

      修改views/edit.js

      修改

      现在试试编辑文字然后修改提交吧

      结语

      至此一个简单的blog就已经制作好了,其他扩展功能相信你已经会了吧!如果出现问题,还望积极提问哈,我会尽快处理的

      所有的代码都在 https://github.com/wclimb/Koa... 里面,如果觉得不错就star一下吧。有问题可以提问哟
      下一篇可能是 Node + express + mongoose 或 zepto源码系列
      感谢您的阅读^_^

      到这里,我们也就讲完了《Node+Koa2+Mysql 搭建简易博客》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于mysql的知识点!

声明:本文转载于:SegmentFault 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>