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

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

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

    posts - 22, comments - 32, trackbacks - 0, articles - 73
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    2009年4月1日

    最近在公司有點時間所以深入研究了下數據庫索引btree/b+tree數據結構和原理,由此牽引出了好多問題,請看如下帶著問題研究。

    1:為什么 btree/b+tree 數據結構適合數據庫索引,它到底是怎么樣一個原理和結構?

    btree/b+tree 數據結構:

    在之前的文章中我們介紹過AVL樹,紅黑樹,它們都屬于二叉樹,即每個節點最多只能擁有2個子節點,而B-tree(B樹)的每個節點可以擁有2個以上的子節點,所以我們簡單概括一下:B-tree就是一顆多路平衡查找樹,它廣泛應用于數據庫索引和文件系統中。

    首先我們介紹一下一顆 m 階B-tree的特性,那么這個 m 階是怎么定義的呢?這里我們以一個節點能擁有的最大子節點數來表示這顆樹的階數。舉個例子,如果一個節點最多有 n 個key,那么這個節點最多就會有 n+1 個子節點,這棵樹就叫做 n+1(m=n+1)階樹。一顆 m 階B-tree包括以下5條特性:

    1. 每個節點最多有 m 個子節點
    2. 除根節點和葉子節點,其它每個節點至少有 [m/2] (向上取整的意思)個子節點
    3. 若根節點不是葉子節點,則其至少有2個子節點
    4. 所有NULL節點到根節點的高度都一樣
    5. 除根節點外,其它節點都包含 n 個key,其中 [m/2] -1 <= n <= m-1

    這些特性可能看著不太好理解,下面我們會介紹B-tree的插入,在插入節點的過程中我們就會慢慢理解這些特性了。B-tree的插入比較簡單,就是一個節點至下而上的分裂過程。下面我們具體以一顆4階樹來展示B-tree的插入過程。

    首先我們 插入 200,300,400,沒有什么問題,直接插入就好。

    | 200 | 300 | 400 |

    現在我們接著插入500,這個時候我們發現有點問題,根據定義及特性1我們知道一顆4階B-tree的每個節點最多只能有3個key,插入500后這個節點就有4個key了。

    | 200 | 300 | 400 | 500 |

    這個時候我們就需要分裂,將中間的key上移到父節點,左邊的作為左節點,右邊的作為右節點,如下圖所示:

    這個時候我們是不是就明白特性3了,如果根節點不是葉子節點,那么它肯定發生了分裂,所以至少會有2個子節點。同樣我們接著插入600,700,800,900插入過程如下圖所示:

    現在根節點也已經滿了,如果我們繼續插入910,920,會怎樣呢?根節點就會繼續分裂,樹繼續向上生長。看下圖:

    通過整個的插入過程我們也會發現,B-tree和二叉樹的一個顯著的區別就是,B-tree是從下往上生長,而二叉樹是從上往下生長的。現在我們想想特性2和特性5是為什么?首先我們知道子節點的個數是等于key的數目+1,然后一個節點達到m個key后就會分裂,所以分裂后的節點最少能得到 m/2 - 1個key 。為啥還要減一呢?因為還要拿一個作為父節點。所以這個節點最少回擁有 m/2 - 1 + 1 = m/2 個子節點。同樣得到特性5,因為最少有m/2個子節點,所以最少就含有m/2-1個key,m 階樹,每個節點存到了m個key就會分裂,所以最多就有 m-1個key。

    根據以上特性我們能推出一棵含有N個總關鍵字數的m階的B-tree樹的最大高度h的值,

    樹的高度h: 1, 2, 3 , 4 ,.......... , h

    節點個數s: 1, 2, 2*(m/2), 2*(m/2)(m/2), ........ ,2*(m/2)的h-2次方

    s = 1 + 2(1 - (m/2)^{h-1} )/(1- (m/2))

    N = 1 + s * ((m/2) - 1) = 2 * ((m/2)^{h-1} ) - 1

    h = log┌m/2┐((N+1)/2 )+1

    2:為什么btree/b+tree 為常用數據庫索引結構?

    上文說過,紅黑樹等數據結構也可以用來實現索引,但是文件系統及數據庫系統普遍采用B-/+Tree作為索引結構,這一節將結合計算機組成原理相關知識討論B-/+Tree作為索引的理論基礎。

    一般來說,索引本身也很大,不可能全部存儲在內存中,因此索引往往以索引文件的形式存儲的磁盤上。這樣的話,索引查找過程中就要產生磁盤I/O消耗,相對于內存存取,I/O存取的消耗要高幾個數量級,所以評價一個數據結構作為索引的優劣最重要的指標就是在查找過程中磁盤I/O操作次數的漸進復雜度。換句話說,索引的結構組織要盡量減少查找過程中磁盤I/O的存取次數。下面先介紹內存和磁盤存取原理,然后再結合這些原理分析B-/+Tree作為索引的效率。

    主存存取原理

    目前計算機使用的主存基本都是隨機讀寫存儲器(RAM),現代RAM的結構和存取原理比較復雜,這里本文拋卻具體差別,抽象出一個十分簡單的存取模型來說明RAM的工作原理。

    圖5

    從抽象角度看,主存是一系列的存儲單元組成的矩陣,每個存儲單元存儲固定大小的數據。每個存儲單元有唯一的地址,現代主存的編址規則比較復雜,這里將其簡化成一個二維地址:通過一個行地址和一個列地址可以唯一定位到一個存儲單元。圖5展示了一個4 x 4的主存模型。

    主存的存取過程如下:

    當系統需要讀取主存時,則將地址信號放到地址總線上傳給主存,主存讀到地址信號后,解析信號并定位到指定存儲單元,然后將此存儲單元數據放到數據總線上,供其它部件讀取。

    寫主存的過程類似,系統將要寫入單元地址和數據分別放在地址總線和數據總線上,主存讀取兩個總線的內容,做相應的寫操作。

    這里可以看出,主存存取的時間僅與存取次數呈線性關系,因為不存在機械操作,兩次存取的數據的“距離”不會對時間有任何影響,例如,先取A0再取A1和先取A0再取D3的時間消耗是一樣的。

    磁盤存取原理

    上文說過,索引一般以文件形式存儲在磁盤上,索引檢索需要磁盤I/O操作。與主存不同,磁盤I/O存在機械運動耗費,因此磁盤I/O的時間消耗是巨大的。

    圖6是磁盤的整體結構示意圖。

    圖6

    一個磁盤由大小相同且同軸的圓形盤片組成,磁盤可以轉動(各個磁盤必須同步轉動)。在磁盤的一側有磁頭支架,磁頭支架固定了一組磁頭,每個磁頭負責存取一個磁盤的內容。磁頭不能轉動,但是可以沿磁盤半徑方向運動(實際是斜切向運動),每個磁頭同一時刻也必須是同軸的,即從正上方向下看,所有磁頭任何時候都是重疊的(不過目前已經有多磁頭獨立技術,可不受此限制)。

    圖7是磁盤結構的示意圖。

    圖7

    盤片被劃分成一系列同心環,圓心是盤片中心,每個同心環叫做一個磁道,所有半徑相同的磁道組成一個柱面。磁道被沿半徑線劃分成一個個小的段,每個段叫做一個扇區,每個扇區是磁盤的最小存儲單元。為了簡單起見,我們下面假設磁盤只有一個盤片和一個磁頭。

    當需要從磁盤讀取數據時,系統會將數據邏輯地址傳給磁盤,磁盤的控制電路按照尋址邏輯將邏輯地址翻譯成物理地址,即確定要讀的數據在哪個磁道,哪個扇區。為了讀取這個扇區的數據,需要將磁頭放到這個扇區上方,為了實現這一點,磁頭需要移動對準相應磁道,這個過程叫做尋道,所耗費時間叫做尋道時間,然后磁盤旋轉將目標扇區旋轉到磁頭下,這個過程耗費的時間叫做旋轉時間。

    局部性原理與磁盤預讀

    由于存儲介質的特性,磁盤本身存取就比主存慢很多,再加上機械運動耗費,磁盤的存取速度往往是主存的幾百分分之一,因此為了提高效率,要盡量減少磁盤I/O。為了達到這個目的,磁盤往往不是嚴格按需讀取,而是每次都會預讀,即使只需要一個字節,磁盤也會從這個位置開始,順序向后讀取一定長度的數據放入內存。這樣做的理論依據是計算機科學中著名的局部性原理:

    當一個數據被用到時,其附近的數據也通常會馬上被使用。

    程序運行期間所需要的數據通常比較集中。

    由于磁盤順序讀取的效率很高(不需要尋道時間,只需很少的旋轉時間),因此對于具有局部性的程序來說,預讀可以提高I/O效率。

    預讀的長度一般為頁(page)的整倍數。頁是計算機管理存儲器的邏輯塊,硬件及操作系統往往將主存和磁盤存儲區分割為連續的大小相等的塊,每個存儲塊稱為一頁(在許多操作系統中,頁得大小通常為4k),主存和磁盤以頁為單位交換數據。當程序要讀取的數據不在主存中時,會觸發一個缺頁異常,此時系統會向磁盤發出讀盤信號,磁盤會找到數據的起始位置并向后連續讀取一頁或幾頁載入內存中,然后異常返回,程序繼續運行。

    B-/+Tree索引的性能分析

    到這里終于可以分析B-/+Tree索引的性能了。

    上文說過一般使用磁盤I/O次數評價索引結構的優劣。先從B-Tree分析,根據B-Tree的定義,可知檢索一次最多需要訪問h個節點。數據庫系統的設計者巧妙利用了磁盤預讀原理,將一個節點的大小設為等于一個頁,這樣每個節點只需要一次I/O就可以完全載入。為了達到這個目的,在實際實現B- Tree還需要使用如下技巧:

    每次新建節點時,直接申請一個頁的空間,這樣就保證一個節點物理上也存儲在一個頁里,加之計算機存儲分配都是按頁對齊的,就實現了一個node只需一次I/O。

    B-Tree中一次檢索最多需要h-1次I/O(根節點常駐內存),漸進復雜度為O(h)=O(logdN)。一般實際應用中,出度d是非常大的數字,通常超過100,因此h非常小(通常不超過3)。

    綜上所述,用B-Tree作為索引結構效率是非常高的。

    而紅黑樹這種結構,h明顯要深的多。由于邏輯上很近的節點(父子)物理上可能很遠,無法利用局部性,所以紅黑樹的I/O漸進復雜度也為O(h),效率明顯比B-Tree差很多。

    上文還說過,B+Tree更適合外存索引,原因和內節點出度d有關。從上面分析可以看到,d越大索引的性能越好,而出度的上限取決于節點內key和data的大小:

    dmax = floor(pagesize / (keysize + datasize + pointsize))  (pagesize – dmax >= pointsize)

    dmax = floor(pagesize / (keysize + datasize + pointsize)) - 1  (pagesize – dmax < pointsize)

    floor表示向下取整。由于B+Tree內節點去掉了data域,因此可以擁有更大的出度,擁有更好的性能。

    這一章從理論角度討論了與索引相關的數據結構與算法問題,下一章將討論B+Tree是如何具體實現為MySQL中索引,同時將結合MyISAM和InnDB存儲引擎介紹非聚集索引和聚集索引兩種不同的索引實現形式。



    posted @ 2018-01-25 13:44 為自己代言 閱讀(3821) | 評論 (0)編輯 收藏

    同事遇到問題是一個java web 工程,依賴了一個jar包,但是jar包中也有自己一套配置文件(例spring 配置文件,資源文件等),這樣如果讓web工程中的war 包去加載jar 中的配置文件和資源文件呢?
    我當時也有一個思想誤區,以為web中加載不到jar中的文件,但是經過一番研究,終于明白了,按J2EE規范中web-inf/lib目錄下是web工程的classpath 目錄,容器會自動去掃描這個目錄下所有的配置文件和jar加載到容器中,即:像jar中有自己一套配置文件,war 中又要依賴jar包,這樣只需要把這些jar包打成war時候放到web-inf/lib下即可。
    注意:1:jar包和war包中配置文件和一些資源文件不能重名。
            
             2:要在war包中的spring 配置文件中引入jar包中的配置文件。



    posted @ 2015-04-24 20:42 為自己代言 閱讀(6933) | 評論 (0)編輯 收藏

    1、不同的tomcat的啟動文件startup.sh 中要指定各自的CATALINA_HOME和CATALINA_BASE這兩個環境變量。

    2、不同的tomcat啟動和關閉監聽不同的端口

    很多人喜歡把CATALINA_HOME和CATALINA_BASE配置到系統環境變量中去,我們不這么做,我們要做的只是把JDK及CLASSPATH配置到環境變量中去即可,因為這個可以通用。
    CATALINA_HOME和CATALINA_BASE的區別。簡單的說,CATALINA_HOME是Tomcat的安裝目 錄,CATALINA_BASE是Tomcat的工作目錄。如果我們想要運行Tomcat的 多個實例,但是不想安裝多個Tomcat軟件副本。那么我們可以配置多個工作 目錄,每個運行實例獨占一個工作目錄,但是共享同一個安裝目錄

    下面講具體的配置方法。

    找到Tomcat的startup.sh文件,打開進行編輯。

    在文件的開始位置,可以在一大堆注釋的后面,加入
    export CATALINA_BASE=/usr/ratest/apache-tomcat-7.0.16
    export CATALINA_HOME=/usr/ratest/apache-tomcat-7.0.16

    /usr/ratest/apache-tomcat-7.0.16這個就是tomcat的安裝文件夾位置,不同的tomcat指定相應的文件夾即可。

    注意,這兩句話一定要在exec “$PRGDIR”/”$EXECUTABLE” start “$@”這句話的前面,我們放在文件的開始位置了,所以,就可以不考慮了。

    然后就是要修改shutdown.sh文件,同樣在頭部加入上面的兩行即可,也要在exec “$PRGDIR”/”$EXECUTABLE” stop “$@”的前面。

    好了,解決了第一個問題,下面說第二個問題的解決方法。

    找到并打開server.xml文件,里面有諸如8080,8009,8443等等端口配置,統一給這些數字加上100,或者1000或者其他什么數字,只要是不跟其他Tomcat或者當前linux上其他服務的端口重復即可。

    現在進入Tomcat的bin文件夾,運行./startup.sh看看是不是可以啟動多個了。

    posted @ 2014-03-28 19:58 為自己代言 閱讀(464) | 評論 (0)編輯 收藏

    1,設置跟路徑時,三種方式

    在Tomcat默認安裝后,tomcat的主目錄是webapps/root目錄,所以如果想改變tomcat的主目錄的話可以如下所做,所以
    第一種方法是:
    打開C:/Tomcat/conf/server.xml,在<host></host>之間
    加入代碼:<Context docBase="d:/Tomcat 5.5/webapps/medi" path="" debug="0" reloadable="true"/>
    這樣重新啟動tomcat,我們的主目錄就被設置為dolphin這個項目了。

    第二種方法是:
    將tomcat安裝目錄下的ROOT下的所有文件全部刪除,然后將工程的解壓后的文件全部拷進去。

    第三種方法是:
    Tomcat5.0以下版本在d:/Tomcat/conf/Catalina/localhost目錄下會自動生成了一個ROOT.Xml,
    但是5.0以上版本不再生成此文件,所以可以新建個ROOT.xml,在里面加入如下代碼:
    <?Xml version='1.0' encoding='utf-8'?>
    <Context crossContext="true" docBase="d:/Tomcat 5.5/webapps/medi" path="" reloadable="true">
    </Context>

    2,注意
    此時即然配置了 默認訪問目錄,則不要再tomcat 部署工程了,
    比如 在 conf\Catalina\localhost 增加配置文件 指定的工程路徑 此文件要去掉, 否則會重復加載工程。

    posted @ 2013-11-06 18:44 為自己代言 閱讀(693) | 評論 (0)編輯 收藏

    很多tomcat進程退出(或者進程假死),都是由于頻繁的拋出OutOfMemeoryError導致的。

    為了讓tomcat退出前或者發生OutOfMemeoryError時自動dump堆棧信息,方便事后排查問題,我們可以做如下操作:

    1、 在tomcat啟動參數中加入兩個參數 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/export/home/tomcat/domains/server2/oom.hprof

    2、 重啟tomcat

    參數說明
    (1)-XX:+HeapDumpOnOutOfMemoryError 表示當JVM發生OOM時,自動生成DUMP文件。
    (2)-XX:HeapDumpPath=存儲文件/目錄 表示生成DUMP文件的路徑

    posted @ 2013-10-30 13:51 為自己代言 閱讀(6208) | 評論 (2)編輯 收藏

    想從JAVA轉到obj-c,看了些基礎的東西,感覺很奇怪,可能不太習慣,在網上看到一個不錯文章有助理解obj-c的一些核心機制。

    Objective-C——消息、Category和Protocol

    2012-06-22 20:13 by 池建強, 2627 閱讀, 11 評論, 收藏, 編輯

    面向對象永遠是個可以吐槽的話題,從開始提出到推崇備至,到充滿質疑,一路走來讓人唏噓不已。面向對象的思想可謂歷史悠久,20世紀70年代的Smalltalk可以說是面向對象語言的經典,直到今天我們依然將這門語言視為面向對象語言的基礎。
    面向對象是大部分編程語言的基本特性,像 C++、Java、Objective-C這樣的靜態語言,Ruby、Python這樣的動態語言都是面向對象的語言。但是如何編寫面向對象的程序卻一直是困擾人們的話題,即使是Smalltalk,也有人認為這是一個有缺陷的面向對象的語言實現。
     
    我在2010年翻譯過的一篇InfoQ的文章,《面向對象編程──走錯了路》中提到,面向對象編程的三個原則是:基于消息傳遞機制,對象分離和多態。文章中還舉了Erlang例子,認為Erlang具備了這些原則,“所以可能是唯一的面向對象語言”。除了之前提到的三個特征,單繼承和動態類型也被引用為面向對象語言的“絕對需求”。基于這些考慮,文章指出,Smalltalk在實現對象思想時的“錯誤”──例如,只關注狀態和行為,在類和基于映像的語言里缺乏良好的并發模型和消息機制。
     
    這篇文章中的核心就是,面向對象思想中除了對象的狀態、行為,還應該關注其并發機制、消息機制,后者更為重要。這一點事實上是我在接觸了Objective-C之后才有了更深入的體會。
     
    Ojbective-C的語法設計主要基于Smalltalk,除了提供傳統的面向對象編程特性之外,還增加了很多類似動態語言Ruby、Python才具有的特性,例如動態類型、動態加載、動態綁定等等,同時強化了消息傳遞機制和表意(Intention Revealing Interface)接口的概念。
     
    —消息—
    消息傳遞模型(Message Passing)是Objective-C語言的核心機制。在Objective-C中,沒有方法調用這種說法,只有消息傳遞。在C++或Java中調用某個類的方法,在Objective-C中是給該類發送一個消息。在C++或Java里,類與類的行為方法之間的關系非常緊密,一個方法必定屬于一個類,且于編譯時就已經綁定在一起,所以你不可能調用一個類里沒有的方法。而在Objective-C中就比較簡單了,類和消息之間是松耦合的,方法調用只是向某個類發送一個消息,該類可以在運行時再確定怎么處理接受到的消息。也就是說,一個類不保證一定會響應接收到的消息,如果收到了一個無法處理的消息,那么程序就是簡單報一個錯。甚至你可以向一個值為nil的空對象發送消息,系統都不會出錯或宕掉。這種設計本身也比較符合軟件的隱喻。
     
    在表意接口(Intention Revealing Interface)方面,Objective-C也是設計的比較出色的語言。面向對象語言的特性之一就是通過API把實現封裝起來,為上層建筑提供服務。但是需要注意的一點就是,你封裝的API最好能夠讓調用者看到接口描述就知道怎么使用。如果為了使用一個API必須要去研究它的實現,那么就失去了封裝的意義。Objective-C通過顯式的API描述,讓開發者不自覺的寫出滿足表意接口的API,比如下圖中的API描述。

     
    上圖中描述了一個傳統意義的實例方法,但和Java或C++不同的是,其方法關鍵字由多個字符串組成,在這個例子是insertObject和atIndex,(id)anObject和 (NSUInterger)index分別表示參數類型和參數名稱。整個方法看上去就像一個英語句子,我們可以很容易的知道,這個方法就是在索引為 index處插入一個對象。如果你是從其他語言轉到Objective-C,那么開始的時候會感覺這種寫法有些繁復,但是一旦理解并習慣了你會感受到其巨大的好處,這種寫法會強制你寫出優美易讀的代碼和API,而且有了XCode強大的提示功能,再長的方法也是一蹴而就。
     
    下面我們來說說多態和繼承。
     與Java一樣,Objective-C一樣不支持多重繼承,但是通過類別(Category)和協議(Protocol)可以很好的實現代碼復用和擴展。
     
    —Category—
    首先我們來談談Category。
     
    Objective-C提供了一種與眾不同的方式——Catagory,可以動態的為已經存在的類添加新的行為。這樣可以保證類的原始設計規模較小,功能增加時再逐步擴展。使用Category 對類進行擴展時,不需要訪問其源代碼,也不需要創建子類。Category使用簡單的方式,實現了類的相關方法的模塊化,把不同的類方法分配到不同的分類文件中。
     
    實現起來很簡單,我們舉例說明。
    SomeClass.h
    @interface SomeClass : NSObject{
    }
    -(void) print;
    @end 
     
    這是類SomeClass的聲明文件,其中包含一個實例方法print。如果我們想在不修改原始類、不增加子類的情況下,為該類增加一個hello的方法,只需要簡單的定義兩個文件 SomeClass+Hello.h和SomeClass+Hello.m,在聲明文件和實現文件中用“()”把Category的名稱括起來即可。聲明文件代碼如下:
     
    #import "SomeClass.h"
     
    @interface SomeClass (Hello)
    -(void)hello;
    @end
    實現文件代碼如下
    #import "SomeClass+Hello.h"
    @implementationSomeClass (Hello)
    -(void)hello{
        NSLog (@"name:%@ ", @"Jacky");
    }
    @end 
    其中Hello是Category的名稱,如果你用XCode創建Category,那么需要填寫的內容包括名稱和要擴展的類的名稱。這里還有一個約定成俗的習慣,將聲明文件和實現文件名稱統一采用“原類名+Category”的方式命名。
    調用也非常簡單,毫無壓力,如下:
    首先引入Category的聲明文件,然后正常調用即可。
    #import "SomeClass+Hello.h"
     
    SomeClass * sc =[[SomeClass alloc] init];
    [sc hello] 
    執行結果是:
    nameJacky 
     
    Category的使用場景:
    1、當你在定義類的時候,在某些情況下(例如需求變更),你可能想要為其中的某個或幾個類中添加方法。
    2、一個類中包含了許多不同的方法需要實現,而這些方法需要不同團隊的成員實現
    3、當你在使用基礎類庫中的類時,你可能希望這些類實現一些你需要的方法。
     
    遇到以上這些需求,Category可以幫助你解決問題。當然,使用Category也有些問題需要注意,
    1、Category可以訪問原始類的實例變量,但不能添加變量,如果想添加變量,可以考慮通過繼承創建子類。
    2、Category可以重載原始類的方法,但不推薦這么做,這么做的后果是你再也不能訪問原來的方法。如果確實要重載,正確的選擇是創建子類。
    3、和普通接口有所區別的是,在分類的實現文件中可以不必實現所有聲明的方法,只要你不去調用它。
     
    用好Category可以充分利用Objective-C的動態特性,編寫出靈活簡潔的代碼。
     
    —Protocol— 
    下面我們再來看Protocol。
    Protocol,簡單來說就是一系列不屬于任何類的方法列表,其中聲明的方法可以被任何類實現。這種模式一般稱為代理(delegation)模式。你通過Protocol定義各種行為,在不同的場景采用不同的實現方式。在iOS和OS X開發中,Apple采用了大量的代理模式來實現MVC中View和Controller的解耦。
     
    定義Protocol很簡單,在聲明文件(h文件)中通過關鍵字@protocol定義,然后給出Protocol的名稱,方法列表,然后用@end表示Protocol結束。在@end指令結束之前定義的方法,都屬于這個Protocol。例如:
    @protocol ProcessDataDelegate <NSObject>
    @required
    - (void) processSuccessful: (BOOL)success;
    
    @optional
    - (id) submitOrder: (NSNumber *) orderid;
    @end
     
    以上代碼可以單獨放在一個h文件中,也可以寫在相關類的h文件中,可以視具體情況而定。該Protocol包含兩個方法,processSuccessful和submitOrder。這里還有兩個關鍵字,@required和@optional,表示如果要實現這個協議,那么processSuccessful方法是必須要實現的,submitOrder則是可選的,這兩個注解關鍵字是在Objective-C 2.0之后加入的語法特性。如果不注明,那么方法默認是@required的,必須實現。
     
    那么如何實現這個Protocol呢,很簡單,創建一個普通的Objective-C類,取名為TestAppDelegate,這時會生成一個h文件和m文件。在h文件中引入包含Protocol的h文件,之后聲明采用這個Protocol即可,如下:
    @interface TestAppDelegate : NSObject<ProcessDataDelegate>;
    
    @end
    用尖括號(<...>)括起來的ProcessDataDelegate就是我們創建的Protocol。如果要采用多個Protocol,可以在尖括號內引入多個Protocol 名稱,并用逗號隔開即可。例如<ProcessDataDelegate,xxxDelegate>
     
    m文件如下:
    @implementation TestAppDelegate
    
    - (void) processSuccessful: (BOOL)success{
        if (success) {
            NSLog(@"成功");
        }else {
            NSLog(@"失敗");
        }
    }
    
    @end 
    由于submitOrder方法是可選的,所以我們可以只實現processSuccessful。
     
    Protocol一般使用在哪些場景呢?Objective-C里的Protocol和Java語言中的接口很類似,如果一些類之間沒有繼承關系,但是又具備某些相同的行為,則可以使用 Protocol來描述它們的關系。不同的類,可以遵守同一個Protocol,在不同的場景下注入不同的實例,實現不同的功能。其中最常用的就是委托代理模式,Cocoa框架中大量采用了這種模式實現數據和UI的分離。例如UIView產生的所有事件,都是通過委托的方式交給Controller完成。根據約定,框架中后綴為Delegate的都是Protocol,例如UIApplicationDelegate,UIWebViewDelegate 等,使用時大家可以留意一下,體會其用法。
     
    使用Protocol時還需要注意的是:
    1、Protocol本身是可以繼承的,比如:
    @protocol A
         -(void)methodA;
    @end
    @protocol B <A>
         -(void)methodB;
    @end

    如果你要實現B,那么methodA和methodB都需要實現。 

    2、Protocol是類無關的,任何類都可以實現定義好的Protocol。如果我們想知道某個類是否實現了某個Protocol,還可以使用conformsToProtocol進行判斷,如下:
    [obj conformsToProtocol:@protocol(ProcessDataDelegate)] 
     
    好吧,具體的語言特性這次就介紹這么多。從某種意義上來說,Objective-C是一門古老的語言,發明于1980年。1988年,喬布斯的Next公司獲得了Objective-C語言的授權,并開發出了Objective-C的語言庫和NEXTSTEP的開發環境。NextStep是以Mach和BSD為基礎,Objective-C是其語言和運行庫,后來的事大家都清楚,蘋果買了Next,喬布斯回歸蘋果,開始神奇的蘋果振興之路,NextStep成了Max OS X的基礎。以后發展越來越好,Objctive-C成了Apple的當家語言,現在基本上是Apple在維護Objctive-C的發展。
     
    在蘋果的AppStore推出之前,Objective-C一直相對小眾,但是其優秀的語言特性似乎一直在為后面的爆發積蓄力量,當蘋果平臺級的應用出現之后,Objective-C開始大放異彩,靜態語言的效率和動態語言的特性得到眾多程序員的喜愛,目前它已經以火箭般的速度躥升TIOBE語言排行版第四位。
     
    對于喜愛蘋果技術的技術人員來說,Objective-C是你必須深入了解和值得學習的一門語言,希望以后有機會多寫一些相關的文章。

    轉載于:http://www.cnblogs.com/chijianqiang/archive/2012/06/22/objc-category-protocol.html

     

    posted @ 2012-10-17 13:49 為自己代言 閱讀(354) | 評論 (0)編輯 收藏

         摘要: 我們大部分情況使用默認的或者chain或者redirect,其實struts2還有很多其他類型的,今天我們就來看一下都有哪些類型。 struts2的源碼中struts-default.xml文件有全部類型下邊解釋下: 類型 chain 描述 用來處理Action鏈,被跳轉的action中仍能獲取上個頁面的值,如request信息。 使用的類...  閱讀全文

    posted @ 2012-06-01 12:56 為自己代言 閱讀(416) | 評論 (0)編輯 收藏

     org.apache.cxf.binding.soap.SoapFault: "http://schemas.xmlsoap.org/wsdl/" is  not a valid SOAP version.

    在寫好服務器端測試沒有問題,在客戶端調用時候出現上面錯誤,經過分析原面如下:

    1:CXF 有兩種客戶端調用,一種是動態工廠形式, 第二種是通過CXF 中wsdl2java 命令先把客戶端類生成到本地,在調用;

    第一種: 1:  用org.apache.cxf.jaxws.JaxWsProxyFactoryBean配置

    <bean id="msgWebServiceSoap" class="com.jd.sms.MsgWebServiceSoap" factory-bean="msgClientFactory"
              factory-method="create"/>
        <bean id="msgClientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
            <property name="serviceClass" value="com.jd.sms.MsgWebServiceSoap"/>
            <property name="address" value="    </bean>


    第二種: 2:  

       用標簽<jaxws:client直接配置:

    <jaxws:client id="orderClient" serviceClass=

                    "demo.order.OrderProcess" address=

                     "http://localhost:8080/orderapp/OrderProcess" />

    以上兩種webService 的接口地址都不需要在后面加上?wsdl這個后綴,因為這樣spring 調用時候要先通過 CXF/bin 命令行wsdl2java 這個命令生成本地客戶端調用,把生成的本地客戶端代碼復制到客戶端工程中去,在spring 配置文件中通過上面的任意一種配置方式選擇配置,即可調用。
    以上CXF異常,就是用這種方式調用,但是接口URL 多了?wsdl后綴的原面;
    附wsdl2java 使用方式cd CXF/bin目錄下:

    其作用上面的build.xml作用一樣。
    附加:wsdl2java用法:
    wsdl2java -p com -d src -all aa.wsdl
    -p 指定其wsdl的命名空間,也就是要生成代碼的包名:
    -d 指定要產生代碼所在目錄
    -client 生成客戶端測試web service的代碼
    -server 生成服務器啟動web service的代碼
    -impl 生成web service的實現代碼
    -ant 生成build.xml文件


    posted @ 2012-05-22 14:00 為自己代言 閱讀(2621) | 評論 (0)編輯 收藏

    首先在web工程src目錄下新建一個database.properties 文件
    內容如下:

    user=root
    password=root
    databaseType=com.mysql.jdbc.Driver
    url=jdbc:mysql://192.168.2.232:3306/oa? seUnicode=true&amp;characterEncoding=UTF8&amp;zeroDateTimeBehavior=convertToNull

     這里的內容隨自己的合適而變化,這里不多說了;

    在新建一個讀取.properties文件新類:

    package com.junhai.tamsys.util;

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.Properties;

    public class DatabaseConfigure {
     private Properties property;
     private FileInputStream inputFile;
     private FileOutputStream outputFile;

     public DatabaseConfigure() {
      property = new Properties();
     }

     public DatabaseConfigure(String filePath) {
      property = new Properties();
      try {
       inputFile = new FileInputStream(filePath);
       property.load(inputFile);
       inputFile.close();
      } catch (FileNotFoundException e) {
       System.out.println("讀取屬性文件--->失敗!- 原因:文件路徑錯誤或者文件不存在");
       e.printStackTrace();
      } catch (IOException e) {
       e.printStackTrace();
      }
     }

     /*
      * 重載函數,得到key的值 @param key 取得其值的鍵 @return key的值
      */
     public String getValue(String key) {
      if (property.containsKey(key)) {
       return property.getProperty(key);

      } else
       return "";
     }

     /*
      * 重載函數,得到key的值
      *
      * @param fileName propertys文件的路徑+文件名 @param key 取得其值的鍵 @return key的值
      */
     public String getValue(String fileName, String key) {
      try {
       String value = "";
       inputFile = new FileInputStream(fileName);
       property.load(inputFile);
       inputFile.close();
       if (property.containsKey(key)) {
        value = property.getProperty(key);
        return value;
       } else
        return value;
      } catch (FileNotFoundException e) {
       e.printStackTrace();
       return "";
      } catch (IOException e) {
       e.printStackTrace();
       return "";
      } catch (Exception ex) {
       ex.printStackTrace();
       return "";
      }
     }

     /*
      * 清除properties文件中所有的key和其值
      */
     public void clear() {
      property.clear();
     }

     /*
      * 改變或添加一個key的值,當key存在于properties文件中時該key的值被value所代替, 當key不存在時,該key的值是value
      * @param key 要存入的鍵 @param value 要存入的值
      */
     public void setValue(String key, String value) {
      property.setProperty(key, value);
     }

     /*
      * 將更改后的文件數據存入指定的文件中,該文件可以事先不存在。 @param fileName 文件路徑+文件名稱 @param
      * description 對該文件的描述
      */
     public void saveFile(String fileName, String description) {
      try {
       outputFile = new FileOutputStream(fileName);
       property.store(outputFile, description);
       outputFile.close();
      } catch (FileNotFoundException e) {
       e.printStackTrace();
      } catch (IOException ioe) {
       ioe.printStackTrace();
      }
     }

     public static void main(String[] args) {
      DatabaseConfigure test=new DatabaseConfigure("./src/database.properties");
      System.out.println(test.getValue("user"));
      System.out.println(test.getValue("databaseType")+";"+test.getValue("url"));
      
     }
    }


    這樣就可以通過key得到相應的value了;
    想在這里多說一點是路徑問題,java工程和web 工程讀取.properties路徑是不一樣的,我在這里就花了不少時間。
    JAVA工程: DatabaseConfigure test=new DatabaseConfigure("./src/database.properties");這樣讀取就可以了:
    web工程這樣讀取:DatabaseConfigure  dc = new DatabaseConfigure(Thread.currentThread().getContextClassLoader()
                                                    .getResource("").getPath()+"database.properties");
     
    因為當服務器啟動后工程里面東西會編譯后加到\WEB-INF\classes這個目錄,服務也是從這個目錄下讀取信息的。所以先取到這個路徑,才能正確讀取到database.properties這里邊的內容。

    posted @ 2010-01-28 15:46 為自己代言 閱讀(2976) | 評論 (0)編輯 收藏

         摘要:   Struts2 攔截器詳細配置過程 1:所有攔截器的超級接口Interceptor ,Action去實現這個接口;  Interceptor 它其中有三個方法(init(),destroy() ,interceptor()):       Init()方法:在服務器起動的時候加載一次,并且只加載一次;  ...  閱讀全文

    posted @ 2009-10-12 22:41 為自己代言 閱讀(33098) | 評論 (6)編輯 收藏

     

    Hiberante3 一級緩存總結

    1.             Session 級別的緩存,它同session邦定。它的生命周期和session相同。Session消毀,它也同時消毀;管理一級緩存,一級緩存無法取消,用兩個方法管理,clear(),evict()

    2.             兩個session 不能共享一級緩存,因它會伴隨session的生命周期的創建和消毀;

    3.             Session緩存是實體級別的緩存,就是只有在查詢對象級別的時候才使用,如果

    使用HQLSQL是查詢屬性級別的,是不使用一級緩存的!切記!!!!

    4 .  iterate 查詢使用緩存,會發出查詢IdSQLHQL語句,但不會發出查實體的,

    它查詢完會把相應的實體放到緩存里邊,一些實體查詢如果緩存里邊有,就從緩存中查詢,但還是會發出查詢idSQLHQL語句。如果緩存中沒有它會數據庫中查詢,然后將查詢到的實體一個一個放到緩存中去,所以會有N+1問題出現。

    5 . List()iterate 查詢區別:

    使用iterate,list查詢實體對象*N+1問題,在默認情況下,使用query.iterate查詢,有可以能出現N+1問題

    所謂的N+1是在查詢的時候發出了N+1sql語句1:首先發出一條查詢對象id列表的sqlN:

    根據id列表到緩存中查詢,如果緩存中不存在與之匹配的數據,那么會根據id發出相應的sql語句listiterate的區別?

    list每次都會發出sql語句,list會向緩存中放入數據,而不利用緩存中的數據

    iterate:在默認情況下iterate利用緩存數據,但如果緩存中不存在數據有可以能出現N+1問題

    6Get()load(),iterate方法都會使用一級緩存,

     

    7.hiberate3 session 存儲過程如下:

           例如 object 對象

           Session.save(object);

           這時候不會把數據放到數據庫,會先放到session緩存中去,數據庫中沒有相應記錄,session.flush();才發SQLHQL語句,數據庫中有了相應記錄,

           但是數據庫用select查不到,這是跟數據庫事物級別有關系,(這里在說下數據庫的事務隔離級別一共四種如下:)
        數據庫隔離級別:
            隔離級別                       是否存在臟讀  是否存在不可重復讀     是否存在幻讀;
        Read UnCommited(未提交讀)               Y            Y                     Y
        Read Commited (提交讀 oraclel默認)      N            Y                     Y
        Repeatable Read(不可重復讀(Msql默認))  N            N                     Y 
        Serializable(使用很少)                  N            N                     N

        


           Session.beginTrransaction().commit();

           事物提交后可以查詢到了。

    Session.flush()語句但是為什么不寫呢,因為commit()會默認調用flush();


    Hiberante3 二級緩存總結

    1.Hibernate3的(sessionFactory)二級緩存和session級別的緩存一樣都只對實體對象做緩存,不對屬性級別的查詢做緩存;二級緩存的生命周期和sessionFactory的生命周期是一樣的,sessionFactory可以管理二級緩存;

    2.sessionFactory級別的緩存,需要手動配置;所有的session可以共享sessionFactory 級別的緩存;(一般把一些不經常變化的實體對象放到sessionFactory級別的緩存中,適合放不經常變化的實體對象。)

    3.Hiberante3二級緩存的配置和使用方法如下:

    1. 必須把ehcache.jar包導入,然后到Hibernate3.2etc文件下把ehcache.xml復制到工程src目錄下(ehcache.xml里邊的參數里邊有詳細英文說明);

    (說明:ehcache.jar是第三方法的緩存產品,hiberante只是把它做了集成,還有好多第三方hibernate集成的緩存產品,相關說明請查閱hiberante3開發手冊;ehcache支持分布應用的(這個和Hibernate3.2開發手冊有出入,經過官網查證確實支持了),如果有分布式需求,請換成支持分布式的二級緩存產品,hiberate3開發手冊都有相頭說明。配置方法都類似);

    4.Hibernate3的二級緩存默認是開起的,也可以指定開起。在hibernate.cfg.xml 文件下配置如下:

    *修改hibernate.cfg.xml文件,開戶二級緩存;

                         <property name=”hibernate.cache.use_second_level_cache”>true</property>

                         *指定二級緩存產品的提供商;

    <property name=”hibernate.cache.provider_class”> org.hibernate.cache.EhCacheProvider

    </property>

    要讓那些實體使用二級緩存,在hibernate.cfg.xml配置文件中加入:

    <!—

    讓這個實體用二級緩存 也可以在實體中映射文件去配置即:

    <cache usage="read-only"/>

    -->

    <class-cache class=”com.zzz.hibernate.ClassT” usage=”read-only”/>

    Read-only一般使用這個策略,其它的hibernate3開發手冊中也有詳細介紹;

    CacheModehibernate3開發手冊中搜索這個關鍵字,可以找到一級緩存和二級緩存交互使用的問題;

    posted @ 2009-08-11 23:01 為自己代言 閱讀(7887) | 評論 (3)編輯 收藏

    這里為什么使用struts2.0.14這個版本呢??請看官網的文章如下:

    24 November 2008 - Struts 2.0.14 General Availability Release

    The latest release of Struts 2 is Struts 2.0.14, which was promoted to "General Availability" on 24 November 2008.

    For changes included in Struts 2.0.14, see the release notes. Struts 2.0.14 is a bugfix release for version 2.0.12, which provided important security fixes. Struts 2.0.14 addresses two major bugs introduced with these security fixes, keeping the FilterDispatcher from serving built in static resources, and keeping conversion error messages from being displayed. All developers are strongly encouraged to update existing Struts 2 applications to Struts 2.0.14.

    如果你的英語不差的話,自己去看下吧.這段英語的大概意思是,Struts 2.0.14修正了Struts 2.0.12 的兩個主要的bug ;并且建議開發者更新到Struts 2.0.14
    這個版本.Struts 2.0.14 General Availability Release 這是個通用的開發版本.
    其實我在整合這個S2SH時,struts2 的最新版本是struts2.1.16 這個也是穩家版本,不過最新的版本網上資料很少.所以...........! 如果自己學的話可以選擇這個兩個版本.
    下邊是整合的全過程:
    主要是jar包的引入,我個人比較不喜歡用IDE 工具自動引入jar包,所以下邊是自己用的jar的引入,這樣可以省去相關jar 的沖突;

    1:首先struts2.0.14所需要的jar包如下:
    commons-logging-1.0.4  ;
    freemarker-2.3.8
     ognl-2.6.11
    struts2-core-2.0.14
    xwork-2.0.7
    struts2-spring-plugin-2.0.14  這是整合spring 必需的jar 包,從它的名字就可以看出來了!   

    2:hiberante3.2 jar 包如下 這是我的工程必需的,如果你的工程要用到其它的jar包可以去看一看hibernate 的必讀文件那里有很詳細的解釋;
                這個是做一般的工程,引入最少的jar 了,一般的項目都可以了!

    antlr-2.7.6         cglib-2.1.3     commons-collections-2.1.1    commons-logging-1.0.4      dom4j-1.6.1  
    ehcache-1.2.3    hibernate3     jaas        jaxen-1.1-beta-7     jdbc2_0-stdext     jta    log4j-1.2.11  
    xml-apis             asm             asm-attrs 

    如果你自己不做整合的,就是單獨做hibernate 學習,本人建議你把所有jar 都導入項目的lib目錄下!這里不在做任何解釋了!

    3:  spring 2.5.6  相關的jar 也是做項目最少引入的jar包了,如果自己還需要特定的自己去引入;

        aspectjrt    aspectjweaver   ( 這兩個是AOP 相關的jar包,因為spring  2.5的AOP實現,沒有自己去做,也用到了第三方組件,分開了,這好像和2.0版本有出入!有關細節,請自己去查閱相關文檔)
        spring

    好的,這三個框架所有jar 包,都介紹完了,(不要奇怪我的所有jar 包沒有后綴名,是我自己給隱藏了)

    好的進入主題了(順序最好 hibernate --->spring---->struts)

    1:把相關的hibernate  jar 包導入項目lib 目錄下!
    2: 把spring  相關jar   包導入項目lib 目錄下!
    3: 把struts2相關jar   包導入項目lib 目錄下!

    三者整合:
    web.xml文件如下里邊都有解釋自己看吧:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

     <!-- 配置spring監聽器和上下文變量 -->
     <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/applicationContext-*.xml</param-value>
     </context-param>

     <listener>
      <listener-class>
       org.springframework.web.context.ContextLoaderListener
      </listener-class>
     </listener>
     <!-- spring end -->

    <!-- 配置字符過濾器-->
     <filter>
      <filter-name>encodingFilter</filter-name>
      <filter-class>
       org.springframework.web.filter.CharacterEncodingFilter
      </filter-class>
      <init-param>
       <param-name>encoding</param-name>
       <param-value>GBK</param-value>
      </init-param>
     </filter>
     <filter-mapping>
      <filter-name>encodingFilter</filter-name>
      <url-pattern>/*</url-pattern>
     </filter-mapping>

     <!--讓spring來過濾管理Hiberante中的session-->
     <filter>
      <filter-name>lazyLoadingFilter</filter-name>
      <filter-class>
       org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
      </filter-class>
     </filter>

     <!-- spring end -->

     <!-- 增加struts2所需要的過濾器,以便在服務器啟動時,攔截URL請求 -->
     <filter>
      <filter-name>struts2</filter-name>
      <filter-class>
       org.apache.struts2.dispatcher.FilterDispatcher
      </filter-class>
     </filter>

     <filter-mapping>
      <filter-name>lazyLoadingFilter</filter-name>
      <url-pattern>*.action</url-pattern>
     </filter-mapping>


     <filter-mapping>
      <filter-name>struts2</filter-name>
      <url-pattern>/*</url-pattern>
     </filter-mapping>
      </web-app>


    applicationContext-common.xml 文件:其中我使用了,DBCP數據庫連接波,如果你自己想用,
                               還的去下載相關的jar 包( commons-dbcp-1.2.2   commons-pool-1.3)記著引入哦!

    我下邊注釋掉的就是沒有用數據庫連接池的,也就是不把src目錄下的hibernate.cfg.xml刪除.上邊用到的數據庫連接池的,就不用這個文件了,直接都用spring來管理啦!!!!

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:aop="http://www.springframework.org/schema/aop"
     xmlns:tx="http://www.springframework.org/schema/tx"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
               http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
               http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
     <!-- 用DBCP數據庫連接波來配置hibernate數據庫連接 -->
     
      <bean id="dataSource"
      class="org.apache.commons.dbcp.BasicDataSource">
      <property name="driverClassName"
      value="com.mysql.jdbc.Driver">
      </property>
      <property name="url" value="jdbc:mysql://localhost/oa"></property>
      <property name="username" value="root"></property>
      <property name="password" value="root"></property>
      </bean>
     
     <!-- 配置sessionFactory -->
      
      <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
      <property name="dataSource">
      <ref bean="dataSource" />
      </property>
      <property name="hibernateProperties">
      <props>
      <prop key="hibernate.dialect">
      org.hibernate.dialect.MySQLDialect
      </prop>
      <prop key="hibernate.show_sql">true</prop>
      <prop key="format_sql">true</prop>
      <prop key="hibernate.hbm2ddl.auto">update</prop>
      </props>
      </property>
      <property name="mappingResources">
      <list>
      <value>com/oa/model/Person.hbm.xml</value>
      <value>com/oa/model/Organization.hbm.xml</value>
      </list>
      </property>
      </bean>
      
    <!-- 讓spring管理sessionFactory的加一種方法 ,就是不刪除hibernate.cfg.xml文件;
     <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
      <property name="configLocation">
       <value>classpath:hibernate.cfg.xml</value>
      </property>
     </bean>
    --> 
      
     <!-- 配置hibernate事物讓spring來管理 -->
     <bean id="transactionManager"
      class="org.springframework.orm.hibernate3.HibernateTransactionManager">
      <property name="sessionFactory">
       <ref bean="sessionFactory" />
      </property>
     </bean>
     <!-- 配置事物的傳播特性 -->
     <tx:advice id="txAdvice" transaction-manager="transactionManager">
      <tx:attributes>
       <tx:method name="add*" propagation="REQUIRED" />
       <tx:method name="delete*" propagation="REQUIRED" />
       <tx:method name="update*" propagation="REQUIRED" />
       <tx:method name="*" read-only="true" />
      </tx:attributes>
     </tx:advice>
     <!-- 那些類的那些方法需要事物; -->
     <aop:config>
      <aop:pointcut id="allManagerMethod"
       expression="execution(* com.oa.manager.*.*(..))" />
      <aop:advisor pointcut-ref="allManagerMethod"
       advice-ref="txAdvice" />
     </aop:config>
    </beans>

    對了還需要注意的一個地方就是如果用了,我這種數據庫連接池技術,得把你的數據庫驅動類,復制tomcat lib 目錄下.不然會報錯的!

    好了三個東西整合好,我也是費了九牛二虎之力才整合成功的.
    如果有什么問題發我的郵箱一起交流:zzzlyr@163.com



    posted @ 2009-07-11 00:03 為自己代言 閱讀(1652) | 評論 (1)編輯 收藏

    下面以三個頁面分別命名為framedemo.html,left.html,right.html為例來具體說明如何做。

    其中framedemo.html由左右兩個頁面組成,代碼如下:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <HTML>
    <HEAD>
    <TITLE> frameDemo </TITLE>
    </HEAD>
    <frameset cols="200,*">
    <frame name=top src="left.html">
    <frame name=button src="right.html">
    </frameset>
    </HTML>

    現在假設left.html即上面的頁面有一個button來實現對下面頁面的刷新,可以用以下七種語句,哪個好用自己看著辦了。

    語句1. window.parent.frames[1].location.reload();

    語句2. window.parent.frames.bottom.location.reload();

    語句3. window.parent.frames["bottom"].location.reload();

    語句4. window.parent.frames.item(1).location.reload();

    語句5. window.parent.frames.item('bottom').location.reload();

    語句6. window.parent.bottom.location.reload();

    語句7. window.parent['bottom'].location.reload();

    解釋一下:

    1.window指代的是當前頁面,例如對于此例它指的是top.html頁面。

    2.parent指的是當前頁面的父頁面,也就是包含它的框架頁面。例如對于此例它指的是framedemo.html。

    3.frames是window對象,是一個數組。代表著該框架內所有子頁面。

    4.item是方法。返回數組里面的元素。

    5.如果子頁面也是個框架頁面,里面還是其它的子頁面,那么上面的有些方法可能不行。
    top.html源代碼;(頁面上有七個按鈕,功能都是刷新下面的框架頁面)

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <HTML>
    <HEAD>
    </HEAD>
    <BODY>
    <input type=button value="刷新1" onclick="window.parent.frames[1].location.reload()"><br>
    <input type=button value="刷新2" onclick="window.parent.frames.bottom.location.reload()"><br>
    <input type=button value="刷新3" onclick="window.parent.frames['bottom'].location.reload()"><br>
    <input type=button value="刷新4" onclick="window.parent.frames.item(1).location.reload()"><br>
    <input type=button value="刷新5" onclick="window.parent.frames.item('bottom').location.reload()"><br>
    <input type=button value="刷新6" onclick="window.parent.bottom.location.reload()"><br>
    <input type=button value="刷新7" onclick="window.parent['bottom'].location.reload()"><br>
    </BODY>
    </HTML>

    下面是right.html頁面源代碼,為了證明下方頁面的確被刷新了,在裝載完頁面彈出一個對話框。

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <HTML>
    <HEAD>
    </HEAD>
    <BODY onload="alert('我被加載了!')">
    <h1>This is the content in button.html.</h1>
    </BODY>
    </HTML>

    經我測試,只能1 和4 顯示效果,別的好像不對喲
    ============================

    附:
    Javascript刷新頁面的幾種方法:
    1    history.go(0)
    2    location.reload()
    3    location=location
    4    location.assign(location)
    5    document.execCommand('Refresh')
    6    window.navigate(location)
    7    location.replace(location)
    8    document.URL=location.href

     

     

     

    自動刷新頁面的方法:
    1.頁面自動刷新:把如下代碼加入<head>區域中
    <meta http-equiv="refresh" content="20">
    其中20指每隔20秒刷新一次頁面.

    2.頁面自動跳轉:把如下代碼加入<head>區域中
    <meta http-equiv="refresh" content="20;url=http://www.wyxg.com">
    其中20指隔20秒后跳轉到http://www.wyxg.com頁面

    3.頁面自動刷新js版
    <script language="JavaScript">
    function myrefresh()
    {
           window.location.reload();
    }
    setTimeout('myrefresh()',1000); //指定1秒刷新一次
    </script>

    ASP.NET如何輸出刷新父窗口腳本語句
    1.   this.response.write("<script>opener.location.reload();</script>");  

    2.   this.response.write("<script>opener.window.location.href = opener.window.location.href;</script>");   

    3.   Response.Write("<script language=javascript>opener.window.navigate(''你要刷新的頁.asp'');</script>")


    JS刷新框架的腳本語句

    //如何刷新包含該框架的頁面用   
    <script language=JavaScript>
       parent.location.reload();
    </script>   

    //子窗口刷新父窗口
    <script language=JavaScript>
        self.opener.location.reload();
    </script>

    ( 或 <a href="javascript:opener.location.reload()">刷新</a>   )

    //如何刷新另一個框架的頁面用   
    <script language=JavaScript>
       parent.另一FrameID.location.reload();
    </script>

    如果想關閉窗口時刷新或者想開窗時刷新的話,在<body>中調用以下語句即可。

    <body onload="opener.location.reload()">
    開窗時刷新
    <body onUnload="opener.location.reload()">
    關閉時刷新

    <script language="javascript">
    window.opener.document.location.reload()
    </script>

    posted @ 2009-05-22 22:55 為自己代言 閱讀(4609) | 評論 (0)編輯 收藏

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
    <title>js退出使用!</title>
     <script language="javascript">
      function logout(){
      if( confirm("你確實要退出嗎??")){
       window.parent.location.;
      }
      else{
       return;
      }
     }
     </script>
    </head>
     <p> <a href="javascript:logout()"> 退出</a></p>
    <a href="javascript:history.back();">返回</a>
    <body>
    </body>
    </html>

    posted @ 2009-05-22 22:44 為自己代言 閱讀(5102) | 評論 (0)編輯 收藏

    <%@include file="/common/taglib.jsp"%>
    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <title>網站后臺管理系統</title>
     <%@include file="/common/metadata.jsp"%>
     <link href="${ctx}/admin/style/css_body.css" rel="stylesheet" type="text/css" />
     <script type="text/javascript">
          function del(id){
            if(confirm("您確認要刪除該項嗎?")){
              document.location.href="${ctx}/NewsManage?action=deleteNews&id="+id;
            }else{
              return;
            }
          }
          function pagging(pageNo){
             document.location.href="${ctx}/MemeberRegisterServlet?action=list&pageNo="+pageNo;
         }
        </script>
    </head>
    <body>
     
      <div class="bodytitle">
        <div>
          <span class="bodytitletxt">新聞列表</span>
        </div>
      </div>
     
      <div class="list-div">
      <table border="0" cellpadding="10" cellspacing="1">
       <tr>
        <td align="center"><a href="${ctx}/NewsManage?action=refresh">刷新新聞列表</a></td>
        </tr>
      </table>
     
        <table border="0" cellpadding="10" cellspacing="1">
      
          <tr>
            <th>新聞編號</th>
            <th>新聞名稱</th>
            <th>發布者</th>
            <th>發布時間</th>
            <th>修改時間</th>
            <th>瀏覽次數</th>
            <th>操作</th>
          </tr>
          <c:forEach items="${newsList}" var="news">
          <tr>
            <td align="center">${news.id}</td>
            <td align="center"><a href="${ctx}/BrowerNewsServlet?action=browerNews&id=${news.id}">${news.topic}</a></td>
            <td align="center">${news.publishuser}</td>
            <td align="center">${news.publishtimes}</td>
            <td align="center">${news.modifytimes}</td>
            <td align="center">${news.hits}</td>
           <td align="center">
              <a href="${ctx}/NewsManage?action=modifyNews&id=${news.id}"><img src="${ctx}/icons/icon_edit.gif"></a>
              &nbsp;&nbsp;|&nbsp;&nbsp;
              <a href="javascript:del(${news.id})"><img src="${ctx}/icons/icon_drop.gif"></a>
            </td>
          </tr>
          </c:forEach>
          <tr>
            <td align="right" bgcolor="#f9ffe6" colspan="7"><%@include file="/common/paggingDiv.jsp" %></td>
          </tr>
        </table>
       
      </div>
     
      <div id="footer"><br />版權所有 &copy; 2005-2008 Onest's Studio 工作室,并保留所有權利。</div>

    </body>
    </html>

    posted @ 2009-05-22 22:18 為自己代言 閱讀(1865) | 評論 (0)編輯 收藏

    今天去面試了問我最簡單的JS對話框的使用,我竟然沒有回答上來!丟人,回來看了一個晚上的JS!好像懂點了。

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
    <title>三種彈出對話框的用法實例</title>
    <script language="javascript">
    function ale()
    {//這個基本沒有什么說的,就是彈出一個提醒的對話框 ,這個方法也可以帶參數的
        alert("提示對話框!");
    }
    function firm()
    {//利用對話框返回的值 (true 或者 false)
        if(confirm("你確信要轉去 天轟穿的博客?"))
        {//如果是true ,那么就把頁面轉向thcjp.cnblogs.com
            location.;
        }
        else
        {//否則說明下了,赫赫
            alert("你按了取消,那就是返回false");
        }
    }
    function prom()
    {
        var name=prompt("請輸入您的名字","");//將輸入的內容賦給變量 name ,
        //這里需要注意的是,prompt有兩個參數,前面是提示的話,后面是當對話框出來后,在對話框里的默認值
        if(name)//如果返回的有內容
        {
            alert("歡迎您:"+ name)
        }
    }
    </script>
    </head>

    <body>
    <p>對話框有三種</p>
    <p>1:只是提醒,不能對腳本產生任何改變;</p>
    <p>2:一般用于確認,返回 true 或者 false ,所以可以輕松用于 ifelse判斷 </p>
    <p>3: 一個帶輸入的對話框,可以返回用戶填入的字符串,常見于某些留言本或者論壇輸入內容那里的 插入UBB格式圖片 </p>
    <p>下面我們分別演示:</p>
    <p>演示一:提醒 對話框</p>
    <p>
      <input type="submit" name="Submit" value="提交" onclick="ale()" />
    </p>
    <p>演示二 :確認對話框 </p>
    <p>
      <input type="submit" name="Submit2" value="提交" onclick="firm()" />
    </p>
    <p>演示三 :要求用戶輸入,然后給個結果</p>
    <p>
      <input type="submit" name="Submit3" value="提交" onclick="prom()" />
    </p>
    </body>
    </html>

    posted @ 2009-05-22 22:15 為自己代言 閱讀(2587) | 評論 (0)編輯 收藏

    一、抽象類:

    抽象類是特殊的類,只是不能被實例化;除此以外,具有類的其他特性;重要的是抽象類可以包括抽象方法,這是普通類所不能的。抽象方法只能聲明于抽象類中,且不包含任何實現,派生類必須覆蓋它們。另外,抽象類可以派生自一個抽象類,可以覆蓋基類的抽象方法也可以不覆蓋,如果不覆蓋,則其派生類必須覆蓋它們。

    二、接口:

    接口是引用類型的,類似于類,和抽象類的相似之處有三點:

    1、不能實例化;

    2、包含未實現的方法聲明;

    3、派生類必須實現未實現的方法,抽象類是抽象方法,接口則是所有成員(不僅是方法包括其他成員);

    另外,接口有如下特性:
    接口除了可以包含方法之外,還可以包含屬性、索引器、事件,而且這些成員都被定義為公有的。除此之外,不能包含任何其他的成員,例如:常量、域、構造函數、析構函數、靜態成員。一個類可以直接繼承多個接口,但只能直接繼承一個類(包括抽象類)。

    三、抽象類和接口的區別:

    1.類是對對象的抽象,可以把抽象類理解為把類當作對象,抽象成的類叫做抽象類.而接口只是一個行為的規范或規定,微軟的自定義接口總是后帶able字段,證明其是表述一類類“我能做。。。”.抽象類更多的是定義在一系列緊密相關的類間,而接口大多數是關系疏松但都實現某一功能的類中.

    2.接口基本上不具備繼承的任何具體特點,它僅僅承諾了能夠調用的方法;    

    3.一個類一次可以實現若干個接口,但是只能擴展一個父類    

    4.接口可以用于支持回調,而繼承并不具備這個特點.    

    5.抽象類不能被密封。  

    6.抽象類實現的具體方法默認為虛的,但實現接口的類中的接口方法卻默認為非虛的,當然您也可以聲明為虛的.

    7.(接口)與非抽象類類似,抽象類也必須為在該類的基類列表中列出的接口的所有成員提供它自己的實現。但是,允許抽象類將接口方法映射到抽象方法上。  

    8.抽象類實現了oop中的一個原則,把可變的與不可變的分離。抽象類和接口就是定義為不可變的,而把可變的座位子類去實現。

    9.好的接口定義應該是具有專一功能性的,而不是多功能的,否則造成接口污染。如果一個類只是實現了這個接口的中一個功能,而不得不去實現接口中的其他方法,就叫接口污染。  

    10.盡量避免使用繼承來實現組建功能,而是使用黑箱復用,即對象組合。因為繼承的層次增多,造成最直接的后果就是當你調用這個類群中某一類,就必須把他們全部加載到棧中!后果可想而知.(結合堆棧原理理解)。同時,有心的朋友可以留意到微軟在構建一個類時,很多時候用到了對象組合的方法。比如asp.net中,Page類,有Server Request等屬性,但其實他們都是某個類的對象。使用Page類的這個對象來調用另外的類的方法和屬性,這個是非常基本的一個設計原則。  

    11.如果抽象類實現接口,則可以把接口中方法映射到抽象類中作為抽象方法而不必實現,而在抽象類的子類中實現接口中方法.

    四、抽象類和接口的使用:

    1. 如果預計要創建組件的多個版本,則創建抽象類。抽象類提供簡單的方法來控制組件版本。

    2.如果創建的功能將在大范圍的全異對象間使用,則使用接口。如果要設計小而簡練的功能塊,則使用接口。

    3.如果要設計大的功能單元,則使用抽象類.如果要在組件的所有實現間提供通用的已實現功能,則使用抽象類。  

    4.抽象類主要用于關系密切的對象;而接口適合為不相關的類提供通用功能。

    以下是我在網上看到的幾個形象比喻,真的非常不錯,呵呵:

    1.飛機會飛,鳥會飛,他們都繼承了同一個接口“飛”;但是F22屬于飛機抽象類,鴿子屬于鳥抽象類。

    2. 就像鐵門木門都是門(抽象類),你想要個門我給不了(不能實例化),但我可以給你個具體的鐵門或木門(多態);而且只能是門,你不能說它是窗(單繼承);一個門可以有鎖(接口)也可以有門鈴(多實現)。 門(抽象類)定義了你是什么,接口(鎖)規定了你能做什么(一個接口最好只能做一件事,你不能要求鎖也能發出聲音吧(接口污染)

    posted @ 2009-05-12 11:06 為自己代言 閱讀(1469) | 評論 (0)編輯 收藏

         摘要:   閱讀全文

    posted @ 2009-05-11 09:09 為自己代言 閱讀(487) | 評論 (1)編輯 收藏

         摘要:   閱讀全文

    posted @ 2009-04-01 11:18 為自己代言 閱讀(2460) | 評論 (5)編輯 收藏

    主站蜘蛛池模板: 好吊妞998视频免费观看在线| 亚洲精品在线播放| 成年女人18级毛片毛片免费| a视频在线免费观看| jizzjizz亚洲日本少妇| 亚洲精品mv在线观看| 精品亚洲综合在线第一区| 妞干网免费视频观看| 亚洲啪啪免费视频| 暖暖在线视频免费视频| 久久久精品国产亚洲成人满18免费网站 | 最近中文字幕国语免费完整| 一级做a爰全过程免费视频毛片| 亚洲av最新在线观看网址| 亚洲国产成人资源在线软件| 亚洲AV区无码字幕中文色| 亚洲午夜福利AV一区二区无码| 国产亚洲福利一区二区免费看| 午夜a级成人免费毛片| 免费无码精品黄AV电影| 日本zzzzwww大片免费| 久久久久免费精品国产小说| 青青操免费在线观看| 久草免费福利在线| 国产精品小视频免费无限app| 一个人看的www免费在线视频| 猫咪免费人成在线网站 | 成人毛片免费观看视频在线| 亚洲一区二区三区免费视频| 99精品热线在线观看免费视频| 午夜精品射精入后重之免费观看| 中文无码成人免费视频在线观看| 97无码人妻福利免费公开在线视频 | 最近免费中文在线视频| 99热这里有免费国产精品| 99re6在线视频精品免费下载| 久久免费的精品国产V∧| 久久午夜无码免费| 99久久综合精品免费| 在免费jizzjizz在线播| 91视频国产免费|