Koa2學習系列05-程式碼分層——梳理程式碼,漸近於 MVC 分層模式
重構
在前面幾節中,我們已經實現了專案中的幾個常見操作:啟動伺服器、路由中介軟體、Get
和 Post
形式的請求處理等。現在你已經邁出了走向成功的第一步。
目前,整個示例中所有的程式碼都寫在 app.js
中。然而在業務程式碼持續增大,場景更加複雜的情況下,這種做法無論是對後期維護還是對患有強迫症的同學來說都不是好事。所以我們現在要做的就是:『分梨』。
分離 router
路由部分的程式碼可以分離成一個獨立的檔案,並根據個人喜好放置於專案根目錄下,或獨立放置於 router
router.js
並將之放置於根目錄下。
修改路由 router.js
const router = require('koa-router')() module.exports = (app) => { router.get('/', async(ctx, next) => { ctx.response.body = `<h1>index page</h1>` }) router.get('/home', async(ctx, next) => { console.log(ctx.request.query) console.log(ctx.request.querystring) ctx.response.body = '<h1>HOME page</h1>' }) router.get('/home/:id/:name', async(ctx, next)=>{ console.log(ctx.params) ctx.response.body = '<h1>HOME page /:id/:name</h1>' }) router.get('/user', async(ctx, next)=>{ ctx.response.body = ` <form action="/user/register" method="post"> <input name="name" type="text" placeholder="請輸入使用者名稱:ikcamp"/> <br/> <input name="password" type="text" placeholder="請輸入密碼:123456"/> <br/> <button>GoGoGo</button> </form> ` }) // 增加響應表單請求的路由 router.post('/user/register',async(ctx, next)=>{ let {name, password} = ctx.request.body if( name == 'ikcamp' && password == '123456' ){ ctx.response.body = `Hello, ${name}!` }else{ ctx.response.body = '賬號資訊錯誤' } }) app.use(router.routes()) .use(router.allowedMethods()) }
修改 app.js
const Koa = require('koa') const bodyParser = require('koa-bodyparser') const app = new Koa() const router = require('./router') app.use(bodyParser()) router(app) app.listen(3000, () => { console.log('server is running at http://localhost:3000') })
程式碼看起來清爽了很多。
然而到了這一步,還是不能夠高枕無憂。router
檔案獨立出來以後,應用的主檔案 app.js
雖然暫時看起來比較清爽,但這是在只有一個路由,並且處理函式也非常簡單的情況下。如果有多個路由,每個處理函式函式程式碼量也都繁複可觀,這就不是主管們喜聞樂見的事情了。
接下來我們對結構進行進一步優化。
分離 controller 層
我們把路由對應的業務邏輯也分離出來。
新增 controller/home.js
新建 controller
資料夾,增加一個 home.js
檔案,並從 router.js
中提取出業務邏輯程式碼。
module.exports = { index: async(ctx, next) => { ctx.response.body = `<h1>index page</h1>` }, home: async(ctx, next) => { console.log(ctx.request.query) console.log(ctx.request.querystring) ctx.response.body = '<h1>HOME page</h1>' }, homeParams: async(ctx, next) => { console.log(ctx.params) ctx.response.body = '<h1>HOME page /:id/:name</h1>' }, login: async(ctx, next) => { ctx.response.body = ` <form action="/user/register" method="post"> <input name="name" type="text" placeholder="請輸入使用者名稱:ikcamp"/> <br/> <input name="password" type="text" placeholder="請輸入密碼:123456"/> <br/> <button>GoGoGo</button> </form> ` }, register: async(ctx, next) => { let { name, password } = ctx.request.body if (name == 'ikcamp' && password == '123456') { ctx.response.body = `Hello, ${name}!` } else { ctx.response.body = '賬號資訊錯誤' } } }
修改路由 router.js
修改 router.js
檔案,在裡面引入 controler/home
:
const router = require('koa-router')() const HomeController = require('./controller/home') module.exports = (app) => { router.get( '/', HomeController.index ) router.get('/home', HomeController.home) router.get('/home/:id/:name', HomeController.homeParams) router.get('/user', HomeController.login) router.post('/user/register', HomeController.register) app.use(router.routes()) .use(router.allowedMethods()) }
如此,將每個路由的處理邏輯分離到 controller
下的獨立檔案當中,便於後期維護。
目前的程式碼結構已經比較清晰了,適用於以 node
作為中間層、中轉層的專案。如果想要把 node
作為真正的後端去操作資料庫等,建議再分出一層 service
,用於處理資料層面的互動,比如呼叫 model
處理資料庫,呼叫第三方介面等,而controller
裡面只做一些簡單的引數處理。
分離 service 層
這一層的分離,非必需,可以根據專案情況適當增加,或者把所有的業務邏輯都放置於
controller
當中。
新建 service/home.js
新建 service
資料夾,並於該資料夾下新增一個 home.js
檔案,用於抽離 controller/home.js
中的部分程式碼:
module.exports = { register: async(name, pwd) => { let data if (name == 'ikcamp' && pwd == '123456') { data = `Hello, ${name}!` } else { data = '賬號資訊錯誤' } return data } }
修改 controller/home.js
// 引入 service 檔案 const HomeService = require('../service/home') module.exports = { // ……省略上面程式碼 // 重寫 register 方法 register: async(ctx, next) => { let { name, password } = ctx.request.body let data = await HomeService.register(name, password) ctx.response.body = data } }
重構完成
下一節我們將引入檢視層 views
,還會介紹使用第三方中介軟體來設定靜態資源目錄等。新增的部分前端資原始碼會讓我們的用例更加生動,盡情期待吧。