<!----><!----> <!-- /* Font Definitions */ @font-face {font-family:Wingdings; panose-1:5 0 0 0 0 0 0 0 0 0; mso-font-charset:2; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:0 268435456 0 0 -2147483648 0;} @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:Verdana; panose-1:2 11 6 4 3 5 4 4 2 4; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:536871559 0 0 0 415 0;} @font-face {font-family:"\@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-font-kerning:1.0pt;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} /* List Definitions */ @list l0 {mso-list-id:848981233; mso-list-template-ids:802194774;} @list l0:level1 {mso-level-tab-stop:36.0pt; mso-level-number-position:left; text-indent:-18.0pt;} @list l1 {mso-list-id:990063059; mso-list-template-ids:-1985988758;} @list l1:level1 {mso-level-tab-stop:36.0pt; mso-level-number-position:left; text-indent:-18.0pt;} @list l2 {mso-list-id:1050421959; mso-list-template-ids:-1951515512;} @list l2:level1 {mso-level-tab-stop:36.0pt; mso-level-number-position:left; text-indent:-18.0pt;} @list l3 {mso-list-id:1488664008; mso-list-template-ids:-496185514;} @list l3:level1 {mso-level-tab-stop:36.0pt; mso-level-number-position:left; text-indent:-18.0pt;} @list l4 {mso-list-id:1498499988; mso-list-template-ids:1329344206;} @list l4:level1 {mso-level-number-format:bullet; mso-level-text:; mso-level-tab-stop:36.0pt; mso-level-number-position:left; text-indent:-18.0pt; mso-ansi-font-size:10.0pt; font-family:Symbol;} @list l5 {mso-list-id:1766685587; mso-list-template-ids:849530270;} @list l5:level1 {mso-level-tab-stop:36.0pt; mso-level-number-position:left; text-indent:-18.0pt;} ol {margin-bottom:0cm;} ul {margin-bottom:0cm;} --> <!---->
最近与同是开发者的朋友一起,谈论各种各样Java 的之外的构架。似乎有一些现象( 我不会讨论任何现象, 但是Googling 能很快的给你一些符合条件的结果) 表明, Java 正在因为许多原因成为Web 的老警卫( 译者按,应该是不成作用的没有成效的意思) ,其中一个是代码行(LOC) 。做同一件事情Java 的某一些参数需要其他语言的2 倍的代码量,我个人以为LOC 仅仅是一个问题,它让你把一些本不该花的时间都花在你本不该去做的事情上。例如,象手工编写你所有的Bean 一样, 或许你也正在手工的为你的构架XML 定义所有的条目! 我承认, 我正是这样。
不久之前我使用RubyOnRails ,一个让我喜欢用它们的原因就是他们能很容易产生完全的代码,从简单的script 到复杂的代码。 这让我考虑我的当前的工作和编码期间我的有效情况是怎么样的。 “ 多少工作我做好VS 多少时间被做我花费试着把工作做好” 的思想在过去的数星期内不停的在我脑子里萦绕。虽然有各种框架帮助我们使工作变的容易一些—-- 比喻说在使用的Spring—-- 它一些时候看起来很笨重,为一个web 应用程序做一个页面或者一个模块就需要很长的时间。因此在一些思考以后, 我决定了做一些东西。
我多年前已经知道XDoclet 并且在它首次出现的时候试用了它。但是我没有进行长期的考虑, 所以当时我还不是一个在代码生成方面的大拿。我想要了解事情到底是怎么工作的, 因此我花了大量时间手工编写任何代码,包括config 文件和deployment 文件。
然而,我今天发现代码生成的两个主要的益处:
使用 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 根据不同位置的标签来生成在我们的模板中使用的类和属性对象。这是一个很重要的区别,我们将在接下来研究。
看一下上面的代码,我们将做下面的操作:
很有争议的是,我可能把所有的属性定义发在类的层次上而不是 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. }