本文将详细讲解使用node+koa2+mysql搭建博客后台的全过程。

开发环境

node 8.3.0及以上

npm 5.3.0及以上

mysql 5.7.21

具体的环境配置可查看我的上一篇文章

准备工作

npm下载pm2(进程守护),并设置全局变量

创建博客需要的数据库与表

开启mysql并创建数据库test: create database test;

切换到数据库testuse tests;,输入命令创建以下数据表:

//系统管理员表 t_user

CREATE TABLE `t_user` (

`uid` int(11) unsigned NOT NULL AUTO_INCREMENT,

`name` varchar(20) DEFAULT NULL COMMENT '姓名',

`password` varchar(50) NOT NULL COMMENT '密码',

`create_time` datetime NOT NULL COMMENT '注册时间',

`update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',

`is_delete` tinyint(1) DEFAULT '0',

PRIMARY KEY (`uid`),

UNIQUE KEY `name` (`name`) USING BTREE

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

//笔记本表 t_note

CREATE TABLE `t_note` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`name` varchar(20) DEFAULT NULL COMMENT '笔记本名',

`uid` int(11) NOT NULL COMMENT 'uid',

`create_time` datetime NOT NULL COMMENT '创建时间',

`update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',

`is_delete` tinyint(1) DEFAULT '0',

PRIMARY KEY (`id`),

UNIQUE KEY `name` (`name`) USING BTREE

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

//博客记录表 t_blog

CREATE TABLE `t_blog` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`title` varchar(200) DEFAULT NULL COMMENT '标题',

`uid` int(11) DEFAULT '1' COMMENT 'uid',

`content` text COMMENT '内容',

`create_time` datetime NOT NULL COMMENT '注册时间',

`update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',

`note_id` varchar(45) DEFAULT NULL,

`publish` tinyint(4) DEFAULT '0' COMMENT '是否发布',

`brief` text,

`is_delete` tinyint(1) DEFAULT '0' COMMENT '是否删除',

`ext_info` text,

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

//图片上传记录表 t_img

CREATE TABLE `t_img` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`uid` int(11) NOT NULL COMMENT 'uid',

`create_time` datetime NOT NULL COMMENT '注册时间',

`update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',

`name` varchar(40) DEFAULT NULL,

`is_delete` tinyint(1) DEFAULT '0',

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

复制代码

node后台目录创建及npm包安装

创建项目文件夹server,进入文件夹后初始化项目npm init。

在项目下创建以下文件夹和文件

安装以下依赖包:

koa node框架

koa-bodyparser 表单解析中间件

koa-router 路由框架

koa-session 基于koa的session模块

mysql 数据库

md5 md5加密

async-busboy 带文件的表单解析模块

is 数据格式校验插件

node连接mysql

db/index.js配置文件如下:

var mysql = require('mysql');

let config = {

host : 'localhost',

user : 'root',

password : '123456',

database : 'test',

port:3306,

multipleStatements: true//允许多条sql同时执行

};

let pool = mysql.createPool(config);

let query = (sql, values) => {

return new Promise((resolve, reject) => {

pool.getConnection((err, connection) => {

if (err) {

reject(err)

} else {

connection.query(sql, values, (err, rows) => {

if (err) {

reject(err)

} else {

resolve(rows)

}

connection.end()

})

}

})

})

};

module.exports = {

query

}

复制代码

其他配置

框架公用方法,包括参数校验、登录态校验等。config/index.js

路由 Rouer

以上配置完成后,便可以开始写设计路由了。

引入相关配置

const router = require('koa-router')();

const Utils = require('../utils');

const Tips = require('../utils/tip');

const db = require('../db');

复制代码

根据表设计路由

user表 -> user.js 管理员管理,可登录、查询登录态、退出登录

note表 -> note.js 笔记本管理,可添加、修改、删除,查询笔记本列表

blog表 -> blog.js 博客管理 可添加、修改、删除、查询博客列表。每篇博客必须关联对应的笔记本。可根据笔记本查询博客列表

img表 -> img.js 图片管理,可上传、删除、查询图片列表

具体路由部分实现内容

注意:所有的删除操作均为将表字段is_delete设置为1即可,方便恢复数据

user.js 管理员

登录

router.post('/oa/login', async (ctx, next) => {

let data = Utils.filter(ctx.request.body, ['name', 'password']);

let res = Utils.formatData(data,[

{key:'name',type:'string'},

{key:'password',type:'string'}

]);

if(!res) return ctx.body = Tips[1007];

let { name, password } = data;

let sql = 'SELECT uid FROM t_user WHERE name=? and password=? and is_delete=0', value = [name, md5(password)];

await db.query(sql, value).then(res => {

if (res && res.length > 0) {

let val = res[0];

let uid = val['uid']

ctx.session.uid = uid;

ctx.cookies.set('uid', uid, {

maxAge:86400000,

httpOnly: true

});

ctx.body = {...Tips[0],data:{uid}};

} else {

ctx.body = Tips[1006];

}

}).catch(e => {

ctx.body = Tips[1002];

})

});

复制代码查询登录信息

router.get('/oa/user/auth', async (ctx, next) => {

let uid = ctx.session.uid;

let sql = 'SELECT name,uid,nick_name FROM t_user WHERE uid=? AND is_delete=0', value = [uid];

await db.query(sql, value).then(res => {

if (res && res.length > 0) {

ctx.body = { ...Tips[0], data: res[0] };

} else {

ctx.body = Tips[1005];

}

}).catch(e => {

ctx.body = Tips[1005];

})

});

复制代码

note.js 笔记本管理

创建笔记本

router.post('/oa/user/addNote',async (ctx,next)=>{

let data = Utils.filter(ctx.request.body, ['name']);

let {name} = data, uid = ctx.session.uid;

let res = Utils.formatData(data, [

{key: 'name', type: 'string'}

]);

if (! res) return ctx.body = Tips[1007];

let create_time = Utils.formatCurrentTime();

let sql = `INSERT INTO t_note(name,uid,create_time) VALUES(?,?,?)`,

value = [name, uid, create_time];

await db.query(sql, value).then(res => {

let {insertId: id} = res;

if (id) {

ctx.body = {

...Tips[0],

data: {

id

}

}

} else {

ctx.body = Tips[1002]

}

}).catch(e => {

if(+e.errno === 1062){//笔记本不能重复

ctx.body = {

code: 1010,

msg: '笔记本已存在!'

};

}else{

ctx.body = Tips[1002]

}

})

});

复制代码(分页)查询笔记本列表

router.get('/oa/user/myNote', async (ctx, next) => {

let data = Utils.filter(ctx.request.query, ['pageSize', 'pageNum', 'type']), uid = ctx.session.uid;

let res = Utils.formatData(data, [

{key: 'type', type: 'number'},

]);

if (! res) return ctx.body = Tips[1007];

let {pageSize = 15, pageNum = 1, type = 0} = data;

pageSize = Number(pageSize);

pageNum = Number(pageNum);

let offset = (pageNum - 1) * pageSize;

let sql1 = `SELECT count(1) FROM t_note WHERE uid=${uid} AND is_delete=0;`,

sql= `SELECT name,id,create_time,update_time FROM t_note WHERE uid=${uid} AND is_delete=0 ORDER BY create_time DESC`;

if(+type === 1){

sql += ` limit ${offset},${pageSize};`

}

await db.query(sql1+sql).then(async result => {

let res1 = result[0],res2 = result[1],total = 0,list = []

if(res1 && res1.length >0 && res2 && res2.length >0){

total = res1[0]['count(1)']

list = res2

}

ctx.body = {

...Tips[0],

data: {

list,

pageSize,

total

}

};

}).catch(e => {

ctx.body = Tips[1002];

})

});

复制代码

blog.js 博客

创建博客

router.post('/oa/user/addBlog', async (ctx, next) => {

let data = Utils.filter(ctx.request.body, ['title', 'content', 'tag_id', 'note_id', 'brief', 'publish', 'create_time']),

uid = ctx.session.uid;

let res = Utils.formatData(data, [

{key: 'note_id', type: 'number'},

{key: 'title', type: 'string'},

{key: 'brief', type: 'string'},

{key: 'content', type: 'string'},

{key: 'publish', type: 'number'}

]);

if (! res) return ctx.body = Tips[1007];

let {title = '无标题', content = '', note_id = '', brief = '', publish = 0, create_time = ''} = data;

create_time = Utils.formatCurrentTime(create_time);

let sql = `INSERT INTO t_blog(title,content,note_id,create_time,uid,brief,publish) VALUES (?,?,?,?,?,?,?)`,

value = [title, content, note_id, create_time, uid, brief, publish];

await db.query(sql, value).then(async res => {

let {insertId: id} = res;

ctx.body = {

...Tips[0],

data: {id}

}

}).catch(e => {

ctx.body = Tips[1002];

});

});

复制代码分页查询博客,与笔记本列表查询类似

img.js 图片管理

上传图片

router.post('/oa/user/upFiles', async (ctx, next) => {

try {

let data = await asyncBusboy(ctx.req), uid = ctx.session.uid;

let { files = [] } = data;

if(files.length === 0) return ctx.body = Tips[1002];

let file = files[0];

let { mimeType = '', filename, path: filepath } = file;

if(mimeType.indexOf('image') === -1) return ctx.body = Tips[1002];

let name = Date.now() + '.' + filename.split('.').pop();

let savePath = path.join(__dirname, `../../img/${name}`);

try {

let create_time = Utils.formatCurrentTime();

let sql = 'INSERT INTO t_user_img(name,uid,create_time) VALUES (?,?,?)', value = [name, uid, create_time];

await db.query(sql, value).then(res => {

let img = fs.readFileSync(filepath);

fs.writeFileSync(savePath, img);

fs.unlinkSync(filepath);//清除缓存文件

ctx.body = {

...Tips[0], data: { name }

};

}).catch(() => {

ctx.body = Tips[1002];

})

} catch (e) {

ctx.body = Tips[1005];

}

} catch (e) {

ctx.body = Tips[1002];

}

});

复制代码

2.删除图片

router.post('/oa/user/removeImg', async (ctx, next) => {

let data = Utils.filter(ctx.request.body, ['name']), uid = ctx.session.uid;

let res = Utils.formatData(data, [

{ key: 'name', type: 'string' }

]);

if (!res) return ctx.body = Tips[1007];

let { name } = data;

let sql = 'UPDATE t_user_img set is_delete=1 WHERE name=? AND uid=?;', value = [name, uid];

await db.query(sql, value).then(res => {

fs.unlinkSync(path.join(__dirname, `../../img/${name}`));//清除缓存文件

ctx.body = Tips[0];

}).catch(() => {

ctx.body = Tips[1002];

})

});

复制代码图片列表查询同笔记本列表查询

路由统一管理

router/index.js将所有的路由集成并挂载至app.js

router/index.js

const user = require('./user');

const note = require('./note');

const blog = require('./blog');

const img = require('./img');

module.exports = function(app){

app.use(user.routes()).use(user.allowedMethods());

app.use(note.routes()).use(note.allowedMethods());

app.use(blog.routes()).use(blog.allowedMethods());

app.use(img.routes()).use(img.allowedMethods());

}

复制代码

app.js(对需要登录的路由统一管理)

const http = require('http');

const koa = require('koa');

const etag = require('koa-etag');

const session = require('koa-session');

const bodyParser = require('koa-bodyparser');

const errorHandler = require('koa-error');

const compress = require('koa-compress');

const PORT = process.env.PORT || 8080;

const koaBody = require('koa-body');

const app = new koa();

const Utils = require('./utils');

const router = require('./router');

app.keys = ['session@&'];

app.use(session({

key: 'abc::sess',

maxAge: 86400000,

overwrite: true,

httpOnly: true,

signed: true,

rolling: false

}, app));

app.use(koaBody());

app.use(async(ctx, next) => {

let {url = ''} = ctx;

if(url.indexOf('/oa/user/') >-1){//需要校验登录态

let check = Utils.checkLogin(ctx);

if(check.code != 0) return ctx.body = check;

}

await next();

});

app.use(errorHandler());

app.use(bodyParser());

app.use(etag());

// compressor

app.use(compress({

filter: contentType => /text|javascript/i.test(contentType),

threshold: 2048

}));

router(app);

http.createServer(app.callback()).listen(PORT);

log('server is running on port: %s', PORT);

复制代码

以上便是后台搭建全过程,点此查看后台源码。

node mysql和koa_node+koa2+mysql搭建博客后台相关推荐

  1. node+koa2+mysql搭建博客后台

    本文将详细讲解使用node+koa2+mysql搭建博客后台的全过程. 开发环境 node 8.3.0及以上 npm 5.3.0及以上 mysql 5.7.21 具体的环境配置可查看我的上一篇文章 准 ...

  2. mysql与citespace_CiteSpace与MySQL数据库的连接-科学网—博客.PDF

    CiteSpace与MySQL数据库的连接-科学网-博客.PDF CiteSpace与MySQL数据库的连接 1,2 3 李杰 ,陈超美 1.上海海事大学海洋科学与工程学院 2.上海海事大学科技情报研 ...

  3. 基于SSM+SpringBoot+MySQL+Vue前后端分离的博客论坛系统

    项目运行截图 系统首页 技术描述 开发工具: idea/eclipse 数据库: mysql Jar包仓库: Maven 前段框架: vue/ElementUI/echart 后端框架: spring ...

  4. 建站规划—基于私有化gitlab/node+hexo搭建博客网站

    目录 概述 建站方案及成本 建站方案 成本 低成本替代方案 概述 本合辑(建站合辑)将介绍如何基于私有化gitlab+pages+Hexo搭建博客网站,由于域名备案周期较长,因此更新可能较慢.根据功能 ...

  5. Ghost 搭建博客小记

    前言 点击 我用 Ghost 搭建的博客 查看成品示例. 早就听说 Ghost 的大名了,不过一直都是处于观望状态.主要是想等 Ghost 各方面再成熟一些,所以迟迟没有行动.最近听闻 Ghost 已 ...

  6. Vue、Node全栈项目~面向小白的博客系统~

    个人博客系统 前言 ❝ 代码质量问题轻点喷(去年才学的前端),有啥建议欢迎联系我,联系方式见最下方,感谢! 页面有啥bug也可以反馈给我,感谢! 这是一套包含前后端代码的个人博客系统,欢迎各位提出建议 ...

  7. 详解Hexo搭建博客的底层原理

    文章目录 前言 Github page Hexo 工作原理 每次部署的流程 模板引擎--Hexo怎样生成HTML 数据填充 配置文件中的数据 配置文件中数据的使用 总结 前言 在2021年初对照着攻略 ...

  8. 《全栈营销之如何制作个人博客》之二:php环境安装及个人博客后台搭建 让你的博客跑起来...

    上一节我们讲了个人博客用什么开发语言,用什么CMS系统,从这一节我们就开始真正的干货,这一节我们讨论一下PHP环境的安装,及个人博客后台的搭建,让你的博客在正常的PHP环境中运行起来,你就可以进行后台 ...

  9. 使用Docker 实现微服务并搭建博客,一文全掌握

    转载自  使用Docker 实现微服务并搭建博客,一文全掌握 Docker 是一个容器工具,提供虚拟环境.很多人认为,它改变了我们对软件的认识. 本文,通过搭建一个博客的例子,来介绍如何使用Docke ...

最新文章

  1. Linux 磁盘挂载
  2. apk修改strings.xml后重新打包出错
  3. [NOIP2014] 解方程
  4. 如何在window上把你的项目提交到github
  5. MySQL 常见索引的使用场景与区别(SQL小技巧)
  6. vue ----vue-cli
  7. 深度学习基础(三)—— 权值矩阵的初始化
  8. JavaEE学习14(应用)--用户自动登陆
  9. Java拦截器实现拦截controller方法
  10. 想批量转换音频?来试试这几个会议录音转文字软件
  11. Jquery Uploadify之Java获取动态传参参数
  12. 在线定时任务表达式生成连接
  13. 一款超好用的开源密码管理器?
  14. 文字下划线从中间往两头延伸动画
  15. Python3 歌词解析的练习
  16. 急性心机梗护理查房PPT模板
  17. POJ 1584 计算几何 凸包
  18. 话说13款浏览器哪个好?
  19. TIMO 后台管理系统 v2.0 发布,带来全新的项目结构,支持前后台模块分离部署!...
  20. echarts主题配置

热门文章

  1. 使用Spark Streaming进行情感分析
  2. oVirt guest | VM HOST HA in one Cluster
  3. 这样就算会了PHP么?-7
  4. HBase安装笔记一Hadoop
  5. Rman 非catalog恢复
  6. ubuntu下Pure-FTPd的安装和配置
  7. ADO.NET Entity Framework支持多Provider
  8. Linux 命令(115)—— rev 命令
  9. 列出搜索过的数据(类似京东顶部搜索框)
  10. 那些让程序员提升30-80%的快捷键大全整理