天天看點

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 都是可以自己設定的,預設值是上述形式。