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

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

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

    byterat

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      54 隨筆 :: 0 文章 :: 15 評論 :: 0 Trackbacks

    2007年3月5日 #

    Eclipse及其插件介紹和下載

    0.Eclipse下載
    EMF,GEF - Graphical Editor Framework,UML2,VE - Visual Editor都在這里下載
    http://www.eclipse.org/downloads/index.php

    0.5.lomboz J2EE插件,開發(fā)JSP,EJB
    http://forge.objectweb.org/projects/lomboz
    1.MyEclipse J2EE開發(fā)插件,支持SERVLET/JSP/EJB/數(shù)據(jù)庫操縱等
    http://www.myeclipseide.com

    2.Properties Editor 編輯java的屬性文件,并可以自動存盤為Unicode格式
    http://propedit.sourceforge.jp/index_en.html

    3.Colorer Take 為上百種類型的文件按語法著色
    http://colorer.sourceforge.net/

    4.XMLBuddy 編輯xml文件
    http://www.xmlbuddy.com

    5.Code Folding 加入多種代碼折疊功能(比eclipse自帶的更多)
    http://www.coffee-bytes.com/servlet/PlatformSupport

    6.Easy Explorer 從eclipse中訪問選定文件、目錄所在的文件夾
    http://easystruts.sourceforge.net/

    7.Fat Jar 打包插件,可以方便的完成各種打包任務(wù),可以包含外部的包等
    http://fjep.sourceforge.net/

    8.RegEx Test 測試正則表達式
    http://brosinski.com/stephan/archives/000028.php

    9.JasperAssistant 報表插件(強,要錢的)
    http://www.jasperassistant.com/

    10.Jigloo GUI Builder JAVA的GUI編輯插件
    http://cloudgarden.com/jigloo/

    11.Profiler 性能跟蹤、測量工具,能跟蹤、測量BS程序
    http://sourceforge.net/projects/eclipsecolorer/

    12.AdvanQas 提供對if/else等條件語句的提示和快捷幫助(自動更改結(jié)構(gòu)等)
    http://eclipsecolorer.sourceforge.net/advanqas/index.html

    13.Log4E Log4j插件,提供各種和Log4j相關(guān)的任務(wù),如為方法、類添加一個logger等
    http://log4e.jayefem.de/index.php/Main_Page

    14.VSSPlugin VSS插件
    http://sourceforge.net/projects/vssplugin

    15.Implementors 提供跳轉(zhuǎn)到一個方法的實現(xiàn)類,而不是接中的功能(實用!)
    http://eclipse-tools.sourceforge.net/implementors/
    16.Call Hierarchy 顯示一個方法的調(diào)用層次(被哪些方法調(diào),調(diào)了哪些方法)
    http://eclipse-tools.sourceforge.net/call-hierarchy/index.html

    17.EclipseTidy 檢查和格式化HTML/XML文件
    http://eclipsetidy.sourceforge.net/

    18.Checkclipse 檢查代碼的風格、寫法是否符合規(guī)范
    http://www.mvmsoft.de/content/plugins/checkclipse/checkclipse.htm

    19.Hibernate Synchronizer Hibernate插件,自動映射等
    http://www.binamics.com/hibernatesync/

    20.VeloEclipse Velocity插件
    http://propsorter.sourceforge.net/

    21.EditorList 方便的列出所有打開的Editor
    http://editorlist.sourceforge.net/

    22.MemoryManager 內(nèi)存占用率的監(jiān)視
    http://cloudgarden.com/memorymanager/

    23.swt-designer java的GUI插件
    http://www.swt-designer.com/

    24.TomcatPlugin 支持Tomcat插件
    http://www.eclipsetotale.com/tomcatPlugin.html

    25.XML Viewer
    http://tabaquismo.freehosting.net/ignacio/eclipse/xmlview/index.html

    26.quantum 數(shù)據(jù)庫插件
    http://quantum.sourceforge.net/

    27.Dbedit 數(shù)據(jù)庫插件
    http://sourceforge.net/projects/dbedit

    28.clay.core 可視化的數(shù)據(jù)庫插件
    http://www.azzurri.jp/en/software/index.jsp
    http://www.azzurri.jp/eclipse/plugins

    29.hiberclipse hibernate插件
    http://hiberclipse.sourceforge.net
    http://www.binamics.com/hibernatesync

    30.struts-console Struts插件
    http://www.jamesholmes.com/struts/console/

    31.easystruts Struts插件
    http://easystruts.sourceforge.net

    32.veloedit Velocity插件
    http://veloedit.sourceforge.net/

    33.jalopy 代碼整理插件
    http://jalopy.sourceforge.net/

    34.JDepend 包關(guān)系分析
    http://andrei.gmxhome.de/jdepend4eclipse/links.html

    35.Spring IDE Spring插件
    http://springide-eclip.sourceforge.net/updatesite/

    36.doclipse 可以產(chǎn)生xdoclet 的代碼提示
    http://beust.com/doclipse/
    posted @ 2008-06-05 15:44 比特鼠| 編輯 收藏

         摘要: 有這樣一個函數(shù), 它接受一個函數(shù)(或者說閉包)作為參數(shù)  閱讀全文
    posted @ 2008-05-30 15:19 比特鼠| 編輯 收藏

    當談到表格數(shù)據(jù)的設(shè)計時,沒有太多的網(wǎng)頁設(shè)計師會有太大的興趣。今天我們已經(jīng)收集了20多個功能超大且看上去挺漂亮的Ajax/CSS表格設(shè)計,并且教你一些表格設(shè)計中所運用的技巧,例如表格數(shù)據(jù)的排序和過濾等。

    OK,讓我們來看一下這些表格:

    1. Tablecloth

    Tablecloth 由CSS Globe 開發(fā),是一個輕巧易于使用的表格,簡潔的將表格樣式添加到你的HTML 表格元素中。

    21個新奇漂亮的Ajax/CSS表格設(shè)計-Tablecloth

    2. Ask the CSS Guy Table

    Ask the CSS Guy Table教給我們要如何去創(chuàng)建能夠清晰顯出去資料之間的相關(guān)聯(lián)系的表格,例如:點擊一個表格元素時,將突了顯示這個元素,并且在縱列和橫列都顯示出相關(guān)的類別關(guān)系。

    21個新奇漂亮的Ajax/CSS表格設(shè)計-Ask the CSS Guy Table

    #3. A CSS styled table version 2

    Veerle Duoh 為我們展示了一個漂亮的表格設(shè)計,并教我們?nèi)绾问褂肅SS來吸引用戶的眼球。

    21個新奇漂亮的Ajax/CSS表格設(shè)計-A CSS styled table version 2

    #4. Sortable Table

    Sortable Table 演示了如何按升序或降序排列以及如何過濾表格中的數(shù)據(jù)。

    21個新奇漂亮的Ajax/CSS表格設(shè)計-Sortable Table

    5. Row Locking with CSS and JavaScript

    Css Guy再次對表格使用了聚焦高亮的效果,除非用戶再次點擊,否則表單數(shù)據(jù)將一直保持亮高。

    21個新奇漂亮的Ajax/CSS表格設(shè)計-Row Locking with CSS and JavaScript

    他還給了我們另一個示例:another example to Lock rows with radios .

    #6. Vertical scrolling tables

    如果您有大量的表格數(shù)據(jù),但卻沒有太大的空間來展示它,這可能是個比較好的方法:一個純CSS的表格與固定的標題和頁腳,以及滾動顯示的內(nèi)容。

    21個新奇漂亮的Ajax/CSS表格設(shè)計-Vertical scrolling tables

    7. Replicating a Tree table

    這是一個使用HTML 和CSS 設(shè)計的樹形狀表格。

    21個新奇漂亮的Ajax/CSS表格設(shè)計-Replicating a Tree table

    8 ) Paginate, sort and search a table with Ajax and Rails

    這個表格提供了一個動態(tài)的界面,而不需要重新刷新整個頁面。

    21個新奇漂亮的Ajax/CSS表格設(shè)計-ajax tables

    9. Collapsible tables with DOM and CSS

    此表格加上箭頭形象的腳本提示,用來控制表格的伸展和收縮。

    21個新奇漂亮的Ajax/CSS表格設(shè)計-Collapsible tables with DOM and CSS

    10. TableSorter plug-in for jQuery

    它的主要特性包括多列排序,支持<TH>的rowspan和colspan屬性以及許多其他功能。

    21個新奇漂亮的Ajax/CSS表格設(shè)計-TableSorter plug-in for jQuery

    11. Stripe your tables the OO way

    使用了Javascript 為表格中的行進行顏色交替,并且添加了onmouseoveronmouseout 事件,當鼠標點擊時,切換背景顏色。

    21個新奇漂亮的Ajax/CSS表格設(shè)計-Stripe your tables the OO way

    12. MooTools Table Row & Column highlighting

    基于MooTools 框架,高亮顯示鼠標懸停時的單元格所在的行和列。

    21個新奇漂亮的Ajax/CSS表格設(shè)計-MooTools Table Row & Column highlighting

    13. CSS Table Gallery

    93 styled tables是一個專門收集表格樣式的站點,下面是來自一個表格樣式的截圖:

    21個新奇漂亮的Ajax/CSS表格設(shè)計-CSS Table Gallery

    14. jQuery Table Filter

    可以對數(shù)據(jù)進行各種不同的排序、過濾。

    21個新奇漂亮的Ajax/CSS表格設(shè)計-jQuery Table Filter

    15. Sortable/Resizable/Editable TableKit

    TableKit基于Prototype框架,專門收集各種HTML表格,可以利用Ajax實時的進行表格欄目大小、排序等編輯。

    21個新奇漂亮的Ajax/CSS表格設(shè)計-sortable, resizable, editable

    16. Make all your tables sortable

    21個新奇漂亮的Ajax/CSS表格設(shè)計-sortable table

    17. Zebra Tables

    alistapart為我們提供了一個極好的例子,如何使用JavaScript和DOM的改變背景色風格,以突出顯示單元格。

    21個新奇漂亮的Ajax/CSS表格設(shè)計-Zebra Tables

    18. Standardista Table Sorting

    Standardista Table Sorting 是一個Javascript模塊,讓您可以對HTML數(shù)據(jù)表的任何欄目進行排序。

    21個新奇漂亮的Ajax/CSS表格設(shè)計-Standardista Table Sorting

    19. GridView3 Example

    21個新奇漂亮的Ajax/CSS表格設(shè)計-GridView3 Example

    20. Mootable

    21個新奇漂亮的Ajax/CSS表格設(shè)計-Mootable

    21. Drag & Drop Sortable Lists with JavaScript and CSS

    21個新奇漂亮的Ajax/CSS表格設(shè)計-Drag & Drop Sortable Lists with JavaScript and CSS

    可能還會有一些你更想尋找的詳細資料,下面是一些相關(guān)的資源鏈接:

    如果你知道其它更強大的Ajax/CSS表格,歡迎在此留言。

    posted @ 2008-01-23 17:46 比特鼠 閱讀(3200) | 評論 (0)編輯 收藏

    一個在線調(diào)色工具
    posted @ 2008-01-23 17:44 比特鼠 閱讀(392) | 評論 (1)編輯 收藏

    /**
     * 加碼解碼工具
     * @author lwm
     *
     */

    public class Encode {
     
     /*
      * 對應(yīng)javascript的escape()函數(shù), 加碼后的串可直接使用javascript的unescape()進行解碼
      */
     public static String escape(String src) {
      int i;
      char j;
      StringBuffer tmp = new StringBuffer();
      tmp.ensureCapacity(src.length() * 6);
      for (i = 0; i < src.length(); i++) {
       j = src.charAt(i);
       if (Character.isDigit(j) || Character.isLowerCase(j)
         || Character.isUpperCase(j))
        tmp.append(j);
       else if (j < 256) {
        tmp.append("%");
        if (j < 16)
         tmp.append("0");
        tmp.append(Integer.toString(j, 16));
       } else {
        tmp.append("%u");
        tmp.append(Integer.toString(j, 16));
       }
      }
      return tmp.toString();
     }

     /*
      * 對應(yīng)javascript的unescape()函數(shù), 可對javascript的escape()進行解碼
      */
     public static String unescape(String src) {
      StringBuffer tmp = new StringBuffer();
      tmp.ensureCapacity(src.length());
      int lastPos = 0, pos = 0;
      char ch;
      while (lastPos < src.length()) {
       pos = src.indexOf("%", lastPos);
       if (pos == lastPos) {
        if (src.charAt(pos + 1) == 'u') {
         ch = (char) Integer.parseInt(src
           .substring(pos + 2, pos + 6), 16);
         tmp.append(ch);
         lastPos = pos + 6;
        } else {
         ch = (char) Integer.parseInt(src
           .substring(pos + 1, pos + 3), 16);
         tmp.append(ch);
         lastPos = pos + 3;
        }
       } else {
        if (pos == -1) {
         tmp.append(src.substring(lastPos));
         lastPos = src.length();
        } else {
         tmp.append(src.substring(lastPos, pos));
         lastPos = pos;
        }
       }
      }
      return tmp.toString();
     }

    }

    posted @ 2008-01-11 17:08 比特鼠 閱讀(1837) | 評論 (0)編輯 收藏

    讀 YUI ,EXT等源碼的時候看JS天旋地轉(zhuǎn),那可不是51JS上那種挪挪位置就能理解的,此刻如果沒有JavaScrip的基礎(chǔ),更是像沒有星光的黑夜…….

    自以為覺得Js對象是很好理解的東東,然而真實踐起來卻一片糊涂。
    通過查閱經(jīng)典書籍《Professional JavaScript For Web Developers》稍微有些理解了

    JavaScript的基本類型
    原始類型如: Undefined Null Boolean Number String 等 用 typeof方法能辨別之
    引用類型如: Object Function Array Boolean Number String Date等,用insanceof方法辨別之

    嚴格來講,JavaScript沒有對象(Object),但是由于和OO術(shù)語對應(yīng),所以也稱之為對象。所以Array,Function,基本類型,引用類型,函數(shù),以及函數(shù)的屬性 等等這些都是對象。

    而對象分類,則可以分為內(nèi)置對象(Built-in Object) 和宿主對象(host object)。
    內(nèi)置對象如 Math,Data啊。
    宿主對象則如 BOM,DOM之類.

    重新回顧了下這些基本概念之后,在做簡單實踐就有些理解了。
    因此對象的使用,創(chuàng)建方式不盡相同,最簡單的歸類如下:

    1 基本創(chuàng)建方式

    function Class() {
    window.alert("Hello Class!");
    }
    var clz= new Class();

    2 訪問對象成員

    function Class(){
    this.x = " this is x";
    this.y = "this is y";
    this.z = viewXY;
    function viewXY(){
    alert("x+","+y);
    }
    }
    var clz= new Class();
    clz.viewXY();

    3 對象繼承

    function Parent() {
    this.type= "human!";
    }
    function Child(){
    this.age = "26";
    this.sex ="male";
    this.say= myInfo;
    function myInfo(msg){
    alert(msg+this.type+ ","+this.age+","+this.sex);
    }
    }
    Child.prototype = new Parent();
    var clild = new Child();
    clild.say("I'm ");

    4.重用原對象 (書上的例子太好了,搬來了)

    Funcion.prototype.toString() = function(){
    return "Function code hidden";
    }
    function sayHi(){
    alert("hi");
    }
    alert(sayHi.toString());
    posted @ 2008-01-02 11:06 比特鼠 閱讀(272) | 評論 (0)編輯 收藏

    希望能做到以下幾點:

    1. 在Java服務(wù)端架構(gòu)的設(shè)計, 選型, 方案等方面有所突破! -- 這是最主要的!
    2. 也想玩一玩Web前端的AJAX編程, RIA(富互聯(lián)網(wǎng)應(yīng)用)等等
    3. 熟悉Linux/Unix系統(tǒng)的命令行操作
    4. 在Java中跑腳本語言Python, JRuby等等
    5. 項目管理

    暫時就這么多吧!

    posted @ 2007-12-28 09:41 比特鼠 閱讀(209) | 評論 (0)編輯 收藏

    為 Ajax 安全性所提出的經(jīng)驗法則:
    1. 如果你使用身份驗證, 確定你在請求頁上檢查!
    2. 為 SQL 注入檢查。
    3. 為 JavaScript 注入檢查。
    4. 保留商務(wù)邏輯在服務(wù)器上!
    5. 不要假設(shè)每個請求是真正的!
    6. 確認檢查數(shù)據(jù)!
    7. 審查請求的數(shù)據(jù)而且確定它是正確的。
    posted @ 2007-12-19 17:10 比特鼠 閱讀(280) | 評論 (0)編輯 收藏

    1. jvm內(nèi)部分為主工作區(qū)和線程工作區(qū)。主工作區(qū)是實例的所有線程共有,線程工作區(qū)是實例的每個線程專有的工作區(qū),其中包括一些主工作區(qū)的一些實例字段數(shù)據(jù)的拷貝。

    2. 服務(wù)器一般都有線程池,線程資源是可以重復(fù)利用的。你2000個用戶在線,不見得能又200個用戶同時(或者說并發(fā))訪問。再說,只要對象不是太大,我寧愿用200個拷貝,也不想讓用戶在這個200個任務(wù)的隊列里等待。

    3. 兩個DB之間的復(fù)制數(shù)據(jù),每個DB各自使用自己的Sequane來生成id。復(fù)制數(shù)據(jù)時,如果DB中的外鍵是由DB維護的,則不會產(chǎn)生id沖突,如果外鍵是由外部程序維護的,則可能會產(chǎn)生錯誤!

    4. 對于非static的類的數(shù)據(jù)成員來說,在該類產(chǎn)生的實例中都有一份,并且相互獨立(修改后并不影響其他實例), 但static的數(shù)據(jù)成員則變成了每個類只有一份,即在該類產(chǎn)生的所有實例共享這一個數(shù)據(jù)成員, 該數(shù)據(jù)成員的改變會影響到其他的實例. 而static的方法則是讓你不用創(chuàng)建對象及能調(diào)用這個方法.

    5. ThreadLocal的作用就是將經(jīng)常要用到的對象的引用放到屬于線程自己的一個存儲空間中,在該線程的執(zhí)行過程中,可以通過類的靜態(tài)的ThreadLocal來方便的獲取到這個對象,而不用通過參數(shù)的形式傳來傳去。
    posted @ 2007-12-19 14:54 比特鼠 閱讀(255) | 評論 (0)編輯 收藏

    很多高分辨率的圖像真的能夠扮靚一個Web網(wǎng)站。但是它們也可能會降低網(wǎng)站的(響應(yīng))速度——圖像都是文件,文件就要占用帶寬,而帶寬與等待時間直接相關(guān)。現(xiàn)在是你進行自我學習,了解如何利用一種叫做圖像預(yù)加載的小技巧給網(wǎng)站提速的時候了。

    圖像的預(yù)加載

           瀏覽器通常的工作方式是:只有當要求加載圖像的HTTP請求被發(fā)送的時候,圖像才會被加載,而不論它是被動地通過<img>標記加載,還是主動地通過方法調(diào)用加載。所以,如果你有一段JavaScript,需要在鼠標懸停的時候切換圖像,或者在超時之后自動地更換圖像,那么你就可能會在從服務(wù)器取回圖像的時候隨時碰到等待,時間會從數(shù)秒鐘到幾分鐘不等。當你以較慢的速度連接到Internet上的時候,或者被取回的圖像非常巨大的時候,這種狀況尤其顯著,而這種數(shù)據(jù)延遲通常都會毀掉你所期望的效果。

            有些瀏覽器會試圖轉(zhuǎn)嫁這一問題,比如把圖像保存在本地緩沖區(qū)里,這樣以后對它的調(diào)用就能夠很快進行了,但是需要第一次調(diào)用圖像的時候仍然會產(chǎn)生延遲。預(yù)加載是一項在需要圖像之前就把它下載到緩沖區(qū)里的技術(shù)。通過這種方式,當真的需要圖像的時候,它可以被從緩沖區(qū)里取出來,并立即顯示出來。

    Image()對象
            預(yù)加載圖像最簡單的方法用JavaScript將一個新的Image()對象實例化,并把你想要預(yù)加載的圖像的URL傳遞給它。假設(shè)我們有一個叫做
    http://www.host01.com/Get/jsp/00040004/heavyimagefile.jpg的圖像,我們希望,當用戶把鼠標放在一個已經(jīng)顯示過的圖像上的時,系統(tǒng)能夠顯示出這個圖像。為了預(yù)加載這個圖像,以便實現(xiàn)更快的響應(yīng)時間,我們只用創(chuàng)建一個新的Image()對象,將其命名為heavyImage,并使用onLoad()事件處理程序把它同時加載到頁面上。

    1 < html >< head >< script  language  = "JavaScript" > function  preloader()  {heavyImage  =   new  Image(); heavyImage.src = " http://www.host01.com/Get/jsp/00040004/heavyimagefile.jpg " ;} </ script ></ head >< body  onLoad ="javascript:preloader()" >< href ="#"  onMouseOver ="javascript:document.img01.src='http://www.host01.com/Get/jsp/00040004/heavyimagefile.jpg'" >< img  name ="img01"  src =http://www.host01.com/Get/jsp/00040004/"justanotherfile.jpg" ></ a ></ body ></ html >
    2

     

              要注意的是,圖像標記自身并不會處理onMouseOver()和onMouseOut()事件,這就是為什么上面例子里的<img>標記被放在一個<a>標記里,后者的確加入了對這些事件類型的支持。
    用數(shù)組加載多個圖像


               在實際操作中,你可能需要預(yù)加載一幅以上的圖像;例如,在包含有多個圖像翻滾(rollover)的菜單條里,或者如果你正在嘗試創(chuàng)建平滑的動態(tài)效果。這并不困難;你所需要做的就是使用JavaScript的數(shù)組,就像下面例子里的一樣:

     

    1 < script language = " JavaScript " > function  preloader()  //  counter var i = 0; // create object imageObj = new Image(); // set image list images = new Array(); images[0]="image1.jpg" images[1]="image2.jpg" images[2]="image3.jpg" images[3]="image4.jpg" // start preloading for(i=0; i<=3; i++) { imageObj.src=images[i]; }
    2 }
      </ script >


             在上面的例子里,你先定義變量i和叫做imageObj的Image()對象。然后定義一個叫做images[]的新數(shù)組,在這個數(shù)組里,每個數(shù)組元素都保存著需要預(yù)加載的圖像來源。最后,創(chuàng)建一個for()循環(huán),讓它在數(shù)組里循環(huán),并將它們中的每一個都指派給Image()對象,這樣就能夠把它預(yù)加載到緩沖區(qū)里。
    onLoad()事件處理程序
            就和JavaScript里的其它很多對象一樣,Image()對象也帶有多個事件處理程序。這其中最有用的毫無疑問的就是onLoad()處理程序了,它會在完成圖像加載的時候被調(diào)用。這個處理程序可以與自定義的函數(shù)一起使用,以便在完成圖像加載之后進行特定的任務(wù)。下面的例子通過在圖像加載的時候顯示“請等待(please wait)”提示信息來說明這個問題,然后在圖像完成加載之后就向瀏覽器發(fā)送一個新的URL。

     

    < html >< head >< script  language ="JavaScript" > //  create an image objectobjImage = new Image(); // set what happens once the image has loaded objImage.onLoad=imagesLoaded(); // preload the image fileobjImage.src='http://www.host01.com/Get/jsp/00040004/images/image1n.gif';// function invoked on image loadfunction imagesLoaded(){ document.location.href='index2.html';}</script></head><body>Please wait, loading images</body></html>

     


           當然,你還可以創(chuàng)建一個圖像數(shù)組,對它進行循環(huán),預(yù)加載每個圖像,并在每個階段對已加載圖像的數(shù)量保持跟蹤。一旦加載了所有的圖像,事件處理程序就能夠按照設(shè)定把瀏覽器帶到下一個頁面(或者進行其他的任務(wù))。

    預(yù)加載與多狀態(tài)菜單

              現(xiàn)在,把你剛剛學到的理論付諸真正的實踐怎么樣?下面一部分內(nèi)容就是我碰巧編寫的一段代碼——一個由多個按鈕(圖像鏈接)組成的菜單條——其中每個按鈕都可能處于三種狀態(tài)中的一種:正常(normal)、hover(懸停)和點擊(click)。由于所有的按鈕都有多個狀態(tài),所以就有必要使用圖像預(yù)加載來確保菜單能夠根據(jù)其切換到的狀態(tài)進行快速的響應(yīng)。列表A里的代碼就說了這一點。

               列表A里的HTML代碼會建立一個由四個按鈕組成的菜單條,每個按鈕都有三種狀態(tài):正常、懸停和點擊。其要求如下:

              但鼠標移動到處于正常狀態(tài)的按鈕上時,按鈕會變?yōu)閼彝顟B(tài)。當鼠標移開的時候,按鈕又會恢復(fù)到正常狀態(tài)。當鼠標點擊按鈕的時候,按鈕就會變?yōu)辄c擊狀態(tài)。它會一直保持這個狀態(tài),直到另外一個按鈕被點擊。如果有一個按鈕被點擊,那么其他的按鈕就都不能處于點擊狀態(tài)。其他的按鈕只能夠處于懸停或者正常狀態(tài)。一次只能有一個按鈕可以被點擊。一次只能有一個按鈕處于懸停狀態(tài)。
            第一項任務(wù)是建立保存有菜單每個狀態(tài)的圖像的數(shù)組。與這些數(shù)組元素相對應(yīng)的<img>元素也都在HTML文檔的主體里被創(chuàng)建,并按順序命名。要注意的是,對數(shù)組值的索引是從0開始的,而相應(yīng)的<img>元素是從1開始命名的——這就需要在腳本后面的一段里進行某種計算上的調(diào)整。

            PreloadImages()函數(shù)會負責把所有的圖像都加載到緩沖區(qū)里,這樣的話對鼠標移動的響應(yīng)時間會被減到最小。一個for()循環(huán)被用在第一步里創(chuàng)建的圖像里進行迭代,并預(yù)加載每一個圖像。

                ResetAll()函數(shù)是把所有圖像恢復(fù)都到它們正常狀態(tài)的方便方法。這是有必要的,因為當菜單的項目被點擊的時候,菜單里其他所有的項目都必須在被點擊項目能夠切換到點擊狀態(tài)之前恢復(fù)到正常狀態(tài)。

            SetNormal()、setHover()和setClick()函數(shù)負責把特定圖像(圖像的編號被作為函數(shù)的自變量進行傳遞)的來源分別改為正常、懸停或者點擊狀態(tài)。由于被點擊的圖像必須一直保持點擊狀態(tài),直到另外一個圖像被點擊(見第二項要求),所以它們暫時不會對鼠標移動作出反應(yīng);這樣的話,如果按鈕還不是處在點擊狀態(tài),那么setNormal()和setHover()函數(shù)所包括的代碼就只能用來改變按鈕的狀態(tài)。

             上面所提到的預(yù)加載只是提高你JavaScript效果響應(yīng)時間的多種方法之一。就在你的網(wǎng)站上使用上面列出的技巧,并根據(jù)你的要求在需要的地方更改它們吧。祝你好運!

    posted @ 2007-12-19 10:40 比特鼠 閱讀(254) | 評論 (0)編輯 收藏

    這些東西都是Java Script大部分都是由老外寫的,并且封裝得很好,在運用上也很方便,而且也都兼容FF與OPERA,檔案中少部分是由中國的高手寫的。

     

      一、多樣化摺疊菜單:下載

      一個由老外寫的折疊式垂直菜單,多樣化,多功能,可自訂,使用容易,支持FF。

    國內(nèi)外 Java Script 經(jīng)典封裝
    圖1

      二、CSS圓角邊框:下載

      以CSS為主要,用Java Script封裝的相當完整,也是老外寫的,支持多瀏覽器,可以自訂樣式,目前有十多種可以運用。

    國內(nèi)外 Java Script 經(jīng)典封裝
    圖2

    國內(nèi)外 Java Script 經(jīng)典封裝
    圖3

      三、模擬視窗:下載

      用層模擬的視窗,是一個中國高手寫的,Java Script封裝的相當好,使用上也很容易

    國內(nèi)外 Java Script 經(jīng)典封裝
    圖4
      

      四、支持FF的省略符:下載

      說到省略符,那非CSS莫屬,有個老外用Java Script來實現(xiàn),并且是批量處理的,重點是支持FF。

    國內(nèi)外 Java Script 經(jīng)典封裝
    圖5

      五、TAB選項卡:下載

      用Java Script模仿各種作業(yè)系統(tǒng)的選項卡,老外就是牛,不僅支援多樣式的即時切換,同時也支援每個選項卡是否附帶圖示的切換選項,選項卡也可以上下切換。

    國內(nèi)外 Java Script 經(jīng)典封裝
    圖6
      

      六、最佳化多樣式Windows:下載

      用層模擬視窗的最佳代表作,這是我看過功能最多的模擬式窗,內(nèi)附多達74項功能與樣式,你完完全全可以把它當成是一個真正的視窗來應(yīng)用,可以根據(jù)你的需求來應(yīng)用,快丟掉你那認為好用的層視窗,這套封裝非常完整的視窗絕對可以滿足你的各種需求。

    國內(nèi)外 Java Script 經(jīng)典封裝
    圖7

    國內(nèi)外 Java Script 經(jīng)典封裝
    圖8

      七、多樣化的垂直菜單:附件

      別具風格的方塊式垂直折疊菜單,目前有8種風格可以運用,如果你已經(jīng)厭煩WEB上平凡的菜單,這套在國外頗受歡迎的菜單肯定是你的最佳首選。

    國內(nèi)外 Java Script 經(jīng)典封裝
    圖9
      

      八、多樣化的連結(jié)提示效果:下載

      這個連結(jié)提示樣式允許你直接寫入css與html,共有14項功能可以讓你自訂。

    國內(nèi)外 Java Script 經(jīng)典封裝
    圖10

      九、側(cè)欄式折疊菜單:下載

      這是一個側(cè)欄式的折疊菜單,它允許你設(shè)置它是否有過渡效果、側(cè)欄菜單是否自動伸縮、菜單項切換是否允許動畫過渡、是否輪替切換等多項設(shè)置,并且也有多種樣式可以運用。

      這個腳本有個很好玩的東東,下載并且解壓後,請進入samples的目錄并打show.html看看效果,我不知道這效果容不容易實現(xiàn),但是這效果很牛,菜單全自動運行的~

    國內(nèi)外 Java Script 經(jīng)典封裝
    圖11
      

      十、圖形滾動條:下載

      老外寫的圖形滾動條,有多種樣式,在ie里頭還支持滾輪滾動。

    國內(nèi)外 Java Script 經(jīng)典封裝
    圖12

      十一、圖片倒影效果:下載
      說到圖片倒影,不外乎就是直接作成圖片跟css濾鏡來實現(xiàn),但是這個是用Java Script實現(xiàn)的,值得借鏡。

    國內(nèi)外 Java Script 經(jīng)典封裝
    圖13

      十二、代碼自動高亮:下載

      雖說這不是什麼新東西,但總是會有人需要吧,而且想學正則表達的人,這肯定是最佳借鏡的作品。

    國內(nèi)外 Java Script 經(jīng)典封裝
    圖14
      
      

      十三、酷似flash效果的圖片展示:下載

      這個老外牛到有點變態(tài),這圖片展示效果已經(jīng)跟FLASH沒什麼兩樣,用Java Script寫的耶。

    國內(nèi)外 Java Script 經(jīng)典封裝
    圖15

      十四、讓ie6支援png圖檔:下載

    國內(nèi)外 Java Script 經(jīng)典封裝
    圖16

      這個問題之前被很多人討論過,我就不多說什麼了,有需要下吧。

    posted @ 2007-12-13 17:29 比特鼠 閱讀(5341) | 評論 (5)編輯 收藏

    在一個老外的Blog上看到了這個網(wǎng)站,發(fā)現(xiàn)原來是一個以C語言為基準的性能比較網(wǎng)站!

    Java還算不錯,Ruby就不怎么樣了, 在腳本語言中居然排在了最后!

    看來,解析性的語言玩起來是簡單方便了,可是卻是以損失性能為代價的!
    posted @ 2007-12-13 16:34 比特鼠 閱讀(468) | 評論 (0)編輯 收藏

    BIG-ENDIAN(大字節(jié)序、高字節(jié)序)
    LITTLE-ENDIAN(小字節(jié)序、低字節(jié)序)
    主機字節(jié)序
    網(wǎng)絡(luò)字節(jié)順序
    JAVA字節(jié)序

    1.BIG-ENDIAN、LITTLE-ENDIAN跟多字節(jié)類型的數(shù)據(jù)有關(guān)的比如int,short,long型,而對單字節(jié)數(shù)據(jù)byte卻沒有影響。BIG-ENDIAN就是低位字節(jié)排放在內(nèi)存的低端,高位字節(jié)排放在內(nèi)存的高端。而LITTLE-ENDIAN正好相反。
    比如 int a = 0x05060708
    在BIG-ENDIAN的情況下存放為:
    字節(jié)號 0 1 2 3
    數(shù)據(jù) 05 06 07 08
    在LITTLE-ENDIAN的情況下存放為:
    字節(jié)號 0 1 2 3
    數(shù)據(jù) 08 07 06 05

    2.BIG-ENDIAN、LITTLE-ENDIAN、跟CPU有關(guān)的,每一種CPU不是BIG-ENDIAN就是LITTLE-ENDIAN、。IA架構(gòu)的CPU中是Little-Endian,而PowerPC 、SPARC和Motorola處理器。這其實就是所謂的主機字節(jié)序。而網(wǎng)絡(luò)字節(jié)序是指數(shù)據(jù)在網(wǎng)絡(luò)上傳輸時是大頭還是小頭的,在Internet的網(wǎng)絡(luò)字節(jié)序是BIG-ENDIAN。所謂的JAVA字節(jié)序指的是在JAVA虛擬機中多字節(jié)類型數(shù)據(jù)的存放順序,JAVA字節(jié)序也是BIG-ENDIAN。

    3.所以在用C/C++寫通信程序時,在發(fā)送數(shù)據(jù)前務(wù)必用htonl和htons去把整型和短整型的數(shù)據(jù)進行從主機字節(jié)序到網(wǎng)絡(luò)字節(jié)序的轉(zhuǎn)換,而接收數(shù)據(jù)后對于整型和短整型數(shù)據(jù)則必須調(diào)用ntohl和ntohs實現(xiàn)從網(wǎng)絡(luò)字節(jié)序到主機字節(jié)序的轉(zhuǎn)換。如果通信的一方是JAVA程序、一方是C/C++程序時,則需要在C/C++一側(cè)使用以上幾個方法進行字節(jié)序的轉(zhuǎn)換,而JAVA一側(cè),則不需要做任何處理,因為JAVA字節(jié)序與網(wǎng)絡(luò)字節(jié)序都是BIG-ENDIAN,只要C/C++一側(cè)能正確進行轉(zhuǎn)換即可(發(fā)送前從主機序到網(wǎng)絡(luò)序,接收時反變換)。如果通信的雙方都是JAVA,則根本不用考慮字節(jié)序的問題了。

    4.如果網(wǎng)絡(luò)上全部是PowerPC,SPARC和Motorola CPU的主機那么不會出現(xiàn)任何問題,但由于實際存在大量的IA架構(gòu)的CPU,所以經(jīng)常出現(xiàn)數(shù)據(jù)傳輸錯誤。

    5.文章開頭所提出的問題,就是因為程序運行在X86架構(gòu)的PC SERVER上,發(fā)送數(shù)據(jù)的一端用C實現(xiàn)的,接收一端是用JAVA實現(xiàn)的,而發(fā)送端在發(fā)送數(shù)據(jù)前未進行從主機字節(jié)序到網(wǎng)絡(luò)字節(jié)序的轉(zhuǎn)換,這樣接收端接收到的是LITTLE-ENDIAN的數(shù)據(jù),數(shù)據(jù)解釋自然出錯。
    具體數(shù)據(jù)如下,實際發(fā)送的數(shù)據(jù)為23578
    發(fā)送端發(fā)送數(shù)據(jù): 1A 5C
    接收端接收到數(shù)據(jù)后,按BIG-ENDIAN進行解釋具體數(shù)據(jù)是多少?你們自己去計算并比較吧!


    ===============================================================================================

    Big Endian and Little Endian

        談到字節(jié)序的問題,必然牽涉到兩大CPU派系。那就是Motorola的PowerPC系列CPU和Intel的x86系列CPU。PowerPC系列采用big endian方式存儲數(shù)據(jù),而x86系列則采用little endian方式存儲數(shù)據(jù)。那么究竟什么是big endian,什么又是little endian呢?

        其實big endian是指低地址存放最高有效字節(jié)(MSB),而little endian則是低地址存放最低有效字節(jié)(LSB),即常說的低位在先,高位在后。
        用文字說明可能比較抽象,下面用圖像加以說明。比如數(shù)字0x12345678在兩種不同字節(jié)序CPU中的存儲順序如下所示:

    Big Endian

      低地址                           高地址
      ----------------------------------------->
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |     12     |      34    |     56      |     78    |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    Little Endian

      低地址                           高地址
      ----------------------------------------->
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |     78     |      56    |     34      |     12    |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

        從上面兩圖可以看出,采用big endian方式存儲數(shù)據(jù)是符合我們?nèi)祟惖乃季S習慣的。而little endian,!@#$%^&*,見鬼去吧 -_-|||

        為什么要注意字節(jié)序的問題呢?你可能這么問。當然,如果你寫的程序只在單機環(huán)境下面運行,并且不和別人的程序打交道,那么你完全可以忽略字節(jié)序的存在。但是,如果你的程序要跟別人的程序產(chǎn)生交互呢?尤其是當你把你在微機上運算的結(jié)果運用到計算機群上去的話。在這里我想說說兩種語言。C/C++語言編寫的程序里數(shù)據(jù)存儲順序是跟編譯平臺所在的CPU相關(guān)的,而JAVA編寫的程序則唯一采用big endian方式來存儲數(shù)據(jù)。試想,如果你用C/C++語言在x86平臺下編寫的程序跟別人的JAVA程序互通時會產(chǎn)生什么結(jié)果?就拿上面的 0x12345678來說,你的程序傳遞給別人的一個數(shù)據(jù),將指向0x12345678的指針傳給了JAVA程序,由于JAVA采取big endian方式存儲數(shù)據(jù),很自然的它會將你的數(shù)據(jù)翻譯為0x78563412。什么?竟然變成另外一個數(shù)字了?是的,就是這種后果。因此,在你的C程序傳給JAVA程序之前有必要進行字節(jié)序的轉(zhuǎn)換工作。

        無獨有偶,所有網(wǎng)絡(luò)協(xié)議也都是采用big endian的方式來傳輸數(shù)據(jù)的。所以有時我們也會把big endian方式稱之為網(wǎng)絡(luò)字節(jié)序。當兩臺采用不同字節(jié)序的主機通信時,在發(fā)送數(shù)據(jù)之前都必須經(jīng)過字節(jié)序的轉(zhuǎn)換成為網(wǎng)絡(luò)字節(jié)序后再進行傳輸。ANSI C中提供了四個轉(zhuǎn)換字節(jié)序的宏。


    ========================================================================================================

    /**
    * 通信格式轉(zhuǎn)換
    *
    * Java和一些windows編程語言如c、c++、delphi所寫的網(wǎng)絡(luò)程序進行通訊時,需要進行相應(yīng)的轉(zhuǎn)換
    * 高、低字節(jié)之間的轉(zhuǎn)換
    * windows的字節(jié)序為低字節(jié)開頭
    * linux,unix的字節(jié)序為高字節(jié)開頭
    * java則無論平臺變化,都是高字節(jié)開頭
    */

    public class FormatTransfer {
    /**
      * 將int轉(zhuǎn)為低字節(jié)在前,高字節(jié)在后的byte數(shù)組
      * @param n int
      * @return byte[]
      */
    public static byte[] toLH(int n) {
      byte[] b = new byte[4];
      b[0] = (byte) (n & 0xff);
      b[1] = (byte) (n >> 8 & 0xff);
      b[2] = (byte) (n >> 16 & 0xff);
      b[3] = (byte) (n >> 24 & 0xff);
      return b;
    }

    /**
      * 將int轉(zhuǎn)為高字節(jié)在前,低字節(jié)在后的byte數(shù)組
      * @param n int
      * @return byte[]
      */
    public static byte[] toHH(int n) {
      byte[] b = new byte[4];
      b[3] = (byte) (n & 0xff);
      b[2] = (byte) (n >> 8 & 0xff);
      b[1] = (byte) (n >> 16 & 0xff);
      b[0] = (byte) (n >> 24 & 0xff);
      return b;
    }

    /**
      * 將short轉(zhuǎn)為低字節(jié)在前,高字節(jié)在后的byte數(shù)組
      * @param n short
      * @return byte[]
      */
    public static byte[] toLH(short n) {
      byte[] b = new byte[2];
      b[0] = (byte) (n & 0xff);
      b[1] = (byte) (n >> 8 & 0xff);
      return b;
    }

    /**
      * 將short轉(zhuǎn)為高字節(jié)在前,低字節(jié)在后的byte數(shù)組
      * @param n short
      * @return byte[]
      */
    public static byte[] toHH(short n) {
      byte[] b = new byte[2];
      b[1] = (byte) (n & 0xff);
      b[0] = (byte) (n >> 8 & 0xff);
      return b;
    }

     

    /**
      * 將將int轉(zhuǎn)為高字節(jié)在前,低字節(jié)在后的byte數(shù)組

    public static byte[] toHH(int number) {
      int temp = number;
      byte[] b = new byte[4];
      for (int i = b.length - 1; i > -1; i--) {
        b = new Integer(temp & 0xff).byteValue();
        temp = temp >> 8;
      }
      return b;
    }

    public static byte[] IntToByteArray(int i) {
        byte[] abyte0 = new byte[4];
        abyte0[3] = (byte) (0xff & i);
        abyte0[2] = (byte) ((0xff00 & i) >> 8);
        abyte0[1] = (byte) ((0xff0000 & i) >> 16);
        abyte0[0] = (byte) ((0xff000000 & i) >> 24);
        return abyte0;
    }


    */

    /**
      * 將float轉(zhuǎn)為低字節(jié)在前,高字節(jié)在后的byte數(shù)組
      */
    public static byte[] toLH(float f) {
      return toLH(Float.floatToRawIntBits(f));
    }

    /**
      * 將float轉(zhuǎn)為高字節(jié)在前,低字節(jié)在后的byte數(shù)組
      */
    public static byte[] toHH(float f) {
      return toHH(Float.floatToRawIntBits(f));
    }

    /**
      * 將String轉(zhuǎn)為byte數(shù)組
      */
    public static byte[] stringToBytes(String s, int length) {
      while (s.getBytes().length < length) {
        s += " ";
      }
      return s.getBytes();
    }


    /**
      * 將字節(jié)數(shù)組轉(zhuǎn)換為String
      * @param b byte[]
      * @return String
      */
    public static String bytesToString(byte[] b) {
      StringBuffer result = new StringBuffer("");
      int length = b.length;
      for (int i=0; i<length; i++) {
        result.append((char)(b & 0xff));
      }
      return result.toString();
    }

    /**
      * 將字符串轉(zhuǎn)換為byte數(shù)組
      * @param s String
      * @return byte[]
      */
    public static byte[] stringToBytes(String s) {
      return s.getBytes();
    }

    /**
      * 將高字節(jié)數(shù)組轉(zhuǎn)換為int
      * @param b byte[]
      * @return int
      */
    public static int hBytesToInt(byte[] b) {
      int s = 0;
      for (int i = 0; i < 3; i++) {
        if (b >= 0) {
        s = s + b;
        } else {
        s = s + 256 + b;
        }
        s = s * 256;
      }
      if (b[3] >= 0) {
        s = s + b[3];
      } else {
        s = s + 256 + b[3];
      }
      return s;
    }

    /**
      * 將低字節(jié)數(shù)組轉(zhuǎn)換為int
      * @param b byte[]
      * @return int
      */
    public static int lBytesToInt(byte[] b) {
      int s = 0;
      for (int i = 0; i < 3; i++) {
        if (b[3-i] >= 0) {
        s = s + b[3-i];
        } else {
        s = s + 256 + b[3-i];
        }
        s = s * 256;
      }
      if (b[0] >= 0) {
        s = s + b[0];
      } else {
        s = s + 256 + b[0];
      }
      return s;
    }


    /**
      * 高字節(jié)數(shù)組到short的轉(zhuǎn)換
      * @param b byte[]
      * @return short
      */
    public static short hBytesToShort(byte[] b) {
      int s = 0;
      if (b[0] >= 0) {
        s = s + b[0];
        } else {
        s = s + 256 + b[0];
        }
        s = s * 256;
      if (b[1] >= 0) {
        s = s + b[1];
      } else {
        s = s + 256 + b[1];
      }
      short result = (short)s;
      return result;
    }

    /**
      * 低字節(jié)數(shù)組到short的轉(zhuǎn)換
      * @param b byte[]
      * @return short
      */
    public static short lBytesToShort(byte[] b) {
      int s = 0;
      if (b[1] >= 0) {
        s = s + b[1];
        } else {
        s = s + 256 + b[1];
        }
        s = s * 256;
      if (b[0] >= 0) {
        s = s + b[0];
      } else {
        s = s + 256 + b[0];
      }
      short result = (short)s;
      return result;
    }

    /**
      * 高字節(jié)數(shù)組轉(zhuǎn)換為float
      * @param b byte[]
      * @return float
      */
    public static float hBytesToFloat(byte[] b) {
      int i = 0;
      Float F = new Float(0.0);
      i = ((((b[0]&0xff)<<8 | (b[1]&0xff))<<8) | (b[2]&0xff))<<8 | (b[3]&0xff);
      return F.intBitsToFloat(i);
    }

    /**
      * 低字節(jié)數(shù)組轉(zhuǎn)換為float
      * @param b byte[]
      * @return float
      */
    public static float lBytesToFloat(byte[] b) {
      int i = 0;
      Float F = new Float(0.0);
      i = ((((b[3]&0xff)<<8 | (b[2]&0xff))<<8) | (b[1]&0xff))<<8 | (b[0]&0xff);
      return F.intBitsToFloat(i);
    }

    /**
      * 將byte數(shù)組中的元素倒序排列
      */
    public static byte[] bytesReverseOrder(byte[] b) {
      int length = b.length;
      byte[] result = new byte[length];
      for(int i=0; i<length; i++) {
        result[length-i-1] = b;
      }
      return result;
    }

    /**
      * 打印byte數(shù)組
      */
    public static void printBytes(byte[] bb) {
      int length = bb.length;
      for (int i=0; i<length; i++) {
        System.out.print(bb + " ");
      }
      System.out.println("");
    }

    public static void logBytes(byte[] bb) {
      int length = bb.length;
      String ut = "";
      for (int i=0; i<length; i++) {
        ut = out + bb + " ";
      }

    }

    /**
      * 將int類型的值轉(zhuǎn)換為字節(jié)序顛倒過來對應(yīng)的int值
      * @param i int
      * @return int
      */
    public static int reverseInt(int i) {
      int result = FormatTransfer.hBytesToInt(FormatTransfer.toLH(i));
      return result;
    }

    /**
      * 將short類型的值轉(zhuǎn)換為字節(jié)序顛倒過來對應(yīng)的short值
      * @param s short
      * @return short
      */
    public static short reverseShort(short s) {
      short result = FormatTransfer.hBytesToShort(FormatTransfer.toLH(s));
      return result;
    }

    /**
      * 將float類型的值轉(zhuǎn)換為字節(jié)序顛倒過來對應(yīng)的float值
      * @param f float
      * @return float
      */
    public static float reverseFloat(float f) {
      float result = FormatTransfer.hBytesToFloat(FormatTransfer.toLH(f));
      return result;
    }

    }

    posted @ 2007-10-24 09:57 比特鼠 閱讀(3406) | 評論 (0)編輯 收藏

    實現(xiàn)Leader/Fellows模式的項目--CAJ, 地址是:http://caj.cosylab.com/
    posted @ 2007-10-23 14:57 比特鼠 閱讀(198) | 評論 (0)編輯 收藏

    網(wǎng)址:http://httpd.apache.org/docs/2.0/programs/ab.html
    posted @ 2007-10-23 14:53 比特鼠 閱讀(273) | 評論 (0)編輯 收藏

    緩沖區(qū)基礎(chǔ)

    抽象類Buffer是java.nio包支持緩沖區(qū)的基礎(chǔ)。 Buffer 的工作方式就象內(nèi)存中用于讀寫基本數(shù)據(jù)類型的 RandomAccessFile 。象 RandomAccessFile 一樣,使用 Buffer ,所執(zhí)行的下一個操作(讀/寫)在當前某個位置發(fā)生。執(zhí)行讀/寫操作中的任一個都會改變那個位置,所以在寫操作之后進行讀操作不會讀到剛才所寫的內(nèi)容,而會讀到剛才所寫內(nèi)容之后的數(shù)據(jù)。 Buffer 提供了四個指示方法,用于訪問線性結(jié)構(gòu)(從最高值到最低值):

    capacity() :表明緩沖區(qū)的容量大小, 一旦確定了大小, 將不能再改變;
    limit() :告訴您到目前為止已經(jīng)往緩沖區(qū)填了多少字節(jié),或者讓您用 :limit(int newLimit) 來改變這個限制
    position() :告訴您當前的位置,以執(zhí)行下一個讀/寫操作
    mark() :為了稍后用 reset() 進行重新設(shè)置而記住某個位置
    flip() :交換限制指針和位置指針,然后將位置置為 0,并廢棄已經(jīng)做的mark標記

    緩沖區(qū)的基本操作是讀 get() 和寫 put() ;然而,這些方法在子類中都是針對每種數(shù)據(jù)類型的特定方法。為了說明這一情況,讓我們研究一個簡單示例,該示例演示了從同一個緩沖區(qū)讀和寫一個字符。在清單 1 中, flip() 方法交換限制和位置,然后將位置置為 0,并廢棄標記,讓您讀剛才所寫的數(shù)據(jù):


    清單 1. 讀/寫示例
    import java.nio.*;
    ...
    CharBuffer buff = ...;
    buff.put('A');
    buff.flip();
    char c = buff.get();
    System.out.println("An A: " + c);
     


    現(xiàn)在讓我們研究一些具體的 Buffer 子類。

     

    緩沖區(qū)類型

    Merlin 具有 7 種特定的 Buffer 類型,每種類型對應(yīng)著一個基本數(shù)據(jù)類型(不包括 boolean):

    ByteBuffer       //存放任何除boolean類型外的其他基本類型
    CharBuffer       //存放char
    DoubleBuffer     //存放double
    FloatBuffer      //存放float
    IntBuffer        //存放int
    LongBuffer       //存放long
    ShortBuffer      //存放short

    在本文后面,我將討論第 8 種類型 MappedByteBuffer ,它用于內(nèi)存映射文件。如果您必須使用的類型不是這些基本類型,則可以先從 ByteBuffer 獲得字節(jié)類型,然后將其轉(zhuǎn)換成 Object 或其它任何類型。


    創(chuàng)建緩沖區(qū)
    一共有兩種類型的緩沖區(qū),直接緩沖區(qū)和非直接緩沖區(qū)。

    在創(chuàng)建緩沖區(qū)時,可以要求創(chuàng)建直接緩沖區(qū),創(chuàng)建直接緩沖區(qū)的成本要比創(chuàng)建間接緩沖區(qū)高,但這可以使運行時環(huán)境直接在該緩沖區(qū)上進行較快的本機 I/O 操作。因為創(chuàng)建直接緩沖區(qū)所增加的成本,所以直接緩沖區(qū)只用于長生存期的緩沖區(qū),而不用于短生存期、一次性且用完就丟棄的緩沖區(qū)。而且,只能在 ByteBuffer 這個級別上創(chuàng)建直接緩沖區(qū),如果希望使用其它類型,則必須將 Buffer 轉(zhuǎn)換成更具體的類型。

    判斷一個緩沖區(qū)是否是直接緩沖區(qū),可以調(diào)用isDirect()方法。

    有三種方式來獲取一個緩沖區(qū)的對象:
    a. 調(diào)用allocate()或者allocateDirect()方法直接分配,其中allocateDirect()返回的是直接緩沖區(qū)。
    b. 包裝一個數(shù)組,如:
          byte[] b = new byte[1024];
          ByteBuffer bb = ByteBuffer.wrap(b);
    c. 內(nèi)存映射,即調(diào)用FileChannel的map()方法。

    緩沖區(qū)基本屬性
    這幾個屬性是每個緩沖區(qū)都有的并且是常用的操作。
    a. 容量(capacity),緩沖區(qū)大小
    b. 限制(limit),第一個不應(yīng)被讀取或?qū)懭氲淖止?jié)的索引,總是小于容量。
    c. 位置(position),下一個被讀取或?qū)懭氲淖止?jié)的索引,總是小于限制。
    d. clear()方法:設(shè)置limit為capacity,position為0。
    e. filp()方法:設(shè)置limit為當前position,然后設(shè)置position為0。
    f. rewind()方法:保持limit不變,設(shè)置position為0。

    緩沖區(qū)數(shù)據(jù)操作
    操作包括了讀取和寫入數(shù)據(jù)兩種。
    讀取數(shù)據(jù)使用get()及其系列方法,除boolean外,每一種類型包括了對應(yīng)的get()方法,如getInt(),getChar()等,get()方法用來讀取字節(jié),支持相對和絕對索引兩種方式。
    寫入數(shù)據(jù)使用put()及其系列方法,和get()方法是對應(yīng)的。

    package nio;

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;

    public class BufferDemo ...{

        
        public static void main(String[] args) throws Exception...{
            //分配一個非直接緩沖區(qū)
            ByteBuffer bb = ByteBuffer.allocate(100);
            //向緩沖區(qū)寫入0到100的字節(jié)制
            for(int i = 0; i <100; i++)...{
                byte b = (byte) (Math.random() * 100);
                bb.put(b);
            }
            
            System.out.println("寫入文件前的緩沖區(qū)數(shù)據(jù)");
            bb.flip();
            while(bb.hasRemaining())
                System.out.print(bb.get() + " ");
            System.out.println();
            
            //獲取一個關(guān)聯(lián)到文件buffer.txt的信道
            FileChannel fc = new FileOutputStream("buffer.txt").getChannel();
            //將緩沖區(qū)數(shù)據(jù)寫到文件中
            bb.flip();
            fc.write(bb);
            //防止緩存
            fc.force(true);
            //關(guān)閉信道
            fc.close();
            bb = null;
            fc = null;
            
            //下面從文件中讀取數(shù)據(jù)
            fc = new FileInputStream("buffer.txt").getChannel();
            ByteBuffer bb2 = ByteBuffer.allocate((int) fc.size());
            fc.read(bb2);
            System.out.println("從文件讀取的緩沖區(qū)數(shù)據(jù)");
            bb2.flip();
            while(bb2.hasRemaining())
                System.out.print(bb2.get() + " ");
            System.out.println();
            fc.close();
            bb2 = null;
            fc = null;
            

        }

    }

    內(nèi)存映射文件

    第 8 種 Buffer 類型 MappedByteBuffer 只是一種特殊的 ByteBuffer 。 MappedByteBuffer 將文件所在區(qū)域直接映射到內(nèi)存。通常,該區(qū)域包含整個文件,但也可以只映射部分文件。所以,必須指定要映射文件的哪部分。而且,與其它 Buffer 對象一樣,這里沒有構(gòu)造函數(shù);必須讓 java.nio.channels.FileChannel 的 map() 方法來獲取 MappedByteBuffer 。此外,無需過多涉及通道就可以用 getChannel() 方法從 FileInputStream 或 FileOutputStream 獲取 FileChannel 。通過從命令行傳入文件名來讀取文本文件的內(nèi)容,清單 4 顯示了 MappedByteBuffer :


    清單 4. 讀取內(nèi)存映射文本文件
    import java.io.*;
    import java.nio.*;
    import java.nio.channels.*;
    import java.nio.charset.*;
    public class ReadFileBuff {
      public static void main(String args[]) throws IOException {
         if (args.length != 0) {
          String filename = args[0];
          FileInputStream fis = new FileInputStream(filename);
          FileChannel channel = fis.getChannel();
          int length = (int)channel.size();
          MappedByteBuffer byteBuffer =
            channel.map(FileChannel.MapMode.READ_ONLY, 0, length);
          Charset charset = Charset.forName("ISO-8859-1");
          CharsetDecoder decoder = charset.newDecoder();
          CharBuffer charBuffer = decoder.decode(byteBuffer);
          for (int i=0, n=charBuffer.length(); i<n; i++) {
            System.out.print(charBuffer.get());
          }
        }
      }
    }

    posted @ 2007-08-01 11:13 比特鼠 閱讀(3826) | 評論 (0)編輯 收藏

    1. 左移操作: x << n
      x可以是byte, short, char, int, long基本類型, n(位移量)只能是int型

      編譯器的執(zhí)行步驟:
      1) 如果x是byte, short, char類型, 則將x提升為int;
      2) 如果x是byte, short, char, int類型, 則n被重新賦值(過程是:取n的補碼的低5位再轉(zhuǎn)成十進制的int值,相當對n取32模: n=n%32);
         如果x是long型, 則n被重新賦值(過程是:取n的補碼的低6位再轉(zhuǎn)成十進制的int值,相當對n取64模: n=n%64);
         (因為int類型為4個字節(jié),即32位,移動32位將沒有任何意義.對于long則是模64)
      3) 對x左移n個位數(shù), 整個表達式產(chǎn)生一個新值(x的值不變);
    2. <<是左移符號,列x<<1,就是x的內(nèi)容左移一位(x的內(nèi)容并不改變)
    3. >>是帶符號位的右移符號,x>>1就是x的內(nèi)容右移一位,如果開頭是1則補1,是0責補0,(x的內(nèi)容并不改變).
    4. >>>是不帶符號位的右移,x>>>1就是x的內(nèi)容右移一位,開頭補0(x的內(nèi)容并不改變)
    posted @ 2007-08-01 10:12 比特鼠 閱讀(2804) | 評論 (0)編輯 收藏

    原文地址 http://www.programbbs.com/doc/2433.htm
    為什么會排隊等待?

    下面的這個簡單的 Java 程序完成四項不相關(guān)的任務(wù)。這樣的程序有單個控制線程,控制在這四個任務(wù)之間線性地移動。此外,因為所需的資源 — 打印機、磁盤、數(shù)據(jù)庫和顯示屏 -- 由于硬件和軟件的限制都有內(nèi)在的潛伏時間,所以每項任務(wù)都包含明顯的等待時間。因此,程序在訪問數(shù)據(jù)庫之前必須等待打印機完成打印文件的任務(wù),等等。如果您正在等待程序的完成,則這是對計算資源和您的時間的一種拙劣使用。改進此程序的一種方法是使它成為多線程的。
     
    四項不相關(guān)的任務(wù)
     

    class myclass {
        static public void main(String args[]) {
            print_a_file();
            manipulate_another_file();
            access_database();
            draw_picture_on_screen();
        }
    }

    在本例中,每項任務(wù)在開始之前必須等待前一項任務(wù)完成,即使所涉及的任務(wù)毫不相關(guān)也是這樣。但是,在現(xiàn)實生活中,我們經(jīng)常使用多線程模型。我們在處理某些任務(wù)的同時也可以讓孩子、配偶和父母完成別的任務(wù)。例如,我在寫信的同時可能打發(fā)我的兒子去郵局買郵票。用軟件術(shù)語來說,這稱為多個控制(或執(zhí)行)線程。

    可以用兩種不同的方法來獲得多個控制線程:

    多個進程
    在大多數(shù)操作系統(tǒng)中都可以創(chuàng)建多個進程。當一個程序啟動時,它可以為即將開始的每項任務(wù)創(chuàng)建一個進程,并允許它們同時運行。當一個程序因等待網(wǎng)絡(luò)訪問或用戶輸入而被阻塞時,另一個程序還可以運行,這樣就增加了資源利用率。但是,按照這種方式創(chuàng)建每個進程要付出一定的代價:設(shè)置一個進程要占用相當一部分處理器時間和內(nèi)存資源。而且,大多數(shù)操作系統(tǒng)不允許進程訪問其他進程的內(nèi)存空間。因此,進程間的通信很不方便,并且也不會將它自己提供給容易的編程模型。


    線程
    線程也稱為輕型進程 (LWP)。因為線程只能在單個進程的作用域內(nèi)活動,所以創(chuàng)建線程比創(chuàng)建進程要廉價得多。這樣,因為線程允許協(xié)作和數(shù)據(jù)交換,并且在計算資源方面非常廉價,所以線程比進程更可取。線程需要操作系統(tǒng)的支持,因此不是所有的機器都提供線程。Java 編程語言,作為相當新的一種語言,已將線程支持與語言本身合為一體,這樣就對線程提供了強健的支持。


    使用 Java 編程語言實現(xiàn)線程
    Java 編程語言使多線程如此簡單有效,以致于某些程序員說它實際上是自然的。盡管在 Java 中使用線程比在其他語言中要容易得多,仍然有一些概念需要掌握。要記住的一件重要的事情是 main() 函數(shù)也是一個線程,并可用來做有用的工作。程序員只有在需要多個線程時才需要創(chuàng)建新的線程。

    Thread 類
    Thread 類是一個具體的類,即不是抽象類,該類封裝了線程的行為。要創(chuàng)建一個線程,程序員必須創(chuàng)建一個從 Thread 類導(dǎo)出的新類。程序員必須覆蓋 Thread 的 run() 函數(shù)來完成有用的工作。用戶并不直接調(diào)用此函數(shù);而是必須調(diào)用 Thread 的 start() 函數(shù),該函數(shù)再調(diào)用 run()。下面的代碼說明了它的用法:

    創(chuàng)建兩個新線程

    import java.util.*;

    class TimePrinter extends Thread {
        int pauseTime;

        String name;

        public TimePrinter(int x, String n) {
            pauseTime = x;
            name = n;
        }

        public void run() {
            while (true) {
                try {
                    System.out.println(name + ":"
                            + new Date(System.currentTimeMillis()));
                    Thread.sleep(pauseTime);
                } catch (Exception e) {
                    System.out.println(e);
                }
            }
        }

        static public void main(String args[]) {
            TimePrinter tp1 = new TimePrinter(1000, "Fast Guy");
            tp1.start();
            TimePrinter tp2 = new TimePrinter(3000, "Slow Guy");
            tp2.start();

        }
    }

    在本例中,我們可以看到一個簡單的程序,它按兩個不同的時間間隔(1 秒和 3 秒)在屏幕上顯示當前時間。這是通過創(chuàng)建兩個新線程來完成的,包括 main() 共三個線程。但是,因為有時要作為線程運行的類可能已經(jīng)是某個類層次的一部分,所以就不能再按這種機制創(chuàng)建線程。雖然在同一個類中可以實現(xiàn)任意數(shù)量的接口,但 Java 編程語言只允許一個類有一個父類。同時,某些程序員避免從 Thread 類導(dǎo)出,因為它強加了類層次。對于這種情況,就要 runnable 接口。

    Runnable 接口
    此接口只有一個函數(shù),run(),此函數(shù)必須由實現(xiàn)了此接口的類實現(xiàn)。但是,就運行這個類而論,其語義與前一個示例稍有不同。我們可以用 runnable 接口改寫前一個示例。(不同的部分用黑體表示。)

    創(chuàng)建兩個新線程而不強加類層次

    import java.util.*;

    class TimePrinter implements Runnable {
        int pauseTime;

        String name;

        public TimePrinter(int x, String n) {
            pauseTime = x;
            name = n;
        }

        public void run() {
            while (true) {
                try {
                    System.out.println(name + ":"
                            + new Date(System.currentTimeMillis()));
                    Thread.sleep(pauseTime);
                } catch (Exception e) {
                    System.out.println(e);
                }
            }
        }

        static public void main(String args[]) {
            Thread t1 = new Thread(new TimePrinter(1000, "Fast Guy"));
            t1.start();
            Thread t2 = new Thread(new TimePrinter(3000, "Slow Guy"));
            t2.start();

        }
    }

    請注意,當使用 runnable 接口時,您不能直接創(chuàng)建所需類的對象并運行它;必須從 Thread 類的一個實例內(nèi)部運行它。許多程序員更喜歡 runnable 接口,因為從 Thread 類繼承會強加類層次。

    synchronized 關(guān)鍵字
    到目前為止,我們看到的示例都只是以非常簡單的方式來利用線程。只有最小的數(shù)據(jù)流,而且不會出現(xiàn)兩個線程訪問同一個對象的情況。但是,在大多數(shù)有用的程序中,線程之間通常有信息流。試考慮一個金融應(yīng)用程序,它有一個 Account 對象,如下例中所示:

    一個銀行中的多項活動

    public class Account {
        String holderName;

        float amount;

        public Account(String name, float amt) {
            holderName = name;
            amount = amt;
        }

        public void deposit(float amt) {
            amount += amt;
        }

        public void withdraw(float amt) {
            amount -= amt;
        }

        public float checkBalance() {
            return amount;
        }
    }

    在此代碼樣例中潛伏著一個錯誤。如果此類用于單線程應(yīng)用程序,不會有任何問題。但是,在多線程應(yīng)用程序的情況中,不同的線程就有可能同時訪問同一個 Account 對象,比如說一個聯(lián)合帳戶的所有者在不同的 ATM 上同時進行訪問。在這種情況下,存入和支出就可能以這樣的方式發(fā)生:一個事務(wù)被另一個事務(wù)覆蓋。這種情況將是災(zāi)難性的。但是,Java 編程語言提供了一種簡單的機制來防止發(fā)生這種覆蓋。每個對象在運行時都有一個關(guān)聯(lián)的鎖。這個鎖可通過為方法添加關(guān)鍵字 synchronized 來獲得。這樣,修訂過的 Account 對象(如下所示)將不會遭受像數(shù)據(jù)損壞這樣的錯誤:

    對一個銀行中的多項活動進行同步處理

    public class Account {
        String holderName;

        float amount;

        public Account(String name, float amt) {
            holderName = name;
            amount = amt;
        }

        public synchronized void deposit(float amt) {
            amount += amt;
        }

        public synchronized void withdraw(float amt) {
            amount -= amt;
        }

        public float checkBalance() {
            return amount;
        }
    }

    deposit() 和 withdraw() 函數(shù)都需要這個鎖來進行操作,所以當一個函數(shù)運行時,另一個函數(shù)就被阻塞。請注意,checkBalance() 未作更改,它嚴格是一個讀函數(shù)。因為 checkBalance() 未作同步處理,所以任何其他方法都不會阻塞它,它也不會阻塞任何其他方法,不管那些方法是否進行了同步處理。

    Java 編程語言中的高級多線程支持

    線程組
    線程是被個別創(chuàng)建的,但可以將它們歸類到線程組中,以便于調(diào)試和監(jiān)視。只能在創(chuàng)建線程的同時將它與一個線程組相關(guān)聯(lián)。在使用大量線程的程序中,使用線程組組織線程可能很有幫助。可以將它們看作是計算機上的目錄和文件結(jié)構(gòu)。

    線程間發(fā)信
    當線程在繼續(xù)執(zhí)行前需要等待一個條件時,僅有 synchronized 關(guān)鍵字是不夠的。雖然 synchronized 關(guān)鍵字阻止并發(fā)更新一個對象,但它沒有實現(xiàn)線程間發(fā)信。Object 類為此提供了三個函數(shù):wait()、notify() 和 notifyAll()。以全球氣候預(yù)測程序為例。這些程序通過將地球分為許多單元,在每個循環(huán)中,每個單元的計算都是隔離進行的,直到這些值趨于穩(wěn)定,然后相鄰單元之間就會交換一些數(shù)據(jù)。所以,從本質(zhì)上講,在每個循環(huán)中各個線程都必須等待所有線程完成各自的任務(wù)以后才能進入下一個循環(huán)。這個模型稱為屏蔽同步,下例說明了這個模型:

    屏蔽同步

    public class BSync {
        int totalThreads;

        int currentThreads;

        public BSync(int x) {
            totalThreads = x;
            currentThreads = 0;
        }

        public synchronized void waitForAll() {
            currentThreads++;
            if (currentThreads < totalThreads) {
                try {
                    wait();
                } catch (Exception e) {
                }
            } else {
                currentThreads = 0;
                notifyAll();
            }
        }
    }

    當對一個線程調(diào)用 wait() 時,該線程就被有效阻塞,只到另一個線程對同一個對象調(diào)用 notify() 或 notifyAll() 為止。因此,在前一個示例中,不同的線程在完成它們的工作以后將調(diào)用 waitForAll() 函數(shù),最后一個線程將觸發(fā) notifyAll() 函數(shù),該函數(shù)將釋放所有的線程。第三個函數(shù) notify() 只通知一個正在等待的線程,當對每次只能由一個線程使用的資源進行訪問限制時,這個函數(shù)很有用。但是,不可能預(yù)知哪個線程會獲得這個通知,因為這取決于 Java 虛擬機 (JVM) 調(diào)度算法。

    將 CPU 讓給另一個線程
    當線程放棄某個稀有的資源(如數(shù)據(jù)庫連接或網(wǎng)絡(luò)端口)時,它可能調(diào)用 yield() 函數(shù)臨時降低自己的優(yōu)先級,以便某個其他線程能夠運行。

    守護線程
    有兩類線程:用戶線程和守護線程。用戶線程是那些完成有用工作的線程。守護線程是那些僅提供輔助功能的線程。Thread 類提供了 setDaemon() 函數(shù)。Java 程序?qū)⑦\行到所有用戶線程終止,然后它將破壞所有的守護線程。在 Java 虛擬機 (JVM) 中,即使在 main 結(jié)束以后,如果另一個用戶線程仍在運行,則程序仍然可以繼續(xù)運行。

    避免不提倡使用的方法
    不提倡使用的方法是為支持向后兼容性而保留的那些方法,它們在以后的版本中可能出現(xiàn),也可能不出現(xiàn)。Java 多線程支持在版本 1.1 和版本 1.2 中做了重大修訂,stop()、suspend() 和 resume() 函數(shù)已不提倡使用。這些函數(shù)在 JVM 中可能引入微妙的錯誤。雖然函數(shù)名可能聽起來很誘人,但請抵制誘惑不要使用它們。

    調(diào)試線程化的程序
    在線程化的程序中,可能發(fā)生的某些常見而討厭的情況是死鎖、活鎖、內(nèi)存損壞和資源耗盡。

    死鎖
    死鎖可能是多線程程序最常見的問題。當一個線程需要一個資源而另一個線程持有該資源的鎖時,就會發(fā)生死鎖。這種情況通常很難檢測。但是,解決方案卻相當好:在所有的線程中按相同的次序獲取所有資源鎖。例如,如果有四個資源 —A、B、C 和 D — 并且一個線程可能要獲取四個資源中任何一個資源的鎖,則請確保在獲取對 B 的鎖之前首先獲取對 A 的鎖,依此類推。如果“線程 1”希望獲取對 B 和 C 的鎖,而“線程 2”獲取了 A、C 和 D 的鎖,則這一技術(shù)可能導(dǎo)致阻塞,但它永遠不會在這四個鎖上造成死鎖。

    活鎖
    當一個線程忙于接受新任務(wù)以致它永遠沒有機會完成任何任務(wù)時,就會發(fā)生活鎖。這個線程最終將超出緩沖區(qū)并導(dǎo)致程序崩潰。試想一個秘書需要錄入一封信,但她一直在忙于接電話,所以這封信永遠不會被錄入。

    內(nèi)存損壞
    如果明智地使用 synchronized 關(guān)鍵字,則完全可以避免內(nèi)存錯誤這種氣死人的問題。

    資源耗盡
    某些系統(tǒng)資源是有限的,如文件描述符。多線程程序可能耗盡資源,因為每個線程都可能希望有一個這樣的資源。如果線程數(shù)相當大,或者某個資源的侯選線程數(shù)遠遠超過了可用的資源數(shù),則最好使用資源池。一個最好的示例是數(shù)據(jù)庫連接池。只要線程需要使用一個數(shù)據(jù)庫連接,它就從池中取出一個,使用以后再將它返回池中。資源池也稱為資源庫。

    調(diào)試大量的線程
    有時一個程序因為有大量的線程在運行而極難調(diào)試。在這種情況下,下面的這個類可能會派上用場:

    public class Probe extends Thread {
        public Probe() {
        }

        public void run() {

            while (true) {
                Thread[] x = new Thread[100];
                Thread.enumerate(x);

                for (int i = 0; i < 100; i++) {
                    Thread t = x[i];
                    if (t == null)
                        break;
                    else
                        System.out.println(t.getName() + "\t" + t.getPriority()
                                + "\t" + t.isAlive() + "\t" + t.isDaemon());
                }
            }
        }
    }

    限制線程優(yōu)先級和調(diào)度
    Java 線程模型涉及可以動態(tài)更改的線程優(yōu)先級。本質(zhì)上,線程的優(yōu)先級是從 1 到 10 之間的一個數(shù)字,數(shù)字越大表明任務(wù)越緊急。JVM 標準首先調(diào)用優(yōu)先級較高的線程,然后才調(diào)用優(yōu)先級較低的線程。但是,該標準對具有相同優(yōu)先級的線程的處理是隨機的。如何處理這些線程取決于基層的操作系統(tǒng)策略。在某些情況下,優(yōu)先級相同的線程分時運行;在另一些情況下,線程將一直運行到結(jié)束。請記住,Java 支持 10 個優(yōu)先級,基層操作系統(tǒng)支持的優(yōu)先級可能要少得多,這樣會造成一些混亂。因此,只能將優(yōu)先級作為一種很粗略的工具使用。最后的控制可以通過明智地使用 yield() 函數(shù)來完成。通常情況下,請不要依靠線程優(yōu)先級來控制線程的狀態(tài)。

    小結(jié)
    本文說明了在 Java 程序中如何使用線程。像是否應(yīng)該使用線程這樣的更重要的問題在很大程序上取決于手頭的應(yīng)用程序。決定是否在應(yīng)用程序中使用多線程的一種方法是,估計可以并行運行的代碼量。并記住以下幾點:

    使用多線程不會增加 CPU 的能力。但是如果使用 JVM 的本地線程實現(xiàn),則不同的線程可以在不同的處理器上同時運行(在多 CPU 的機器中),從而使多 CPU 機器得到充分利用。
    如果應(yīng)用程序是計算密集型的,并受 CPU 功能的制約,則只有多 CPU 機器能夠從更多的線程中受益。
    當應(yīng)用程序必須等待緩慢的資源(如網(wǎng)絡(luò)連接或數(shù)據(jù)庫連接)時,或者當應(yīng)用程序是非交互式的時,多線程通常是有利的。
    基于 Internet 的軟件有必要是多線程的;否則,用戶將感覺應(yīng)用程序反映遲鈍。例如,當開發(fā)要支持大量客戶機的服務(wù)器時,多線程可以使編程較為容易。在這種情況下,每個線程可以為不同的客戶或客戶組服務(wù),從而縮短了響應(yīng)時間。

    某些程序員可能在 C 和其他語言中使用過線程,在那些語言中對線程沒有語言支持。這些程序員可能通常都被搞得對線程失去了信心。

    posted @ 2007-07-30 09:36 比特鼠 閱讀(209) | 評論 (0)編輯 收藏

    眾所周知, Java在從XML文件中裝載內(nèi)容到內(nèi)存過程中,不論用何種方式,IO操作的開銷都無可避免。本文嘗試比較dom4j中的XPP3和SAX兩種方式裝載XML文件的性能,以便將IO操作的開銷降到最小!

    package gz.lwm;

    import java.io.File;
    import org.apache.log4j.Logger;
    import org.dom4j.Document;
    import org.dom4j.DocumentHelper;
    import org.dom4j.io.SAXReader;
    import org.dom4j.io.XPP3Reader;

    public class TestDom4j {
     private static final Logger log = Logger.getLogger(TestDom4j.class);
     private static long bt; 
     
     public static void main(String[] args) {
      Document doc = DocumentHelper.createDocument();   
      //先運行g(shù)etXmlSAX()
      bt = System.currentTimeMillis();
      String strXml = getXmlSAX("xml/test.xml");
      if(log.isDebugEnabled()){
       log.debug("\ngetXmlSAX() use time: " + (System.currentTimeMillis() - bt) + " millis\n");
      }

      //再運行g(shù)etXmlXPP3()
      bt = System.currentTimeMillis();
      String s1 =getXmlXPP3("xml/test.xml");
      if(log.isDebugEnabled()){
       log.debug("\ngetXmlXPP3() use time: " + (System.currentTimeMillis() - bt) + " millis\n");
      }
      
      
     }
     
     public static String getXmlSAX(String xmlFile){
      String result = "";
      try {
       SAXReader reader = new SAXReader();
       Document document = reader.read(new File(xmlFile));
       result = document.asXML();
      } catch (Exception e) {
       e.printStackTrace();
      }
      return result;
     }
     
     public static String getXmlXPP3(String xmlFile){
      String result = "";
      try {
       XPP3Reader reader = new XPP3Reader();
       Document document = reader.read(new File(xmlFile));
       result = document.asXML();
      } catch (Exception e) {
       e.printStackTrace();
      }
      return result;
     }


     
    }

    有沒有這一句"Document doc = DocumentHelper.createDocument()",對性能的影響很大,特別是對大xml文件(盡管并沒有使用doc)

    另外, getXmlXSAX()和getXmlXPP3()運行的先后次序?qū)π阅艿挠绊懸埠艽螅?br>
    測試:
        在我的機器上,對一個100k左右的XML文件進行多次測試后的均值結(jié)果為:

        getXmlXPP3() use time: 265 millis
        ...
        getXmlXSAX() use time: 359 millis
        ...

    結(jié)論:
        通過比較,在讀取XML文件上,XPP3略為優(yōu)于SAX!


    注意:

    要運行例子,classpath需包含:
    dom4j-1.6.1.jar
    jaxen-1.1-beta-10.jar
    log4j-1.2.9.jar
    pull-parser-2.1.10.jar
    xpp3-1.1.4c.jar


    參考:
    dom4j :  http://www.dom4j.org/
    XPP   :  http://www.extreme.indiana.edu/xgws/xsoap/xpp/

    posted @ 2007-05-19 00:39 比特鼠 閱讀(2509) | 評論 (0)編輯 收藏

       Namespace namespace ...

       //第一種方法
       Document doc = DocumentHelper.createDocument();
       Element root = doc.addElement("Root", namespace.getURI());
       Element eResultMessage = root.addElement("ResultMessage");

       結(jié)果為:
       <Root xmlns="http://aaaaaa"><ResultMessage>...</ResultMessage></Root>



       //第二種方法
       Document doc = DocumentHelper.createDocument();
       Element root = doc.addElement(("Root");
       root.add(namespace);
       Element eResultMessage = root.addElement("ResultMessage");
       
       結(jié)果為:
       <Root xmlns="
    http://aaaaaa"><ResultMessage xmlns="">...</ResultMessage></Root>

    posted @ 2007-05-17 21:08 比特鼠 閱讀(2659) | 評論 (0)編輯 收藏

    正則表達式語法 
     

    正則表達式是一種文本模式,包括普通字符(例如,a 到 z 之間的字母)和特殊字符(稱為“元字符”)。模式描述在搜索文本時要匹配的一個或多個字符串。

    正則表達式示例
     
    表達式  匹配 
    /^\s*$/
     匹配空行。
     
    /\d{2}-\d{5}/
     驗證由兩位數(shù)字、一個連字符再加 5 位數(shù)字組成的 ID 號。
     
    /<\s*(\S+)(\s[^>]*)?>[\s\S]*<\s*\/\1\s*>/
     匹配 HTML 標記。
     

    下表包含了元字符的完整列表以及它們在正則表達式上下文中的行為:

     
    字符  說明 
    \
     將下一字符標記為特殊字符、文本、反向引用或八進制轉(zhuǎn)義符。例如,“n”匹配字符“n”。“\n”匹配換行符。序列“\\”匹配“\”,“\(”匹配“(”。
     
    ^
     匹配輸入字符串開始的位置。如果設(shè)置了 RegExp 對象的 Multiline 屬性,^ 還會與“\n”或“\r”之后的位置匹配。
     
    $
     匹配輸入字符串結(jié)尾的位置。如果設(shè)置了 RegExp 對象的 Multiline 屬性,$ 還會與“\n”或“\r”之前的位置匹配。
     
    *
     零次或多次匹配前面的字符或子表達式。例如,zo* 匹配“z”和“zoo”。* 等效于 {0,}。
     
    +
     一次或多次匹配前面的字符或子表達式。例如,“zo+”與“zo”和“zoo”匹配,但與“z”不匹配。+ 等效于 {1,}。
     
    ?
     零次或一次匹配前面的字符或子表達式。例如,“do(es)?”匹配“do”或“does”中的“do”。? 等效于 {0,1}。
     
    {n}
     n 是非負整數(shù)。正好匹配 n 次。例如,“o{2}”與“Bob”中的“o”不匹配,但與“food”中的兩個“o”匹配。
     
    {n,}
     n 是非負整數(shù)。至少匹配 n 次。例如,“o{2,}”不匹配“Bob”中的“o”,而匹配“foooood”中的所有 o。“o{1,}”等效于“o+”。“o{0,}”等效于“o*”。
     
    {n,m}
     M 和 n 是非負整數(shù),其中 n <= m。匹配至少 n 次,至多 m 次。例如,“o{1,3}”匹配“fooooood”中的頭三個 o。'o{0,1}' 等效于 'o?'。注意:您不能將空格插入逗號和數(shù)字之間。
     
    ?
     當此字符緊隨任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后時,匹配模式是“非貪心的”。“非貪心的”模式匹配搜索到的、盡可能短的字符串,而默認的“貪心的”模式匹配搜索到的、盡可能長的字符串。例如,在字符串“oooo”中,“o+?”只匹配單個“o”,而“o+”匹配所有“o”。
     
    .
     匹配除“\n”之外的任何單個字符。若要匹配包括“\n”在內(nèi)的任意字符,請使用諸如“[\s\S]”之類的模式。
     
    (pattern)
     匹配 pattern 并捕獲該匹配的子表達式。可以使用 $0…$9 屬性從結(jié)果“匹配”集合中檢索捕獲的匹配。若要匹配括號字符 ( ),請使用“\(”或者“\)”。
     
    (?:pattern)
     匹配 pattern 但不捕獲該匹配的子表達式,即它是一個非捕獲匹配,不存儲供以后使用的匹配。這對于用“or”字符 (|) 組合模式部件的情況很有用。例如,'industr(?:y|ies) 是比 'industry|industries' 更經(jīng)濟的表達式。
     
    (?=pattern)
     執(zhí)行正向預(yù)測先行搜索的子表達式,該表達式匹配處于匹配 pattern 的字符串的起始點的字符串。它是一個非捕獲匹配,即不能捕獲供以后使用的匹配。例如,'Windows (?=95|98|NT|2000)' 匹配“Windows 2000”中的“Windows”,但不匹配“Windows 3.1”中的“Windows”。預(yù)測先行不占用字符,即發(fā)生匹配后,下一匹配的搜索緊隨上一匹配之后,而不是在組成預(yù)測先行的字符后。
     
    (?!pattern)
     執(zhí)行反向預(yù)測先行搜索的子表達式,該表達式匹配不處于匹配 pattern 的字符串的起始點的搜索字符串。它是一個非捕獲匹配,即不能捕獲供以后使用的匹配。例如,'Windows (?!95|98|NT|2000)' 匹配“Windows 3.1”中的 “Windows”,但不匹配“Windows 2000”中的“Windows”。預(yù)測先行不占用字符,即發(fā)生匹配后,下一匹配的搜索緊隨上一匹配之后,而不是在組成預(yù)測先行的字符后。
     
    x|y
     匹配 x 或 y。例如,'z|food' 匹配“z”或“food”。'(z|f)ood' 匹配“zood”或“food”。
     
    [xyz]
     字符集。匹配包含的任一字符。例如,“[abc]”匹配“plain”中的“a”。
     
    [^xyz]
     反向字符集。匹配未包含的任何字符。例如,“[^abc]”匹配“plain”中的“p”。
     
    [a-z]
     字符范圍。匹配指定范圍內(nèi)的任何字符。例如,“[a-z]”匹配“a”到“z”范圍內(nèi)的任何小寫字母。
     
    [^a-z]
     反向范圍字符。匹配不在指定的范圍內(nèi)的任何字符。例如,“[^a-z]”匹配任何不在“a”到“z”范圍內(nèi)的任何字符。
     
    \b
     匹配一個字邊界,即字與空格間的位置。例如,“er\b”匹配“never”中的“er”,但不匹配“verb”中的“er”。
     
    \B
     非字邊界匹配。“er\B”匹配“verb”中的“er”,但不匹配“never”中的“er”。
     
    \cx
     匹配 x 指示的控制字符。例如,\cM 匹配 Control-M 或回車符。x 的值必須在 A-Z 或 a-z 之間。如果不是這樣,則假定 c 就是“c”字符本身。
     
    \d
     數(shù)字字符匹配。等效于 [0-9]。
     
    \D
     非數(shù)字字符匹配。等效于 [^0-9]。
     
    \f
     換頁符匹配。等效于 \x0c 和 \cL。
     
    \n
     換行符匹配。等效于 \x0a 和 \cJ。
     
    \r
     匹配一個回車符。等效于 \x0d 和 \cM。
     
    \s
     匹配任何空白字符,包括空格、制表符、換頁符等。與 [ \f\n\r\t\v] 等效。
     
    \S
     匹配任何非空白字符。與 [^ \f\n\r\t\v] 等效。
     
    \t
     制表符匹配。與 \x09 和 \cI 等效。
     
    \v
     垂直制表符匹配。與 \x0b 和 \cK 等效。
     
    \w
     匹配任何字類字符,包括下劃線。與“[A-Za-z0-9_]”等效。
     
    \W
     與任何非單詞字符匹配。與“[^A-Za-z0-9_]”等效。
     
    \xn
     匹配 n,此處的 n 是一個十六進制轉(zhuǎn)義碼。十六進制轉(zhuǎn)義碼必須正好是兩位數(shù)長。例如,“\x41”匹配“A”。“\x041”與“\x04”&“1”等效。允許在正則表達式中使用 ASCII 代碼。
     
    \num
     匹配 num,此處的 num 是一個正整數(shù)。到捕獲匹配的反向引用。例如,“(.)\1”匹配兩個連續(xù)的相同字符。
     
    \n
     標識一個八進制轉(zhuǎn)義碼或反向引用。如果 \n 前面至少有 n 個捕獲子表達式,那么 n 是反向引用。否則,如果 n 是八進制數(shù) (0-7),那么 n 是八進制轉(zhuǎn)義碼。
     
    \nm
     標識一個八進制轉(zhuǎn)義碼或反向引用。如果 \nm 前面至少有 nm 個捕獲子表達式,那么 nm 是反向引用。如果 \nm 前面至少有 n 個捕獲,則 n 是反向引用,后面跟有字符 m。如果兩種前面的情況都不存在,則 \nm 匹配八進制值 nm,其中 n 和 m 是八進制數(shù)字 (0-7)。
     
    \nml
     當 n 是八進制數(shù) (0-3),m 和 l 是八進制數(shù) (0-7) 時,匹配八進制轉(zhuǎn)義碼 nml。
     
    \un
     匹配 n,其中 n 是以四位十六進制數(shù)表示的 Unicode 字符。例如,\u00A9 匹配版權(quán)符號 (?)。
     

    posted @ 2007-05-17 10:48 比特鼠 閱讀(7536) | 評論 (0)編輯 收藏

    package com.sunrise.ocs.webservice.unicom.test;

    import java.io.File;
    import java.io.StringWriter;
    import java.util.HashMap;
    import java.util.Iterator;

    import javax.xml.parsers.DocumentBuilderFactory;

    import org.apache.log4j.Logger;
    import org.dom4j.Document;
    import org.dom4j.DocumentHelper;
    import org.dom4j.Element;
    import org.dom4j.XPath;
    import org.dom4j.io.SAXReader;

    import com.sun.org.apache.xml.internal.serialize.OutputFormat;
    import com.sun.org.apache.xml.internal.serialize.XMLSerializer;

    public class TestDom4j {
     private static final Logger log = Logger.getLogger(TestDom4j.class);

     private static long bt;

     public static void main(String[] args) {
      String strXml = "";
      int b = 0;
      String file1 = "xml/CreateUserRequest.xml";
      String file2 = "xml/CancelUserRequest.xml";
      if(b==0){
       bt = System.currentTimeMillis();
       strXml = xmlFile2String(file1);
       if (log.isDebugEnabled()) {
        log.debug("\nxmlFile2String() use time: "
          + (System.currentTimeMillis() - bt) + " millis\n");
       }
      }else{
       bt = System.currentTimeMillis();
       strXml = xmlFile2String2(file1);
       if (log.isDebugEnabled()) {
        log.debug("\nxmlFile2String2() use time: "
          + (System.currentTimeMillis() - bt) + " millis\n");
       }
      }

      if(b==0){
       bt = System.currentTimeMillis();
       findElement4XPath1(strXml);
       if (log.isDebugEnabled()) {
        log.debug("\nfindElement4XPath1() use time: "
          + (System.currentTimeMillis() - bt) + " millis\n");
       }
      }else{
       bt = System.currentTimeMillis();
       findElement4XPath2(strXml);
       if (log.isDebugEnabled()) {
        log.debug("\nfindElement4XPath2() use time: "
          + (System.currentTimeMillis() - bt) + " millis\n");
       } 
       
      }
     }

     public static void findElement4XPath1(String xml) {
      try {
       String str = delNamespace4Pattern(xml);
       Document doc = DocumentHelper.parseText(str);
       Element e = (Element) doc.selectSingleNode("http://CreateUserRequest/RequestMessage/MessageHeader");
       if (e != null) {
        Iterator iter = e.elementIterator();
        while (iter.hasNext()) {
         Element sub = (Element) iter.next();
         log.debug("\n" + sub.getText() + "\n");
        }
       }
       
       /* 讀取屬性的例子
       List childNodes = doc.selectNodes("http://Config/Child/ChildNode");
             for(Object obj:childNodes) {
                 Node childNode = (Node)obj;
                 String name = childNode.valueOf("@name"); //讀取屬性
                 String text = childNode.getText();
             }
             */

       
      } catch (Exception e) {
       e.printStackTrace();
      }
     }
     public static void findElement4XPath2(String xml) {
      try {
       Document doc = DocumentHelper.parseText(xml);
       Element root = doc.getRootElement();
       
       HashMap map = new HashMap();
       map.put("tns", "   XPath x = doc.createXPath("http://tns:CreateUserRequest/tns:RequestMessage/tns:MessageHeader");
       x.setNamespaceURIs(map);
       
       Element e = (Element) x.selectSingleNode(doc);
       if (e != null) {
        Iterator iter = e.elementIterator();
        while (iter.hasNext()) {
         Element sub = (Element) iter.next();
         if (log.isDebugEnabled()) {
          log.debug("\n" + sub.getText() + "\n");
         }
        }
       }
      } catch (Exception e) {
       e.printStackTrace();
      }
     }

     public static Document xml2Document(String xml) {
      try {
       return DocumentHelper.parseText(xml);
      } catch (Exception e) {
       e.printStackTrace();
      }
      return null;
     }

     public static String xmlFile2String(String xmlFile) {
      try {
       return new SAXReader().read(new File(xmlFile)).asXML();
      } catch (Exception e) {
       e.printStackTrace();
      }
      return null;
     }
     
     //讀取xml文件為xml串
     public static String xmlFile2String2(String xmlFile) {
      try {
       org.w3c.dom.Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlFile); 
       OutputFormat format = new OutputFormat(document);
       //format.setEncoding("UTF-8");
       StringWriter stringOut = new StringWriter();
       XMLSerializer serial = new XMLSerializer(stringOut, format);
       serial.asDOMSerializer();
       serial.serialize(document.getDocumentElement());
       return stringOut.toString();
      } catch (Exception e) {
       e.printStackTrace();
      }
      return "";
     }
     
     
     public static String delNamespace4Pattern(String xml){
      String result = "";
      try {
       result = xml.replaceFirst("xmlns([^ ]*)=([^ ]*)http([^>^\"]*)\"", "");
      } catch (Exception e) {
       e.printStackTrace();
      }
      return result;
      
     }

     

    }

    posted @ 2007-05-17 10:46 比特鼠 閱讀(208) | 評論 (0)編輯 收藏

    package com.sunrise.ocs.webservice.unicom.test;

    import java.io.File;
    import java.io.StringReader;
    import java.io.StringWriter;

    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;

    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    import org.w3c.dom.Node;
    import org.xml.sax.InputSource;

    import com.sun.org.apache.xml.internal.serialize.OutputFormat;
    import com.sun.org.apache.xml.internal.serialize.XMLSerializer;

    public class TestDom {
     
     //將xml串轉(zhuǎn)換為document
     public static Document xml2Document(String xml) {
      Document doc = null;
      try {
       DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
       doc = builder.parse(new InputSource(new StringReader(xml)));
      } catch (Exception e) {
       e.printStackTrace();
      }
      return doc;
     }
     
     //將xml文件串轉(zhuǎn)換為document
     public static Document xmlFile2Document(String xmlFile) {
      Document doc = null;
      try {
       DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
       doc = builder.parse(new File(xmlFile));
      } catch (Exception e) {
       e.printStackTrace();
      }
      return doc;
     }
     
     //刪除命名空間: xmlns="..."
     public static String delNamespace(String xml) {
      String result = xml;
      try {
       Document doc = xml2Document(xml);
       Element root = doc.getDocumentElement();
       root.removeAttribute("xmlns");
       result = asXml(doc);
      } catch (Exception e) {
       e.printStackTrace();
      }
      return result;
     }
     
     //將doc轉(zhuǎn)換為xml串
     public static String asXml(Document doc) {
      String strxml = "";
      try {
       OutputFormat format = new OutputFormat(doc);
       // format.setEncoding("UTF-8");
       StringWriter stringOut = new StringWriter();
       XMLSerializer serial = new XMLSerializer(stringOut, format);
       serial.asDOMSerializer();
       serial.serialize(doc.getDocumentElement());
       strxml = stringOut.toString();
      } catch (Exception e) {
       e.printStackTrace();
      }
      return strxml;
     }
     
     //將node轉(zhuǎn)換為xml串
     public static String asXml(Node node, Document doc) {
      String strxml = "";
      try {
       OutputFormat format = new OutputFormat(doc);
       // format.setEncoding("UTF-8");
       StringWriter stringOut = new StringWriter();
       XMLSerializer serial = new XMLSerializer(stringOut, format);
       serial.asDOMSerializer();
       serial.serialize((Element)node);
       strxml = stringOut.toString();
      } catch (Exception e) {
       e.printStackTrace();
      }
      return strxml;
     }
    }

    posted @ 2007-05-17 10:10 比特鼠 閱讀(283) | 評論 (0)編輯 收藏

    vi 是visual edit 的縮寫
    文本編輯器是所有計算機系統(tǒng)中最常用的一種工具。UNIX下的編輯器有ex,sed和vi等,其中,使用最為廣泛的是vi,而vi命令繁多,論壇里好像這方面的總結(jié)不多,以下稍做總結(jié),以資共享!渴望更正和補充!

    進入vi的命令
    vi filename :打開或新建文件,并將光標置于第一行首
    vi +n filename :打開文件,并將光標置于第n行首
    vi + filename :打開文件,并將光標置于最后一行首
    vi +/pattern filename:打開文件,并將光標置于第一個與pattern匹配的串處
    vi -r filename :在上次正用vi編輯時發(fā)生系統(tǒng)崩潰,恢復(fù)filename
    vi filename....filename :打開多個文件,依次進行編輯

    移動光標類命令
    h :光標左移一個字符
    l :光標右移一個字符
    space:光標右移一個字符
    Backspace:光標左移一個字符
    k或Ctrl+p:光標上移一行
    j或Ctrl+n :光標下移一行
    Enter :光標下移一行
    w或W :光標右移一個字至字首
    b或B :光標左移一個字至字首
    e或E :光標右移一個字至字尾
    ) :光標移至句尾
    ( :光標移至句首
    }:光標移至段落開頭
    { :光標移至段落結(jié)尾
    nG:光標移至第n行首
    n+:光標下移n行
    n-:光標上移n行
    n$:光標移至第n行尾
    H :光標移至屏幕頂行
    M :光標移至屏幕中間行
    L :光標移至屏幕最后行
    0:(注意是數(shù)字零)光標移至當前行首
    $:光標移至當前行尾

    屏幕翻滾類命令
    Ctrl+u:向文件首翻半屏
    Ctrl+d:向文件尾翻半屏
    Ctrl+f:向文件尾翻一屏
    Ctrl+b;向文件首翻一屏
    nz:將第n行滾至屏幕頂部,不指定n時將當前行滾至屏幕頂部。

    插入文本類命令
    i :在光標前
    I :在當前行首
    a:光標后
    A:在當前行尾
    o:在當前行之下新開一行
    O:在當前行之上新開一行
    r:替換當前字符
    R:替換當前字符及其后的字符,直至按ESC鍵
    s:從當前光標位置處開始,以輸入的文本替代指定數(shù)目的字符
    S:刪除指定數(shù)目的行,并以所輸入文本代替之
    ncw或nCW:修改指定數(shù)目的字
    nCC:修改指定數(shù)目的行

    刪除命令
    ndw或ndW:刪除光標處開始及其后的n-1個字
    do:刪至行首
    d$:刪至行尾
    ndd:刪除當前行及其后n-1行
    x或X:刪除一個字符,x刪除光標后的,而X刪除光標前的
    Ctrl+u:刪除輸入方式下所輸入的文本

    搜索及替換命令
    /pattern:從光標開始處向文件尾搜索pattern
    ?pattern:從光標開始處向文件首搜索pattern
    n:在同一方向重復(fù)上一次搜索命令
    N:在反方向上重復(fù)上一次搜索命令
    :s/p1/p2/g:將當前行中所有p1均用p2替代
    :n1,n2s/p1/p2/g:將第n1至n2行中所有p1均用p2替代
    :g/p1/s//p2/g:將文件中所有p1均用p2替換

    選項設(shè)置
    all:列出所有選項設(shè)置情況
    term:設(shè)置終端類型
    ignorance:在搜索中忽略大小寫
    list:顯示制表位(Ctrl+I)和行尾標志($)
    number:顯示行號
    report:顯示由面向行的命令修改過的數(shù)目
    terse:顯示簡短的警告信息
    warn:在轉(zhuǎn)到別的文件時若沒保存當前文件則顯示NO write信息
    nomagic:允許在搜索模式中,使用前面不帶“\”的特殊字符
    nowrapscan:禁止vi在搜索到達文件兩端時,又從另一端開始
    mesg:允許vi顯示其他用戶用write寫到自己終端上的信息

    最后行方式命令
    :n1,n2 co n3:將n1行到n2行之間的內(nèi)容拷貝到第n3行下
    :n1,n2 m n3:將n1行到n2行之間的內(nèi)容移至到第n3行下
    :n1,n2 d :將n1行到n2行之間的內(nèi)容刪除
    :w :保存當前文件
    :e filename:打開文件filename進行編輯
    :x:保存當前文件并退出
    :q:退出vi
    :q!:不保存文件并退出vi
    :!command:執(zhí)行shell命令command
    :n1,n2 w!command:將文件中n1行至n2行的內(nèi)容作為command的輸入并執(zhí)行之,若不指定n1,n2,則表示將整個文件內(nèi)容作為command的輸入
    :r!command:將命令command的輸出結(jié)果放到當前行

    寄存器操作
    "?nyy:將當前行及其下n行的內(nèi)容保存到寄存器?中,其中?為一個字母,n為一個數(shù)字
    "?nyw:將當前行及其下n個字保存到寄存器?中,其中?為一個字母,n為一個數(shù)字
    "?nyl:將當前行及其下n個字符保存到寄存器?中,其中?為一個字母,n為一個數(shù)字
    "?p:取出寄存器?中的內(nèi)容并將其放到光標位置處。這里?可以是一個字母,也可以是一個數(shù)字
    ndd:將當前行及其下共n行文本刪除,并將所刪內(nèi)容放到1號刪除寄存器中。


    進入vi
    vi test
    離開vi
    :q! 離開vi,并放棄剛在緩沖區(qū)內(nèi)編輯的內(nèi)容。
       :wq 將緩沖區(qū)內(nèi)的資料寫入磁盤中,并離開vi。
       :ZZ 同wq
    同wq
    :w 將緩沖區(qū)內(nèi)的資料寫入磁盤中,但并不離開vi。
      :q 離開vi,若文件被修改過,則會被要求確認是否放棄修改的內(nèi)容,此指令可與: w 配合使用。
    Vi 的操作模式
    Vi 提供兩種操作模式:
    輸入模式(insert mode)
    指令模式(command mode)
    當使用者進入vi后,既處于指令模式下,此刻鍵入任何字元皆被視為指令。

    輸入模式:a(append) 游標之后加入資料。
    A 該行之末加入資料
    i (insert) 游標之前加入資料
    I 該行之首加入資料
    o (open) 新增一行與該行之下供輸入資料
    O 新增一行與該行之上供輸入資料

    指令模式:B      移至該行第一個字符,若光標在該行第一字符則光標移至上一行第一字符。
       b    由游標所在位置之前一個字串的第一個字元
         cc 刪除整行,修改整行的內(nèi)容。
         D      以行為單位,刪除游標在內(nèi)后面的所有字符。
    db 刪除該行光標前字符
         dd 刪除該行
         de 刪除自光標開始后面的字符
         d加字符   刪除光標所在位置至字符之間的單
         E      移至該行最后字符,若光標在該行最后字符則光標移至下一行最后字符
     e      由游標所在位置至該字串的最后一個字元
         G 移至該檔案的最后一行 
         h 向前移一個字元
    j 向下移一個字元
    k 向上移一個字元
    0 移至該行之首
    M 移至視窗的中間那行
    L 移至視窗的最后一行
         l 向后移一個字符
    0 由游標所在位置該行的第一個字元
    nG 移至該檔案的第n行
    n+ 自游標所在位置向后移n行至該行的第一字符
    n- 自游標所在位置向前移n行至該行的第一字符
    R 進入取代狀態(tài),直到《ESC》為止
    s 刪除游標所在字元,并進入取代模式直到《ESC》
    S 刪除游標所在之該行資料,并進入輸入模式直到《ESC》
    w 由游標所在位置之下一個字串的第一個字元
    x 刪除游標所在該字元。
    X 刪除游標所在之前一字元。
    r 用接于此指令之后的字元取代(replace)游標所在字元
    yy yank整行,使游標所在該行復(fù)制到記憶體緩沖區(qū)
    顯示該行之行號、檔案名稱、檔案中最末之行號、游標所在行號占
    總行號之百分比
    $ 由游標所在位置至該行的最后一個字元。
    ) 由游標所在位置至下一個句子的第一個字元。
    ( 由游標所在位置至該句子的第一個字元。
    {  由游標所在位置至該段落的最后一個字元。
    } 由游標所在位置至該段落的第一個字元

    yank和delete可將指定的資料復(fù)制到記憶體緩沖區(qū),而藉有put指令可將緩沖區(qū)內(nèi)的資料復(fù)制到熒幕上
    例如:搬移一行 :在該行執(zhí)行dd
    游標移至目的地
    執(zhí)行p
    復(fù)制一行 :在該行執(zhí)行yy
    游標移至目的地
    執(zhí)行p
    視窗移動:
    視窗往下卷一頁
    視窗往上卷一頁
    視窗往下卷半頁
    視窗往上卷半頁
    視窗往下卷一行
    視窗往上卷一行
    刪除、復(fù)制及修改指令介紹:
    d(delete)、c(change)和y(yank)這一類的指令在vi 中的指令格式為:
    operation+scope=command
    (運算子)(范圍)
    運算子:
    d 刪除指令。刪除資料,但會將刪除資料復(fù)制到記憶體緩沖區(qū)。
    y 將資料(字組、行列、句子或段落)復(fù)制到緩沖區(qū)。
    p 放置(put)指令,與d和y配合使用。可將最后delete或yank的資料放置于游標所在位置之行列下。
    c 修改(change)指令,類似delete于insert的組合。刪除一個字組、句子等資料,并插入新鍵入的




    posted @ 2007-05-15 11:33 比特鼠 閱讀(247) | 評論 (0)編輯 收藏

    1、使用JdbcTemplate的execute()方法執(zhí)行SQL語句

    代碼

    2、如果是UPDATE或INSERT,可以用update()方法。
    代碼

    3、帶參數(shù)的更新
    代碼

    代碼

    4、使用JdbcTemplate進行查詢時,使用queryForXXX()等方法
    代碼

    代碼

    代碼

    代碼

    JdbcTemplate將我們使用的JDBC的流程封裝起來,包括了異常的捕捉、SQL的執(zhí)行、查詢結(jié)果的轉(zhuǎn)換等等。spring大量使用Template Method模式來封裝固定流程的動作,XXXTemplate等類別都是基于這種方式的實現(xiàn)。
    除了大量使用Template Method來封裝一些底層的操作細節(jié),spring也大量使用callback方式類回調(diào)相關(guān)類別的方法以提供JDBC相關(guān)類別的功能,使傳統(tǒng)的JDBC的使用者也能清楚了解spring所提供的相關(guān)封裝類別方法的使用。

    JDBC的PreparedStatement

    代碼

    代碼

    代碼

    在getUser(id)里面使用UserRowMapper

    代碼

    網(wǎng)上收集
    org.springframework.jdbc.core.PreparedStatementCreator 返回預(yù)編譯SQL 不能于Object[]一起用

    代碼

    1.增刪改
    org.springframework.jdbc.core.JdbcTemplate 類(必須指定數(shù)據(jù)源dataSource)
    代碼


    代碼

    org.springframework.jdbc.core.PreparedStatementSetter 接口 處理預(yù)編譯SQL
    代碼

    2.查詢JdbcTemplate.query(String,[Object[]/PreparedStatementSetter],RowMapper/RowCallbackHandler)
    org.springframework.jdbc.core.RowMapper 記錄映射接口 處理結(jié)果集
    代碼

    org.springframework.jdbc.core.RowCallbackHandler 記錄回調(diào)管理器接口 處理結(jié)果集
    代碼

    posted @ 2007-04-11 18:48 比特鼠 閱讀(516) | 評論 (0)編輯 收藏

    制作可執(zhí)行的JAR文件包及jar命令詳解


    常常在網(wǎng)上看到有人詢問:如何把 java 程序編譯成 .exe 文件。通常回答只有兩種,一種是制作一個可執(zhí)行的 JAR 文件包,然后就可以像.chm 文檔一樣雙擊運行了;而另一種是使用 JET 來進行 編譯。但是 JET 是要用錢買的,而且據(jù)說 JET 也不是能把所有的 Java 程序都編譯成執(zhí)行文件,性能也要打些折扣。所以,使用制作可執(zhí)行 JAR 文件包的方法就是最佳選擇了,何況它還能保持 Java 的跨平臺特性。 

    下面就來看看什么是 JAR 文件包吧: 

    1. JAR 文件包 

    JAR 文件就是 Java Archive File,顧名思意,它的應(yīng)用是與 Java 息息相關(guān)的,是 Java 的一種文檔格式。JAR 文件非常類似 ZIP 文件——準確的說,它就是 ZIP 文件,所以叫它文件包。JAR 文件與 ZIP 文件唯一的區(qū)別就是在 JAR 文件的內(nèi)容中,包含了一個 META-INF/MANIFEST.MF 文件,這個文件是在生成 JAR 文件的時候自動創(chuàng)建的。舉個例子,如果我們具有如下目錄結(jié)構(gòu)的一些文件: 

      == 

      `-- test 

        `-- Test.class 

    把它壓縮成 ZIP 文件 test.zip,則這個 ZIP 文件的內(nèi)部目錄結(jié)構(gòu)為: 

      test.zip 

      `-- test 

        `-- Test.class 

    如果我們使用 JDK 的 jar 命令把它打成 JAR 文件包 test.jar,則這個 JAR 文件的內(nèi)部目錄結(jié)構(gòu)為: 

      test.jar 

      |-- META-INF 

      |  `-- MANIFEST.MF 

      `-- test 

        `--Test.class 

    2. 創(chuàng)建可執(zhí)行的 JAR 文件包 

    制作一個可執(zhí)行的 JAR 文件包來發(fā)布你的程序是 JAR 文件包最典型的用法。 

    Java 程序是由若干個 .class 文件組成的。這些 .class 文件必須根據(jù)它們所屬的包不同而分級分目錄存放;運行前需要把所有用到的包的根目錄指定給 CLASSPATH 環(huán)境變量或者 java 命令的 -cp 參數(shù);運行時還要到控制臺下去使用 java 命令來運行,如果需要直接雙擊運行必須寫 Windows 的批處理文件 (.bat) 或者 Linux 的 Shell 程序。因此,許多人說,Java 是一種方便開發(fā)者苦了用戶的程序設(shè)計語言。 

    其實不然,如果開發(fā)者能夠制作一個可執(zhí)行的 JAR 文件包交給用戶,那么用戶使用起來就方便了。在 Windows 下安裝 JRE (Java Runtime Environment) 的時候,安裝文件會將 .jar 文件映射給 javaw.exe 打開。那么,對于一個可執(zhí)行的 JAR 文件包,用戶只需要雙擊它就可以運行程序了,和閱讀 .chm 文檔一樣方便 (.chm 文檔默認是由 hh.exe 打開的)。那么,現(xiàn)在的關(guān)鍵,就是如何來創(chuàng)建這個可執(zhí)行的 JAR 文件包。 

    創(chuàng)建可執(zhí)行的 JAR 文件包,需要使用帶 cvfm 參數(shù)的 jar 命令,同樣以上述 test 目錄為例,命令如下: 

    jar cvfm test.jar manifest.mf test 

    這里 test.jar 和 manifest.mf 兩個文件,分別是對應(yīng)的參數(shù) f 和 m,其重頭戲在 manifest.mf。因為要創(chuàng)建可執(zhí)行的 JAR 文件包,光靠指定一個 manifest.mf 文件是不夠的,因為 MANIFEST 是 JAR 文件包的特征,可執(zhí)行的 JAR 文件包和不可執(zhí)行的 JAR 文件包都包含 MANIFEST。關(guān)鍵在于可執(zhí)行 JAR 文件包的 MANIFEST,其內(nèi)容包含了 Main-Class 一項。這在 MANIFEST 中書寫格式如下: 

    Main-Class: 可執(zhí)行主類全名(包含包名) 

    例如,假設(shè)上例中的 Test.class 是屬于 test 包的,而且是可執(zhí)行的類 (定義了 public static void main(String[]) 方法),那么這個 manifest.mf 可以編輯如下: 

    Main-Class: test.Test <回車>; 

    這個 manifest.mf 可以放在任何位置,也可以是其它的文件名,只需要有 Main-Class: test.Test 一行,且該行以一個回車符結(jié)束即可。創(chuàng)建了 manifest.mf 文件之后,我們的目錄結(jié)構(gòu)變?yōu)椋?nbsp;

      == 

      |-- test 

      |  `-- Test.class 

      `-- manifest.mf 

    這時候,需要到 test 目錄的上級目錄中去使用 jar 命令來創(chuàng)建 JAR 文件包。也就是在目錄樹中使用“==”表示的那個目錄中,使用如下命令: 

    jar cvfm test.jar manifest.mf test 

    之后在“==”目錄中創(chuàng)建了 test.jar,這個 test.jar 就是執(zhí)行的 JAR 文件包。運行時只需要使用 java -jar test.jar 命令即可。 

    需要注意的是,創(chuàng)建的 JAR 文件包中需要包含完整的、與 Java 程序的包結(jié)構(gòu)對應(yīng)的目錄結(jié)構(gòu),就像上例一樣。而 Main-Class 指定的類,也必須是完整的、包含包路徑的類名,如上例的 test.Test;而且在沒有打成 JAR 文件包之前可以使用 java <類名>; 來運行這個類,即在上例中 java test.Test 是可以正確運行的 (當然要在 CLASSPATH 正確的情況下)。 

    3. jar 命令詳解 

    jar 是隨 JDK 安裝的,在 JDK 安裝目錄下的 bin 目錄中,Windows 下文件名為 jar.exe,Linux 下文件名為 jar。它的運行需要用到 JDK 安裝目錄下 lib 目錄中的 tools.jar 文件。不過我們除了安裝 JDK 什么也不需要做,因為 SUN 已經(jīng)幫我們做好了。我們甚至不需要將 tools.jar 放到 CLASSPATH 中。 

    使用不帶任何的 jar 命令我們可以看到 jar 命令的用法如下: 

    jar {ctxu}[vfm0M] [jar-文件] [manifest-文件] [-C 目錄] 文件名 ... 

    其中 {ctxu} 是 jar 命令的子命令,每次 jar 命令只能包含 ctxu 中的一個,它們分別表示: 

    -c 創(chuàng)建新的 JAR 文件包 

    -t 列出 JAR 文件包的內(nèi)容列表 

    -x 展開 JAR 文件包的指定文件或者所有文件 

    -u 更新已存在的 JAR 文件包 (添加文件到 JAR 文件包中) 

    [vfm0M] 中的選項可以任選,也可以不選,它們是 jar 命令的選項參數(shù) 

    -v 生成詳細報告并打印到標準輸出 

    -f 指定 JAR 文件名,通常這個參數(shù)是必須的 

    -m 指定需要包含的 MANIFEST 清單文件 

    -0 只存儲,不壓縮,這樣產(chǎn)生的 JAR 文件包會比不用該參數(shù)產(chǎn)生的體積大,但速度更快 

    -M 不產(chǎn)生所有項的清單(MANIFEST〕文件,此參數(shù)會忽略 -m 參數(shù) 

    [jar-文件] 即需要生成、查看、更新或者解開的 JAR 文件包,它是 -f 參數(shù)的附屬參數(shù) 

    [manifest-文件] 即 MANIFEST 清單文件,它是 -m 參數(shù)的附屬參數(shù) 

    [-C 目錄] 表示轉(zhuǎn)到指定目錄下去執(zhí)行這個 jar 命令的操作。它相當于先使用 cd 命令轉(zhuǎn)該目錄下再執(zhí)行不帶 -C 參數(shù)的 jar 命令,它只能在創(chuàng)建和更新 JAR 文件包的時候可用。   

    文件名 ... 指定一個文件/目錄列表,這些文件/目錄就是要添加到 JAR 文件包中的文件/目錄。如果指定了目錄,那么 jar 命令打包的時候會自動把該目錄中的所有文件和子目錄打入包中。 

    下面舉一些例子來說明 jar 命令的用法: 

    1) jar cf test.jar test 

    該命令沒有執(zhí)行過程的顯示,執(zhí)行結(jié)果是在當前目錄生成了 test.jar 文件。如果當前目錄已經(jīng)存在 test.jar,那么該文件將被覆蓋。 

    2) jar cvf test.jar test 

    該命令與上例中的結(jié)果相同,但是由于 v 參數(shù)的作用,顯示出了打包過程,如下: 

    標明清單(manifest) 

    增加:test/(讀入= 0) (寫出= 0)(存儲了 0%) 

    增加:test/Test.class(讀入= 7) (寫出= 6)(壓縮了 14%) 

    3) jar cvfM test.jar test 

    該命令與 2) 結(jié)果類似,但在生成的 test.jar 中沒有包含 META-INF/MANIFEST 文件,打包過程的信息也略有差別: 

    增加:test/(讀入= 0) (寫出= 0)(存儲了 0%) 

    增加:test/Test.class(讀入= 7) (寫出= 6)(壓縮了 14%) 

    4) jar cvfm test.jar manifest.mf test 

    運行結(jié)果與 2) 相似,顯示信息也相同,只是生成 JAR 包中的 META-INF/MANIFEST 內(nèi)容不同,是包含了 manifest.mf 的內(nèi)容 

    5) jar tf test.jar 

    在 test.jar 已經(jīng)存在的情況下,可以查看 test.jar 中的內(nèi)容,如對于 2) 和 3) 生成的 test.jar 分別應(yīng)該此命令,結(jié)果如下; 

    對于 2) 

    META-INF/ 

    META-INF/MANIFEST.MF 

    test/ 

    test/Test.class 

    對于 3) 

    test/ 

    test/Test.class 

    6) jar tvf test.jar 

    除顯示 5) 中顯示的內(nèi)容外,還包括包內(nèi)文件的詳細信息,如: 

    0 Wed Jun 19 15:39:06 GMT 2002 META-INF/ 

    86 Wed Jun 19 15:39:06 GMT 2002 META-INF/MANIFEST.MF 

    0 Wed Jun 19 15:33:04 GMT 2002 test/ 

    7 Wed Jun 19 15:33:04 GMT 2002 test/Test.class 

    7) jar xf test.jar 

    解開 test.jar 到當前目錄,不顯示任何信息,對于 2) 生成的 test.jar,解開后的目錄結(jié)構(gòu)如下: 

      == 

      |-- META-INF 

      |  `-- MANIFEST 

      `-- test 

        `--Test.class 

    8) jar xvf test.jar 

    運行結(jié)果與 7) 相同,對于解壓過程有詳細信息顯示,如: 

    創(chuàng)建:META-INF/ 

    展開:META-INF/MANIFEST.MF 

    創(chuàng)建:test/ 

    展開:test/Test.class 

    9) jar uf test.jar manifest.mf 

    在 test.jar 中添加了文件 manifest.mf,此使用 jar tf 來查看 test.jar 可以發(fā)現(xiàn) test.jar 中比原來多了一個 manifest。這里順便提一下,如果使用 -m 參數(shù)并指定 manifest.mf 文件,那么 manifest.mf 是作為清單文件 MANIFEST 來使用的,它的內(nèi)容會被添加到 MANIFEST 中;但是,如果作為一般文件添加到 JAR 文件包中,它跟一般文件無異。 

    10) jar uvf test.jar manifest.mf 

    與 9) 結(jié)果相同,同時有詳細信息顯示,如: 

    增加:manifest.mf(讀入= 17) (寫出= 19)(壓縮了 -11%) 

    4. 關(guān)于 JAR 文件包的一些技巧 

    1) 使用 unzip 來解壓 JAR 文件 

    在介紹 JAR 文件的時候就已經(jīng)說過了,JAR 文件實際上就是 ZIP 文件,所以可以使用常見的一些解壓 ZIP 文件的工具來解壓 JAR 文件,如 Windows 下的 WinZip、WinRAR 等和 Linux 下的 unzip 等。使用 WinZip 和 WinRAR 等來解壓是因為它們解壓比較直觀,方便。而使用 unzip,則是因為它解壓時可以使用 -d 參數(shù)指定目標目錄。 

    在解壓一個 JAR 文件的時候是不能使用 jar 的 -C 參數(shù)來指定解壓的目標的,因為 -C 參數(shù)只在創(chuàng)建或者更新包的時候可用。那么需要將文件解壓到某個指定目錄下的時候就需要先將這具 JAR 文件拷貝到目標目錄下,再進行解壓,比較麻煩。如果使用 unzip,就不需要這么麻煩了,只需要指定一個 -d 參數(shù)即可。如: 

    unzip test.jar -d dest/ 

    2) 使用 WinZip 或者 WinRAR 等工具創(chuàng)建 JAR 文件 

    上面提到 JAR 文件就是包含了 META-INF/MANIFEST 的 ZIP 文件,所以,只需要使用 WinZip、WinRAR 等工具創(chuàng)建所需要 ZIP 壓縮包,再往這個 ZIP 壓縮包中添加一個包含 MANIFEST 文件的 META-INF 目錄即可。對于使用 jar 命令的 -m 參數(shù)指定清單文件的情況,只需要將這個 MANIFEST 按需要修改即可。 

    3) 使用 jar 命令創(chuàng)建 ZIP 文件 

    有些 Linux 下提供了 unzip 命令,但沒有 zip 命令,所以需要可以對 ZIP 文件進行解壓,即不能創(chuàng)建 ZIP 文件。如要創(chuàng)建一個 ZIP 文件,使用帶 -M 參數(shù)的 jar 命令即可,因為 -M 參數(shù)表示制作 JAR 包的時候不添加 MANIFEST 清單,那么只需要在指定目標 JAR 文件的地方將 .jar 擴展名改為 .zip 擴展名,創(chuàng)建的就是一個不折不扣的 ZIP 文件了,如將上一節(jié)的第 3) 個例子略作改動: 

    jar cvfM test.zip test
    posted @ 2007-04-11 18:19 比特鼠 閱讀(327) | 評論 (1)編輯 收藏

     

    import java.io.File;

    public class Test {
        
    public static void main(String[] args) {
             System.out.println(
    "1:"+Thread.currentThread().getContextClassLoader().getResource(""));     

              System.out.println(
    "2:"+Test.class.getClassLoader().getResource(""));        

              System.out.println(
    "3:"+ClassLoader.getSystemResource(""));        
              System.out.println(
    "4:"+Test.class.getResource(""));        
              System.out.println(
    "5:"+Test.class.getResource("/")); //Class文件所在路徑  
              System.out.println("6:"+new File("").getAbsolutePath());        
              System.out.println(
    "7:"+System.getProperty("user.dir"));  
              
              String s 
    = ClassLoader.getSystemResource("").getPath();
              System.out.println(s.substring(
    1));
              System.out.println(s.substring(
    1).substring(0, s.lastIndexOf("/classes")));

        }

    }
    posted @ 2007-04-04 16:49 比特鼠 閱讀(170) | 評論 (0)編輯 收藏

    dom4j 直接往Element中加入符合格式的xml串!

    下面的代碼直接往root元素插入符合格式的xml串:

    String strXml = "<aaa><bbb></bbb><ccc></ccc></aaa>";
    Document doc = DocumentHelper.createDocument();
    Element??root = doc.getRootElement();
    root.add(DocumentHelper.parseText(strXml).getRootElement());
    posted @ 2007-03-27 16:20 比特鼠 閱讀(485) | 評論 (1)編輯 收藏

    ?public long algo(){
    ????int a = 0;
    ????String b = null;
    ????long st = System.currentTimeMillis();
    ????for (int i = 0; i < 2000000; i++){
    ??????b = Integer.toString(a);
    ????}
    ????long et = System.currentTimeMillis();
    ????return (et - st);
    ??}
    posted @ 2007-03-27 15:11 比特鼠 閱讀(1423) | 評論 (1)編輯 收藏

    玩轉(zhuǎn) XPath 和缺省命名空間(Default Namespaces)

    原文出自:http://www.edankert.com/defaultnamespaces.html
    翻譯文出自:http://wakan.blog.51cto.com/blog/59583/7220



    諸如“為什么用 XPath 的表達式進行查詢,卻沒有返回所期望的結(jié)果?”的問題通常都與命名空間(NameSpace)有關(guān),而且絕大多數(shù)是與缺省命名空間(Default Namespace)有關(guān)。本文試圖解釋這個問題并針對三種流行的 XPath 實現(xiàn)給出解決方法:Jaxen、JAXP XPPathFactory 以及 XSLT。
    內(nèi)容列表
    問題描述
    “前綴-命名空間”映射
    Jaxen 和 Dom4J
    Jaxen 和 XOM
    Jaxen 和 JDOM
    JAXP XPathFactory
    XSLT
    結(jié)束語
    資源


    問題描述
    看下述 XML:
    <catalog>
    ? <cd>
    ??? <artist>Sufjan Stevens</artist>
    ??? <title>Illinois</title>
    ??? <src>http://www.sufjan.com/</src>
    ? </cd>
    ? <cd>
    ??? <artist>Stoat</artist>
    ??? <title>Future come and get me</title>
    ??? <src>http://www.stoatmusic.com/</src>
    ? </cd>
    ? <cd>
    ??? <artist>The White Stripes</artist>
    ??? <title>Get behind me satan</title>
    ??? <src>http://www.whitestripes.com/</src>
    ? </cd>
    </catalog>

    ??? 你可以使用“//cd”來得到?jīng)]有在任何命名空間中定義的“cd”節(jié)點。?


    ??? 現(xiàn)在讓我們來改造這個 XML,讓它的所有元素都屬于 'http://www.edankert.com/examples/' 命名空間中。
    ?
    ??? 為了避免在每個不同的元素前都要加個前綴,我們在根元素上定義通常所說的缺省命名空間。改造后的 XML 如下:
    ?
    <catalog xmlns="
    http://www.edankert.com/examples/ ">
    ? <cd>
    ??? <artist>Sufjan Stevens</artist>
    ??? <title>Illinois</title>
    ??? <src>http://www.sufjan.com/</src>
    ? </cd>
    ? <cd>
    ??? <artist>Stoat</artist>
    ??? <title>Future come and get me</title>
    ??? <src>http://www.stoatmusic.com/</src>
    ? </cd>
    ? <cd>
    ??? <artist>The White Stripes</artist>
    ??? <title>Get behind me satan</title>
    ??? <src>http://www.whitestripes.com/</src>
    ? </cd>
    </catalog>

    ??? 當我們使用與上文相同的 XPath “//cd”,將得不到任何元素。這是因為指定的 XPath 返回的是所有不屬于任何命名空間的“cd”節(jié)點,而本例中,所有的“cd”元素都屬于缺省的命名空間“http://www.edankert.com/examples/”。


    “前綴-命名空間”映射
    ??? 為了取出命名空間“http://www.edankert.com/examples/”中的所有“cd”元素,我們需要對 XPath 表達式做一些額外的工作。
    ?
    ??? 為了解決這個問題,XPath 規(guī)范允許我們使用 QName 來指定元素或者屬性。QName 可以是元素的直接名稱(形如“element”),或者包含一個前綴(形如“pre:element”)。這個前綴需要映射到一個命名空間的 URI 上。例如,如果把“pre”前綴映射到“http://www.edankert.com/test”上,則通過“pre:element”可以查找出屬于命名空間“http://www.edankert.com/test”的所有 “element”元素。
    ?
    ??? 在本例中,我們把“edx”映射到“'http://www.edankert.com/examples/”命名空間上。通過 XPath“//edx:cd”就可以查找出屬于“'http://www.edankert.com/examples/”命名空間的所有“cd”元素。?
    ?
    ??? XPath 處理器允許設(shè)置“前綴-命名空間”的映射,但是,如何去映射,卻要依賴于具體的實現(xiàn)。下文舉例說明 Jaxen (JDOM/dom4j/XOM)、JAXP 以及 XSLT 中是如何進行“前綴-命名空間”的映射的。

    Jaxen 和 Dom4J
    ??? 下述代碼從文件系統(tǒng)讀入一個 XML 文件到 org.dom4j.Document 對象中,并且在 Document 中查找屬于“http://www.edankert.com/examples/”命名空間的所有“cd”元素。
    ?
    try {
    ? SAXReader reader = new SAXReader();
    ? Document document = reader.read( "file:catalog.xml");
    ?
    ? HashMap map = new HashMap();
    ? map.put( "edx", "
    http://www.edankert.com/examples/ ");
    ?
    ? XPath xpath = new Dom4jXPath( "http://edx:cd");
    ? xpath.setNamespaceContext( new SimpleNamespaceContext( map));
    ?
    ? List nodes = xpath.selectNodes( document);
    ?
    ? ...
    ?
    } catch ( JaxenException e) { // An error occurred parsing or executing the XPath ... } catch ( DocumentException e) {
    ? // the document is not well-formed.
    ? ...
    }
    ??? 第一步,創(chuàng)建一個 SAXReader,用來從文件系統(tǒng)中讀取“catalog.xml”并創(chuàng)建一個特定于 Dom4j 的 Document 對象。

    ??? 第二步,對于所有 Jaxen 實現(xiàn)都一樣,就是創(chuàng)建一個 HashMap 對象,用于保存“前綴-命名空間的 URI”的映射。
    ?
    ??? 為了能通過 Dom4j 使用 Jaxen 的 XPath 功能,需要創(chuàng)建一個與 Dom4j 相關(guān)的 XPath 對象:Dom4jXPath。創(chuàng)建方法是把 XPath 的表達式(即“//edx:cd”)傳給 Dom4jXPath 的構(gòu)造方法。
    ?
    ??? 現(xiàn)在,我們已經(jīng)創(chuàng)建了 XPath 對象,接下來可以把“前綴-命名空間”的映射表傳遞給 XPath 引擎:把這個 HashMap 映射表用 SimpleNamespaceContext 包裝起來。SimpleNamespaceContext 是 Jaxen 的 NamespaceContext 接口的默認實現(xiàn)類。
    ?
    ??? 最后一步就是調(diào)用 XPath 對象的 selectNodes() 方法進行查找。并把完整的 Dom4j? Document 對象作為參數(shù)傳遞進去。實際上,Document 中的任何結(jié)點都可以作為參數(shù)。

    Jaxen 和 XOM
    ??? XOM 是基于簡單的 Java DOM APIs 之上的最新工具,它的設(shè)計初衷是提供簡單和易學易用的接口。
    ?
    try {
    ? Builder builder = new Builder();
    ? Document document = builder.build( "file:catalog.xml");
    ?
    ? HashMap map = new HashMap();
    ? map.put( "edx", "
    http://www.edankert.com/examples/ ");
    ?
    ? XPath xpath = new XOMXPath( "http://edx:cd");
    ? xpath.setNamespaceContext( new SimpleNamespaceContext( map));
    ?
    ? List nodes = xpath.selectNodes( document);
    ?
    ? ...
    ?
    } catch ( JaxenException e) { // An error occurred parsing or executing the XPath ... } catch ( IOException e) {
    ? // An error occurred opening the document
    ? ...
    } catch ( ParsingException e) {
    ? // An error occurred parsing the document
    ? ...
    }

    ?
    ??? 我們需要創(chuàng)建一個 Builder 對象,從文件系統(tǒng)中讀取“catalog.xml”文件,并創(chuàng)建出與 XOM 相關(guān)的 Document 對象。
    ?
    ??? 下一步創(chuàng)建出包含了“前綴-命名空間”映射關(guān)系的 HashMap 對象。
    ?
    ??? 我們需要創(chuàng)建一個特定于 XOM 的 XPath 對象:XOMXPath。創(chuàng)建方法是把 XPath 表達式傳遞給構(gòu)造方法,然后就可以通過 XOM 使用 Jaxen 的 XPath 功能了。
    ?
    ??? 創(chuàng)建完 XPath 對象后,同樣,我們把“前綴-命名空間”的映射表用 SimpleNamespaceContext 對象封裝后,傳遞給 XPath 引擎。
    ?
    ??? 最后調(diào)用 XPath 對象的“selectNodes()”方法進行查找,把 XOM Document 對象作為本方法的參數(shù)。
    Jaxen 和 JDOM
    ??? JDOM 是第一個提供簡單的 XML 訪問 API 的工具。
    ?
    try {
    ? SAXBuilder builder = new SAXBuilder();
    ? Document document = builder.build( "file:catalog.xml");
    ?
    ? HashMap map = new HashMap();
    ? map.put( "edx", "
    http://www.edankert.com/examples/ ");
    ?
    ? XPath xpath = new JDOMXPath( "http://edx:cd");
    ? xpath.setNamespaceContext( new SimpleNamespaceContext( map));
    ?
    ? List nodes = xpath.selectNodes( document);
    ?
    ? ...
    ?
    } catch ( JaxenException e) { // An error occurred parsing or executing the XPath ... } catch ( IOException e) {
    ? // An error occurred opening the document
    ? ...
    } catch ( JDOMException e) {
    ? // An error occurred parsing the document
    ? ...
    }

    ?
    ??? 首先,通過 SAXBuilder 創(chuàng)建了一個特定于 JDom 的 Document 對象。
    ?
    ??? 接著創(chuàng)建一個特定于 JDOM 的 XPath 對象:JDOMXPath。
    ?
    ??? 然后,把“前綴-命名空間”的映射表(HashMap)用 SimpleNamespaceContext 對象封裝起來,傳遞給 XPath 引擎。
    ?
    ??? 最后調(diào)用 XPath 對象的“selectNodes()”方法來進行查找,并把 JDOM 的 Document 對象作為本方法的輸入?yún)?shù)。
    JAXP XPathFactory
    ??? 從 1.3 版起, JAXP 還提供了一種在 XML Object Models 上進行查詢的通用機制。
    ?
    try {
    ?DocumentBuilderFactory domFactory =DocumentBuilderFactory.newInstance();
    ? domFactory.setNamespaceAware( true);
    ?
    ?DocumentBuilder builder = domFactory.newDocumentBuilder();Document document = builder.parse( new InputSource( "file:catalog.xml"));
    ?
    ?XPathFactory factory =XPathFactory.newInstance();
    ?XPath xpath = factory.newXPath();
    ? xpath.setNamespaceContext( new NamespaceContext() {
    ??? public String getNamespaceURI(String prefix) {
    ????? if ( prefix.equals( "edx")) {
    ??????? return "
    http://www.edankert.com/examples/ ";
    ????? } else if ...
    ??????? ...
    ????? }
    ?????
    ????? return XPathConstants.NULL_NS_URI;
    ??? }
    ?
    ??? public String getPrefix(String namespaceURI) {
    ????? if ( namespaceURI.equals( "
    http://www.edankert.com/examples/ ")) {
    ??????? return "edx";
    ????? } else if ...
    ??????? ...
    ????? }?
    ???
    ????? return null;
    ??? }
    ?
    ??? public Iterator getPrefixes(String namespaceURI) {
    ???? ArrayList list = new ArrayList();
    ???
    ????? if ( namespaceURI.equals( "
    http://www.edankert.com/examples/ ")) {
    ??????? list.add( "edx");
    ????? } else if ...
    ??????? ...
    ????? }
    ???
    ????? return list.iterator();
    ??? }
    ? });
    ?
    ?Object nodes = xpath.evaluate( "http://edx:cd", document.getDocumentElement(),
    ??????????????????????????????? XPathConstants.NODESET);
    ?
    ? ...
    ?
    } catch (ParserConfigurationException e) {
    ? ...
    } catch (XPathExpressionException e) {
    ? ...
    } catch (SAXException e) {
    ? ...
    } catch (IOException e) {
    ? ...
    }

    ??? 首先用 JAXP 的 DocumentBuilderFactory 創(chuàng)建一個org.w3c.dom.Document 對象,確保啟用了 namespace 處理功能。
    ?
    ??? 現(xiàn)在可以通過 XPathFactory 來創(chuàng)建 XPath 對象,并通過 XPath 對象對文檔進行查詢。
    ?
    ??? 為了創(chuàng)建“前綴-命名空間”映射并傳遞給 XPath 引擎,我們需要實現(xiàn) NamespaceContext 接口,該接口目前還沒有默認實現(xiàn)類。這就意味著要實現(xiàn) getNamespaceURI、getPrefix 和getPrefixes 方法,并確保這些方法能返回正確的值,包括“xmlns”和“xml”前綴所對應(yīng)的命名空間的 URI 值。
    ?
    ??? 把我們自己實現(xiàn)的 NamespaceContext 對象傳遞給 XPath 引擎后,就可以通過 evaluate 方法來查詢 XPath 表達式所對應(yīng)的元素:使用上文中提到的 XPath 表達式,并使用 Document 的根節(jié)點作為輸入入?yún)?shù),并接收一個 NodeList 對象作為返回結(jié)果。
    XSLT
    ??? XPath 設(shè)計的初衷是用于 XSLT。這也許能解釋“為什么在 XSLT 中定義命名空間的前綴是一件很平常的事”(也許因為 XSLT 也是一個 XML 名詞的緣故吧)。
    ?
    <xsl:stylesheet version="1.1" xmlns:xsl="
    http://www.w3.org/1999/XSL/Transform ">
    ? <xsl:template match="http://edx:cd" xmlns:edx="
    http://www.edankert.com/examples/ ">
    ??? <xsl:apply-templates/>
    ? </xsl:template>
    </xsl:stylesheet>
    ?
    ??? 只需要使用 XML 本身的機制,簡單地為 edx 前綴賦予一個命名空間的 URI 值。
    ?
    ??? 通過與我們的 XPath 表達式“//edx:cd”相匹配的 xsl:template,能得到與上文其他例子相同的輸出結(jié)果。

    結(jié)束語
    ??? 為了在(缺省)命名空間上使用 XPath 表達式,我們需要指定一個“前綴-命名空間”映射。正如我們所看到的,具體使用什么樣的前綴名稱,是無關(guān)緊要的。
    ?
    ??? 同樣的方法,也可以用于查詢那些用其他前綴修飾的元素。這意味著上面的例子對下述 XML 也有效。下述 XML 沒有使用缺省命名空間,而是使用了 examples 作命名空間的前綴:
    ?
    <examples:catalog xmlns:examples="
    http://www.edankert.com/examples/ ">
    ? <examples:cd>
    ??? <examples:artist>Sufjan Stevens</examples:artist>
    ??? <examples:title>Illinois</examples:title>
    ??? <examples:src>http://www.sufjan.com/</examples:src>
    ? </examples:cd>
    ? <examples:cd>
    ??? <examples:artist>Stoat</examples:artist>
    ??? <examples:title>Future come and get me</examples:title>
    ??? <examples:src>http://www.stoatmusic.com/</examples:src>
    ? </examples:cd>
    ? <examples:cd>
    ??? <examples:artist>The White Stripes</examples:artist>
    ??? <examples:title>Get behind me satan</examples:title>
    ??? <examples:src>http://www.whitestripes.com/</examples:src>
    ? </examples:cd>
    </examples:catalog>

    ?
    ??? 使用“//edx:cd”作為 XPath 表達式,使用與前文例子相同的“前綴-命名空間”映射,在這個 XML 上同樣能查詢出屬于“http://www.edankert.com/examples/”命名空間的所有“cd”元素。
    資源
    Extensible Markup Language (XML) 1.0 (Third Edition)
    http://www.w3.org/TR/REC-xml/
    Namespaces in XML
    http://www.w3.org/TR/REC-xml-names/
    XML Path Language (XPath) Version 1.0
    http://www.w3.org/TR/xpath
    XSL Transformations (XSLT) Version 1.0
    http://www.w3.org/TR/xslt
    dom4j
    http://www.dom4j.org/
    XOM
    http://www.xom.nu/
    JDOM
    http://www.jdom.org/
    Jaxen
    http://www.jaxen.org/
    Java 5.0
    http://java.sun.com/j2se/1.5.0/

    posted @ 2007-03-21 10:13 比特鼠 閱讀(1722) | 評論 (1)編輯 收藏

    spring事務(wù)探索

    原文出處:
    http://www.javaeye.com/topic/11190

    spring自建事務(wù)管理模塊。而且這個事務(wù)管理是一個抽象設(shè)計,可以應(yīng)用到很多場合,包括普通的DataSource,jta,jms和hibernate上。

    要正確使用spring的事務(wù),首先需要了解spring在事務(wù)設(shè)計上的一些概念
    統(tǒng)觀spring事務(wù),圍繞著兩個核心PlatformTransactionManager和TransactionStatus

    PlatformTransactionManager直譯過來就是平臺相關(guān)事務(wù),這里的平臺指的是“事務(wù)源”,包括剛才我說的DataSource,jta等等。這些無一不是一個事務(wù)源。廣義的說,凡是可以完成事務(wù)性操作的對象,都可以設(shè)計出相對應(yīng)的PlatformTransactionManager,只要這個事務(wù)源支持commit,rollback和getTransaction語意。

    查看spring代碼,可以發(fā)現(xiàn)這些manager實現(xiàn)事務(wù),就是調(diào)用事務(wù)源的事務(wù)操作方法

    比如

    HibernateTransactionManager

    代碼

    ?

    1. protected ? void ?doCommit(DefaultTransactionStatus?status)?{ ??
    2. ????????HibernateTransactionObject?txObject?=?(HibernateTransactionObject)?status.getTransaction(); ??
    3. ???????? if ?(status.isDebug())?{ ??
    4. ????????????logger.debug( "Committing?Hibernate?transaction?on?session?[" ?+ ??
    5. ????????????????????txObject.getSessionHolder().getSession()?+? "]" ); ??
    6. ????????} ??
    7. ???????? try ?{ ??
    8. ????????????txObject.getSessionHolder().getTransaction().commit(); ??
    9. ????????} ??
    10. ... ??
    11. ??
    12. ????}??

    jdbc 的DataSourceTransactionManager

    代碼

    ?

    1. protected ? void ?doCommit(DefaultTransactionStatus?status)?{ ??
    2. ????????DataSourceTransactionObject?txObject?=?(DataSourceTransactionObject)?status.getTransaction(); ??
    3. ????????Connection?con?=?txObject.getConnectionHolder().getConnection(); ??
    4. ???????? if ?(status.isDebug())?{ ??
    5. ????????????logger.debug( "Committing?JDBC?transaction?on?connection?[" ?+?con?+? "]" ); ??
    6. ????????} ??
    7. ???????? try ?{ ??
    8. ????????????con.commit(); ??
    9. ????????} ??
    10. ????????... ??
    11. ????}??

    那么PlatformTransactionManager以什么依據(jù)處理事務(wù)呢?
    是TransactionStatus
    查看api發(fā)現(xiàn)這個接口有三個方法
    isNewTransaction() ,isRollbackOnly(),setRollbackOnly()
    PlatformTransactionManager就是根據(jù)前兩個方法決定是否要創(chuàng)建一個新事務(wù),是要遞交還是回滾。至于第三個方法是改變事務(wù)當前狀態(tài)的,很多地方都要用到,偏偏PlatformTransactionManager自身好像不怎么用,畢竟事務(wù)狀態(tài)的改變是由程序員代碼決定的,不需要一個manager多管閑事。

    總結(jié)上面所說的,spring的事務(wù)由PlatformTransactionManager管理,manager最后調(diào)用事務(wù)源的方法來實現(xiàn)一個事務(wù)過程。而manager通過TransactionStatus 來決定如何實現(xiàn)。

    接下去說spring事務(wù)中的TransactionTemplate和TransactionInterceptor

    TransactionTemplate其實和spring中其他的template的作用類似,起到化簡代碼的作用,不要被它那么長的名字嚇倒了,事實上這個template并不是什么非常核心的對象。如果比較學究派的,可以去看看template設(shè)計模式,在此就不再對此贅述了。
    為什么要有TransactionTemplate?先來看看如果沒有TransactionTemplate,我們的代碼該怎么寫

    先來看看spring reference中的一段代碼

    代碼

    ?

    1. DefaultTransactionDefinition?def?=? new ?DefaultTransactionDefinition() ??
    2. def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); ??
    3. ??
    4. TransactionStatus?status?=?transactionManager.getTransaction(def); ??
    5. ??
    6. try ?{ ??
    7. ???? //?execute?your?business?logic?here ??
    8. }? catch ?(MyException?ex)?{ ??
    9. ????transactionManager.rollback(status); ??
    10. ???? throw ?ex; ??
    11. } ??
    12. transactionManager.commit(status);??


    這是直接使用transactionManager的例子,可以看到真正執(zhí)行business logic 的地方是在try當中那段,前后的代碼都是為了完成事務(wù)管理的。如果每個business logic都要寫上那么一段,我肯定是瘋了。我們翻出TransactionTemplate的代碼看看他怎么化簡了我們的代碼

    代碼

    ?

    1. public ?Object?execute(TransactionCallback?action)? throws ?TransactionException?{ ??
    2. ????????TransactionStatus?status?=? this .transactionManager.getTransaction( this ); ??
    3. ????????Object?result?=? null ; ??
    4. ???????? try ?{ ??
    5. ????????????result?=?action.doInTransaction(status); ??
    6. ????????} ??
    7. ???????? catch ?(RuntimeException?ex)?{ ??
    8. ???????????? //?transactional?code?threw?application?exception?->?rollback ??
    9. ????????????rollbackOnException(status,?ex); ??
    10. ???????????? throw ?ex; ??
    11. ????????} ??
    12. ???????? catch ?(Error?err)?{ ??
    13. ???????????? //?transactional?code?threw?error?->?rollback ??
    14. ????????????rollbackOnException(status,?err); ??
    15. ???????????? throw ?err; ??
    16. ????????} ??
    17. ???????? this .transactionManager.commit(status); ??
    18. ???????? return ?result; ??
    19. ????}??

    同上面的代碼如出一轍,前后是事務(wù)處理代碼,當中那段result = action.doInTransaction(status);是我們的應(yīng)用代碼。至于action是什么,全看各位的需要了。但是有一點要主要,如果利用TransactionTemplate,那么他不管你扔出什么異常都會回滾事務(wù),但是回滾的是哪個事務(wù)呢?繼續(xù)挖代碼

    代碼

    ?

    1. private ? void ?rollbackOnException(TransactionStatus?status,?Throwable?ex)? throws ?TransactionException?{ ??
    2. ???????? if ?(logger.isDebugEnabled())?{ ??
    3. ????????????logger.debug( "Initiating?transaction?rollback?on?application?exception" ,?ex); ??
    4. ????????} ??
    5. ???????? try ?{ ??
    6. ???????????? this .transactionManager.rollback(status); ??
    7. ????????} ??
    8. ???????? catch ?(RuntimeException?ex2)?{ ??
    9. ????????????logger.error( "Application?exception?overridden?by?rollback?exception" ,?ex); ??
    10. ???????????? throw ?ex2; ??
    11. ????????} ??
    12. ???????? catch ?(Error?err)?{ ??
    13. ????????????logger.error( "Application?exception?overridden?by?rollback?error" ,?ex); ??
    14. ???????????? throw ?err; ??
    15. ????????} ??
    16. ????}??


    真相大白,是對template所持有的某個transactionManager進行回滾。所以如果你的應(yīng)用代碼用的是事務(wù)源a的一些資源,比如到服務(wù)器a的一個datasource,但是你的transactionManager管理的是另一些資源,比如服務(wù)器b的一個datasource,代碼鐵定不會正常運行

    特別是在一些多事務(wù)源的程序里,這點千萬不能搞錯。如果多個事務(wù)源之間要完成全局事務(wù),還是老老實實用分布式事務(wù)管理服務(wù)吧(jta)

    那么TransactionInterceptor是干什么的?這個是spring 的聲明式事務(wù)的支持方式。因為用TransactionTemplate要硬編碼,而且調(diào)整事務(wù)策略很麻煩(不是說不能調(diào)。舉個例子原來程序拋出異常A需要回滾,現(xiàn)在不需要要,我就可以把a catch吃掉。這時候template就不會回滾了。但是每次調(diào)整都要重寫編碼。)而用TransactionInterceptor就可以將這些調(diào)整寫在配置中。我們再來挖TransactionInterceptor的代碼

    代碼

    ?

    1. public ?Object?invoke(MethodInvocation?invocation)? throws ?Throwable?{ ??
    2. ???????? //?Work?out?the?target?class:?may?be?null. ??
    3. ???????? //?The?TransactionAttributeSource?should?be?passed?the?target?class ??
    4. ???????? //?as?well?as?the?method,?which?may?be?from?an?interface ??
    5. ????????Class?targetClass?=?(invocation.getThis()?!=? null )???invocation.getThis().getClass()?:? null ; ??
    6. ???????? ??
    7. ???????? //?Create?transaction?if?necessary ??
    8. ????????TransactionInfo?txInfo?=?createTransactionIfNecessary(invocation.getMethod(),?targetClass); ??
    9. ??
    10. ????????Object?retVal?=? null ; ??
    11. ???????? try ?{ ??
    12. ???????????? //?This?is?an?around?advice. ??
    13. ???????????? //?Invoke?the?next?interceptor?in?the?chain. ??
    14. ???????????? //?This?will?normally?result?in?a?target?object?being?invoked. ??
    15. ????????????retVal?=?invocation.proceed(); ??
    16. ????????} ??
    17. ???????? catch ?(Throwable?ex)?{ ??
    18. ???????????? //?target?invocation?exception ??
    19. ????????????doCloseTransactionAfterThrowing(txInfo,?ex); ??
    20. ???????????? throw ?ex; ??
    21. ????????} ??
    22. ???????? finally ?{ ??
    23. ????????????doFinally(txInfo); ??
    24. ????????} ??
    25. ????????doCommitTransactionAfterReturning(txInfo); ??
    26. ??
    27. ???????? return ?retVal; ??
    28. ????}??


    萬變不離其宗。

    所以使用spring的事務(wù)管理需要作這些事
    1,設(shè)置好事務(wù)源,比如DataSource,hibernate的session。如果有多個事務(wù)源要考慮他們之間是否有全局事務(wù),如果有,老老實實用jta,否則就需要自己寫一個manager了
    2,設(shè)置manager,根據(jù)你的事務(wù)源選擇對應(yīng)的PlatformTransactionManager
    3,選擇實現(xiàn)事物的方式,用template還是interceptor。用template代碼直觀點,但是template所管轄的manager和你應(yīng)用代碼所用的事務(wù)源要一致。如果用interceptor千萬注意,一定要調(diào)用interceptor那個bean,而不是原始的那個target。在壇子上我已經(jīng)看到至少有兩個朋友說spring事物不起作用,從配置和代碼上看都正確,這時要好好查查,調(diào)用的bean是哪一個。
    4,這個是設(shè)計問題了,推薦事務(wù)處于一個較高層次,比如service上的某個函數(shù),而底層的dao可以不考慮事務(wù),否則可能會出現(xiàn)事務(wù)嵌套,增加程序復(fù)雜度。

    posted @ 2007-03-05 14:45 比特鼠 閱讀(244) | 評論 (0)編輯 收藏

    主站蜘蛛池模板: 精品一区二区三区无码免费视频 | 亚洲av日韩av无码av| 免费无码又爽又黄又刺激网站| 一级中文字幕免费乱码专区| 日韩在线播放全免费| 在线观看免费亚洲| 久久亚洲日韩看片无码| 亚洲色大18成人网站WWW在线播放 亚洲色大成WWW亚洲女子 | 免费一区二区三区在线视频| a级精品九九九大片免费看| 免费看少妇作爱视频| 1区1区3区4区产品亚洲| 亚洲乱色伦图片区小说| 99久在线国内在线播放免费观看| 波多野结衣久久高清免费| 亚洲电影在线播放| 久久免费观看国产精品| a级亚洲片精品久久久久久久| 91亚洲自偷在线观看国产馆| baoyu777永久免费视频| 国产精品亚洲高清一区二区| 国产AV无码专区亚洲AV麻豆丫| 国产一区二区三区免费观看在线| 黄页免费的网站勿入免费直接进入| 免费一级毛片一级毛片aa| 亚洲AV男人的天堂在线观看| 成人免费的性色视频| 亚洲国产成人久久综合碰碰动漫3d| WWW国产亚洲精品久久麻豆| 成人免费一级毛片在线播放视频| 久久精品国产亚洲精品| 狠狠综合亚洲综合亚洲色| 在线jlzzjlzz免费播放| 97久久国产亚洲精品超碰热| 精品熟女少妇aⅴ免费久久| 99久久综合国产精品免费| 亚洲欧洲日产国产最新| 久久精品无码专区免费青青| 亚洲国产精品丝袜在线观看| 亚洲va中文字幕| 免费成人激情视频|