日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

node+koa2+mysql搭建博客后台

發(fā)布時(shí)間:2023/12/10 数据库 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 node+koa2+mysql搭建博客后台 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文將詳細(xì)講解使用node+koa2+mysql搭建博客后臺的全過程。

開發(fā)環(huán)境

  • node 8.3.0及以上
  • npm 5.3.0及以上
  • mysql 5.7.21

具體的環(huán)境配置可查看我的上一篇文章

準(zhǔn)備工作

  • npm下載pm2(進(jìn)程守護(hù)),并設(shè)置全局變量
  • 創(chuàng)建博客需要的數(shù)據(jù)庫與表
  • 開啟mysql并創(chuàng)建數(shù)據(jù)庫test: create database test;
  • 切換到數(shù)據(jù)庫testuse tests;,輸入命令創(chuàng)建以下數(shù)據(jù)表:
//系統(tǒng)管理員表 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 '注冊時(shí)間',`update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時(shí)間',`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 '創(chuàng)建時(shí)間',`update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時(shí)間',`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 '標(biāo)題',`uid` int(11) DEFAULT '1' COMMENT 'uid',`content` text COMMENT '內(nèi)容',`create_time` datetime NOT NULL COMMENT '注冊時(shí)間',`update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時(shí)間',`note_id` varchar(45) DEFAULT NULL,`publish` tinyint(4) DEFAULT '0' COMMENT '是否發(fā)布',`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 '注冊時(shí)間',`update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時(shí)間',`name` varchar(40) DEFAULT NULL,`is_delete` tinyint(1) DEFAULT '0',PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;復(fù)制代碼

node后臺目錄創(chuàng)建及npm包安裝

  • 創(chuàng)建項(xiàng)目文件夾server,進(jìn)入文件夾后初始化項(xiàng)目npm init。
  • 在項(xiàng)目下創(chuàng)建以下文件夾和文件
  • 安裝以下依賴包:
  • koa node框架
  • koa-bodyparser 表單解析中間件
  • koa-router 路由框架
  • koa-session 基于koa的session模塊
  • mysql 數(shù)據(jù)庫
  • md5 md5加密
  • async-busboy 帶文件的表單解析模塊
  • is 數(shù)據(jù)格式校驗(yàn)插件

node連接mysql

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

var mysql = require('mysql'); let config = {host : 'localhost',user : 'root',password : '123456',database : 'test',port:3306,multipleStatements: true//允許多條sql同時(shí)執(zhí)行 }; 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 } 復(fù)制代碼

其他配置

  • 框架公用方法,包括參數(shù)校驗(yàn)、登錄態(tài)校驗(yàn)等。config/index.js
  • 框架接口返回碼規(guī)范 config/tip.js

路由 Rouer

以上配置完成后,便可以開始寫設(shè)計(jì)路由了。

引入相關(guān)配置

const router = require('koa-router')(); const Utils = require('../utils'); const Tips = require('../utils/tip'); const db = require('../db'); 復(fù)制代碼

根據(jù)表設(shè)計(jì)路由

  • user表 -> user.js 管理員管理,可登錄、查詢登錄態(tài)、退出登錄
  • note表 -> note.js 筆記本管理,可添加、修改、刪除,查詢筆記本列表
  • blog表 -> blog.js 博客管理 可添加、修改、刪除、查詢博客列表。每篇博客必須關(guān)聯(lián)對應(yīng)的筆記本。可根據(jù)筆記本查詢博客列表
  • img表 -> img.js 圖片管理,可上傳、刪除、查詢圖片列表

具體路由部分實(shí)現(xiàn)內(nèi)容

注意:所有的刪除操作均為將表字段is_delete設(shè)置為1即可,方便恢復(fù)數(shù)據(jù)

  • 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];})});復(fù)制代碼
  • 查詢登錄信息
  • 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];}) }); 復(fù)制代碼
  • note.js 筆記本管理

  • 創(chuàng)建筆記本
  • 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){//筆記本不能重復(fù)ctx.body = {code: 1010,msg: '筆記本已存在!'};}else{ctx.body = Tips[1002]}}) }); 復(fù)制代碼
  • (分頁)查詢筆記本列表
  • 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];})}); 復(fù)制代碼
  • blog.js 博客

  • 創(chuàng)建博客
  • 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 = '無標(biāo)題', 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];});}); 復(fù)制代碼
  • 分頁查詢博客,與筆記本列表查詢類似
  • 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];} }); 復(fù)制代碼

    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];})}); 復(fù)制代碼
  • 圖片列表查詢同筆記本列表查詢

路由統(tǒng)一管理

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()); }復(fù)制代碼
  • app.js(對需要登錄的路由統(tǒng)一管理)

    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){//需要校驗(yàn)登錄態(tài)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); 復(fù)制代碼

以上便是后臺搭建全過程,點(diǎn)此查看后臺源碼。

閱讀原文

前端項(xiàng)目源碼

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的node+koa2+mysql搭建博客后台的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。