jasonfreak

一个懒惰的人,总是想设计更智能的程序来避免做重复性工作

easyconf——基于AugularJS的配置管理系统开发框架

目录

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后端。

posted on 2016-07-07 11:59  jasonfreak  阅读(2514)  评论(2编辑  收藏  举报

导航