你的位置:首页 > Java教程

[Java教程]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-Date14         control:<0>,      //列在页面上显示的控件类型,0-text/1-combo box15         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     else16       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后端。