1.1 安装koa-generator
$ npm install -g koa-generator
1.2 使用koa-generator生成koa2项目
koa2 -e project(项目名称) (-e 代表使用模板引擎ejs) -e 可以不加
1.3 进入项目
$ cd project
$ npm install
app.js
包括链接redis、morgan日志、 session 配置 一定要在注册路由之前写
const Koa = require('koa')
const app = new Koa()
const views = require('koa-views')
const json = require('koa-json') // 处理json
const onerror = require('koa-onerror') // 处理错误
const bodyparser = require('koa-bodyparser') // post data
const logger = require('koa-logger') // 比较简单、美观的日志
const session = require('koa-generic-session') // 插件一 链接redis
const redisStore = require('koa-redis') // 插件二 链接redis
const path = require('path')
const fs = require('fs')
const morgan = require('koa-morgan') // morgan 日志
const index = require('./routes/index')
const users = require('./routes/users')
const blog = require('./routes/blog')
const user = require('./routes/user')
const { REDIS_CONF } = require('./conf/db')
// error handler
onerror(app)
// middlewares
app.use(bodyparser({
enableTypes:['json', 'form', 'text']
}))
app.use(json())
app.use(logger())
app.use(require('koa-static')(__dirname + '/public'))
app.use(views(__dirname + '/views', {
extension: 'pug'
}))
// logger 看当前请求的服务耗时
app.use(async (ctx, next) => {
const start = new Date()
await next()
const ms = new Date() - start
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
})
const ENV = process.env.NODE_ENV
if (ENV !== 'production') {
// 开发环境 / 测试环境
app.use(morgan('dev'));
} else {
// 线上环境
const logFileName = path.join(__dirname, 'logs', 'access.log')
const writeStream = fs.createWriteStream(logFileName, {
flags: 'a'
})
app.use(morgan('combined', {
stream: writeStream
}));
}
// session 配置 一定要在注册路由之前写
app.keys = ['WJiol#23123_']
app.use(session({
// 配置 cookie
cookie: {
path: '/',
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000
},
// 配置 redis
store: redisStore({
// all: '127.0.0.1:6379' // 写死本地的 redis
all: `${REDIS_CONF.host}:${REDIS_CONF.port}`
})
}))
// routes
app.use(index.routes(), index.allowedMethods())
app.use(users.routes(), users.allowedMethods())
app.use(blog.routes(), blog.allowedMethods())
app.use(user.routes(), user.allowedMethods())
// error-handling
app.on('error', (err, ctx) => {
console.error('server error', err, ctx)
});
module.exports = app
package.json
{
"name": "blog-koa2",
"version": "0.1.0",
"private": true,
"scripts": {
"start": "node bin/www",
"dev": "cross-env NODE_ENV=dev ./node_modules/.bin/nodemon bin/www",
"prd": "cross-env NODE_ENV=production pm2 start bin/www",
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"debug": "^2.6.3",
"koa": "^2.2.0",
"koa-bodyparser": "^3.2.0",
"koa-convert": "^1.2.0",
"koa-generic-session": "^2.0.1",
"koa-json": "^2.0.2",
"koa-logger": "^2.0.1",
"koa-morgan": "^1.0.1",
"koa-onerror": "^1.2.1",
"koa-redis": "^3.1.3",
"koa-router": "^7.1.1",
"koa-static": "^3.0.0",
"koa-views": "^5.2.1",
"mysql": "^2.16.0",
"pug": "^2.0.0-rc.1",
"redis": "^2.8.0",
"xss": "^1.0.3"
},
"devDependencies": {
"cross-env": "^5.2.0",
"nodemon": "^1.8.1"
}
}
介绍koa2 async\await 以及拆分出来的路由
mysql.js
const mysql = require('mysql')
const { MYSQL_CONF } = require('../conf/db')
// 创建链接对象
const con = mysql.createConnection(MYSQL_CONF)
// 开始链接
con.connect()
// 统一执行 sql 的函数
function exec(sql) {
const promise = new Promise((resolve, reject) => {
con.query(sql, (err, result) => {
if (err) {
reject(err)
return
}
resolve(result)
})
})
return promise
}
module.exports = {
exec,
escape: mysql.escape
}
controller/blog.js
const xss = require('xss')
const { exec } = require('../db/mysql')
const getList = async (author, keyword) => {
let sql = `select * from blogs where 1=1 `
if (author) {
sql += `and author='${author}' `
}
if (keyword) {
sql += `and title like '%${keyword}%' `
}
sql += `order by createtime desc;`
return await exec(sql)
}
const getDetail = async (id) => {
const sql = `select * from blogs where id='${id}'`
const rows = await exec(sql)
return rows[0]
}
const newBlog = async (blogData = {}) => {
// blogData 是一个博客对象,包含 title content author 属性
const title = xss(blogData.title)
// console.log('title is', title)
const content = xss(blogData.content)
const author = blogData.author
const createTime = Date.now()
const sql = `
insert into blogs (title, content, createtime, author)
values ('${title}', '${content}', ${createTime}, '${author}');
`
const insertData = await exec(sql)
return {
id: insertData.insertId
}
}
const updateBlog = async (id, blogData = {}) => {
// id 就是要更新博客的 id
// blogData 是一个博客对象,包含 title content 属性
const title = xss(blogData.title)
const content = xss(blogData.content)
const sql = `
update blogs set title='${title}', content='${content}' where id=${id}
`
const updateData = await exec(sql)
if (updateData.affectedRows > 0) {
return true
}
return false
}
const delBlog = async (id, author) => {
// id 就是要删除博客的 id
const sql = `delete from blogs where id='${id}' and author='${author}';`
const delData = await exec(sql)
if (delData.affectedRows > 0) {
return true
}
return false
}
module.exports = {
getList,
getDetail,
newBlog,
updateBlog,
delBlog
}
routes/blog.js
const router = require('koa-router')()
const {
getList,
getDetail,
newBlog,
updateBlog,
delBlog
} = require('../controller/blog')
const { SuccessModel, ErrorModel } = require('../model/resModel')
const loginCheck = require('../middleware/loginCheck')
router.prefix('/api/blog')
router.get('/list', async function (ctx, next) {
let author = ctx.query.author || ''
const keyword = ctx.query.keyword || ''
if (ctx.query.isadmin) {
console.log('is admin')
// 管理员界面
if (ctx.session.username == null) {
console.error('is admin, but no login')
// 未登录
ctx.body = new ErrorModel('未登录')
return
}
// 强制查询自己的博客
author = ctx.session.username
}
const listData = await getList(author, keyword)
ctx.body = new SuccessModel(listData)
})
router.get('/detail', async function (ctx, next) {
const data = await getDetail(ctx.query.id)
ctx.body = new SuccessModel(data)
})
router.post('/new', loginCheck, async function (ctx, next) {
const body = ctx.request.body
body.author = ctx.session.username
const data = await newBlog(body)
ctx.body = new SuccessModel(data)
})
router.post('/update', loginCheck, async function (ctx, next) {
const val = await updateBlog(ctx.query.id, ctx.request.body)
if (val) {
ctx.body = new SuccessModel()
} else {
ctx.body = new ErrorModel('更新博客失败')
}
})
router.post('/del', loginCheck, async function (ctx, next) {
const author = ctx.session.username
const val = await delBlog(ctx.query.id, author)
if (val) {
ctx.body = new SuccessModel()
} else {
ctx.body = new ErrorModel('删除博客失败')
}
})
module.exports = router