一、初始化koa2项目
> koa2 koa2-mvc
初始目录:
│ ?app.js
│ ?package.json
├─bin
│ ? ? ?www
├─public
├─routes
│ ? ? ?index.js
│ ? ? ?users.js
└─views
? ? ? ? error.ejs
? ? ? ? index.ejs
二、MVC嵌套
?变更后的目录:
│ ?app.js
│ ?mount.js ---- 主挂载文件
│ ?package.json
├─bin
│ ? ? ?www
├─config ---- 配置文件
│ ? ? ?database.json ---- 数据库环境变量
├─controllers
│ ? ? ?home.js
├─database
│ ? ? ?index.js ---- 数据库连接
├─public
├─routes ---- 路由文件
│ ? ? ?index.js
│ ? ? ?users.js
├─services ---- 接口文件
│ ? ? ?home.js
└─views ---- 页面文件
? ? ? ? error.ejs
? ? ? ? index.ejs
1、app.js 配置修改
// app.js
const Koa = require('koa')
const app = new Koa()
const views = require('koa-views')
const json = require('koa-json')
const onerror = require('koa-onerror')
const bodyparser = require('koa-bodyparser')
const logger = require('koa-logger')
const Mount = require('./mount')
// 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: 'ejs',
})
)
// 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`)
})
// mount config
Mount(app)
// error-handling
app.on('error', (err, ctx) => {
console.error('server error', err, ctx)
})
module.exports = app
2、mount.js 配置挂载
文件挂载按照调用与被调用顺序依次加载并挂载在app上,依赖顺序为:
app => config => database => services => controllers => routes
文件内容:
// mount.js
const path = require('path')
const fs = require('fs')
const Database = require('./database')
/**
* 扫指定目录并读取文件内容
* @param {*} dir 目录
* @param {*} cb 回调
* @param {*} env 环境
*/
function scanFilesByFolder(dir, cb, env = 'development') {
let _folder = path.resolve(__dirname, dir)
if (!hasFolder(_folder)) return
try {
const files = fs.readdirSync(_folder)
files.forEach(file => {
const [name, type] = file.split('.')
switch (type) {
case 'js':
cb && cb(name, require(_folder + '/' + name))
break
case 'json': // 主要针对config配置文件使用
cb && cb(name, require(_folder + '/' + file)[env])
break
default:
}
})
} catch (error) {
console.log('文件自动加载失败...', error)
}
}
/**
* 检测文件夹是否存在
* @param {*} path 文件夹路径
* @returns Boolean
*/
function hasFolder(path) {
try {
fs.statSync(path)
return true
} catch (err) {
return false
}
}
module.exports = app => {
// mount config
app.$config = {}
scanFilesByFolder(
'./config',
(key, value) => {
app.$config[key] = value
},
app.env
)
// mount database
app.$database = Database(app)
// mount services
app.$services = {}
scanFilesByFolder('./services', (key, value) => {
app.$services[key] = value(app)
})
// mount controllers
app.$controllers = {}
scanFilesByFolder('./controllers', (key, value) => {
app.$controllers[key] = value(app)
})
// mount routes
scanFilesByFolder('./routes', (key, value) => {
const router = require('koa-router')()
const route = value({ ...app, router })
app.use(route.routes(), route.allowedMethods())
})
}
3、config目录文件
注:此处.json文件结构统一,需包含"development"和"production"配置。
// config/database.json
{
"development": {
"database": "develop",
"user": "root",
"password": "123456",
"host": "127.0.0.1",
"port": 3306
},
"production": {
"database": "product",
"user": "root",
"password": "123456",
"host": "127.0.0.1",
"port": 3306
}
}
4、database目录文件
// database/index.js
const mysql = require('mysql')
module.exports = ({ $config }) => {
// 创建MySQL连接池 依赖db环境配置
const pool = mysql.createPool($config.database)
return {
// 通用SQL查询模块
runSql: (sql, val = {}) => {
return new Promise((resolve, reject) => {
pool.getConnection(function (err, connection) {
if (err) reject(err)
else {
connection.query(sql, val, (err, fields) => {
connection.release()
if (err) reject(err)
else resolve(fields)
})
}
})
})
},
}
}
5、services目录文件
// services/home.js
module.exports = ({ $database }) => {
return {
index: async () => {
// TODO
return {
title: 'Hello Koa 2!',
content: await $database.runSql('SELECT * FROM users'),
}
},
}
}
6、controllers目录文件
// controllers/home.js
module.exports = ({ $services }) => {
return {
index: async (ctx, next) => {
// TODO
const { title, content } = await $services.home.index()
await ctx.render('index', { title, content })
},
}
}
7、routes目录文件
// routes/index.js
module.exports = ({ router, $controllers }) => {
router.get('/', $controllers.home.index)
router.get('/string', async (ctx, next) => {
ctx.body = 'koa2 string'
})
router.get('/json', async (ctx, next) => {
ctx.body = {
title: 'koa2 json',
}
})
return router
}
附录:
结尾附上完整项目地址:?koa2-mvc-template
|