koa2,之前沒有接觸過,只知道是express的原班人馬開發的,在一些方面優於express,又經歷了一次從koa到koa2的升級,應該說是比較成熟的了。
根據如今的技術實現方案,如今大部分的web服務基本都是先後端分離模式的,因此koa2的讓web應用開發和api的使用更加簡便優點,更值得咱們去學習。javascript
本文只簡單介紹將環境搭建起來,可讓初次學習koa或者web應用的同窗可以更快的看到學習成果,增長學習的自信心,其中涉及到的不少的知識和技術點,咱們後續補充,不在本文作過多的闡述
本文的目的就是作知識的普及,文中可能會有些代碼是從網絡中複製的,可是都是親手調試可運行,保證代碼的正常運行的
這個不用想也不用考慮,koa項目是基於node的,上來什麼都別說,先安裝node。但這裏有個細節須要注意,node須要最低版本爲7.6.0,主要是爲了一些es6的語法支持。前端
brew install node
我這裏是在mac環境上安裝的node,因爲本人習慣使用homebrew安裝,若是不是mac環境的同窗,也能夠直接到官網下載安裝包安裝。這個步驟比較簡單,通常狀況下看下官網的文檔介紹,能夠直接搞定。
node安裝完成後,要查看下node的版本,有兩個目的,一是查看node是否安裝成功,再就是檢查是否知足koa的版本需求。
node -v npm -v
npm集成到node中了,只要成功的安裝了node,npm也會被成功安裝。
咱們學習和應用的是koa項目,就先安裝上koa吧。
npm install koa --savejava
npm install koa-generator -g koa2 bbs
這裏的koa-generator,並非官方的項目生成器,而是狼叔-桑世龍爲咱們貢獻的財富,在這裏,咱們感謝狼叔。
koa2 bbs,這行代碼建立了基於koa2的項目,並生成基本的項目架構。基本的項目架構以下:node
項目也建立完了,可是隻是完成了一個基本的骨架,尚未血肉,接下來就須要安裝項目的依賴了mysql
cd bbs npm install
這個步驟可能消耗的時間有點長,這個和網絡環境有關,因爲網絡的緣由,還有可能某些依賴會安裝失敗,這個時候,咱們能夠經過修改npm鏡像來減小因爲網絡環境致使安裝依賴失敗的問題。
具體可參考淘寶NPM鏡像。git
npm start
npm能夠啓動服務,但不支持熱更新,咱們這裏只是測試項目可否正常啓動,執行,熱更新的內容,咱們後續再講。
服務正常啓動以後,瀏覽器輸入:localhost:3000,若是頁面中展現瞭如"Hello Koa 2"的內容,說明項目搭建成功。es6
這裏的搭建項目,不是前面的使用koa2初始化一個項目,而是把前面經過koa2初始化的項目補充養分,讓它豐滿起來。github
暫且不要關心sequelize是什麼,之後會有專題細講,只須要了解一點就能夠了:Sequelize是一個基於promise的nodejs ORM,目前支持Postgres、mysql、SQLite和Microsoft SQL Server。它具備強大的事務支持,關聯關係,讀取和複製等功能。web
npm install sequelize --save
項目須要mysql的數據庫支持sql
npm install mysql mysql2 --save
在項目的根目錄下建立一個config目錄,config目錄中建立db.js,該文件主要用來建立mysql的數據庫連接的。
const Sequelize = require('sequelize'); const sequelize = new Sequelize('dbname','dbusername','password',{ host:'localhost', dialect:'mysql', operatorsAliases:false, dialectOptions:{ //字符集 charset:'utf8mb4', collate:'utf8mb4_unicode_ci', supportBigNumbers: true, bigNumberStrings: true }, pool:{ max: 5, min: 0, acquire: 30000, idle: 10000 }, timezone: '+08:00' //東八時區 }); module.exports = { sequelize };
這些代碼能夠直接使用,只須要將代碼中實例化Sequelie對象語句中的dbname更改成你的數據庫名,dbusername更改成你的數據庫用戶名,passoword更改成你的數據庫密碼,其中數據庫名和數據庫用戶名不能爲空,密碼能夠爲空,爲空時則爲空的字符串就能夠了。
const sequelize = new Sequelize('bbs','root','',{ ……
schema:數據表模型實例
modules:實體模型
controllers:控制器
3個目錄下分別建立article.js。
在schema目錄下新建一個article.js文件,該文件的主要做用就是創建與數據表的對應關係,也能夠理解爲代碼的建表。
首先來分析表結構:
字段 | 說明 | 是否必填 |
---|---|---|
id | 文章自增ID,主鍵 | 否,自動填的 |
title | 文章標題 | 是 |
author | 做者 | 是 |
content | 文章內容 | 是 |
category | 文章分類 | 是 |
分析表結構,主要是爲了用來建表的,表結構,是咱們根據實體的關係抽象出來的實體關係,根據這些關係創建表,將實體的關係存儲到表中。建表有兩種方式:一是使用mysql數據庫的命令行工具或者UI工具建表,再就是使用咱們前面介紹的Sequelize,讓程序去建立表。
使用mysql工具建表方式:
DROP TABLE IF EXISTS `article`; CREATE TABLE `article` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(255) NOT NULL, `author` varchar(255) NOT NULL, `content` varchar(255) NOT NULL, `category` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; SET FOREIGN_KEY_CHECKS = 1;
這是使用sql語句建立表的方式,咱們看另外一種藉助Sequelize建表方式(Sequelize不光是能建表,還能作數據庫的管理);
咱們剛纔在schema目錄下的article.js用來建立數據表模型的,也能夠理解爲建立一張數據表,代碼以下:
const moment = require("moment"); module.exports = function(sequelize,DataTypes){ return sequelize.define('article',{ id:{ type: DataTypes.INTEGER, primaryKey: true, allowNull: true, autoIncrement: true }, //文章標題 title:{ type: DataTypes.STRING, allowNull: false, field: 'title' }, //做者 author:{ type: DataTypes.STRING, allowNull: false, field: 'author' }, //內容 content:{ type: DataTypes.STRING, allowNull: false, field:'content' }, //文章分類 category:{ type: DataTypes.STRING, allowNull: false, field: 'category' }, // 建立時間 createdAt:{ type: DataTypes.DATE }, // 更新時間 updatedAt:{ type: DataTypes.DATE } } },{ /** * 若是爲true,則表示名稱和model相同,即user * 若是爲fasle,mysql建立的表名稱會是複數,即users * 若是指定的表名稱自己就是複數,則形式不變 */ freezeTableName: true }); }
在項目中modules目錄下建立article.js文件,爲文章表,該文件爲文章的實例。
// 引入mysql的配置文件 const db = require('../config/db'); // 引入sequelize對象 const Sequelize = db.sequelize; // 引入數據表模型 const Article = Sequelize.import('../schema/article'); Article.sync({force: false}); //自動建立表 class ArticleModel { /** * 建立文章模型 * @param data * @returns {Promise<*>} */ static async createArticle(data){ return await Article.create({ title: data.title, //標題 author: data.author, //做者 content: data.content, //文章內容 category: data.category //文章分類 }); } /** * 查詢文章的詳情 * @param id 文章ID * @returns {Promise<Model>} */ static async getArticleDetail(id){ return await Article.findOne({ where:{ id } }); } } module.exports = ArticleModel;
控制器的主要做用爲功能的處理,項目中controller目錄下建立article.js,代碼以下:
const ArticleModel = require("../modules/article"); class articleController { /** * 建立文章 * @param ctx * @returns {Promise.<void>} */ static async create(ctx){ //接收客服端 let req = ctx.request.body; if(req.title && req.author && req.content && req.category){ try{ //建立文章模型 const ret = await ArticleModel.createArticle(req); //使用剛剛建立的文章ID查詢文章詳情,且返回文章詳情信息 const data = await ArticleModel.getArticleDetail(ret.id); ctx.response.status = 200; ctx.body = { code: 200, msg: '建立文章成功', data } }catch(err){ ctx.response.status = 412; ctx.body = { code: 412, msg: '建立文章失敗', data: err } } }else { ctx.response.status = 416; ctx.body = { code: 200, msg: '參數不齊全' } } } /** * 獲取文章詳情 * @param ctx * @returns {Promise.<void>} */ static async detail(ctx){ let id = ctx.params.id; if(id){ try{ // 查詢文章詳情模型 let data = await ArticleModel.getArticleDetail(id); ctx.response.status = 200; ctx.body = { code: 200, msg: '查詢成功', data } }catch(err){ ctx.response.status = 412; ctx.body = { code: 412, msg: '查詢失敗', data } } }else { ctx.response.status = 416; ctx.body = { code: 416, msg: '文章ID必須傳' } } } } module.exports = articleController;
路由,也能夠簡單理解爲路徑,主要是做爲請求的url,請求的路徑來處理一些請求,返回數據。通常狀況下,基於node的項目,路由都是在一個叫作routes的目錄下面。
const Router = require('koa-router'); const ArtileController = require('../controllers/article'); const router = new Router({ prefix: '/api/v1' }); /** * 文章接口 */ //建立文章 router.post('/article/create',ArtileController.create); //獲取文章詳情 router.get('/article/:id',ArtileController.detail) module.exports = router
這裏主要測試服務可否正常啓動,可否正常運行。
npm start
若是啓動過程當中出現下面的結果,說明服務啓動成功
➜ bbs npm start > bbs@0.1.0 start /usr/local/var/www/koa/bbs > node bin/www koa deprecated Support for generators will be removed in v3. See the documentation for examples of how to convert old middleware https://github.com/koajs/koa/blob/master/docs/migration.md app.js:20:5 Ignoring invalid configuration option passed to Connection: collate. This is currently a warning, but in future versions of MySQL2, an error will be thrown if you pass an invalid configuration options to a Connection Ignoring invalid configuration option passed to Connection: collate. This is currently a warning, but in future versions of MySQL2, an error will be thrown if you pass an invalid configuration options to a Connection Executing (default): CREATE TABLE IF NOT EXISTS `article` (`id` INTEGER auto_increment , `title` VARCHAR(255) NOT NULL, `author` VARCHAR(255) NOT NULL, `content` VARCHAR(255) NOT NULL, `category` VARCHAR(255) NOT NULL, `createdAt` DATETIME, `updatedAt` DATETIME, PRIMARY KEY (`id`)) ENGINE=InnoDB; Executing (default): SHOW INDEX FROM `article`
接下來,就能夠測試接口了。
我使用的測試接口工具爲postman,之前postman好像是做爲瀏覽器的一個插件存在的,如今不做爲瀏覽器的插件了,直接作成了應用了,能夠直接從postmna官網下載。 官網地址https://www.getpostman.com/,而後咱們根據咱們的系統平臺來選擇合適的版本下載就能夠了。
跨域是web開發中不可避免的一個必需要解決的問題了。跨域問題,主要是要解決服務器端的通訊問題。在node的開發中,只須要實現一個CORS標準就能夠了。
npm install koa-cors --save
而後在根目錄下的app.js加入koa-cors的引用:
const cors = require('koa-cors') app.use(cors()) //使用cors
而後從新啓動服務。到這裏爲止,還不能支持熱更新,如今主要測試功能,暫且先這麼手動重啓吧,後面會有專題描述熱更新服務。
前面我下載而且安裝好了postman,工具備了,代碼層面也準備就緒,解決了跨域問題,下面就能夠測試接口是否可用了。
測試接口,咱們先看下咱們的路由管理文件routes目錄下的index.js文件。
//建立文章 router.post('/article/create',ArtileController.create); //獲取文章詳情 router.get('/article/:id',ArtileController.detail)
這裏有2個文章相關的接口,一個是建立新文章,一個是獲取文章詳情。咱們先來測試建立新的文章。
看路由,建立新文章須要的請求方式爲post,url爲/article/create,那咱們就根據這些信息使用postman進行測試吧。
這是我建立新文章的接口測試,而後看測試結果:
運行結果告訴咱們建立新文章的接口已經測試成功了,說明這個接口能夠走通了。若是咱們如今是先後端分離的開發模式,咱們須要提供api的話,那麼這個api就能夠提供給前端同窗使用了。
咱們也能夠從數據庫中驗證一下執行結果的正確性:
數據也成功插入到數據庫中了,咱們也更加驗證了咱們接口的正確性和可執行性了,這個接口到此結束。
而後看下一個獲取文章詳情的接口。須要使用get的請求方式,請求的URL爲/article/:id。
到如今爲止,咱們基本已經完成了從0開始搭建一個koa項目,並完成一些簡單的api接口的實現,固然了,只是最基本的實現,裏面還有不少可優化的空間,對於一個做爲入門案例來講,已經夠了。對於有深刻了解或學習的朋友,但願咱們功能學習,共同提升。