基於koa二、關係數據庫(暫時只支持mysql)創建的智能微服務快速開發框架,將同時支持graphql與rest標準,使用typescript語言編寫,力求安全、高效。 前端
相關開源項目(gels -- 凝膠),希冀該項目能成爲聯結設計、開發,前端、後端的「強力膠水」,成爲微服務快速開發的有力框架。
項目地址:https://github.com/zhoutk/gelsjava
中小型企業,更多的是注重快速開發、功能迭代。關係數據庫爲咱們提供了不少有用的支持,我試圖把數據庫設計與程序開發有機的結合起來,讓前端送到後端的json對象自動映射成爲標準的SQL查詢語句。個人這種ORM方式,服務端不須要寫一行代碼,只需完成關係數據庫的設計,就能爲前端提供標準服務接口。
我設計了一套數據庫訪問標準接口,在實踐中已經獲得很好的運用。我已經在es6, typescript, java, python & go中實現;下一步是對數據庫支持的擴展,準備支持流行的關係數據庫(Mssql, sqlite3, prostgres等),有選擇支持一些nosql,好比:mongo。node
事務元素接口,sql參數用於手動書寫sql語句,id會做爲最後一個參數被送入參數數組。python
export default interface TransElement { table: string; method: string; params: object | Array<any>; sql?: string; id?: string | number; }
數據庫操做接口,包括基本CURD,兩個執行手寫sql接口,一個批量插入與更新二合一接口,一個事務操做接口。實踐證實,下面八個接口,在絕大部分狀況下已經足夠。mysql
export default interface IDao { select(tablename: string, params: object, fields?: Array<string>): Promise<any>; insert(tablename: string, params: object): Promise<any>; update(tablename: string, params: object, id: string|number): Promise<any>; delete(tablename: string, id: string|number): Promise<any>; querySql(sql: string, values: Array<any>, params: object, fields?: Array<string>): Promise<any>; execSql(sql: string, values: Array<any>): Promise<any>; insertBatch(tablename: string, elements: Array<any>): Promise<any>; transGo(elements: Array<TransElement>, isAsync?: boolean): Promise<any>; }
BaseDao,爲業務層提供標準數據庫訪問的基類,是自動提供標準rest微服務的關鍵git
import IDao from './idao' let dialect = G.CONFIGS.db_dialect //依賴注入 let Dao = require(`./${dialect}Dao`).default export default class BaseDao { private table: string static dao: IDao //以組合的模式,解耦業務層與數據庫訪問層 constructor(table?: string) { this.table = table || '' if (!BaseDao.dao) { BaseDao.dao = new Dao() } } async retrieve(params = {}, fields = [], session = {userid: ''}): Promise<any> { let rs try { rs = await BaseDao.dao.select(this.table, params, fields) } catch (err) { err.message = `data query fail: ${err.message}` return err } return rs } async create(params = {}, fields = [], session = {userid: ''}): Promise<any> { let rs try { rs = await BaseDao.dao.insert(this.table, params) } catch (err) { err.message = `data insert fail: ${err.message}` return err } let { affectedRows } = rs return G.jsResponse(200, 'data insert success.', { affectedRows, id: rs.insertId }) } async update(params, fields = [], session = { userid: '' }): Promise<any> { params = params || {} const { id, ...restParams } = params let rs try { rs = await BaseDao.dao.update(this.table, restParams, id) } catch (err) { err.message = `data update fail: ${err.message}` return err } let { affectedRows } = rs return G.jsResponse(200, 'data update success.', { affectedRows, id }) } async delete(params = {}, fields = [], session = {userid: ''}): Promise<any> { let id = params['id'] let rs try { rs = await BaseDao.dao.delete(this.table, id) } catch (err) { err.message = `data delete fail: ${err.message}` return err } let {affectedRows} = rs return G.jsResponse(200, 'data delete success.', { affectedRows, id }) } }
/op/:command,只支持POST請求,不鑑權,提供登陸等特定服務支持es6
session,使用jsonwebtoken,實現鑑權;同時,爲經過的鑑權的用戶生成對應的sessiongithub
數據表庫設計完成後,會自動提供以下形式的標準restful api,多表關係可用關係數據庫的視圖來完成。web
查詢保留字:fields, page, size, sort, search, lks, ins, ors, count, sum, group
fields, 定義查詢結果字段,支持數組和逗號分隔字符串兩種形式ajax
查詢示例: /rs/users?username=white&age=22&fields=["username","age"] 生成sql: SELECT username,age FROM users WHERE username = ? and age = ?
sort, 查詢結果排序參數
查詢示例: /rs/users?page=1&size=10&sort=age desc 生成sql: SELECT * FROM users ORDER BY age desc LIMIT 0,10
search, 模糊查詢切換參數,不提供時爲精確匹配
查詢示例: /rs/users?username=i&password=1&search 生成sql: SELECT * FROM users WHERE username like ? and password like ?
ins, 數據庫表單字段in查詢,一字段對多個值,例:
查詢示例: /rs/users?ins=["age",11,22,26] 生成sql: SELECT * FROM users WHERE age in ( ? )
ors, 數據庫表多字段精確查詢,or鏈接,多個字段對多個值,支持null值查詢,例:
查詢示例: /rs/users?ors=["age",1,"age",22,"password",null] 生成sql: SELECT * FROM users WHERE ( age = ? or age = ? or password is null )
lks, 數據庫表多字段模糊查詢,or鏈接,多個字段對多個值,支持null值查詢,例:
查詢示例: /rs/users?lks=["username","i","password",null] 生成sql: SELECT * FROM users WHERE ( username like ? or password is null )
count, 數據庫查詢函數count,行統計,例:
查詢示例: /rs/users?count=["1","total"]&fields=["username"] 生成sql: SELECT username,count(1) as total FROM users
sum, 數據庫查詢函數sum,字段求和,例:
查詢示例: /rs/users?sum=["age","ageSum"]&fields=["username"] 生成sql: SELECT username,sum(age) as ageSum FROM users
group, 數據庫分組函數group,例:
查詢示例: /rs/users?group=age&count=["*","total"]&fields=["age"] 生成sql: SELECT age,count(*) as total FROM users GROUP BY age
不等操做符查詢支持
支持的不等操做符有:>, >=, <, <=, <>, =;逗號符爲分隔符,一個字段支持一或二個操做。
特殊處:使用"="可使某個字段跳過search影響,讓模糊匹配與精確匹配同時出如今一個查詢語句中
一個字段一個操做,示例:
查詢示例: /rs/users?age=>,10 生成sql: SELECT * FROM users WHERE age> ?
一個字段二個操做,示例:
查詢示例: /rs/users?age=>,10,<=,35 生成sql: SELECT * FROM users WHERE age> ? and age<= ?
使用"="去除字段的search影響,示例:
查詢示例: /rs/users?age==,22&username=i&search 生成sql: SELECT * FROM users WHERE age= ? and username like ?
新增一條記錄
[POST]/rs/users
Content-Type: application/json token: eyJhbGciOiJIUzI1NiIsInR...
{ "username":"bill", "password":"abcd", "age":46, "power": "[\"admin\",\"data\"]" }
{ "affectedRows": 1, "id": 7, "status": 200, "message": "data insert success." }
execSql執行手寫sql語句,供後端內部調用
await new BaseDao().execSql("update users set username = ?, age = ? where id = ? ", ["gels","99","6"])
{ "affectedRows": 1, "status": 200, "message": "data execSql success." }
insertBatch批量插入與更新二合一接口,供後端內部調用
let params = [ { "username":"bill2", "password":"523", "age":4 }, { "username":"bill3", "password":"4", "age":44 }, { "username":"bill6", "password":"46", "age":46 } ] await new BaseDao().insertBatch('users', params)
{ "affectedRows": 3, "status": 200, "message": "data batch success." }
tranGo事務處理接口,供後端內部調用
let trs = [ { table: 'users', method: 'Insert', params: { username: 'zhou1', password: '1', age: 1 } }, { table: 'users', method: 'Insert', params: { username: 'zhou2', password: '2', age: 2 } }, { table: 'users', method: 'Insert', params: { username: 'zhou3', password: '3', age: 3 } } ] await new BaseDao().transGo(trs, true) //true,異步執行;false,同步執行
{ "affectedRows": 3, "status": 200, "message": "data trans success." }
運行數據腳本
SET NAMES utf8; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for `users` -- ---------------------------- DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, `age` int(11) DEFAULT NULL, `power` json DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4; -- ---------------------------- -- Records of `users` -- ---------------------------- BEGIN; INSERT INTO `users` VALUES ('1', 'white', '123', '22', null), ('2', 'john', '456i', '25', null), ('3', 'marry', null, '22', null), ('4', 'bill', '123', '11', null), ('5', 'alice', '122', '16', null), ('6', 'zhoutk', '123456', '26', null); COMMIT; SET FOREIGN_KEY_CHECKS = 1;
配置文件示例,./src/config/configs.ts
export default { inits: { directory: { run: false, dirs: ['public/upload', 'public/temp'] } }, port: 5000, db_dialect: 'mysql', dbconfig: { db_host: 'localhost', db_port: 3306, db_name: 'strest', db_user: 'root', db_pass: '123456', db_char: 'utf8mb4', db_conn: 10, }, jwt: { secret: 'zh-tf2Gp4SFU>a4bh_$3#46d0e85W10aGMkE5xKQ', expires_max: 36000 //10小時,單位:秒 }, }
在終端(Terminal)中依次運行以下命令
git clone https://github.com/zhoutk/gels cd gels npm i -g yarn yarn global install typescript tslint nodemon yarn install tsc -w //或 command + shift + B,選 tsc:監視 yarn start //或 node ./dist/index.js
├── package.json ├── src //源代碼目錄 │ ├── app.ts //koa配置及啓動 │ ├── common //通用函數或元素目錄 │ │ ├── globUtils.ts │ ├── config //配置文件目錄 │ │ ├── configs.ts │ ├── db //數據封裝目錄 │ │ ├── baseDao.ts │ ├── globals.d.ts //全局聲明定義文件 │ ├── index.ts //運行入口 │ ├── inits //啓動初始化配置目錄 │ │ ├── global.ts │ │ ├── index.ts │ │ ├── initDirectory.ts │ ├── middlewares //中間件目錄 │ │ ├── globalError.ts │ │ ├── logger.ts │ │ ├── router │ │ └── session.ts │ └── routers //路由配置目錄 │ ├── index.ts │ └── router_rs.ts ├── tsconfig.json └── tslint.json
凝膠(gels)項目: https://github.com/zhoutk/gels
視頻講座資料: https://github.com/zhoutk/sifou
我的博客: https://segmentfault.com/blog...
nodejs實戰之智能微服務快速開發框架
視頻2亮點: