<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    javaGrowing

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      92 隨筆 :: 33 文章 :: 49 評論 :: 0 Trackbacks

    #

    二、Jakarta Commons dbutils:
        用JDBC API時最令人討厭的就是異常處理,也很煩瑣,而且很容易出錯,本人曾考慮過利用模板進行處理,后來看到了dbutils,之后就采用那個dbutils,采用模板的方式各位朋友可以參考Spring,Spring的JdbcTemplate不靈活而強大,呵呵,說句閑話,實在太佩服Rod Johnson了,Rod Johnson真的很令人尊敬。
        Dbutils的QueryRunner把大多數與關閉資源相關的封裝起來,另外,你也可以使用DbUtils進行關閉,當然DbUtils提供的功能當然不止這些,它提過了幾個常用的靜態方法,除了上述的關閉資源外,DbUtils. commitAndClose(Connection conn)還提供事務提及等操作。
    還是以一個例子來說說吧,畢竟我不是搞業務的,小嘴巴吧嗒吧噠不起來啊,呵呵。
        為了和采用Beanutils更好的進行對比,這個例子還是實現同樣的功能,數據庫同樣采用前一篇文章中提到的publish。
    同樣的,用你喜歡的編輯器建立一個類DbutilsJDBCTest,示例代碼如下所示:
    package cn.qtone.test;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.util.List;
    import java.util.Map;
    import org.apache.commons.dbutils.DbUtils;
    import org.apache.commons.dbutils.QueryRunner;
    import org.apache.commons.dbutils.handlers.MapListHandler;
    public class DbutilsJDBCTest{
        public static void main(String[] args) {
            Connection conn = null;
            String jdbcURL = "jdbc:mysql://127.0.0.1:3306/publish?useUnicode=true&characterEncoding=GBK";
            String jdbcDriver = "com.mysql.jdbc.Driver";
            try {
                DbUtils.loadDriver(jdbcDriver);
                // Username "root". Password "root"
                conn = DriverManager.getConnection(jdbcURL, "root", "root");
                QueryRunner qRunner = new QueryRunner();
                System.out.println("***Using MapListHandler***");
                //以下部分代碼采用Map存儲方式,可以采用Bean的方式代替進行處理
                List lMap = (List) qRunner.query(conn,
                        "select title,authors  from books", new MapListHandler());
                //以下是處理代碼,可以抽取出來
    System.out.println("title ------------- authors ");
                    for (int i = 0; i < lMap.size(); i++) {
                            Map vals = (Map) lMap.get(i);
                            System.out.println(vals.get("title")+"-------------"+ vals.get("authors"));
                    }
            } catch (SQLException ex) {
                ex.printStackTrace();
            } finally {
                DbUtils.closeQuietly(conn);
            }
        }
    }

    怎么樣?是不是比采用Beanutils的ResultSetDynaTrial和RowSetDynaClass好多了?采用Beanutils令人難纏的是關閉那些資源以及處理那些異常,而這里采用Dbutils顯然代碼量減少了很多。
    上例在處理結果集時,它把數據庫中的每一行映射成一個Map,其中列名作為Key,該列對應的值作為Value存放,查詢的所有的數據一起放在一個List里,然后進行處理,當然,一個更明智的處理是直接返回List然后再單獨進行處理。
    事實上上例返回的結果集中的每一行不必放在一個Map里,你可以放在一個Bean里,當然如果你真的很懶,你也可以使用Beanutils的LazyDynaClass和LazyDynaBean,不過也許沒有必要那么做,至于原因請看下文。

    如果使用Bean而不是用Map,那么,你也許需要建立一個Bean,如下:
    package cn.qtone.test;
    public class Book {
        public int id;
        public String title;
        public String authors ;
        public StudentBean() {
        }
        public String getAuthors() {
            return authors;
        }
        public void setAuthors(String authors) {
            this.authors = authors;
        }
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getTitle() {
            return title;
        }
        public void setTitle(String title) {
            this.title = title;
        }
    }

    然后簡單修改一下DbutilsJDBCTest 中的部分代碼即可,代替之后的源代碼如下:

    package cn.qtone.test;

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.util.List;
    import java.util.Map;
    import org.apache.commons.dbutils.DbUtils;
    import org.apache.commons.dbutils.QueryRunner;
    import org.apache.commons.dbutils.handlers.BeanListHandler;

    public class DbutilsJDBCTest{
        public static void main(String[] args) {
            Connection conn = null;
            String jdbcURL = "jdbc:mysql://127.0.0.1:3306/publish?useUnicode=true&characterEncoding=GBK";
            String jdbcDriver = "com.mysql.jdbc.Driver";
            try {
                DbUtils.loadDriver(jdbcDriver);
                // Username "root". Password "root"
                conn = DriverManager.getConnection(jdbcURL, "root", "root");
                QueryRunner qRunner = new QueryRunner();
                System.out.println("***Using BeanListHandler ***");
                //以下部分代碼采用Map存儲方式,可以采用Bean的方式代替進行處理
    List lBeans = (List) qRunner.query(conn," select title,authors from books ", new BeanListHandler(Book.class));
        //以下是處理代碼,可以抽取出來
    System.out.println("title ------------- authors ");
        for (int i = 0; i < lBeans.size(); i++) {
                Book vals = (Book) lBeans.get(i);    
              System.out.println(vals.getTitle ()+"-------------"+ vals. getAuthors ());
                    }
            } catch (SQLException ex) {
                ex.printStackTrace();
            } finally {
                DbUtils.closeQuietly(conn);
            }
        }
    }
        這兩種法輸出的結果應該是一樣的。兩種處理方式都差不多,但我更愿意采用第一種,因為第一種少寫一個bean,而且我測試過采用Map的方式即第一種方式性能要好的多,采用Bean性能比較低可能是因為采用反射的緣故,采用反射的東東性能和不采用反射的還是有點差距。也是這個原因,不推薦采用LazyDynaClass和LazyDynaBean,因為采用這二者是在運行期動態創建Bean類和Bean屬性,然后再創建Bean對象的,其性能可想而知了(不過我沒有測試過啊,所以我說這個話可說是沒有根據的,感興趣的朋友自己測試一下,記得告訴我結果哦,呵呵),除了MapListHandler以及BeanListHandler之外,DButils還提供了其他的Handler,如果這些不能滿足你的需求,你也可以自己實現一個Handler。
        最后,也是最大的體會,也許是最大的收獲吧,那就是:對于每一個項目,在根據每一個需求獲取相應解決方案時,先尋找開源組件,看是否已經有滿足某些功能需求的開源組件,如果沒有,再考慮自主開發或者向第三方購買,否則盡量采用開源組件.
        請盡量享用開源的魅力,盡情的擁抱開源吧。
        好了,終于寫完了,有什么問題請聯系我,大家互相交流交流。
    posted @ 2005-12-29 22:39 javaGrowing 閱讀(283) | 評論 (0)編輯 收藏



    1. Ant是什么?
    2. 安裝Ant
    3. 運行Ant
    4. 編寫build.xml
    5. 內置task(internet)
    6. EAR task(internet)
    7. WAR task(internet)
    8. JUnit task(internet)

    --------------------------------------------------------------------------------

    1.Ant是什么?

    --------------------------------------------------------------------------------

    Ant是一種基于Java的build工具。理論上來說,它有些類似于(Unix)C中的make ,但沒有make的缺陷。

    既 然我們已經有了make, gnumake, nmake, jam以及其他的build工具為什么還要要一種新的build工具呢?因為Ant的原作者在多種(硬件)平臺上開發軟件時,無法忍受這些工具的限制和不 便。類似于make的工具本質上是基于shell(語言)的:他們計算依賴關系,然后執行命令(這些命令與你在命令行敲的命令沒太大區別)。這就意味著你 可以很容易地通過使用OS特有的或編寫新的(命令)程序擴展該工具;然而,這也意味著你將自己限制在了特定的OS,或特定的OS類型上,如Unix。

    Makefile也很可惡。任何使用過他們的人都碰到過可惡的tab問題。Ant的原作者經常這樣問自己:“是否我的命令不執行只是因為在我的tab前有一個空格?!!”。類似于jam的工具很好地處理了這類問題,但是(用戶)必須記住和使用一種新的格式。

    Ant 就不同了。與基于shell命令的擴展模式不同,Ant用Java的類來擴展。(用戶)不必編寫shell命令,配置文件是基于XML的,通過調用 target樹,就可執行各種task。每個task由實現了一個實現了特定Task接口的對象來運行。(如果你對Ant一點概念都沒有的話,可能看不懂 這一節,沒有關系,后面會對target,task做詳細的介紹。你如果沒有太多的時間甚至可以略過這一節,然后再回來瀏覽一下這里的介紹,那時你就會看 懂了。同樣,如果你對make之類的工具不熟悉也沒關系,下面的介紹根本不會用到make中的概念。)

    必須承認,這樣做,在構造 shell命令時會失去一些特有的表達能力。如`find . -name foo -exec rm {}`,但卻給了你跨平臺的能力-你可以在任何地方工作。如果你真的需要執行一些shell命令,Ant有一個<exec> task,這個task允許執行特定OS上的命令。

    2.安裝Ant

    --------------------------------------------------------------------------------

    由于Ant是一個Open Source的軟件,所以有兩種安裝Ant的方式,一種是用已編譯好的binary 文件安裝Ant,另一種是用源代碼自己build Ant。

    binary 形式的Ant可以從http://jakarta.apache.org/builds/ant/release/v1.4.1/bin下載。如果你希望 你能自己編譯Ant,則可從 http://jakarta.apache.org/builds/ant/release/v1.4.1/src。注意所列出的連接都是最新發行版的 Ant。如果你讀到此文時,發現已經有了更新的版本,那么請用新版本。如果你是一個瘋狂的技術追求者,你也可以從Ant CVS repository下載最新版本的Ant。

    系統需求

    要想自己build Ant。你需要一個JAXP兼容的XML解析器(parser)放在你的CLASSPATH系統變量中。

    binary 形式的Ant包括最新版的Apache Crimson XML解析器。你可以從http://java.sun.com/xml/ 得到更多的關于JAXP的信息。如果你希望使用其他的JAXP兼容的解析器。你要從Ant的lib目錄中刪掉jaxp.jar以及 crimson.jar。然后你可將你心愛的解析器的jar文件放到Ant的lib目錄中或放在你的CLASSPATH系統變量中。

    對于當前版本的Ant,需要你的系統中有JDK,1.1版或更高。未來的Ant版本會要求使用JDK 1.2或更高版本。

    安裝Ant

    binary 版的Ant包括三個目錄:bin, docs 和lib。只有bin和lib目錄是運行Ant所需的。要想安裝Ant,選擇一個目錄并將發行版的文件拷貝到該目錄下。這個目錄被稱作ANT_HOME。

    在你運行Ant之前需要做一些配置工作。

    將bin目錄加入PATH環境變量。
    設定ANT_HOME環境變量,指向你安裝Ant的目錄。在一些OS上,Ant的腳本可以猜測ANT_HOME(Unix和Windos NT/2000)-但最好不要依賴這一特性。
    可選地,設定JAVA_HOME環境變量(參考下面的高級小節),該變量應該指向你安裝JDK的目錄。

    注意:不要將Ant的ant.jar文件放到JDK/JRE的lib/ext目錄下。Ant是個應用程序,而lib/ext目錄是為JDK擴展使用的(如JCE,JSSE擴展)。而且通過擴展裝入的類會有安全方面的限制。

    可選Task

    Ant 支持一些可選task。一個可選task一般需要額外的庫才能工作。可選task與Ant的內置task分開,單獨打包。這個可選包可以從你下載Ant的 同一個地方下載。目前包含可選task的jar文件名叫jakarta-ant-1.4.1-optional.jar。這個jar文件應該放到Ant安 裝目錄的lib目錄下。

    每個可選task所需的外部庫可參看依賴庫小節。這些外部庫可以放到Ant的lib目錄下,這樣Ant就能自動裝入,或者將其放入環境變量中。

    Windows

    假定Ant安裝在c:\ant\目錄下。下面是設定環境的命令:

    set ANT_HOME=c:\ant
    set JAVA_HOME=c:\jdk1.2.2
    set PATH=%PATH%;%ANT_HOME%\bin
    Unix (bash)

    假定Ant安裝在/usr/local/ant目錄下。下面是設定環境的命令:

    export ANT_HOME=/usr/local/ant
    export JAVA_HOME=/usr/local/jdk-1.2.2
    export PATH=${PATH}:${ANT_HOME}/bin
    高級

    要想運行Ant必須使用很多的變量。你至少參考需要下面的內容:

    Ant的CLASSPATH必須包含ant.jar以及你所選的JAXP兼容的XML解析器的jar文件。
    當 你需要JDK的功能(如javac或rmic task)時,對于JDK 1.1,JDK的classes.zip文件必須放入CLASSPATH中;對于JDK 1.2或JDK 1.3,則必須加入tools.jar。如果設定了正確的JAVA_HOME環境變量,Ant所帶的腳本,在bin目錄下,會自動加入所需的JDK類。
    當你執行特定平臺的程序(如exec task或cvs task)時,必須設定ant.home屬性指向Ant的安裝目錄。同樣,Ant所帶的腳本利用ANT_HOME環境變量自動設置該屬性。
    Building Ant

    要想從源代碼build Ant,你要先安裝Ant源代碼發行版或從CVS中checkout jakarta-ant模塊。

    安裝好源代碼后,進入安裝目錄。

    設定JAVA_HOME環境變量指向JDK的安裝目錄。要想知道怎么做請參看安裝Ant小節。

    確 保你已下載了任何輔助jar文件,以便build你所感興趣的task。這些jar文件可以放在CLASSPATH中,也可以放在 lib/optional目錄下。參看依賴庫小節可知不同的task需要那些jar文件。注意這些jar文件只是用作build Ant之用。要想運行Ant,你還要像安裝Ant小節中所做的那樣設定這些jar文件。

    現在你可以build Ant了:

    build -Ddist.dir=<directory_to_contain_Ant_distribution> dist (Windows)
    build.sh -Ddist.dir=<directory_to_contain_Ant_distribution> dist (Unix)

    這樣就可你指定的目錄中創建一個binary版本。

    上面的命令執行下面的動作:

    如果有必要可以bootstrap Ant的代碼。bootstrap 包括手工編輯一些Ant代碼以便運行Ant。bootstrap 用于下面的build步驟。
    向build腳本傳遞參數以調用bootstrap Ant。參數定義了Ant的屬性值并指定了Ant自己的build.xml文件的"dist" target。

    大多數情況下,你不必直接bootstrap Ant,因為build腳本為你完成這一切。運行bootstrap.bat (Windows) 或 bootstrap.sh (UNIX) 可以build一個新的bootstrap版Ant。


    如果你希望將Ant安裝到ANT_HOME目錄下,你可以使用:

    build install (Windows)
    build.sh install (Unix)

    如果你希望跳過冗長的Javadoc步驟,可以用:

    build install-lite (Windows)
    build.sh install-lite (Unix)

    這樣就只會安裝bin和lib目錄。

    注意install和install-lite都會覆蓋ANT_HOME中的當前Ant版本。

    依賴庫

    如果你需要執行特定的task,你需要將對應的庫放入CLASSPATH或放到Ant安裝目錄的lib目錄下。注意使用mapper時只需要一個regexp庫。同時,你也要安裝Ant的可選jar包,它包含了task的定義。參考上面的安裝Ant小節。

    Jar Name Needed For Available At
    An XSL transformer like Xalan or XSL:P style task http://xml.apache.org/xalan-j/index.html or http://www.clc-marketing.com/xslp/
    jakarta-regexp-1.2.jar regexp type with mappers jakarta.apache.org/regexp/
    jakarta-oro-2.0.1.jar regexp type with mappers and the perforce tasks jakarta.apache.org/oro/
    junit.jar junit tasks www.junit.org
    stylebook.jar stylebook task CVS repository of xml.apache.org
    testlet.jar test task java.apache.org/framework
    antlr.jar antlr task www.antlr.org
    bsf.jar script task oss.software.ibm.com/developerworks/projects/bsf
    netrexx.jar netrexx task www2.hursley.ibm.com/netrexx
    rhino.jar javascript with script task www.mozilla.org
    jpython.jar python with script task www.jpython.org
    netcomponents.jar ftp and telnet tasks www.savarese.org/oro/downloads

    3.運行Ant

    --------------------------------------------------------------------------------

    運行Ant非常簡單,當你正確地安裝Ant后,只要輸入ant就可以了。

    沒 有指定任何參數時,Ant會在當前目錄下查詢build.xml文件。如果找到了就用該文件作為buildfile。如果你用 -find 選項。Ant就會在上級目錄中尋找buildfile,直至到達文件系統的根。要想讓Ant使用其他的buildfile,可以用參數 -buildfile file,這里file指定了你想使用的buildfile。

    你也可以設定一些屬性,以覆蓋buildfile中 指定的屬性值(參看property task)。可以用 -Dproperty=value 選項,這里property是指屬性的名稱,而value則是指屬性的值。也可以用這種辦法來指定一些環境變量的值。你也可以用property task來存取環境變量。只要將 -DMYVAR=%MYVAR% (Windows) 或 -DMYVAR=$MYVAR (Unix) 傳遞給Ant -你就可以在你的buildfile中用${MYVAR}來存取這些環境變量。

    還有兩個選項 -quite,告訴Ant運行時只輸出少量的必要信息。而 -verbose,告訴Ant運行時要輸出更多的信息。

    可以指定執行一個或多個target。當省略target時,Ant使用標簽<project>的default屬性所指定的target。

    如果有的話,-projecthelp 選項輸出項目的描述信息和項目target的列表。先列出那些有描述的,然后是沒有描述的target。

    命令行選項總結:

    ant [options] [target [target2 [target3] ...]]
    Options:
    -help print this message
    -projecthelp print project help information
    -version print the version information and exit
    -quiet be extra quiet
    -verbose be extra verbose
    -debug print debugging information
    -emacs produce logging information without adornments
    -logfile file use given file for log output
    -logger classname the class that is to perform logging
    -listener classname add an instance of class as a project listener
    -buildfile file use specified buildfile
    -find file search for buildfile towards the root of the filesystem and use the first one found
    -Dproperty=value set property to value
    例子

    ant

    使用當前目錄下的build.xml運行Ant,執行缺省的target。

    ant -buildfile test.xml

    使用當前目錄下的test.xml運行Ant,執行缺省的target。

    ant -buildfile test.xml dist

    使用當前目錄下的test.xml運行Ant,執行一個叫做dist的target。

    ant -buildfile test.xml -Dbuild=build/classes dist

    使用當前目錄下的test.xml運行Ant,執行一個叫做dist的target,并設定build屬性的值為build/classes。

    文件

    在Unix 上,Ant的執行腳本在做任何事之前都會source(讀并計算值)~/.antrc 文件;在Windows上,Ant的批處理文件會在開始時調用%HOME%\antrc_pre.bat,在結束時調用%HOME%\ antrc_post.bat。你可以用這些文件配置或取消一些只有在運行Ant時才需要的環境變量。看下面的例子。

    環境變量

    包裹腳本(wrapper scripts)使用下面的環境變量(如果有的話):

    JAVACMD Java可執行文件的絕對路徑。用這個值可以指定一個不同于JAVA_HOME/bin/java(.exe)的JVM。
    ANT_OPTS 傳遞給JVM的命令行變量-例如,你可以定義屬性或設定Java堆的最大值

    手工運行Ant

    如果你自己動手安裝(DIY)Ant,你可以用下面的命令啟動Ant:

    java -Dant.home=c:\ant org.apache.tools.ant.Main [options] [target]

    這個命令與前面的ant命令一樣。選項和target也和用ant命令時一樣。這個例子假定你的CLASSPATH包含:

    ant.jar

    jars/classes for your XML parser

    the JDK's required jar/zip files

    4.編寫build.xml

    --------------------------------------------------------------------------------

    Ant的buildfile是用XML寫的。每個buildfile含有一個project。

    buildfile中每個task元素可以有一個id屬性,可以用這個id值引用指定的任務。這個值必須是唯一的。(詳情請參考下面的Task小節)

    Projects

    project有下面的屬性:

    Attribute Description Required
    name 項目名稱. No
    default 當沒有指定target時使用的缺省target Yes
    basedir 用于計算所有其他路徑的基路徑。該屬性可以被basedir property覆蓋。當覆蓋時,該屬性被忽略。如果屬性和basedir property都沒有設定,就使用buildfile文件的父目錄。 No

    項目的描述以一個頂級的<description>元素的形式出現(參看description小節)。

    一個項目可以定義一個或多個target。一個target是一系列你想要執行的。執行Ant時,你可以選擇執行那個target。當沒有給定target時,使用project的default屬性所確定的target。

    Targets

    一個target可以依賴于其他的target。例如,你可能會有一個target用于編譯程序,一個target用于生成可執行文件。你在生成可執行文件之前必須先編譯通過,所以生成可執行文件的target依賴于編譯target。Ant會處理這種依賴關系。

    然而,應當注意到,Ant的depends屬性只指定了target應該被執行的順序-如果被依賴的target無法運行,這種depends對于指定了依賴關系的target就沒有影響。

    Ant會依照depends屬性中target出現的順序(從左到右)依次執行每個target。然而,要記住的是只要某個target依賴于一個target,后者就會被先執行。

    <target name="A"/>
    <target name="B" depends="A"/>
    <target name="C" depends="B"/>
    <target name="D" depends="C,B,A"/>

    假定我們要執行target D。從它的依賴屬性來看,你可能認為先執行C,然后B,最后A被執行。錯了,C依賴于B,B依賴于A,所以先執行A,然后B,然后C,最后D被執行。

    一個target只能被執行一次,即時有多個target依賴于它(看上面的例子)。

    如 果(或如果不)某些屬性被設定,才執行某個target。這樣,允許根據系統的狀態(java version, OS, 命令行屬性定義等等)來更好地控制build的過程。要想讓一個target這樣做,你就應該在target元素中,加入if(或unless)屬性,帶 上target因該有所判斷的屬性。例如:

    <target name="build-module-A" if="module-A-present"/>
    <target name="build-own-fake-module-A" unless="module-A-present"/>

    如果沒有if或unless屬性,target總會被執行。

    可選的description屬性可用來提供關于target的一行描述,這些描述可由-projecthelp命令行選項輸出。

    將你的tstamp task在一個所謂的初始化target是很好的做法,其他的target依賴這個初始化target。要確保初始化target是出現在其他target依賴表中的第一個target。在本手冊中大多數的初始化target的名字是"init"。

    target有下面的屬性:

    Attribute Description Required
    name target的名字 Yes
    depends 用逗號分隔的target的名字列表,也就是依賴表。 No
    if 執行target所需要設定的屬性名。 No
    unless 執行target需要清除設定的屬性名。 No
    description 關于target功能的簡短描述。 No

    Tasks

    一個task是一段可執行的代碼。

    一個task可以有多個屬性(如果你愿意的話,可以將其稱之為變量)。屬性只可能包含對property的引用。這些引用會在task執行前被解析。

    下面是Task的一般構造形式:

    <name attribute1="value1" attribute2="value2" ... />

    這里name是task的名字,attributeN是屬性名,valueN是屬性值。

    有一套內置的(built-in)task,以及一些可選task,但你也可以編寫自己的task。

    所有的task都有一個task名字屬性。Ant用屬性值來產生日志信息。

    可以給task賦一個id屬性:

    <taskname id="taskID" ... />

    這里taskname是task的名字,而taskID是這個task的唯一標識符。通過這個標識符,你可以在腳本中引用相應的task。例如,在腳本中你可以這樣:

    <script ... >
    task1.setFoo("bar");
    </script>

    設定某個task實例的foo屬性。在另一個task中(用java編寫),你可以利用下面的語句存取相應的實例。

    project.getReference("task1").

    注意1:如果task1還沒有運行,就不會被生效(例如:不設定屬性),如果你在隨后配置它,你所作的一切都會被覆蓋。

    注意2:未來的Ant版本可能不會兼容這里所提的屬性,因為很有可能根本沒有task實例,只有proxies。

    Properties

    一 個project可以有很多的properties。可以在buildfile中用property task來設定,或在Ant之外設定。一個property有一個名字和一個值。property可用于task的屬性值。這是通過將屬性名放在"${" 和"}"之間并放在屬性值的位置來實現的。例如如果有一個property builddir的值是"build",這個property就可用于屬性值:${builddir}/classes。這個值就可被解析為 build/classes。

    內置屬性

    如果你使用了<property> task 定義了所有的系統屬性,Ant允許你使用這些屬性。例如,${os.name}對應操作系統的名字。

    要想得到系統屬性的列表可參考the Javadoc of System.getProperties。

    除了Java的系統屬性,Ant還定義了一些自己的內置屬性:
    basedir project基目錄的絕對路徑 (與<project>的basedir屬性一樣)。
    ant.file buildfile的絕對路徑。
    ant.version Ant的版本。
    ant.project.name 當前執行的project的名字;由<project>的name屬性設定.
    ant.java.version Ant檢測到的JVM的版本; 目前的值有"1.1", "1.2", "1.3" and "1.4".
       
    例子

    <project name="MyProject" default="dist" basedir=".">

    <!-- set global properties for this build -->
    <property name="src" value="."/>
    <property name="build" value="build"/>
    <property name="dist" value="dist"/>
       
    <target name="init">
    <!-- Create the time stamp -->
    <tstamp/>
    <!-- Create the build directory structure used by compile -->
    <mkdir dir="${build}"/>
    </target>
     
    <target name="compile" depends="init">
    <!-- Compile the java code from ${src} into ${build} -->
    <javac srcdir="${src}" destdir="${build}"/>
    </target>

    <target name="dist" depends="compile">
    <!-- Create the distribution directory -->
    <mkdir dir="${dist}/lib"/>
    <!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
    <jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
    </target>

    <target name="clean">
    <!-- Delete the ${build} and ${dist} directory trees -->
    <delete dir="${build}"/>
    <delete dir="${dist}"/>
    </target>

    </project>

    Token Filters

    一個project可以有很多tokens,這些tokens在文件拷貝時會被自動擴展,這要求在支持這一行為的task中選擇過濾拷貝功能。這一功能可用filter task在buildfile中設定。

    既 然這很可能是一個有危害的行為,文件中的tokens必須采取@token@的形式,這里token是filter task中設定的token名。這種token語法與其他build系統執行類似filtering的語法相同,而且與大多數的編程和腳本語言以及文檔系 統并不沖突,

    注意:如果在一個文件中發現了一個@token@形式的token,但沒有filter與這個token關連,則不會發生任何事;因此,沒有轉義方法-但只要你為token選擇合適的名字,就不會產生問題。

    警告:如果你在拷貝binary文件時打開filtering功能,你有可能破壞文件。這個功能只針對文本文件。

    Path-like Structures
    你可以用":"和";"作為分隔符,指定類似PATH和CLASSPATH的引用。Ant會把分隔符轉換為當前系統所用的分隔符。

    當需要指定類似路徑的值時,可以使用嵌套元素。一般的形式是

    <classpath>
    <pathelement path="${classpath}"/>
    <pathelement location="lib/helper.jar"/>
    </classpath>
    location屬性指定了相對于project基目錄的一個文件和目錄,而path屬性接受逗號或分號分隔的一個位置列表。path屬性一般用作預定義的路徑--其他情況下,應該用多個location屬性。

    為簡潔起見,classpath標簽支持自己的path和location屬性。所以:

    <classpath>
    <pathelement path="${classpath}"/>
    </classpath>
    可以被簡寫作:

    <classpath path="${classpath}"/>
    也可通過<fileset>元素指定路徑。構成一個fileset的多個文件加入path-like structure的順序是未定的。

    <classpath>
    <pathelement path="${classpath}"/>
    <fileset dir="lib">
    <include name="**/*.jar"/>
    </fileset>
    <pathelement location="classes"/>
    </classpath>
    上面的例子構造了一個路徑值包括:${classpath}的路徑,跟著lib目錄下的所有jar文件,接著是classes目錄。

    如果你想在多個task中使用相同的path-like structure,你可以用<path>元素定義他們(與target同級),然后通過id屬性引用--參考Referencs例子。

    path-like structure可能包括對另一個path-like structurede的引用(通過嵌套<path>元素):

    <path id="base.path">
    <pathelement path="${classpath}"/>
    <fileset dir="lib">
    <include name="**/*.jar"/>
    </fileset>
    <pathelement location="classes"/>
    </path>
    <path id="tests.path">
    <path refid="base.path"/>
    <pathelement location="testclasses"/>
    </path>

    前面所提的關于<classpath>的簡潔寫法對于<path>也是有效的,如:

    <path id="tests.path">
      <path refid="base.path"/>
    <pathelement location="testclasses"/>
    </path>
    可寫成:

    <path id="base.path" path="${classpath}"/>
    命令行變量

    有些task可接受參數,并將其傳遞給另一個進程。為了能在變量中包含空格字符,可使用嵌套的arg元素。

    Attribute Description Required
    value 一個命令行變量;可包含空格字符。 只能用一個
    line 空格分隔的命令行變量列表。
    file 作為命令行變量的文件名;會被文件的絕對名替代。
    path 一個作為單個命令行變量的path-like的字符串;或作為分隔符,Ant會將其轉變為特定平臺的分隔符。

    例子

    <arg value="-l -a"/>
    是一個含有空格的單個的命令行變量。

    <arg line="-l -a"/>
    是兩個空格分隔的命令行變量。

    <arg path="/dir;/dir2:\dir3"/>
    是一個命令行變量,其值在DOS系統上為\dir;\dir2;\dir3;在Unix系統上為/dir:/dir2:/dir3 。

    References

    buildfile元素的id屬性可用來引用這些元素。如果你需要一遍遍的復制相同的XML代碼塊,這一屬性就很有用--如多次使用<classpath>結構。

    下面的例子:

    <project ... >
    <target ... >    
    <rmic ...>      
    <classpath>        
    <pathelement location="lib/"/>        
    <pathelement path="${java.class.path}/"/>        
    <pathelement path="${additional.path}"/>      
    </classpath>    
    </rmic>  
    </target>
    <target ... >
    <javac ...>
    <classpath>
    <pathelement location="lib/"/>
    <pathelement path="${java.class.path}/"/>
    <pathelement path="${additional.path}"/>
    </classpath>
    </javac>
    </target>
    </project>
    可以寫成如下形式:

    <project ... >
    <path id="project.class.path">  
    <pathelement location="lib/"/>
    <pathelement path="${java.class.path}/"/>  
    <pathelement path="${additional.path}"/>
    </path>
    <target ... >
    <rmic ...>
    <classpath refid="project.class.path"/>
    </rmic>
    </target>
    <target ... >
    <javac ...>
    <classpath refid="project.class.path"/>
    </javac>
    </target>
    </project>
    所有使用PatternSets, FileSets 或 path-like structures嵌套元素的task也接受這種類型的引用。
    posted @ 2005-12-29 09:16 javaGrowing 閱讀(270) | 評論 (0)編輯 收藏

     Oracle的體系太龐大了,對于初學者來說,難免會有些無從下手的感覺,什么都想學,結果什么都學不好,所以把學習經驗共享一下,希望讓剛剛入門的人對Oracle有一個總體的認識,少走一些彎路。

    一、定位

        Oracle分兩大塊,一塊是開發,一塊是管理。開發主要是寫寫存儲
    以下內容為程序代碼:
    <SCRIPT language=javascript src="/CMS/JS/newsad.js">

    </script>

    過程、觸發器什么的,還有就是用Oracle的Develop工具做form。有點類似于程序員,需要有較強的邏輯思維和創造能力,個人覺得會比較辛苦, 是青春飯;管理則需要對Oracle數據庫的原理有深刻的認識,有全局操縱的能力和緊密的思維,責任較大,因為一個小的失誤就會down掉整個數據庫,相 對前者來說,后者更看重經驗。

        因為數據庫管理的責任重大,很少公司愿意請一個剛剛接觸Oracle的人去管理數據庫。對于剛剛畢業的年輕人來說,可以先選擇做開發,有一定經驗后轉型,去做數據庫的管理。當然,這個還是要看人個的實際情況來定。

    二、學習方法

        我的方法很簡單,就是:看書、思考、寫筆記、做實驗、再思考、再寫筆記。

         看完理論的東西,自己靜下心來想想,多問自己幾個為什么,然后把所學和所想的知識點做個筆記;在想不通或有疑問的時候,就做做實驗,想想怎么會這樣,同樣 的,把實驗的結果記下來。思考和做實驗是為了深入的了解這個知識點。而做筆記的過程,也是理清自己思路的過程。

        學習的過程是使一個問題由模糊到清晰,再由清晰到模糊的過程。而每次的改變都代表著你又學到了一個新的知識點。

        學習的過程也是從點到線,從線到網,從網到面的過程。當點變成線的時候,你會有總豁然開朗的感覺。當網到面的時候,你就是高手了。

         很多網友,特別是初學的人,一碰到問題就拿到論壇上來問,在問前,你有沒有查過書,自己有沒有研究過,有沒有搜索一下論壇?這就叫思維惰性。由別人來回答 你的問題,會讓你在短時間內不費勁地弄懂這個知識點,然而通過自己的努力去研究它,不但會更深入的了解這個知識點,更重要的是在研究的過程會提高你解決問 題和分析問題的能力。總的來說,沒有鉆研的學習態度,不管學什么東西,都不會成功的。

        當然,初學的人很多時候是因為遇到問題時,無從下手,也不知道去哪里找資料,才會到論壇上提問題的。但我認為,在提問的時候,是不是可以問別人是如何分析這個問題?從哪里可以找到相關的資料?而不是這個問題的答案是什么?授人以魚不如授人以漁。

        下面我講下我處理問題的過程

        首先要知道Oracle的官方網站:www.oracle.com 這里有Oracle的各種版本的數據庫、應用工具和權威的官方文檔。其次,還要知道http://metalink.oracle.com/這里是買了Oracle服務或是oracle的合作伙伴才可以進去的,里面有很多權威的解決方案和補丁。然后就是一些著名網站:asktom.oracle.com www.orafaq.net, www.dbazine.com。這里有很多經驗之談。

        遇到問題了。如果是概念上的問題,第一時間可以找tahiti.oracle.com,這里會給你最詳細的解釋。如果在運行的過程中出了什么錯誤。可以去metalink看看。如果是想知道事務的處理的經驗之談。可以去asktom。當然。這里只是相對而言。 [page]
    三、Oracle的體系
        Oracle的體系很龐大,要學習它,首先要了解Oracle的框架。在這里,簡要的講一下Oracle的架構,讓初學者對Oracle有一個整體的認識。


         1、物理結構(由控制文件、數據文件、重做日志文件、參數文件、歸檔文件、密碼文件組成)

        控制文件:包含維護和驗證數據庫完整性的必要信息、例如,控制文件用于識別數據文件和重做日志文件,一個數據庫至少需要一個控制文件.

        數據文件:存儲數據的文件.

        重做日志文件:含對數據庫所做的更改記錄,這樣萬一出現故障可以啟用數據恢復。一個數據庫至少需要兩個重做日志文件.

        參數文件:定義Oracle例程的特性,例如它包含調整SGA中一些內存結構大小的參數.

        歸檔文件:是重做日志文件的脫機副本,這些副本可能對于從介質失敗中進行恢復很必要。

        密碼文件:認證哪些用戶有權限啟動和關閉Oracle例程.


        2、邏輯結構(表空間、段、區、塊)

        表空間:是數據庫中的基本邏輯結構,一系列數據文件的集合。
        段:是對象在數據庫中占用的空間.
        區:是為數據一次性預留的一個較大的存儲空間.
        塊:ORACLE最基本的存儲單位,在建立數據庫的時候指定.


        3、內存分配(SGA和PGA)

        SGA:是用于存儲數據庫信息的內存區,該信息為數據庫進程所共享。它包含Oracle 服務器的數據和控制信息,它是在Oracle服務器所駐留的計算機的實際內存中得以分配,如果實際內存不夠再往虛擬內存中寫。

        PGA:包含單個服務器進程或單個后臺進程的數據和控制信息,與幾個進程共享的SGA 正相反PGA 是只被一個進程使用的區域,PGA 在創建進程時分配在終止進程時回收.

        4、后臺進程(數據寫進程、日志寫進程、系統監控、進程監控、檢查點進程、歸檔進程、服務進程、用戶進程)

        數據寫進程:負責將更改的數據從數據庫緩沖區高速緩存寫入數據文件
        日志寫進程:將重做日志緩沖區中的更改寫入在線重做日志文件
        系統監控:檢查數據庫的一致性如有必要還會在數據庫打開時啟動數據庫的恢復
        進程監控:負責在一個Oracle 進程失敗時清理資源
        檢查點進程:負責在每當緩沖區高速緩存中的更改永久地記錄在數據庫中時,更新控制文件和數據文件中的數據庫狀態信息。
        歸檔進程:在每次日志切換時把已滿的日志組進行備份或歸檔
        服務進程:用戶進程服務。
        用戶進程:在客戶端,負責將用戶的SQL語句傳遞給服務進程,并從服務器段拿回查詢數據。

        5、Oracle例程:Oracle例程由SGA內存結構和用于管理數據庫的后臺進程組成。例程一次只能打開和使用一個數據庫。

        6、SCN(System ChangeNumber):系統改變號,一個由系統內部維護的序列號。當系統需要更新的時候自動增加,他是系統中維持數據的一致性和順序恢復的重要標志。

    四、深入學習

         管理:可以考OCP證書,對Oracle先有一個系統的學習,然后看Oracle Concepts、Oracle online document,對oracle的原理會有更深入的了解,同時可以開始進行一些專題的研究如:RMAN、RAS、STATSPACT、 DATAGUARD、TUNING、BACKUP&RECOVER等等。

        開發:對于想做Oracle開發的,在了解完 Oracle基本的體系結構之后,可以重點關注PL/SQL及Oracle的開發工具這一部分。PL/SQL主要是包括怎么寫SQL語句,怎么使用 Oracle本身的函數,怎么寫存儲過程、存儲函數、觸發器等。 Oracle的開發工具主要就是Oracle自己的Developer Suite(Oracle Forms Developer and Reports Developer這些),學會如何熟練使用這些工具。

    介紹幾本oracle入門的好書

        Oracle官方文檔:《concept》上面講了oracle的體系和概念,很適合初學者看。
        OCP的教學用書,也就是STUDY GUIDE(SG)。
        Oracle8i 備份恢復手冊
        Oracle8高級管理與優化
        Oracle8i PLSQL程序設計
        Oracle8數據庫管理員手冊
        以上書本都是機械工業出版社出版。

    介紹幾個網站

        http://tahiti.oracle.com oracle的官方文檔

        現在http://www.oracle.com.cn/onlinedoc/index.htm也有官方文檔,速度奇快

        http://metalink.oracle.com/,Oracle的技術支持網站。需要購買Oracle服務才能有一個帳號,才能登陸,有大量的Knowledge Base,大量問題解決經驗。

        http://www.oracle.com oracle的官方網站,可以在這里down Oracle的軟件、官方文檔和獲得最新的消息

        http://www.dbazine.com/ Oracle的雜志

        http://asktom.oracle.com

        http://www.orafaq.net/

        http://www.ixora.com.au/

        http://www.oracle-base.com

        http://www.dba-oracle.com/oracle_links.htm
    posted @ 2005-12-28 22:59 javaGrowing 閱讀(179) | 評論 (0)編輯 收藏

    轉自 www.javaresearch.org
    作者 fishandfly

    1.使ApplicationResources.properties支持中文
    建立一個ApplicationResources_ISO.properties文件,把應用程序用的message都寫進去,然后在dos下執行這個命令,
    native2ascii -encoding gb2312 ApplicationResources_ISO.properties ApplicationResources.properties
    這樣就會將ISO編碼的ApplicationResources轉換成GB2312編碼的格式了,同時保存到ApplicationResources.properties.
    native2ascii這個工具是jdk自帶的一個東東,所以如果path都設定正確就可以直接運行了,你可以在$java_home$/bin下找到他。
    轉換后的中文類似于這個樣子
    iso 格式下 :tj.type=商品車類型
    gb2312格式下 :tj.type=\u5546\u54c1\u8f66\u7c7b\u578b
    然后在struts-config.xml中設置應用這個資源文件
    <message-resources parameter="com.huahang.tj.ApplicationResources" key="org.apache.struts.action.MESSAGE" />
    開發jsp時在jsp的開頭寫上<%@ page contentType="text/html; charset=gb2312" %>,將字符集設置成gb2312就可以了。

    2.使數據庫操作支持中文。
    數據庫操作支持中文一直讓我比較頭痛,但是感謝善解人衣向我推薦了www.chinaxp.org,這個網站是用struts框架開發的,而且
    開放源碼,下載了源碼后發現它的中文處理得很好,閱讀部分源碼,沒有發現什么特殊的字符集轉換,很納悶,偶然看到樓上網友
    留言知道原來servlet可以統一設置字符轉換。chinaxp.org就是這么做的。
    在web.xml中加上
    <filter>
    <filter-name>Set Character Encoding</filter-name>
    <filter-class>com.huahang.tj.struts.filters.SetCharacterEncodingFilter</filter-class>
    <init-param>
    <param-name>encoding</param-name>
    <param-value>GB2312</param-value>
    </init-param>
    <init-param>
    <param-name>ignore</param-name>
    <param-value>true</param-value>
    </init-param>
    </filter>
    <filter-mapping>
    <filter-name>Set Character Encoding</filter-name>
    <servlet-name>action</servlet-name>
    </filter-mapping>
    這里會涉及一個bean,源碼如下:
    /*
    * XP Forum
    *
    * Copyright Coffee 2002-2003 RedSoft Group. All rights reserved.
    *
    */
    package com.huahang.tj.struts.filters;

    import javax.servlet.*;
    import java.io.IOException;

    /**
    * <p>Filter that sets the character encoding to be used in parsing the
    * incoming request, either unconditionally or only if the client did not
    * specify a character encoding. Configuration of this filter is based on
    * the following initialization parameters:</p>
    * <ul>
    * <li><strong>encoding</strong> - The character encoding to be configured
    * for this request, either conditionally or unconditionally based on
    * the <code>ignore</code> initialization parameter. This parameter
    * is required, so there is no default.</li>
    * <li><strong>ignore</strong> - If set to "true", any character encoding
    * specified by the client is ignored, and the value returned by the
    * <code>selectEncoding()</code> method is set. If set to "false,
    * <code>selectEncoding()</code> is called <strong>only</strong> if the
    * client has not already specified an encoding. By default, this
    * parameter is set to "true".</li>
    * </ul>
    *
    * <p>Although this filter can be used unchanged, it is also easy to
    * subclass it and make the <code>selectEncoding()</code> method more
    * intelligent about what encoding to choose, based on characteristics of
    * the incoming request (such as the values of the <code>Accept-Language</code>
    * and <code>User-Agent</code> headers, or a value stashed in the current
    * user's session.</p>
    *
    * @author <a href="mailto:jwtronics@yahoo.com">John Wong</a>
    *
    * @version $Id: SetCharacterEncodingFilter.java,v 1.1 2002/04/10 13:59:27 johnwong Exp $
    */
    public class SetCharacterEncodingFilter implements Filter {

    // ----------------------------------------------------- Instance Variables

    /**
    * The default character encoding to set for requests that pass through
    * this filter.
    */
    protected String encoding = null;

    /**
    * The filter configuration object we are associated with. If this value
    * is null, this filter instance is not currently configured.
    */
    protected FilterConfig filterConfig = null;

    /**
    * Should a character encoding specified by the client be ignored?
    */
    protected boolean ignore = true;

    // --------------------------------------------------------- Public Methods

    /**
    * Take this filter out of service.
    */
    public void destroy() {

    this.encoding = null;
    this.filterConfig = null;

    }

    /**
    * Select and set (if specified) the character encoding to be used to
    * interpret request parameters for this request.
    *
    * @param request The servlet request we are processing
    * @param result The servlet response we are creating
    * @param chain The filter chain we are processing
    *
    * @exception IOException if an input/output error occurs
    * @exception ServletException if a servlet error occurs
    */
    public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain chain)
    throws IOException, ServletException {

    // Conditionally select and set the character encoding to be used
    if (ignore || (request.getCharacterEncoding() == null)) {
    String encoding = selectEncoding(request);
    if (encoding != null)
    request.setCharacterEncoding(encoding);
    }

    // Pass control on to the next filter
    chain.doFilter(request, response);

    }

    /**
    * Place this filter into service.
    *
    * @param filterConfig The filter configuration object
    */
    public void init(FilterConfig filterConfig) throws ServletException {

    this.filterConfig = filterConfig;
    this.encoding = filterConfig.getInitParameter("encoding");
    String value = filterConfig.getInitParameter("ignore");
    if (value == null)
    this.ignore = true;
    else if (value.equalsIgnoreCase("true"))
    this.ignore = true;
    else if (value.equalsIgnoreCase("yes"))
    this.ignore = true;
    else
    this.ignore = false;

    }

    // ------------------------------------------------------ Protected Methods

    /**
    * Select an appropriate character encoding to be used, based on the
    * characteristics of the current request and/or filter initialization
    * parameters. If no character encoding should be set, return
    * <code>null</code>.
    * <p>
    * The default implementation unconditionally returns the value configured
    * by the <strong>encoding</strong> initialization parameter for this
    * filter.
    *
    * @param request The servlet request we are processing
    */
    protected String selectEncoding(ServletRequest request) {

    return (this.encoding);

    }

    }//EOC
    加上這個后,在action中就可以直接從form中接收gb2312編碼的數據了,返回時自然也是gb2312了。
    但是這個好像需要servlet 2.2以上的容器

    綜合上面的方法,我解決了struts中的中文問題,現在還沒發現新的問題。

    我的環境是
    windows2000 Professional,tomcat 4.04 , struts1.1b2

    posted @ 2005-12-27 15:56 javaGrowing 閱讀(367) | 評論 (0)編輯 收藏

    用Struts Validator檢查你的表單
    2004-05-12 瀏覽次數:1286
     

    用Validator(驗證器)提供的豐富的內置驗證方法簡化Struts的開發過程。

    Struts框架的一個主要好處是它提供了對接收到的表單數據進行驗證的內置界面。如果有任何驗證失敗,則應用程序都會重新顯示HTML表單,這樣就可以改正無效的數據了。如果驗證成功,則處理過程會繼續進行。Struts框架的簡單驗證界面會減少與處理數據驗證有關的令人頭疼的事情,這樣你就可以把精力集中到驗證代碼上,而不是放到捕獲數據、重新顯示不完整或無效數據的技巧上。

    但是,Struts內置的驗證界面也有缺點。例如,在整個應用程序中驗證代碼常常會大量重復,因為許多域需要相同的驗證邏輯。對一些相似字段的驗證邏輯進行任何修改都要求在幾個地方修改代碼,還要重新編譯受影響的代碼。為了解決這個問題并增強Struts驗證界面的功能,作為Struts的第三方附加件創建了Validator框架。后來,Validator被集成到核心Struts代碼庫中,并從Struts中分離出來,現在它是一個獨立的Jakarta Commons項目。雖然Validator是一個獨立的框架,但它仍能與其他程序封裝在一起后提供,并與Struts無縫集成。

    Validator概述

    沒有Validator,你就不得不編寫驗證表單數據所需的全部代碼,并把它放入Form Bean對象的validate( )方法中。對于想在其上進行數據驗證的每個Form Bean域來說,都需要編寫邏輯代碼來實現驗證。此外,你還必須編寫代碼來存儲驗證失敗時的出錯消息。

    有了Validator,你就不必在Form Bean中編寫用于驗證或存儲錯誤消息的任何代碼。相反,Form Bean提供了Validator的一個ActionForm子類,它提供驗證或存儲錯誤消息的功能。

    可把Validator框架作為一個可用于Form Bean驗證的可插入的驗證例行程序系統來進行安裝。每個驗證例行程序都只是一個Java方法,負責執行特定類型的驗證任務,驗證可能通過,也可能失敗。 默認情況下,Validator與幾個有用的驗證例行程序封裝在一起來提供,這些例行程序能滿足大多數情況下的驗證要求。但是,如果Validator框架沒有提供你需要的驗證例行程序,那么你可以自己創建定制的驗證例行程序,并將它插入到該框架中。此外,Validator還支持服務器端和客戶端(JavaScript)的驗證,而Form Bean只提供服務器端驗證界面。

    Validator使用兩個XML配置文件來分別確定安裝哪個驗證例行程序和如何將它們應用于給定的應用程序。第一個配置文件validator-rules.xml說明應該被插入到框架中的驗證例行程序,并提供每個驗證的邏輯的名稱。validator-rules.xml文件還定義了每個驗證例行程序的客戶端JavaScript代碼。可以配置Validator讓它把這個JavaScript代碼發送到瀏覽器上,這樣驗證就可以在客戶端和服務器端進行了。

    第二個配置文件validation.xml確定哪個驗證例行程序應用到哪個Form Bean。文件中的定義使用struts-config.xml文件給出的Form Bean的邏輯名稱以及validator-rules.xml文件給出的驗證例行程序的邏輯名稱,以便把二者關聯起來。

    使用Validator框架包括啟用Validator插件、配置Validator的兩個配置文件,以及創建提供Validator的ActionForm子類的Form Beans。下面詳細解釋如何配置和使用Validator。

    啟用Validator插件

    雖然Validator框架是與Struts封裝在一起提供的,但在默認狀況下Validator并不被啟用。為了啟用Validator,要向你的應用程序的struts-config.xml文件中添加下面的插件定義。

    <!-- Validator Configuration -->
    <plug-in className="org.apache.struts
    .validator.ValidatorPlugIn">
    <set-property property="pathnames"
    value="/WEB-INF/
    validator-rules.xml, /WEB-INF/
    validation.xml"/>
    </plug-in>

    該定義告訴Struts為你的應用程序加載并初始化Validator插件。在初始化時,該插件裝入由路徑名屬性指定的、用逗號分隔的Validator配置文件清單。每個配置文件的路徑應該用與Web應用程序的相關的路徑來指定,如前面的例子所示。

    請注意,你的應用程序的struts-config.xml文件必須與Struts Configuration Document Type Definition(Struts配置文檔類型定義,DTD)一致,后者規定文件中元素出現的順序。所以,你必須把Validator插件定義放到該文件的適當位置。確保文件中元素適當排列的最簡便方法就是使用諸如Struts Console的工具,它自動格式化你的配置文件,以便與DTD保持一致。

    配置validator-rules.xml

    Validator框架可以設置為可插入系統,其驗證例行程序僅僅是插入到該系統中執行具體驗證的Java方法。validator-rules.xml文件說明性地插入Validator用于執行驗證的驗證例行程序中。Struts示例應用程序帶有這個文件的預配置拷貝。在大多數情況下,你不必修改這個預配置拷貝,除非你要向該框架中添加自己定制的驗證。

    清單1 是一個示例validator-rules.xml文件,說明如何將驗證例行程序插入到Validator中。validator-rules.xml文件中的每個驗證例行程序都有自己的定義,它用validator標記聲明,利用name屬性為該驗證例行程序指定邏輯名,并指定該例行程序的類和方法。該例行程序的邏輯名稱供該文件中的其他例行程序以及validation.xml文件中的驗證定義用于引用該例行程序。

    請注意,validator標記放在javascript的標記中,javascript標記用于定義客戶端JavaScript代碼,以便在客戶端執行與服務器端相同的驗證。

    提供的驗證程序

    默認情況下,Validator中包括幾個基本驗證例行程序,你可以用它們來處理大多數驗證問題。這些例行程序具有邏輯名稱,如required(用于輸入要求的值)、CreditCard(用于輸入信用卡號碼值)、email(用于輸入電子郵件地址值),等等。

    創建Form Bean

    為了使用Validator,你的應用程序的Form Bean必須歸到Validator的ActionForm的某一子類,而不是ActionForm本身。Validator的ActionForm子類提供了ActionForm的validate( )方法(它嵌入到Validator框架中)的實施過程。你不必從頭編寫驗證代碼并把它投入validate( )方法中,相反,可以完全忽略該方法,因為Validator為你提供了驗證代碼。

    與Struts提供的核心功能相類似,Validator提供給你兩種可供選擇的方法來創建Form Bean。 你可以選擇的第一種方法就是像下面這樣創建一個特定的Form Bean對象:

    package com.jamesholmes.minihr;

    import org.apache.struts.validator
    .ValidatorForm;

    public class LogonForm extends ValidatorForm {
    private String username;
    private String password;

    public String getUsername() {
    return username;
    }

    public void setUsername(String
    username) {
    this.username = username;
    }

    public String getPassword() {
    return password;
    }
    public void setPassword(String
    password) {
    this.password = password;
    }
    }

    這個類與你不是用Validator所創建的類相似,但它提供ValidatorForm而不是ActionForm。這個類也不提供ActionForm的空reset( )和validate( )方法的實施過程,因為ValidatorForm提供了相應過程。

    在struts-config.xml文件中配置這個特定Form Bean的方法與配置正則Form Bean的方法相同:

    <form-beans>
    <form-bean name="logonForm"
    type="com.jamesholmes
    .minihr.LogonForm"/>
    </form-beans>

    用表單標記的name屬性給特定Form Bean指定的邏輯名是在定義validation.xml文件中的驗證時所使用的名稱,如下所示:

    <!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>
    <formset>
    <form name="logonForm">
    <field property="username"
    depends="required">
    <arg0 key="prompt.username"/>
    </field>
    </form>
    </formset>
    </form-validation>

    Validator使用該表單標記的name屬性的值將驗證定義與要應用這些定義的Form Bean的名稱相匹配。

    創建Form Bean時可以選擇的第二種方法是在struts-config.xml文件中定義一個動態Form Bean,如下所示:

    <form-beans>
    <form-bean name="logonForm"
    type="org.apache
    .struts.validator.DynaValidatorForm">
    <form-property name="username"
    type="java.lang.String"/>
    <form-property name="password"
    type="java.lang.String"/>
    </form-bean>
    </form-beans>

    動態Form Bean不要求創建特定的Form Bean對象;相反,要定義Form Bean應該具有的屬性和類型,而Struts為你動態創建Form Bean。 Validator允許你使用這個概念,就像在核心Struts中使用這個概念一樣。與使用Validator的惟一區別就是要指定Form Bean是org.apache.struts.validator.DynaValidatorForm類型,而不是org.apache.struts.action.DynaActionForm類型。

    分配給動態Form Bean的邏輯名是在定義validation.xml文件中的驗證時使用的名稱。Validator使用與之相匹配的名稱將這些驗證與Form Bean聯系在一起。

    除了創建Form Bean的這兩種標準方法之外,Validator還提供了一個高級特性,用于將多個驗證定義與一個Form Bean定義聯系起來。當你使用基于validatorForm或基于DynaValidatorForm的Form Bean時,Validator使用struts-config.xml文件中的Form Bean的邏輯名稱,將Form Bean映射到validation.xml文件中的驗證定義。這種機制在大多數情況下非常有用,但在某些時候,Form Bean要在多個操作中共享。 一個操作可能使用Form Bean的所有域(fields),而另一個操作可能只使用這些域的一個子集。因為驗證定義被連接到Form Bean,所以只使用域的一個子集的操作就無法繞過對未使用域的驗證。當驗證Form Bean時,就會對未使用的域生成錯誤消息,因為Validator無從知道不去驗證未使用的域,它只是簡單地把它們看作缺失或無效。

    為了解決這個問題,Validator提供了兩個附加的ActionForm子類,它使你能夠將驗證與操作相關聯,而不是與Form Bean相關聯。這樣你就可以根據哪個操作正在使用Form Bean來指定把哪些驗證用于該Form Bean了。對于特定的Form Bean,你要像下面這樣聲明org.apache.struts.validator.ValidatorActionForm子類:

    public class AddressForm extends ValidatorActionForm {
    ...
    }

    對于動態Form Bean,在struts-config.xml文件中為Form Bean定義指定org.apache.struts.validator.DynaValidatorActionForm的類型,如下所示:

    <form-bean name="addressForm"
    type="org.apache.struts
    .validator.DynaValidatorActionForm">
    ...
    </form-bean>

    在validation.xml文件中,把一組驗證映射到一個操作路徑,而不是映射到Form Bean名,因為如果你定義了Create Address和Edit Address兩個操作(它們使用同一個Form Bean),那么每個操作都會有一個惟一的操作名,如下所示:

    <action-mappings>
    <action path="/createAddress"
    type="com.jamesholmes
    .minihr.CreateAddressAction"
    name="addressForm"/>
    <action path="/editAddress"
    type="com.jamesholmes
    .minihr.EditAddressAction"
    name="addressForm"/>
    </action-mappings>

    下面的validation.xml文件片斷顯示了兩組驗證,它們用于同一個Form Bean,但卻有不同的操作路徑:

    <formset>
    <form name="/createAddress">
    <field property="city"
    depends="required">
    <arg0 key="prompt.city"/>
    </field>
    </form>
    <form name="/editAddress">
    <field property="state"
    depends="required">
    <arg0 key="prompt.state"/>
    </field>
    </form>
    </formset>

    因為Form Bean要么屬于ValidatorActionForm子類,要么屬于DynaValidatorActionForm子類,所以Validator知道用一個操作路徑代替Form Bean的邏輯名稱來找出用于Form Bean的驗證。

    配置validation.xml文件

    validation.xml文件用于聲明將應用到Form Beans的一組驗證。要驗證的每個Form Bean在這個文件中都有自己的定義。在這個定義中,指定要應用到該Form Bean的各域的驗證。下面是一個validation.xml文件的例子,說明如何定義驗證:

    <!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>
    <formset>
    <form name="logonForm">
    <field property="username"
    depends="required">
    <arg0 key="prompt.username"/>
    </field>
    <field property="password"
    depends="required">
    <arg0 key="prompt.password"/>
    </field>
    </form>
    </formset>
    </form-validation>

    validation.xml文件的第一個元素是form-validation。這個元素是該文件的主元素,而且只定義一次。在form-validation元素內定義form-set元素,它包括多個表單元素。一般來說,在文件中只定義一個form-set元素,但是如果要將驗證國際化,那就要在每個地方單獨使用一個form-set元素。

    每個表單元素使用name屬性將名稱與其所包含的域驗證集關聯起來。Validator使用這個邏輯名稱將這些驗證映射到在struts-config.xml文件中定義的一個Form Bean。根據要驗證的Form Bean的類型,Validator力求將該名稱與Form Bean的邏輯名稱或操作路徑相匹配。在表單元素內,field元素定義要應用到Form Bean的特定域的驗證。field元素的property屬性對應于特定Form Bean中的域名。depends屬性利用validator-rules.xml文件指定驗證例行程序的邏輯名稱,這些例行程序將應用到域驗證中。

    配置ApplicationResources.properties

    Validator使用Struts的資源綁定(Resource Bundle)機制將錯誤消息具體化。不用在框架中對錯誤消息進行硬編碼,Validator使你能在ApplicationResources.properties文件中為一個消息指定一個鍵值,如果驗證失敗則將返回該鍵值。validator-rules.xml文件中的每個驗證例行程序都用validator標記的msg屬性指定錯誤消息的鍵值,如下所示:

    <validator name="required"
    classname="org.apache
    .struts.validator.FieldChecks"
    method="validateRequired"
    methodParams="java.lang
    .Object, org.apache.commons.validator
    .ValidatorAction, org.apache.commons
    .validator.Field, org.apache.struts
    .action.ActionErrors, javax.servlet
    .http.HttpServletRequest"
    msg="errors.required">

    如果在驗證例行程序運行時驗證失敗,則返回與msg屬性指定的鍵值對應的消息。

    下面的片段顯示來自ApplicationResources.properties文件的驗證出錯時的默認消息集,它們由Struts示例應用程序提供。每個消息的鍵值對應于每個由validator-rules.xml文件中的驗證例行程序所指定的消息,它們由Struts示例應用程序提供。

    # Error messages for Validator framework validations
    errors.required={0} is required.
    errors.minlength={0} cannot be less than {1} characters.
    errors.maxlength={0} cannot be greater than {2} characters.
    errors.invalid={0} is invalid.
    errors.byte={0} must be a byte.
    errors.short={0} must be a short.
    errors.integer={0} must be an integer.
    errors.long={0} must be a long.0. errors.float={0} must be a float.
    errors.double={0} must be a double.
    errors.date={0} is not a date.
    errors.range={0} is not in the range {1} through {2}.
    errors.creditcard={0} is not a valid credit card number.
    errors.email={0} is an invalid e-mail address.

    請注意,每條消息都有占位符,形式為{0}、{1}或{2}。在運行期間,占位符被另一個值代替,如所驗證的域的名稱。這一特性特別有用,它使你能夠創建可被幾個不同的域重復使用的通用驗證錯誤消息。

    例如,下面給出required驗證的錯誤消息errors.required:

    errors.required={0} is required.

    當你使用validation.xml文件中的該required驗證時,必須定義用于替換該錯誤消息中的{0}的值,如下所示:

    <form name="auctionForm">
    <field property="bid" depends="required">
    <arg0 key="prompt.bid"/>
    </field>
    </form>

    錯誤消息最多可以有4個占位符:{0}和{3}。這些占位符分別稱為arg0到arg3,你可以通過使用arg0~arg3標記來指定它們。在上面的例子中,arg0標記指定了用于替換{0}占位符的值。該標記的key屬性指定來自ApplicationResources.properties文件的一個消息鍵值,它的值用于替換占位符,如下所示:
    下一步

    閱讀
    關于Validator的更多文章
    jakarta.apache.org/commons/validator

    關于Struts Console的更多文章
    www.jamesholmes.com/struts

    prompt.bid=Auction Bid

    使用消息鍵值代替占位符的值,這一方法使你不必在validation.xml文件中對替換值反復硬編碼。但是,如果你不想使用Resource Bundle的鍵值/值機制來指定占位符的值,則可以使用arg0標記的如下語法顯式地指定占位符的值:

    <arg0 key="Auction Bid" resource="false"/>

    在這個例子中,resource屬性的值設為false,以便通知Validator要把該key屬性指定的值作為占位符的值,而不要作為ApplicationResources.properties文件中消息的一個鍵值。

    啟用客戶端驗證

    Validator除了提供了簡化服務器端表單數據驗證過程的框架外,它還提供了執行客戶端驗證時易于使用的方法。在validator-rules.xml文件中定義的每一個驗證例行程序都可以隨意指定JavaScript代碼,這些代碼可以在瀏覽器(客戶端上的)中運行,從而執行與服務器端進行的驗證相同的驗證過程。在客戶端進行驗證時,除非所有表單都通過驗證,否則這些表單不允許被提交。

    為了啟用客戶端驗證,必須在每個需要驗證的JSP中放上Struts HTML Tag Library(標記庫)的javascript標記,如下所示:

    <html:javascript formName="logonForm"/>

    javascript標記要求使用formName屬性來為想要對其執行驗證的表單指定validation.xml文件中給出的表單定義名,如下所示:

    <form name="logonForm">
    <field property="username"
    depends="required">
    <arg0 key="prompt.username"/>
    </field>
    <field property="password"
    depends="required">
    <arg0 key="prompt.password"/>
    </field>
    </form>

    為表單定義指定的服務器端的所有驗證都將在客戶端運行。由于客戶端驗證用JavaScript執行,所以可以有多種方法不去執行它。要確保驗證過程總是能運行,不論你是否選擇啟用了客戶端驗證,Validator都在服務器端執行這些驗證。

    結論

    Validator框架針對表單數據的驗證提供了可配置的系統,從而為核心Struts框架添加了很多有價值的功能。通過把Validator框架用于你的應用程序,你可以節約時間并簡化Struts應用程序的開發過程。

    posted @ 2005-12-27 11:50 javaGrowing 閱讀(1793) | 評論 (14)編輯 收藏

    僅列出標題
    共19頁: First 上一頁 11 12 13 14 15 16 17 18 19 下一頁 
    主站蜘蛛池模板: 亚洲av午夜国产精品无码中文字| 美女18毛片免费视频| 97无码免费人妻超级碰碰夜夜| 亚洲色在线无码国产精品不卡| 国产午夜免费秋霞影院| 国产无遮挡又黄又爽免费网站| 亚洲精品熟女国产| 国产美女精品视频免费观看| 成在人线av无码免费高潮水| 亚洲综合小说久久另类区| 国产成人免费a在线视频色戒| 最新久久免费视频| 7777久久亚洲中文字幕| 久久亚洲高清综合| 免费无码A片一区二三区| 一级做a爰全过程免费视频毛片| 亚洲最大的成网4438| 四虎永久在线精品免费影视| 成人久久免费网站| 亚洲国产成人手机在线观看| 亚洲国产精品无码久久SM| 女人被男人躁的女爽免费视频| 成人无码a级毛片免费| 亚洲AV综合色区无码一二三区 | 国产大片51精品免费观看| 久草免费福利视频| 免费播放美女一级毛片| 亚洲乱码一二三四区麻豆| 亚洲综合av永久无码精品一区二区| AV无码免费永久在线观看| 9i9精品国产免费久久| 国产一区二区三区亚洲综合| 亚洲人成片在线观看| 亚洲av一综合av一区| 亚洲精品国产高清嫩草影院| 免费黄色大片网站| 日韩吃奶摸下AA片免费观看| 青青草无码免费一二三区| fc2成年免费共享视频18| 美女黄色毛片免费看| 亚洲人片在线观看天堂无码|