天天看点

cms查询系统(二)json形式参数的设计与解析1 前言2 题目及分析3 代码设计与实现4 DefaultSqlParamsHandler使用解析器5 工程项目

本篇文章主要来说明下代码模块的设计。像我们这种菜鸟级别,只有平时多读读源码,多研究和探讨其中的设计才可能提升自己,写出高质量的代码。

没有最好的设计,只有更好的设计,所以在发表我自己的愚见的同时,希望小伙伴们相互探讨更好的设计,有探讨才有更大的进步。

我们维护了一个数据中心,对外提供查询api,如何能让用户随意的添加查询条件,而不用修改后台的查询代码呢?用户如何配置查询条件,从而达到如下的sql效果呢?:

我们作为api设计者,该如何让用户方便的传递他们任意的查询需求呢?这是我们要思考的地方。

目前来看比较好的方式莫过于:用户通过json来表达他们的查询需求。

从上面的查询来看,我们可以总结出来查询条件无非就是某个字段满足什么样的条件。这里有三个对象:

查询的字段 如 b.age

条件值 如 12

怎样满足条件值 如 >

这样我们就可以清晰明了了,一个查询条件无非就是三个内容,所以可以如下配置:

很显然,上面的确很麻烦,我们无非是要表达这三个内容,所以就要简化配置:

还是不够简化,如何把操作符 > 也放置进去呢?如下

这样我们就可以把三个对象表达清楚了,将查询的字段和操作符合并起来作为key,并使用分隔符@分割两者,条件值作为value。这样就做到了,非常简化的查询配置。

接下来又面临一个问题,如何表达查询条件之间的and or 关系呢?即如何表达下面的内容呢?

借鉴mongodb的查询方案,可以如下配置:

通过配置一个$or作为key表明里面的几个查询条件是or的关系,如果是$and表明里面的查询条件之间是and的关系,外层默认是and的关系。

同时我们再回顾下,mongodb所作出的查询设计,也是通过用户配置json形式来表达查询意图,但是我们来看下它是如何查询

虽然看似我们的更加简单,mongodb的更加繁琐,主要是mongodb认为对于一个字段,可以有多个查询条件的,为了支持更加复杂的查询,如下:

各有各的好处和缺点,我就是我,颜色不一样的烟火。哈哈。。。

对题目进行分析完了之后,就要考虑如何实现这样的json配置到sql的转化。实现起来不难,最重要的是如何做出一个高扩展性的实现?

再来看下下面的例子:

其实就是针对每个自定义的操作符进行相应的处理,所以就有了解析器接口:

其中sqlparamsparseitemresult,则是把解析后的结果分别存储起来,而不是直接拼接成一个字符串,主要为了直接拼接字符串式的sql注入,它的内容如下:

上面的key oper value 则是解析后的内容。下面举例说明

以"b.age@>“:12 为例,其中getparams方法中的 key就是b.age, value就是12, oper就是> 而这个方法的返回的字符串结果为:

以"c.id@in”:[12,13,14]为例,其中getparams方法中的 key就是c.id,value就是一个list集合,oper就是in ,这个方法的返回结果为:

以"d.time@time>“:“2015-3-1"为例,其中getparams方法中的 key就是c.id,value就是一个list集合,oper就是in,这个方法的返回结果为:

解析器有很多相同的地方,这就需要我们进行抽象,抽出共性部分,留给子类去实现不同的部分。所以有了抽象类abstractsqlparamsparser

有哪些共性部分和非共性部分呢?

共性部分: 就是support方法。每个解析器支持某几种操作符,所以判断该解析器是否支持当前的操作符的逻辑是共同的,所以如下:

opers属性表示当前解析器所支持的所有操作符。ignorecase表示在匹配操作符的时候是否忽略大小写。这两个属性都设置成private,然后对子类开放了protected类型的set方法,用于子类来设置这两个属性。

非共性部分:留出了doparams方法供子类来具体实现

目前内置了几个常用的解析器实现,类图如下: 

cms查询系统(二)json形式参数的设计与解析1 前言2 题目及分析3 代码设计与实现4 DefaultSqlParamsHandler使用解析器5 工程项目

以timesqlparamsparser为例来简单说明下:

它主要是用于解析如下形式的:

最终想达到的效果是:

它的解析过程如下:

解析过程其实就是对key value oper 进行了不同程度的转换。

同时timesqlparamsparser还支持其他时间形式的解析,如"2015-3-1 12:23:12”,只需如下方式创建一个解析器:

然后他就能够解析下面的形式:

同时又能保留原有的形式,两者互不干扰。

有了解析器的一系列实现,下面就需要一个综合的类来使用这些解析器。这就是defaultsqlparamshandler:

内部已经注册了几个解析器。同时需要对外留出注册自定义解析器的方法:

这个过程不仅需要使用已经注册的解析器来解析,还包含对解析条件之间的and or 关系的递归处理。代码如下,不再详细说明:

这里进行了递归调用,主要用于处理 $and $or 的嵌套查询,getsqlwhereparamsresultbyandor可能内部调用了processmodelsqlwhereparams,processmodelsqlwhereparams内部又调用了getsqlwhereparamsresultbyandor

这里就是使用解析器进行解析的过程,先遍历每个解析器是否支持当前的操作符,如果支持则进行相应的解析

这里面的@ $or 以及 $and 都是可以自己设定的,默认值是上述形式。