ANT忠誠伴侶XDoclet基本任務手冊(轉)

ANT忠誠伴侶XDoclet基本任務手冊(轉)

最近用appfuse發現裏面使用xdoclet真是方便,雖然以前也用,但是沒有像appfuse那樣什麼都使用xdoclet生成。現在寫程序真是方便啊。本想把自己的收穫寫下來,但是發現網上高人早已編寫完成(又晚了一步,呵呵,快成遲來大師了),現轉貼如下:
任何人都想過自動生成的代碼,自己去寫個分析器不是件容易的事,而XDoclet給我們機會建立自己的代碼生成器。

    XDoclet最早用來對付EJB,因爲生成EJB的本地和遠程接口以及對應的HOME和描述符是一件簡單但是枯燥的事,本來我以爲,只有JBuilder這樣的集成編輯器可以很好的簡化工作,後來知道XDoclet也能夠完成得不錯。
   
    我最早用XDoclet是因爲學習hibernate,hibetnate的描述文件並不複雜,關鍵的部分不多,可是一旦對POJO修改,就必須要勞師動衆的找到對應的描述符來修改,增加了一次出錯的機會,而使用了XDoclet就可以做到同步的修改。
   
    還有就是struts,首先是配置文件,許多人操作同一個文件會產生衝突,有了XDoclet我們就不怕了,還有validate文件也一樣,有了XDoclet就會解決大部分衝突問題。
   
   
    之所以起這麼一個名字,主要因爲XDoclet和Ant結合得很緊,儘管實際上做的工作並沒有直接的聯繫,但XDoclet除了Ant接口就只有些Maven接口插件了,所以XDoclet幾乎是完全依賴Ant的。


本篇文章的目錄結構如下,因爲只是爲了說明問題,在我的ant的build文件中並沒有包括路徑名的引用,一切是直接的方式。
├─classes
├─doc
├─gen
├─lib
│      commons-collections-2.1.jar
│      commons-logging-1.0.3.jar
│      commons-validator.jar
│      log4j-1.2.8.jar
│      servlet.jar
│      struts.jar
│      xdoclet-1.2.1.jar
│      xdoclet-apache-module-1.2.1.jar
│      xdoclet-ejb-module-1.2.1.jar
│      xdoclet-hibernate-module-1.2.1.jar
│      xdoclet-web-module-1.2.1.jar
│      xdoclet-xdoclet-module-1.2.1.jar
│      xjavadoc-1.0.3.jar
├─merge
├─src
├─todo
└─web

只列出lib中的文件,每一個的作用在後面慢慢描述。

build.xml
開頭增加
<path id="xdoclet.classpath">
    <fileset dir="lib">
        <include name="*.jar"/>
    </fileset>
    <pathelement location="classes"/>
</path>
**************************************************************************************************

1,最簡單的todolist

每一篇講XDoclet都送這裏開始,有很多原因的。XDoclet的靈感來自JavaDoc,JavaDoc把文檔寫在代碼裏,緩解了困擾編程領域多年的文檔與程序同步問題。這裏有個很有趣的事,就是UNIX業界的人們傳遞下來這樣一個傳統,就是代碼是最好的文檔,保持文檔的同步實在是費力不討好的事,所以他們提出這樣一個好主意,不過JavaDoc更聰明,文檔是程序註釋的一部分,而且可以提取出來。

來吧,看這個任務。
<target name="todolist" description="todolist">
    <taskdef name="documentdoclet" classname="xdoclet.modules.doc.DocumentDocletTask" classpathref="xdoclet.classpath"/>
    <documentdoclet destdir="todo" >
        <fileset dir="src">   
            <include name="**/*.java" /> 
        </fileset> 
        <info header="Todo list" projectname="XDoclet in Action" tag="todo"/>
    </documentdoclet>
</target>

然後src寫這麼一個文件
package xdoclet;

public class TodoListTest {
/**
* @todo 我有許多工作要做,只是測試,忽略吧
*/
  public TodoListTest() {
  }

  /**
   * @todo 我還不知道名字 ,只是測試,忽略吧
   *
   */
  public String getYourName(){
       return null;
  }
}

注意要按照javadoc的寫法。還要注意ant中的子任務系統,其中info就是我們定義的documentdoclet任務的子任務,我們以後會看到很多類似的情況.
然後運行ant todolist
結果就是一個結構類似javadoc,但是隻包括todo標籤的html文檔,呵呵,可以看看項目裏有哪些待辦的事。





2,web.xml和taglib
作servlet映射是個討厭的工作,當你接收別的項目的時候,這個項目的servlet怎麼用可能比較麻煩,可能當時web.xml的映射找不到了,這時怎麼辦呢?

看這個文件
package com.xdocletbook.blog.servlet;

import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

/**
* @web.servlet
* name="HomePage"
* @web.servlet-init-param
* name="LogLevel"
* value="${LOG_LEVEL}"
* @web.servlet-mapping
* url-pattern="/home"
*
* @web.security-role
*     role-name="${OwnerRole}"
* @web.security-role-ref
*     role-name="blogowner"
*     role-link="${OwnerRole}"
*/


public class HomePageServlet
    extends HttpServlet {
  private static Logger LOGGER = Logger.getLogger(HomePageServlet.class);
  public void init() throws ServletException {
    String logLevel = getInitParameter("LogLevel");
    if (logLevel != null && logLevel.length() > 0) {
      LOGGER.setLevel(Level.toLevel(logLevel));
    }
  }

  public void service(HttpServletRequest request, HttpServletResponse response) throws
      ServletException, IOException {
    LOGGER.debug("Displaying home page");
    request.getRequestDispatcher("jsp/home.jsp").forward(request, response);
  }
}
然後配置build.xml增加如下任務

<target name="generate-web">   
    <taskdef name="webdoclet" classname="xdoclet.modules.web.WebDocletTask" classpathref="xdoclet.classpath"/>   
    <!-- Generate servlet and JSP Tag "stuff" -->   
    <webdoclet destdir="gen" mergeDir="merge">     
         <fileset dir="src">       
             <include name="**/*.java" />       
         </fileset>
         <deploymentdescriptor destdir="web" distributable="false" />      
    </webdoclet> 
</target>

然後運行ant generate-web

結果就是這樣一個web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app >

    <!--
    To use non XDoclet filters, create a filters.xml file that
    contains the additional filters (eg Sitemesh) and place it in your
    project's merge dir.  Don't include filter-mappings in this file,
    include them in a file called filter-mappings.xml and put that in
    the same directory.
    -->

    <!--
    To use non XDoclet filter-mappings, create a filter-mappings.xml file that
    contains the additional filter-mappings and place it in your
    project's merge dir.
    -->

    <!--
    To use non XDoclet listeners, create a listeners.xml file that
    contains the additional listeners and place it in your
    project's merge dir.
    -->

     <servlet> 
        <servlet-name>StrutsActionServlet</servlet-name> 
        <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    </servlet>

   <servlet>
      <servlet-name>HomePage</servlet-name>
     <servlet-class>com.xdocletbook.blog.servlet.HomePageServlet</servlet-class>

      <init-param>
         <param-name>LogLevel</param-name>
         <param-value>1</param-value>
      </init-param>

      <security-role-ref>
         <role-name>blogowner</role-name>
         <role-link>aOwner</role-link>
      </security-role-ref>
   </servlet>

      <servlet-mapping>
         <servlet-name>StrutsActionServlet</servlet-name> 
         <url-pattern>*.do</url-pattern>
    </servlet-mapping>

   <servlet-mapping>
      <servlet-name>HomePage</servlet-name>
      <url-pattern>/home</url-pattern>
   </servlet-mapping>

   <!--
   To specify mime mappings, create a file named mime-mappings.xml, put it in your project's mergedir.
   Organize mime-mappings.xml following this DTD slice:

   <!ELEMENT mime-mapping (extension, mime-type)>
   -->

   <!--
   To specify error pages, create a file named error-pages.xml, put it in your project's mergedir.
   Organize error-pages.xml following this DTD slice:

   <!ELEMENT error-page ((error-code | exception-type), location)>
   -->

  <!--
  To add taglibs by xml, create a file called taglibs.xml and place it
  in your merge dir.
  -->

   <!--
   To set up security settings for your web app, create a file named web-security.xml, put it in your project's mergedir.
   Organize web-security.xml following this DTD slice:

   <!ELEMENT security-constraint (display-name?, web-resource-collection+, auth-constraint?, user-data-constraint?)>
   <!ELEMENT web-resource-collection (web-resource-name, description?, url-pattern*, http-method*)>
   <!ELEMENT web-resource-name (#PCDATA)>
   <!ELEMENT url-pattern (#PCDATA)>
   <!ELEMENT http-method (#PCDATA)>
   <!ELEMENT user-data-constraint (description?, transport-guarantee)>
   <!ELEMENT transport-guarantee (#PCDATA)>

   <!ELEMENT login-config (auth-method?, realm-name?, form-login-config?)>
   <!ELEMENT auth-method (#PCDATA)>
   <!ELEMENT realm-name (#PCDATA)>
   <!ELEMENT form-login-config (form-login-page, form-error-page)>
   <!ELEMENT form-login-page (#PCDATA)>
   <!ELEMENT form-error-page (#PCDATA)>
   -->

   <security-role>
      <role-name>aOwner</role-name>
   </security-role>

</web-app>


仔細看這個文件,你一定詫異struts的配置信息怎樣得來,這是XDoclet的另一種方式,對於第三方的Servlet,我們沒有辦法再處理原代碼,所以我們有了merge選項,看<webdoclet destdir="gen" mergeDir="merge">這一句就知道了,在merge目錄裏我們有兩個文件:
   
servlets.xml

    <servlet> 
        <servlet-name>StrutsActionServlet</servlet-name> 
        <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    </servlet>
   
   
servlet-mappings.xml

    <servlet-mapping>
         <servlet-name>StrutsActionServlet</servlet-name> 
         <url-pattern>*.do</url-pattern>
    </servlet-mapping>
   
   
還要注意的是${LOG_LEVEL},這個是說要引用ant 中的變量,所以我的build.xml前面中增加了這兩項
<property name="LOG_LEVEL" value="1"/>
<property name="OwnerRole" value="aOwner"/>

所以,我們就可以動態的改變部署的Log級別
struts自動配置

Struts中有兩樣比較重要的類,Action和Form。
對於Action,我們需要配置Action的映射和Forward屬性,對於Form我們也需要註冊名字和校驗參數,以下就是我們能用XDoclet做到的。
對於Action我們寫這樣一個Java文件

package com.xdocletbook.blog.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

/**
* Simple class to test Jakarta Struts generation (Jakarta Struts 1.2 beta 2 only).
*
* @struts.action
*    path="/struts/foo"
*    name="userForm"
*     input="jsp/createBlog.jsp"
*
* @struts.action-forward
*    name="success"
*    path="/struts/getAll.do"
*    redirect="false"
*
*
* @struts.action-exception
* type="com.xdocletbook.blog.exception.ApplicationException"
* key="app.exception"
* path="jsp/error.jsp"
*
* @struts.action-form name="blog.Create"
*/
public final class StrutsAction extends Action
{
    public ActionForward execute(ActionMapping mapping, ActionForm form,
                                 HttpServletRequest request, HttpServletResponse response)
    {
        return mapping.findForward("success");
    }
}

關鍵部分就是註釋部分。

看我們增加build.xml一個任務,
<target name="generate-web">   
    <taskdef name="webdoclet" classname="xdoclet.modules.web.WebDocletTask" classpathref="xdoclet.classpath"/>   
    <!-- Generate servlet and JSP Tag "stuff" -->   
    <webdoclet destdir="gen" mergeDir="merge">     
         <fileset dir="src">       
             <include name="**/*.java" />       
         </fileset>
         <strutsconfigxml version="1.1"/>        
    </webdoclet> 
</target>

運行ant generate-web,我們就在gen得到了struts-config.xml
其中關鍵內容如下
    <action
      path="/struts/foo"
      type="com.xdocletbook.blog.servlet.StrutsAction"
      name="userForm"
     

scope="request"
      input="jsp/createBlog.jsp"
      unknown="false"
      validate="true"
    >
      <exception
       

key="app.exception"
        type="com.xdocletbook.blog.exception.ApplicationException"
        path="jsp/error.jsp"
      />


     <forward
        name="success"
        path="/struts/getAll.do"
        redirect="false"
      />
    </action>

如果我們有許多Action,就可以隨時生成這樣一個文件,不必在意有人改過這個文件。同時你也不必擔心不小心忘了改這個文件,因爲你改了

Java時,許多默認的屬性也跟這改了。






看到這裏,許多用過workshop的一定感覺到頁面流不就是這樣嗎?當通過圖形界面定義流程時,看看頁面流的源碼你就會發現,註釋中有一些

特殊的標記,這說明workshop的註釋有着xdoclet一樣的功能,只不過workshop提供了很好的界面,而不需要自己寫註釋,而且workshop提供了

更好的語法檢查,呵呵,只是將許多action寫到一起,是有些亂。



Struts的另一個主要的部分就是Form了,雖然我一開始覺得Form有些麻煩,對付動態的Form有些無能爲力,但是結合一些相關的插件後,效果

確實不錯。


這是我們的Form文件,我們還使用ValidatorForm來做自動驗證。

package com.xdocletbook.blog.servlet;

import java.io.Serializable;
import org.apache.struts.validator.ValidatorForm;

/**
*
* @struts.form
*     name="blog.Create"
*/
public class BlogCreateForm
    extends ValidatorForm
    implements Serializable {
  private String name;
  private String owner;
  private String email;
  public BlogCreateForm() {}

  public String getName() {
    return this.name;
  }
  /**
   * @struts.validator
   * type="required"
   */

  public void setName(String name) {
    this.name = name;
  }


  public String getOwner() {
    return this.owner;
  }
  /**
   * @struts.validator
   * type="required"
   */

  public void setOwner(String owner) {
    this.owner = owner;
  }

  public String getEmail() {
    return this.email;
  }
  /**
   *    @struts.validator
   *    type="required"
   *    @struts.validator       
   *    type="email"
   */

  public void setEmail(String email) {
    this.email = email;
  }
}


然後運行ant generate-web

這樣struts-config.xml就有了 
<form-beans>
    <form-bean
      name="blog.Create"
      type="com.xdocletbook.blog.servlet.BlogCreateForm"
    />

    <!

--
         If you have non XDoclet forms, define them in a file called struts-forms.xml and
         place it in your merge

directory.
    -->
  </form-beans>

這裏有一個陷阱,就是Struts XDoclet處理form-beans時,只處理類型是Form的,對於類型是ValidatorForm的Form如果你不把對應的類文件放

到classpath下,XDoclet就會忽略它,所以struts的包一定要放到類路徑下,讓XDoclet有機會知道ValidatorForm是Form的子類。

還有每一個setXXX方法,有一些表示限制的註釋,這些幫助我們生成了

validation.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE form-validation PUBLIC "-//Apache Software Foundation//DTD Commons

Validator Rules Configuration 1.0//EN" "http://jakarta.apache.org/commons/dtds/validator_1_0.dtd">

<form-validation>
  <!--


   Define global validation config in validation-global.xml
  -->
  <formset>
      <form name="blog.Create">
             

<field property="name"
                     depends="required">

                  <arg0 key="blog.Create.name"/>
           

  </field>
              <field property="owner"
                     depends="required">

                  <arg0

key="blog.Create.owner"/>
              </field>
              <field property="email"
                    

depends="required,email">

                  <arg0 key="blog.Create.email"/>
              </field>
      </form>
 

</formset>
</form-validation>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章