天天看點

寫一個通用的代碼生成器

       代碼生成器對于java碼農來說并不陌生。在一些業務性比較強,但編碼比較規範的項目中,往往會有大量的重複或者類似的代碼要寫。比如對表的增删改查,比如生成用于遠端調用的用戶端方法存根等等。面對這種情況,程式員通常的做法就是拿一個現成子產品的代碼copy過來再改改。于是,為了避免這種低效而容易出錯的編碼方式,誕生了各種各樣的能跟據目前項目特證自動生成代碼的代碼生成器程式。這種程式的本質上就是将大量重複的複制修改工作用程式自動來做,以便自動産生适合自己項目的代碼。

       然而,這種代碼生成器往往都是針對某個單一的項目量身定做的,通用性并不強。而且生成器程式本身所用到的技術架構也各不相同。本文,将介紹本人的一個通用生成器架構,同時展示本人在這個架構上的一個基于eclipse插件的實作。這個架構是将自動生成代碼的邏輯進行一次抽象的設計,封裝了自動生成代碼底層的技術邏輯。使用這個架構,開發人員隻需要跟據自己項目的業務特性,進行一些簡單的配置,就可以達到自己生成代碼的目地。

<b>傳統的代碼生成器原理:</b>

       在講通用生成器之前,簡單說說傳統代碼生成器的原理,大緻上就是使用一些比如velocity或freemark之類的模闆技術,寫一些需要生成代碼的檔案模闆,模闆大部分的内容是代碼檔案可複用的那部分代碼,而其中可能會有變會化的代碼用比如“${}”之類的符号作為占位符。然後通過velocity或freemark的api傳遞一些參數進去,讓velocity或freemark幫我們跟據傳入的參數自動替換掉模闆中的占位符,這樣就生成了我們想要的代碼。

<b>通用代碼生成器原理:</b>

       在傳統的代碼生成器的基礎上,我抽像出三個概念:<b>參數、模闆、規則</b>。這三個概念就是本架構的核心邏輯。以下分别介紹:

<b>參數:</b>

       在用模闆生成代碼之前,程式必須收集到足夠的資訊,作為填充模闆檔案中參數占位符的依據。比如在自動生成增删改查的代碼生成器中,必須告訴生成器,生成的實體類将有哪些屬性、每個屬性的類型是什麼等等。在用velocity或freemark的技術中,傳入的參數是可以是任意的普通變量、集合對像、自定義對像等等。為了規範起見,本架構決定統一使用一個map結構的對象作為參數。之是以選擇map這種資料結構,是為了更好的抽象出這些參數,做到寫生成器程式的開發人員隻需要通過簡單的配置就可以定義出這些參數,而不需要跟據生成器具體的功能,去寫一些業務相關的類。而且map是可以多級嵌套的,也就是說一個map中的value值可以是另一個map,這樣做,可使得參數的層次感強,容易維護。

<b>模闆:</b>

       通用生成器本質上還是基于velocity或freemark等某種模闆技術,開發人員不可避免的要寫一些模闆程式檔案。隻不過,本架構封裝了通過模闆生成代碼的具體的邏輯,使用者隻需要指定模闆和參數并指定一些規則,程式将自動按照規則生成代碼。下面介紹規則的概念:

<b>規則:</b>

       規則就是規定生成器按怎樣的過程來生成想要的代碼。比如,在一個自動生成增删改查的代碼中,一般過程是先生成java實體類,再生成業務層的service類、資料通路層dao類,然後生成界面jsp檔案。這個過程,在傳統的生成器中需要自己寫代碼來做這些事。我把它抽象成“規則”這個概念,就是想實作讓程式員可以通過配置來自己制定這些規則,最後讓程式自動去完成這些過程。

       總體上,通過個這個架構定制代碼生成器的過程式分三步:<b>參數定義、模闆制做、規則制定</b>。而通過這種方式生成具體代碼的過程分兩步:<b>參數收集、将參數傳入模闆按照規則生成代碼</b>。我們可以寫一個web界面或者eclipse插件來實作這些過程。

       以curd為例,下面展示本人用eclipse插件寫的一個自動生成增删改查的生成器:

<b>curd生成器參數定義界面:</b>

<b></b>

寫一個通用的代碼生成器

圖:curd生成器參數定義

       上圖是curd生成器的參數定義,從上圖中,可以看到,curd生成器的參數主要有“實體名稱”、“對應表名”、“屬性定義”等等。而且從上圖的左則可以看到,這些參數是分級的樹狀結構。這樣做,在本生成器生成代碼的“參數收集”的過程中,會把參數按照這個樹狀結構,收集到一個多級嵌套的map對象中,作為模闆的傳入參數。

       上圖中間,是對每個參數的具體屬性定義,比如參數代碼、資料類型、預設值等等。其中最重要的是參數代碼,在同一級所有參數中,參數代碼不能重複,在生成代碼的參數收集過種中,它被處理成參數map中的key(因為參數分級,可按照層級關系生成含點号“.”的key)。比如上圖中“實體名稱(entityname)”這個參數,它是“實體基本資訊(entitywizardpage)”這個參數的下級參數,那麼它在map對像中的key就是“entitywizardpage.entityname”。這樣做,是友善傳入velocity模闆中(本插件用的是velocity模闆技術)。

       上圖的右則,是維護這些參數定義的一些操作按鈕,可以增加參數、修改參數等等(程式員全完不需要懂得eclipse插件,隻要使用這個插件就可以定義出這些參數)。

<b>curd生成器規則定義界面:</b>

寫一個通用的代碼生成器

圖:curd生成器規則定義

       上圖是curd生成器的參數定義,從上圖右則可以看到,此生成器定義了如下規則:生成實體類、生成action類、生成service類、生成dao類、生成jsp檔案。在用這個生成器生成增删改查的代碼時,程式将自動按照這個流程生成實體類、action類和service類等等。上圖中間是對每個規則的具體定義,比如生成實體類的模闆在哪裡,生成的實體類最終在哪個輸出目錄裡,這個規則是否被禁用,觸發條件是什麼等等。上圖右則的按鈕就是制定規則的一些操作,比如增加一個規則、修改一個現有的規則等等。

<b>curd</b><b>生成器模闆制作:</b>

       在定義curd生成器的參數和規則的生同時,可以制定生成相關代碼的模闆。本人通過eclipse插件實作了一個vm模闆文檔編輯器,如下圖所示:

寫一個通用的代碼生成器

圖:curd生成器模闆

       上圖就是curd模闆檔案編寫界面,本架構所有生成器的模闆檔案都是vm格式,eclispe插件會自動使用本插件定制的一個編輯器打開。界面如上圖所示,圖中中間就是模闆檔案内容的編輯界面,圖中用藍色标出的高亮的代碼部分就是用“${}”符号括起來的參數占位符,而且占位符内容就是前文“參數定義”一節的樹狀參數定義,這裡按照層級關系用點号表達出來,這種表達方式也正是典型的velocity文法,能被velocity模闆引擎直接識别。為了友善書寫,我寫了一個eclipse自定義視圖,列出目前生成器定義的所有參數,如上圖右則所示。

<b>curd</b><b>生成器參數收集:</b>

       在用這個生成器生成curd界面時,需要開發人員錄入事先定義的參數資訊,curd參數收集界面的屬性定義界面如下:

寫一個通用的代碼生成器

圖:curd生成器“實體屬性”參數收集

       上圖就是curd生成器生成實體時的實體類屬性定義界面,通過右邊的“添加”、“編輯”等按鈕可以添加或修改實體類中的屬性。值得一提的是,上圖這個界面并不是一成不變的,而是開發人員通過前文的“參數定義”一節自己配置出來的,開發人員就算不懂eclipse插件開發,也可以跟據自己的需要,配置一些這類似的界面。

       以上就是本人按照本文介紹的代碼生成器架構的原理寫的一個自動生成代碼的插件,并展示了一個生成curd代碼的配置過程。大家如果使用這個插件,也可以自己配置一些适合自己項目的生成器。而無需了解velocity模闆引擎,更無需了解eclipse插件開發,隻要跟據自己項目的業務需求,定義參數、編寫模闆、制定規則後,就可以定制出适合自己eclipse插件形式的代碼生成器了。

       目前這個插件,還在不斷的測試和完善之中,等做好後釋出出來給大家用用。如果想關注更多資訊,了解最新動态,可以掃碼關注我的個人公衆号:

寫一個通用的代碼生成器

繼續閱讀