国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

通過XDoclet定制模板進行快速開發

2019-11-18 12:47:03
字體:
來源:轉載
供稿:網友

  最近與同是開發者的朋友一起,談論各種各樣java的之外的構架。似乎有一些現象表明, Java正在因為許多原因成為Web發展的障礙,其中一個問題是代碼行(LOC)。做同一件事情,Java的某一些參數需要其他語言的2倍的代碼量,我個人以為LOC僅僅是一個問題,它讓你把一些本不該花的時間都花在你本不該去做的事情上。例如,象手工編寫你所有的Bean一樣。 或許你也正在手工的為你的構架xml定義所有的條目,以此來節約時間, 我承認, 我正是這樣。
  
  不久之前我使用RubyOnRails,一個讓我喜歡用它們的原因就是他們能很輕易產生完全的代碼,從簡單的script到復雜的代碼。 這讓我考慮我當前的工作和編碼期間我的有效情況是怎么樣的。 “我做好了多少工作VS我花費多少時間”的思想在過去的數星期內不停的在我腦子里縈繞。雖然有各種框架幫助我們使工作變的輕易一些—--比喻說在使用的SPRing—--它一些時候看起來很粗笨,為一個web應用程序做一個頁面或者一個模塊就需要很長的時間。因此在一些思考以后, 我決定了做一些東西。
  
  我多年前已經知道XDoclet,并且在它首次出現的時候試用了它。但是我沒有進行長期的考慮, 所以當時我還不是一個在代碼生成方面的大拿。我想要了解事情到底是怎么工作的, 因此我花了大量時間手工編寫任何代碼,包括config文件和deployment文件。
  
  然而,我今天發現代碼生成的兩個主要的益處:
  
  1.你在想學什么東西的時候,它將是很有幫助的。比喻說,去年我想學Hibernate 的時候,我已經有了存在的表,不想再反復的測試它是怎么工作的了,我也不想花大量的時間來填寫文檔。使用一個方便的叫做Middlegen的工具,我只要告訴它查看我的數據庫并且為我生成代碼就可以了。現在,寫一個mapping文件對我來說已經很輕易了,可是Middlegen的幫助節省了我大量的時間并為我指明了方向。
  
  2.在對你的工程有一個清楚的概念和一個結構甚至一個框架已經搭建起來后,接下來的事情將變的十分的乏味,手工的創建beans,controllers, services 和 DAO,每次都會有一些新的需求要被創建。理想的做法是,你也許會調用一些Ant任務,比喻說, gencontrollers或者genmodules 來生成合適的controller代碼或者一個整個的包含你的beans, controllers, services和DAO的模塊.
  
  使用XDoclet 來減輕痛苦
  
  基于過去的一些經驗,我不敢確信XDoclet對我有多大的幫助。我想要尋找一個工具讓我可以花最少的時間來生成最多的代碼。我在XDoclet網站上看到的大部分的示例都是針對于EJB的生成的,其實這也是XDoclet設計的初衷。但是,情況是這樣的,我的工程不含有任何的EJB代碼,事實上Spring全部是關于POJO的東西,所以EJB方面的工具不是我需要的。同時,XDoclet不含有任何的Spring標簽,所以我一直在尋找一個不同平常的什么東西。
  
  最后我把目光投上了模板。模板是一種繼續XDoclet功能來更好的滿足你的代碼生成要求的方法。例如,你有一個非凡類型的類,與XDoclet所支持的任何一種都很不同(在我看來是一些客戶化的控制類),你就可以用XML文件來把你自己的模板加進去。理想化的,我只想定義一個含有最小量的屬性并不但產生我的控制器代碼而且另外的Spring所要求的XML文件。在實驗了幾次以后,我對結果很滿足。下面就是加標注的假設的代碼測試控制器類。長代碼行以/分開。
  
  TestController.java
  1.   package com.mytest.account.controller;
  2.
  3.   /**
  4.    * @mytest.controller mapping="/acct.ctrl"
  5.    * @mytest.controller actionmethod="create"
  6.    * @mytest.controller actionmethod="read"
  7.    * @mytest.controller actionmethod="update"
  8.    * @mytest.controller actionmethod="delete"
  9.    */
  10.   public class TestController {
  11.
  12.     /**
  13.     * @mytest.controller property="privateView" propertyValue="priv1" propertyMethod="PrivateView"propertyType="String"
  14.     */
  15.     private String privateView = null;
  16.
  17.     /**
  18.     * @mytest.controller property="publicView" propertyValue="priv2" propertyMethod="PublicView" propertyType="String"
  19.     */
  20.     public String publicView = null;21.   }
  
  你首先看到的可能是客戶化的命名空間@mytest.controller標簽。這個是在生成我們類的不同部分時,XDoclet如何知道去查找什么。標簽的位置十分的重要。一些在類要害字的上面一些在屬性定義的下面。XDoclet根據不同位置的標簽來生成在我們的模板中使用的類和屬性對象。這是一個很重要的區別,我們將在接下來研究。
  
  看一下上面的代碼,我們將做下面的操作:
  
  1.為SimpleUrlHandlerMapping建立一個Spring mapping入口,它將在一個叫做mytest-servlet.xml 文件中被描述(是Spring中與Struts中的struts-config.xml 類似的東西).
  
  2.actionmethod 屬性答應我們為一個控制器指定一個方法名,它是從Srping的MultiActionController 繼續而來 (在Struts, 對應的是 DispatchAction)。在我們的例子中,將會有 CRUD (Create, Read, Update, Delete)這么幾個方法名。 XDoclet將會重復的進行不同參數的相同方法名的方法,所以答應我們的模板輸出N個方法。
  
  3.property 標簽 讓我們 定義一個典型的Bean屬性,像你通常在XDoclet中做的一樣,因為我們在這里使用了一個定制的模板,我們增加了更多的屬性。propertyValue 是為mytest-servlet.xml 中對應的屬性所指定的值。對我們的定制的標簽來說,我們正在為控制器類設置private的和public的jsp頁面顯示,我通常管它們叫privateView和publicView—一個是針對簽發者的另一是針對每一個人的。propertyMethod 將為我們提供一種簡單的方法來類指定這個屬性屬于那一個方法,而不用去跳過bean-method-naming的約束。propertyType 屬性指定了我們將要為這個方法get/set什么類型的屬性。
  
  很有爭議的是,我可能把所有的屬性定義發在類的層次上而不是Field的層次上。這也未嘗不可,但是這將為在模板上增加額外的代碼來確定在產生一個方法的時候我使用了正確的屬性,方法,類型。我感覺使用XDoclet的Field 類比往我的模板里增加復雜的代碼要輕易和迅速。
  
  模板
  
  好了,現在讓我們開始干活吧。正像我前面提到的那樣,我選擇XDoclet來生成代碼的原因是我將定義一套定制的模板(不是一些定制的類或者更多的代碼)并使用XDoclet的XML標簽來為我填充這些空白。下面所列就是我們想要生成的模板相應的部分。長代碼已經被/ 分開。
  
  MultiController.xdt
  
  1.   package <XDtPackage:packageName/>;
  2.   import javax.servlet.http.HttpServletRequest;
  3.   import javax.servlet.http.HttpServletResponse;
  4.
  5.   import org.apache.commons.logging.Log;
  6.   import org.apache.commons.logging.LogFactory;
  7.   import org.springframework.validation.BindException;
  8.   import org.springframework.web.servlet.ModelAndView;
  9.
  10.   import com.mytest.system.spring.BaseController;
  11.
  12.   /**
  13.   * MultiAction controller class for <XDtClass:className/>.
  14.   *
  15.   * @author
  16.   * @since
  17.   * @version $Id$
  18.   */
  19.   public class <XDtClass:className/> extends BaseController {
  20.
  21.   // CUT AND PASTE THIS INTO THE mytest-servlet.xml FILE
  22.   //
  23.   //  <!-- ==== <XDtClass:className/> Bean Definition ==== -->
  24.   // <bean id="contr<XDtClass:className/>" class="<XDtPackage:packageName/>.<XDtClass:className/>">
  25.   //  <property name="methodNameResolver" ><ref bean="actionResolver"/></property>
  26.   <XDtField:forAllFields>
  27.     <XDtField:ifHasFieldTag tagName="mytest.controller">
  28.   //  <property name="<XDtField:fieldTagValue tagName="mytest.controller" paramName="property"/>"><value><XDtField:fieldTagValue tagName="mytest.controller" paramName="propertyValue"/></value></property>
  29.     </XDtField:ifHasFieldTag>
  30.     </XDtField:forAllFields>
  31.   // </bean>
  32.   //
  33.   // === PUT THIS UNDER THE URL MAPPINGS SECTION ===
  34.   // <prop key="<XDtClass:classTagValue tagName="mytest.controller" paramName="mapping"/>">contr<XDtClass:className/></prop>
  35.   //
  36.
  37.     protected final Log log = LogFactory.getLog(getClass());
  38.
  39.    <XDtField:forAllFields>
  40.     <XDtField:ifHasFieldTag tagName="mytest.controller">
  41.       public <XDtField:fieldTagValue tagName="mytest.controller" paramName="propertyType"/> get<XDtField:fieldTagValue tagName="mytest.controller" paramName="propertyMethod"/>(){
  42.           return <XDtField:fieldTagValue tagName="mytest.controller" paramName="property"/>;
  43.       }
  44.
  
  45.       public void set<XDtField:fieldTagValue tagName="mytest.controller" paramName="propertyMethod"/>(<XDtField:fieldTagValue tagName="mytest.controller" paramName="propertyType"/> value) {
  46.       <XDtField:fieldTagValue tagName="mytest.controller" paramName="property"/> = value;
  47.       }
  48.    </XDtField:ifHasFieldTag>
  49.    </XDtField:forAllFields>
  50.
  51.     public ModelAndView init(HttpServletRequest request, HttpServletResponse response)
  52.       throws ServletException, IOException {
  53.       if(log.isDebugEnabled()) log.debug("entered");
  54.       // YOUR INIT CODE GOES HERE
  55.       if(log.isDebugEnabled()) log.debug("exited");
  56.       // REPLACE THIS HERE IN YOUR CODE
  57.       return null;
  58.     }
  59.
  60.    <XDtClass:forAllClassTags tagName="mytest.controller">
  61.     <XDtClass:ifHasClassTag tagName="mytest.controller" paramName="actionmethod">
  62.     public ModelAndView <XDtClass:classTagValue tagName="mytest.controller" paramName="actionmethod"/>(HttpServletRequest request, HttpServletResponse response)
  63.       throws ServletException, IOException {
  64.       if(log.isDebugEnabled()) log.debug("entered");
  65.
  66.       if(log.isDebugEnabled()) log.debug("exited");
  67.       // RETURN THE PROPER VIEW HERE
  68.       return null;
  69.     }
  70.
  71.     </XDtClass:ifHasClassTag>
  72.    </XDtClass:forAllClassTags>
  73.
  74.     // Your (other) multiaction methods go here
  75.
  76.   } // <XDtClass:className/>
  
  恩,當這些都完成的時候,我們擁有了一個控制器類,包含對應于Spring中定義bean和URL mapping的mytest-servlet.xml的XML代碼,為視圖屬性提供了適當的get/set方法,我的多action 方法,完整的Debug日志語句。從21行開始,包含了XML(將會被清除)的76行代碼,可以為我們節省大量的敲代碼的時間和排除錯誤。
  
  同時需要注重的是 XDtField 和 XDtClass 標簽。現在應該很清楚的是我們為什么把不同的標簽值給替換了。我們所有的類級的標簽或者定義了類方法或者是XML配置文件的值,而field級別的標簽為我們產生get/set方法。像我前面說到的那樣,我們在這里對field的使用略有不同,因為我們在mytest-servlet.xml 中還利用它來做一些控制器的mapping值。當我們的控制器啟動的時候,Spring會為privateView 和 publicView方法注入合適的值。
  
  把他們整合到一起
  
  問題的最后就是如何把所有的這些東西整合到一起,而且讓我們可以看到產生的代碼。這就是為什么要把Ant引入的原因所在,我們將做下面3件事情:
  
  1.創建一個文件夾,從code base 分離出來,這將是我們保存假的源文件的地方和自動產生的源文件的地方。
  
  2.為我們的模板創建一個目錄。
  
  3.為代碼生成創建一個Ant任務。
  
  在我開發的機器上有如下的文件夾結構
  trunk
  
  +----+- src
  +- xdoclet
  
  +- build
  +- src
  +- com/mytest/account/controller
  +- template
  
  起初,看起來可能有點糊涂,因為這里有兩個src。但是我感覺有個重要的原因就是,我在xdoclet下有一個單獨的src可以讓我把假的源代碼(譯者按,就是要被填充的java文件)和產生的代碼分開。在我運行Ant任務以后,有一個文件就是怎么把文件拷貝到主src目錄(與xdoclet同一級別的)并且把產生的代碼加進去。為達到這篇文章的目的,我把這些東西從source code 分離出來,這也許能防止把在把所有的生成混成一團的時候帶來的各種問題。
  
  根據上面的文件夾結構,這是我們的文件應該在的地方:
  
  trunk/src/xdoclet/src/com/mytest/account/controller/TestController.java
  
  trunk/src/xdoclet/template/MultiController.xdt
  
  .java文件需要包名來與文件夾對應,這樣XDoclet才能熟悉它,并根據它來運行模板。我發現XDoclet只是把log4j的Debug級別設置到INFO, 當我沒有把.java文件放到正確的位置的時候,XDoclet不會顯示任何的錯誤信息,也發現不了也生成不了文件。只有我查看了.jar文件并修改了log4j.properties 以后正確的顯示沒有要處理的錯誤信息才被顯示。從技術角度說,這不是一個錯誤,但是它讓我琢磨了很長的時間,所以要注重這一點。
  
  接下來的Ant任務,使用上面的樹并且在正確的目錄里生成代碼。
  
  1.   <!-- ========Xdoclet Target ======== -->
  2.
  3. <target name="xdoclet">
  4.
  5. <path id="xdoclet.classpath">
  6.  <fileset dir="${xdoc.home}/lib">
  7.   <include name="*.jar"/>
  8.  </fileset>
  9. </path>
  10.
  11. <echo>+------------------------------------+</echo>
  12. <echo>Generating sources from xdoclet tree</echo>
  13. <echo>+------------------------------------+</echo>
  14.
  15. <taskdef name="doclet" classname="xdoclet.DocletTask" classpathref="xdoclet.classpath" />
  16. <doclet destdir="${jxdoc.dir}/build"
  17.   verbose="true">
  18.  <fileset dir="${jxdoc.dir}/src">
  19.   <include name="**/*Controller.java" />
  20.  </fileset>
  21.  <template
  22.    templateFile="${jxdoc.dir}/template/MultiController.xdt"
  23.    destinationFile="{0}.java"
  24.    suBTaskName="Create Controller file(s).." />
  25. </doclet>
  26.
  27. </target>
  
  想要運行這個,需要做一些配置。
  
  1.第6行xdoc.home 應該指向你的XDoclet的安裝目錄。
  
  2.22行為我們的模板文件定義了一個位置和名字。
  
  3.24行指定當doclet運行的時候XDoclet要輸出到控制臺的任務的名稱信息。這只是為了方便而已。
  
  你可以通過下面的命令來運行: ant xdoclet.
  
  假如一切運行正常的話,你應該能看到BUILD SUCCESSFUL的消息。在xdoclet/build/com/mytest/account/controller 目錄下,你的新的文件就應該出現,文件中有必要的骨架屬性和方法。
  
  這個模板可以別修改成不單單產生控制器而且可以產生Bean,Form,Service等等。在xdoclet 中,你只需要為每一個你想要生成的對象類型增加一個新的taskdef然后提供一個不同的模板。比喻說,假如你想產生service對象,你可以使用下面的taskdef:
  
  1. <taskdef name="servicedoclet" classname="xdoclet.DocletTask" classpathref="xdoclet.classpath" />
  2. <servicedoclet destdir="${jxdoc.dir}/build"
  3.    verbose="true">
  4.  <fileset dir="${jxdoc.dir}/src">
  5.   <include name="**/*Service.java" />
  6.  </fileset>
  7.  <template
  8.    templateFile="${jxdoc.dir}/template/Service.xdt"
  9.    destinationFile="{0}.java"
  10.    subTaskName="Create Service files(s).." />
  11. </doclet>
  
  在上面的代碼中,我們看到我把taskdef 的名字改成servicedoclet,并且包含的fileset屬性由*.Controller.java變成*.Service.java, 這將導致任務只去查找以"Service.java."結尾的文件。
  
  在第8行,我們告訴XDoclet使用Service.xdt模板。所以假如我們已經完成初始化工作的話,我們很輕易就能增加一個特定的代碼生成器。完全可能的是(我也正是這樣做的),我們可以在xdoclet任務下生成很多的模板,在這個任務下,讓它一次把每一個對象類型都讀到然后一次性的把每樣東西都生成完畢。
  
  Maven 2.0 和原型的一句話: Maven 2.0 包含了一種稱為原型的機制,它答應基于模板驅動的工程代碼生成。但是實現方式有所不同--Maven使用Velocity 來生成模板--與我們上面講的那些相比,基本上完成同樣的事情,但是工作范圍是在更大的project范圍。
  
  我試過很多次使用Maven ,我很欣賞這個做法。但是我感覺,從上面的例子來說,Maven 需要花費更多的程序員的努力時間(在剛開始的時候)。但Maven 正好說明了我前面提出的我關心的問題,我喜歡基于Rails在project級別和其他程序員合作。當然,Maven,也可以在project級別工作,通過配置參數來生成代碼,從而為程序員節省大量的時間。這才是最有實際意義的一件事情。對于已經存在的工程,這里講到的方法都是一種更快的有著更少結構沖突的實現方式。
  
  結論
  
  下面就是我們這篇文章所提到的:
  
  1.創建了一個不但能生成類,而且能為我們的框架生成必要的XML配置文件的定制的pseudo-Java文件。在我們的例子里,我們定義了一個定制的可以用在Spring Web服務器里的控制器。
  
  2.定義了一個包含了一些我們的類的靜態元素和一些可以在運行的時候提供動態類代碼的組合的XDoclet XML 標簽的模板文件。
  
  3.建立一個文件夾結構和Ant任務,它將調用XDoclet來產生我們的骨干控制器類。
  
  這只討論了XDoclet的皮毛。我們只看到一個小型的,還有點作用的例子,它展示了模板幫助你不但成為一個更有效率的程序員,并且是成為更聰明的一個。我希望它可以為你節省更多的時間。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 石阡县| 桂阳县| 宁海县| 万山特区| 团风县| 赤水市| 南召县| 盖州市| 津市市| 玉屏| 西林县| 曲靖市| 临泉县| 进贤县| 温州市| 台南县| 高淳县| 荃湾区| 宁南县| 揭西县| 峡江县| 北宁市| 石阡县| 苍梧县| 林周县| 攀枝花市| 城步| 驻马店市| 新巴尔虎右旗| 梁平县| 阿拉尔市| 阜南县| 孟州市| 阿巴嘎旗| 类乌齐县| 梅河口市| 鹤庆县| 新建县| 铅山县| 颍上县| 常州市|