目錄
1 easyconf的誕生
2 easyconf的設計理念
2.1 總體設計
2.2 細節設計
2.2.1 CRUD操作
2.2.2 即時校驗
2.2.3 下拉框設計
3 easyconf使用指南
3.1 基本步驟
3.2 表配置文件
3.3 easyconf.js的定制
3.3.1 語言
3.3.2 URL地址
3.3.3 自定義校驗方法
4 easyconf后端開發指南
4.1 請求說明
4.2 返回說明
5 下一步的工作
1 easyconf的誕生
大概半年前做一個原型系統,有很多配置數據存儲在數據庫中,用戶需要對這些配置項進行管理。但凡開發過這樣的配置管理系統的人都會發現,為A表編寫的配置管理的代碼與B表大同小異。如果能夠進一步抽象,我們或許可以只用開發一套前端和后端代碼,就能夠滿足幾乎所有不同的配置表的需求。
我很懶,不喜歡做重復的工作,所以我設計了easyconf——基於AugularJS的配置管理系統開發框架。easyconf支持json格式的表配置文件,我們可以在此文件中定義需要管理的表的各種信息,諸如列信息,以及列對應的前端控件信息等。easyconf的最小集是index.html和easyconf.js兩個前端代碼,后端可按照本文中的指南進行自定義開發,當然,我也提供了一個基於python的demo后端。
雖然,easyconf被設計用來開發配置管理系統,你也可以腦洞大開地拿它來開發各種管理系統,諸如“XX學籍管理系統”,“XX圖書館管理系統”等。很熟悉吧,至少本科的課程設計做過這樣的系統。如果有了easyconf,你甚至無需寫1字節代碼就可以做出一個管理系統,你僅僅需要做好表設計以及對表配置文件的定制化。
截止目前(2016-07),easyconf已支持0-String/1-Long/2-Double/3-Boolean/4-Date,共5種數據類型;0-text/1-combo box,共2種控件類型;0-精確/1-包含/2-小於/3-大於/4-小於等於/5-大於等於,共6種查詢方式。
2 easyconf的設計理念
2.1 總體設計
MVC架構提供了Model將數據與后端中的類進行映射,而另有一些開發者將后端中的類與前端中的控件進行了映射。然而,管理系統是一類非常“單純”的系統,大部分CRUD操作只針對單表進行,所以,我們可以放心地進行簡化映射關系,將數據與前端控件直接映射起來:
上圖顯示了一個生動的實例,假設我們有眾多的服務器架設在全國各地,那么我們需要一張名為service的表存儲這些服務器的信息,其中包括服務器的IP,端口號,所在省市,以及是否啟用。使用MVC架構或者基於MVC的優化架構,我們必須至少為后端編寫一定量的代碼(定義類)。假若使用數據對前端控件的直接映射,那么將免去這方面的工作。
2.2 細節設計
2.2.1 CRUD操作
easyconf支持對有主鍵的單表的CRUD操作。以服務器配置為例,打開配置管理主頁如下:
點擊“新增”,將進入新增面板:
在配置管理主頁,點擊“查找”,將按按照條件在主頁輸出查找結果:
點擊查找結果的“詳情”,將進入詳情面板:
點擊查找結果的“更新”,將進入更新面板:
點擊查找結果的“刪除”,將刪除一條配置數據:
2.2.2 即時校驗
點擊“提交”后再對用戶的輸入進行校驗是不夠人性化的,easyconf能夠即時校驗用戶的輸入:
上圖展示了兩種校驗,第一種是數據類型校驗,由於定義的“服務器監聽端口”字段為整型,當輸入字母“a”時將提示“必須為整數”;第二種是自定義校驗,對的,easyconf還支持自定義校驗函數,在本例中我自定義了IP和端口合法性校驗函數。
唯一性是不太好處理的校驗項:首先,為了追求真正的唯一性,在新增面板打開到關閉這段期間內進行鎖表是不合適的;其次,退而求其次,每次focus在主鍵字段,或者修改主鍵字段,或者從主鍵字段blur都查詢一下是否唯一,這種方式也是不合理的,會大大增加系統的開銷。easyconf采取的是一種准即時的方式,提交新增請求后,若后端判斷不滿足唯一性約束,則前端記錄下本次的主鍵字段的輸入為歷史輸入,下一次提交前,每一次主鍵字段的修改都會與歷史輸入進行比較,只要是一致,就會提示“數據已存在”:
2.2.3 下拉框設計
easyconf使用了兩種下拉框:靜態下拉框和動態下拉框。靜態下拉框的候選內容是固定的,在表配置文件中定義。動態下拉框的候選內容是可變的,其取數的方式也在表配置文件中定義。在本例中,“省”字段的候選內容從數據庫表“province”中讀取,“市”字段的候選內容從數據庫表“city”中讀取,讀取的時候還需要加上“省”字段作為查詢條件;“是否啟用”字段為靜態下拉框:
3 easyconf使用指南
3.1 基本步驟
easyconf的使用可以分為以下幾個基本步驟:
3.2 表配置文件
表配置文件的定制是使用easyconf的核心步驟,讓我們看一下這個配置文件中的各種配置項的說明:
1 { 2 title:<title>, //此處定義了標題顯示內容 3 table:<table>, //表名 4 count:10, //查詢結果每頁條數 5 columns: //此處定義了需要顯示的表的各列信息 6 [ 7 { 8 id:<col1>, //列在數據庫中定義的名稱 9 name:<列1>, //列在頁面上顯示的中文名 10 isShow:<true>, //在查詢結果中是否顯示 11 isPrimaryKey:[true], //是否為主鍵,在新增頁面時,主鍵的列的控件觸發onchange事件后,需要進行唯一性校驗。 12 isNull:<true>, //是否為空,在新增或修改頁面時,主鍵的列的控件觸發onchange事件后,需要進行是否為空校驗。 13 type:<0>, //列的數據類型,0- String /1-Long/2-Double/3-Boolean/4-Date 14 control:<0>, //列在頁面上顯示的控件類型,0-text/1-combo box 15 check: //在新增或修改頁面時,主鍵的列的控件觸發onchange事件后所調用的自定義校驗函數 16 [ 17 { 18 funcname:<function1>, 19 argument:<col1, col2…> 20 }, //調用函數時,第一個參數為本控件的值,之后的參數為argument中列對應的控件的值。 21 … 22 ], 23 isSelect:<true>, //是否作為查詢條件。 24 selectType:<0>, //查詢條件,0-精確/1-包含/2-小於/3-大於/4-小於等於/5-大於等於 25 candidate:<0/1>, //0-固定值,1-動態值,為固定值時從fixed中取候選內容,為動態值時從flexible中取key,value,table和query組sql語句從數據庫中查詢出候選內容。候選內容的格式為”key-value”。 26 fixed: 27 [ 28 {key1:<value1>}, 29 {key2:<value2>}, 30 … 31 ], 32 flexible: 33 { 34 key:<col>, 35 value:<col>, 36 table:<table>, 37 where:<col1, col2…> 38 }, 39 dft:<dft? //默認值,查詢層控件或新增頁面對應控件的默認值。 40 }, 41 … 42 ] 43 }
3.3 easyconf.js的定制
3.3.1 語言
在easyconf.js中我們可以定制前端上顯示的要素的名稱,提示的信息:
1 //定義控件的顯示名稱 2 names:{ 3 SEARCH:"查找", 4 INSERT:"新增", 5 DETAIL:"詳情", 6 UPDATE:"更新", 7 DELETE:"刪除", 8 FRESH:"刷新", 9 PREV:"上頁", 10 NEXT:"下頁", 11 GO:"跳轉", 12 RETURN:"返回", 13 COMMIT:"提交", 14 OPERATIONS:"操作" 15 }, 16 //定義小標題 17 subTitles:['查找', '詳情', '更新', '新增'], 18 //定義提示信息 19 msgs:{ 20 OK:"通過", 21 NOTNULL:"不允許為空", 22 INTEGER:"必須為整數", 23 DOUBLE:"必須為浮點數", 24 TYPEERROR:"類型錯誤", 25 DATE:"必須為日期[YYYY-MM-DD hh:mm:ss.ms]", 26 NOTUNIQUE:"數據已存在", 27 },
3.3.2 URL地址
在easyconf.js中,我們還可以定義URL地址,譬如域名為“www.domain.com”,定義INSERT請求的URL為“Insert”,那么完整的URL地址為“www.domain.com/Insert”:
1 apps:{ 2 INIT:"Init", 3 LIST:"Search", 4 DELETE:"Delete", 5 UPDATE:"Update", 6 INSERT:"Insert", 7 RANGE:"Range" 8 },
3.3.3 自定義校驗方法
在easyconf.js中,我們還可以自定義校驗方法,在服務器配置的例子中,我們定義IP和端口的校驗方法如下:
1 // user's function here 2 userfunc: { 3 checkIp:function(ip) { 4 var exp=/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/; 5 var reg = ip.match(exp); 6 if(reg != null) 7 return true; 8 else 9 return false; 10 }, 11 12 checkPort:function(port) { 13 if (0 <= port && port <= 65535) 14 return true; 15 else 16 return false; 17 } 18 }
4 easyconf后端開發指南
4.1 請求說明
根據本指南,我們可以為easyconf開發自己的后端:
請求 | 方式 | url | 請求數據 | 返回數據 | 說明 |
配置管理主頁 | GET | <domain>/<main>.html | 無 | <main.html> | domain為域名,main.html為index.html的重命名副本 |
初始化 | GET | <domain>/<INIT> | 無 | <table.json> | table.json為表配置文件 |
列表查詢 | GET | <domain>/<LIST>?table=<table>&data=<col1,col2...>&query=<col1:value1,col2:value2...>&begin=<begin>&count=<count> | 無 | 查詢返回,見下 | 后端收到請求后,解析data和query參數,data參數和query中的col和value均進行了base64編碼。然后組sql語句進行查詢,查詢出來的結果為數據庫中的第begin*count+1條到begin*(count+1)條。 |
刪除 | POST | <domain>/<DELETE> | 刪除請求,見下 | 通用返回,見下 | 后端收到請求后,解析query變量。然后組sql語句進行刪除。如果原數據不存在,也返回成功。 |
更新 | POST | <domain>/<UPDATE> | 更新請求,見下 | 通用返回,見下 | 后端收到請求后,解析data和query變量。然后組sql語句進行更新。如果原數據不存在,也返回成功。 |
新增 | POST | <domain>/<INSERT> | 新增請求,見下 | 通用返回,見下 | 后端收到請求后,解析data變量。然后組sql語句進行更新。 |
候選項查詢 | GET | <domain>/<LIST>?table=<table>&key=<key>&value=<value>&query=<col1:value1,col2:value2...> | 無 | 候選項返回,見下 | 后端收到請求后,解析query參數。然后組sql語句進行查詢,返回查詢結果。 |
刪除請求:
1 { 2 table:<table>, 3 query:<col1:value1,col2:value2...> 4 }
更新請求:
1 { 2 table:<table>, 3 data:<col1:value1,col2:value2...>, 4 query=<col1:value1,col2:value2...> 5 }
新增請求:
1 { 2 table:<table>, 3 data:<col1:value1,col2:value2...>, 4 }
4.2 返回說明
查詢返回:
1 { 2 result:<00>, //響應結果,00為成功 3 message:<OK>, //響應信息 4 data:[ //查詢無結果則返回空列表 5 [ //查詢出來的每一條數據 6 value1, //每一條數據的每列的值,如果該列是動態下拉框,那么還需要根據表配置文件進行查詢組成“key|value”的形式,key和value均base64編碼 7 value2, 8 … 9 ], 10 … 11 ] 12 }
通用返回:
1 { 2 result:<00>, //響應結果,00為成功,插入時01為主鍵沖突 3 message:<OK>, //響應信息 4 }
候選項返回:
1 { 2 result:<00>, //響應結果,00為成功 3 message:<OK>, //響應信息 4 data:[ //如果查詢無數據則返回空列表 5 { //每一條數據 6 key:<key> 7 value:<value> 8 } 9 … 10 ] 11 }
5 下一步的工作
easyconf從設計到編碼花了我兩天時間,目前的版本能夠滿足基本的配置管理需求。但是仍由很多地方急需改進和優化,例如:頁面的美化(並且也能夠通過表配置文件定制),更加健全的異常處理,外鍵約束的校驗,表操作的權限管理,等等。由於懶,我搞出來這個一個玩意兒,同時又給自己挖了好大一個坑,之后慢慢填吧。大家可以從GitHub上下載easyconf以及demo后端。