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

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

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

    隨筆-31  評論-2  文章-0  trackbacks-0
      2008年10月8日

    1 set和multiset容器的能力
    set 和multiset容器的內(nèi)部結(jié)構(gòu)通常由平衡二叉樹(balanced binary tree)來實現(xiàn)。當元素放入容器中時,會按照一定的排序法則自動排序,默認是按照less<>排序規(guī)則來排序。這種自動排序的特性加速了元 素查找的過程,但是也帶來了一個問題:不可以直接修改set或multiset容器中的元素值,因為這樣做就可能違反了元素自動排序的規(guī)則。如果你希望修 改一個元素的值,必須先刪除原有的元素,再插入新的元素。

    2 set和multiset容器的操作
    Constructor and Destructor
    • set c: 創(chuàng)建一個空的set或multiset容器
    • set c(op): 創(chuàng)建一個空的使用op作為排序法則的set或multiset容器
    • set c1(c2): 創(chuàng)建一個已存在的set或multiset容器的復(fù)制品,容器的類型和所有元素一同復(fù)制
    • set c(beg, end): 創(chuàng)建一個set或multiset容器,并且以[beg, end)范圍中的元素進行初始化
    • set c(beg, end, op): 創(chuàng)建一個使用op作為排序法則的set或multiset容器,并且以[beg, end)范圍中的元素進行初始化
    • c.~set(): 容器的析構(gòu)函數(shù),銷毀所有的元素,釋放所有的分配內(nèi)存
    上面的set可以是下面幾種形式:
    • set<type>: 以less<>為排序法則的set
    • set<type, op>: 以op為排序法則的set
    • multiset<type>: 以less<>為排序法則的multiset
    • multiset<type, op>: 以op為排序法則的multiset
    從上面我們可以看到,可以從兩個地方來指定排序法則:
    (1)作為模板參數(shù)
    例如:std::set<int, greater<int> > col1;
    這種情況下,排序法則本身作為容器類型的一部分。對于一個set或者multiset容器,只有當元素類型和排序法則類型都相同時,他們的類型才被認為相同,否則就是不同類型的容器。

    (2)作為構(gòu)造函數(shù)參數(shù)
    例如:std::set<int> col1(greater<int>);
    這種情況下指定的排序法則不作為容器類型的一部分,你可以為相同類型的容器指定不同的排序規(guī)則。這通常應(yīng)用于要求相同的容器類型,但排序規(guī)則可以不同的場合。

    Size and Comparing
    set 和multiset容器同樣提供size(), empty(), max_size()三個關(guān)于查詢元素數(shù)目的接口,提供==, !=, <, <=, >, >=等比較操作符。但值得注意的是比較操作符只針對相同類型的容器,元素類型和排序法則類型都必須相同。

    Special Search Operations
    set和multiset容器的內(nèi)部結(jié)構(gòu)對于元素的查找提供了優(yōu)化空間,所以它們提供了一些特殊的查找接口,這些查找操作通常要比同名的通用算法高效,所以在相同的條件下應(yīng)該優(yōu)先使用這些接口。
    • count(val): 返回容器中值等于val的元素數(shù)目。
    • find(val): 返回容器中值等于val的第一個元素的iterator位置;如果沒有匹配元素,則返回end()位置。
    • lower_bound(val): 返回容器中第一個值大于或等于val的元素的iterator位置。
    • upper_bound(val): 返回容器中第一個值大于val的元素的iterator位置。
    • equal_range(val): 返回容器中值等于val的所有元素的范圍[beg, end)組成的pair<beg, end> 。
    下面我們看一個使用lower_bound(), upper_bound和equal_range(val)例子,以加深對它們的理解:
    #include <iostream>
    #include <set>
    #include "print.hpp"
    using namespace std;
    int main()
    {
        multiset<int> col1;

        col1.insert(2);
        col1.insert(5);
        col1.insert(4);
        col1.insert(6);
        col1.insert(1);
        col1.insert(5);

        PRINT_ELEMENTS(col1, "col1: ");
        cout << endl;

        multiset<int>::const_iterator pos;
        pair<multiset<int>::iterator, multiset<int>::iterator> range;

        cout << "lower_bound(3): " << *col1.lower_bound(3) << endl;
        cout << "upper_bound(3): " << *col1.upper_bound(3) << endl;
        range = col1.equal_range(3);
        cout << "equal_range(3): " << *range.first << " " << *range.second << endl;
        cout << "elements with value(3): ";
        for (pos = range.first; pos != range.second; ++pos)
        {
            cout << *pos << " ";
        }
        cout << endl;
        cout << endl;

        cout << "lower_bound(5): " << *col1.lower_bound(5) << endl;
        cout << "upper_bound(5): " << *col1.upper_bound(5) << endl;
        range = col1.equal_range(5);
        cout << "equal_range(5): " << *range.first << " " << *range.second << endl;
        cout << "elements with value(5): ";
        for (pos = range.first; pos != range.second; ++pos)
        {
            cout << *pos << " ";
        }
        cout << endl;
    }
    執(zhí)行結(jié)果如下:
    col1: 1 2 4 5 5 6 

    lower_bound(3): 4
    upper_bound(3): 4
    equal_range(3): 4 4
    elements with value(3): 

    lower_bound(5): 5
    upper_bound(5): 6
    equal_range(5): 5 6
    elements with value(5): 5 5 

    Assignment
    set和multiset容器只提供最基本的賦值操作:
    • c1 = c2: 把c2的所有元素復(fù)制到c1中,同時c1原有的元素被銷毀。
    • c1.swap(c2): 交換c1和c2的元素。
    • swap(c1, c2): 同上,只不過這是一個通用算法。
    需要注意的是兩個容器的類型要一致(包括元素類型和排序法則類型)。

    Inserting and Removing Elements
    set和multiset容器的插入和刪除元素接口跟其他容器也非常類似,但在細節(jié)上卻存在差別。
    • c.insert(elem): 在容器中插入元素elem的一份拷貝,并返回新元素的iterator位置;如果是set容器,同時還返回是否插入成功的標志。
    • c.insert(pos, elem): 在容器中插入元素elem的一份拷貝,并返回新元素的iterator位置;因為set和multiset容器的元素是自動排序的,所以pos位置只是插入位置的一個提示,設(shè)置恰當?shù)脑挘梢蕴岣卟迦朐氐男省?/span>
    • c.insert(beg, end): 在容器中插入[beg, end)范圍中所有元素的拷貝,沒有返回值。
    • c.erase(val): 刪除容器中所有值為val的元素,返回刪除元素的數(shù)目。
    • c.erase(pos): 刪除容器中位置pos處的元素,沒有返回值。
    • c.erase(beg, end): 刪除容器中[ben, end)范圍內(nèi)所有的元素,沒有返回值。
    • c.clear(): 刪除容器中所有元素,使容器成為空容器。

    其中我們重點說一下c.insert(elem)接口。
    對于set容器,它的定義如下:
    pair<iterator, bool> insert(const TYPE& val);
    而對于multiset容器,它的定義如下:
    iterator insert(const TYPE& val);
    它 們的不同就是set容器的insert接口返回的是一個pair<iterator, bool>,而multiset容器的insert接口直接返回一個iterator。這是因為set容器中不允許有重復(fù)的元素,如果容器中已經(jīng)存 在一個跟插入值相同的元素,那么插入操作就會失敗,而pair中的bool值就是標識插入是否成功的。而multiset不存在這個問題。

    3 set和multiset容器的異常處理
    因為set和multiset容器的獨特內(nèi)部結(jié)構(gòu),當發(fā)生異常時,也可以把影響減到最小。也就是說,跟list容器一樣,set和multiset容器的操作要么成功,要么對原有容器沒有影響。

    4 運行時指定排序法則
    通常情況下,我們是在定義容器時指定排序法則,就像下面形式:
    std::set<int, greater<int> > col1;
    或者
    std::set<int> col1;    //use default sorting criterion less<>

    然而,如果你需要在運行時動態(tài)指定容器的排序法則,或者你希望對于相同的容器類型卻有著不同的排序法則,那么就要做一些特殊處理。下面我們看一個例子:
    #include <iostream>
    #include <set>
    #include "print.hpp"
    using namespace std;

    template <typename T>
    class RuntimeCmp 
    {
        public:
            enum cmp_mode {normal, reverse};
        private:
            cmp_mode mode;
        public:
            RuntimeCmp(cmp_mode m = normal) : mode(m) {}

            bool operator() (const T& t1, const T& t2)
            {
                return mode == normal ? t1 < t2 : t1 > t2;
            }

            bool operator== (const T& rhv) 
            {
                return mode == rhv.mode;
            }
    };

    typedef set<int, RuntimeCmp<int> > IntSet;

    //pre-declare
    void fill(IntSet& col1);

    int main()
    {
        IntSet col1;
        fill(col1);
        PRINT_ELEMENTS(col1, "col1: ");

        RuntimeCmp<int> reverse_cmp(RuntimeCmp<int>::reverse);
        IntSet col2(reverse_cmp);
        fill(col2);
        PRINT_ELEMENTS(col2, "col2: ");

        if (col1 == col2) 
        {
            cout << "col1 and col2 is equal" <<endl;
        }
        else
        {
            if (col1 < col2) 
            {
                cout << "col1 is less than col2" << endl;
            }
            else 
            {
                cout << "col1 is greater than col2" << endl;
            }
        }
        return 0;
    }

    void fill(IntSet& col1) 
    {
        col1.insert(2);
        col1.insert(3);
        col1.insert(6);
        col1.insert(5);
        col1.insert(1);
        col1.insert(4);
    }
    運行結(jié)果如下:
    col1 1 2 3 4 5 6 
    col2 6 5 4 3 2 1 
    col1 is less than col2

    這里例子中,col1和col2有著相同的類型:set<int, RuntimeCmp<int> >,但是它們的排序法則卻不相同,一個升序,一個降序。這都是通過自定義的函數(shù)對象來實現(xiàn)的,所以函數(shù)對象比普通函數(shù)有著更加靈活與強大的控制,可 以滿足一些特殊的需求。

    posted @ 2010-10-29 13:51 xiaoxinchen 閱讀(1781) | 評論 (0)編輯 收藏
      眾所周知,Linux動態(tài)庫的默認搜索路徑是/lib/usr/lib。動態(tài)庫被創(chuàng)建后,一般都復(fù)制到這兩個目錄中。當程序執(zhí)行時需要某動態(tài)庫,并且該動態(tài)庫還未加載到內(nèi)存中,則系統(tǒng)會自動到這兩個默認搜索路徑中去查找相應(yīng)的動態(tài)庫文件,然后加載該文件到內(nèi)存中,這樣程序就可以使用該動態(tài)庫中的函數(shù),以及該動態(tài)庫的其它資源了。在Linux 中,動態(tài)庫的搜索路徑除了默認的搜索路徑外,還可以通過以下三種方法來指定。

    方法一:在配置文件/etc/ld.so.conf中指定動態(tài)庫搜索路徑。

    可以通過編輯配置文件/etc/ld.so.conf來指定動態(tài)庫的搜索路徑,該文件中每行為一個動態(tài)庫搜索路徑。每次編輯完該文件后,都必須運行命令ldconfig使修改后的配置生效。我們通過例1來說明該方法。

    例1:

    我們通過以下命令用源程序pos_conf.c(見程序1)來創(chuàng)建動態(tài)庫 libpos.so,詳細創(chuàng)建過程請參考文[1]。

    # gcc -c pos_conf.c
          # gcc -shared -fPCI -o libpos.so pos_conf.o
          #

    #include <stdio.h>
          void pos()
          {
              printf("/root/test/conf/lib\n");

    }

           程序1: pos_conf.c

    接著通過以下命令編譯main.c(見程序2)生成目標程序pos。

    # gcc -o pos main.c -L. -lpos
          #

    void pos();
          int main()
          {
              pos();
                   return 0;
          }

    程序2: main.c

    然后把庫文件移動到目錄/root/test/conf/lib中。

    # mkdir -p /root/test/conf/lib
          # mv libpos.so /root/test/conf/lib
          #

    最后編輯配置文件/etc/ld.so.conf,在該文件中追加一行"/root/test/conf/lib"。

    運行程序pos試試。

    # ./pos
            ./pos: error while loading shared libraries: libpos.so: cannot open shared object file: No such file or directory
          #

    出錯了,系統(tǒng)未找到動態(tài)庫libpos.so。找找原因,原來在編輯完配置文件/etc/ld.so.conf后,沒有運行命令ldconfig,所以剛才的修改還未生效。我們運行l(wèi)dconfig后再試試。

    # ldconfig
          # ./pos     /root/test/conf/lib
          #

    程序pos運行成功,并且打印出正確結(jié)果。

    方法二:通過環(huán)境變量LD_LIBRARY_PATH指定動態(tài)庫搜索路徑(!)。

    通過設(shè)定環(huán)境變量LD_LIBRARY_PATH也可以指定動態(tài)庫搜索路徑。當通過該環(huán)境變量指定多個動態(tài)庫搜索路徑時,路徑之間用冒號":"分隔。

        不過LD_LIBRARY_PATH的設(shè)定作用是全局的,過多的使用可能會影響到其他應(yīng)用程序的運行,所以多用在調(diào)試。(LD_LIBRARY_PATH的缺陷和使用準則,可以參考《Why LD_LIBRARY_PATH is bad》)。通常情況下推薦還是使用gcc的-R或-rpath選項來在編譯時就指定庫的查找路徑,并且該庫的路徑信息保存在可執(zhí)行文件中,運行時它會直接到該路徑查找?guī)欤苊饬耸褂肔D_LIBRARY_PATH環(huán)境變量查找。

    下面通過例2來說明本方法。

    例2:

    我們通過以下命令用源程序pos_env.c(見程序3)來創(chuàng)建動態(tài)庫libpos.so。

    # gcc -c pos_env.c
          # gcc -shared -fPCI -o libpos.so pos_env.o
          #

    #include <stdio.h>
              void pos()
              {
                    printf("/root/test/env/lib\n");
              }
          程序3: pos_env.c

    測試用的可執(zhí)行文件pos可以使用例1中的得到的目標程序pos,不需要再次編譯。因為pos_conf.c中的函數(shù)pos和pos_env.c中的函數(shù)pos 函數(shù)原型一致,且動態(tài)庫名相同,這就好比修改動態(tài)庫pos后重新創(chuàng)建該庫一樣。這也是使用動態(tài)庫的優(yōu)點之一。

    然后把動態(tài)庫libpos.so移動到目錄/root/test/conf/lib中。

    # mkdir -p /root/test/env/lib
          # mv libpos.so /root/test/env/lib
          #

    我們可以使用export來設(shè)置該環(huán)境變量,在設(shè)置該環(huán)境變量后所有的命令中,該環(huán)境變量都有效。

    例如:

    # export LD_LIBRARY_PATH=/root/test/env/lib
          #

    但本文為了舉例方便,使用另一種設(shè)置環(huán)境變量的方法,既在命令前加環(huán)境變量設(shè)置,該環(huán)境變量只對該命令有效,當該命令執(zhí)行完成后,該環(huán)境變量就無效了。如下述命令:

    # LD_LIBRARY_PATH=/root/test/env/lib ./pos  /root/test/env/lib
          #

    程序pos運行成功,并且打印的結(jié)果是"/root/test/env/lib",正是程序pos_env.c中的函數(shù)pos的運行結(jié)果。因此程序pos搜索到的動態(tài)庫是/root/test/env/lib/libpos.so。

    方法三:在編譯目標代碼時指定該程序的動態(tài)庫搜索路徑。

    還可以在編譯目標代碼時指定程序的動態(tài)庫搜索路徑。這是通過gcc 的參數(shù)"-Wl,-rpath,"指定(如例3所示)。當指定多個動態(tài)庫搜索路徑時,路徑之間用冒號":"分隔。

    例3:

    我們通過以下命令用源程序pos.c(見程序4)來創(chuàng)建動態(tài)庫libpos.so。

    # gcc -c pos.c
          # gcc -shared -fPCI -o libpos.so pos.o
          #

    #include <stdio.h>
          void pos()
          {
                    printf("./\n");
          }

          程序4: pos.c

    因為我們需要在編譯目標代碼時指定可執(zhí)行文件的動態(tài)庫搜索路徑,所以需要用gcc命令重新編譯源程序main.c(見程序2)來生成可執(zhí)行文件pos。

    # gcc -o pos main.c -L. -lpos -Wl,-rpath,./
          #

    再運行程序pos試試。

    # ./pos   ./
          #

    程序pos運行成功,輸出的結(jié)果正是pos.c中的函數(shù)pos的運行結(jié)果。因此程序pos搜索到的動態(tài)庫是./libpos.so。

    以上介紹了三種指定動態(tài)庫搜索路徑的方法,加上默認的動態(tài)庫搜索路徑/lib和/usr/lib,共五種動態(tài)庫的搜索路徑,那么它們搜索的先后順序是什么呢?

    在 介紹上述三種方法時,分別創(chuàng)建了動態(tài)庫./libpos.so、 /root/test/env/lib/libpos.so和/root/test/conf/lib/libpos.so。我們再用源程序 pos_lib.c(見程序5)來創(chuàng)建動態(tài)庫/lib/libpos.so,用源程序pos_usrlib.c(見程序6)來創(chuàng)建動態(tài)庫 /usr/lib/libpos.so。

    #include <stdio.h>
          void pos()
          {
                       printf("/lib\n");
          }

          程序5: pos_lib.c

    #include <stdio.h>
          void pos()
          {
                     printf("/usr/lib\n");
          }

          程序6: pos_usrlib.c

    這樣我們得到五個動態(tài)庫libpos.so,這些動態(tài)庫的名字相同,且都包含相同函數(shù)原型的公用函數(shù)pos。但存儲的位置不同和公用函數(shù)pos 打印的結(jié)果不同。每個動態(tài)庫中的公用函數(shù)pos都輸出該動態(tài)庫所存放的位置。這樣我們可以通過執(zhí)行例3中的可執(zhí)行文件pos得到的結(jié)果不同獲知其搜索到了哪個動態(tài)庫,從而獲得第1個動態(tài)庫搜索順序,然后刪除該動態(tài)庫,再執(zhí)行程序pos,獲得第2個動態(tài)庫搜索路徑,再刪除第2個被搜索到的動態(tài)庫,如此往復(fù),將可得到Linux搜索動態(tài)庫的先后順序。程序pos執(zhí)行的輸出結(jié)果和搜索到的動態(tài)庫的對應(yīng)關(guān)系如表1所示:

    程序pos輸出結(jié)果 使用的動態(tài)庫 對應(yīng)的動態(tài)庫搜索路徑指定方式
    ./ ./libpos.so 編譯目標代碼時指定的動態(tài)庫搜索路徑
    /root/test/env/lib /root/test/env/lib/libpos.so 環(huán)境變量LD_LIBRARY_PATH指定的動態(tài)庫搜索路徑
    /root/test/conf/lib /root/test/conf/lib/libpos.so 配置文件/etc/ld.so.conf中指定的動態(tài)庫搜索路徑
    /lib /lib/libpos.so 默認的動態(tài)庫搜索路徑/lib
    /usr/lib /usr/lib/libpos.so 默認的動態(tài)庫搜索路徑/usr/lib
    表1: 程序pos輸出結(jié)果和動態(tài)庫的對應(yīng)關(guān)系

    創(chuàng)建各個動態(tài)庫,并放置在相應(yīng)的目錄中。測試環(huán)境就準備好了。執(zhí)行程序pos,并在該命令行中設(shè)置環(huán)境變量LD_LIBRARY_PATH。

    # LD_LIBRARY_PATH=/root/test/env/lib ./pos  ./
          #

    根據(jù)程序pos的輸出結(jié)果可知,最先搜索的是編譯目標代碼時指定的動態(tài)庫搜索路徑。然后我們把動態(tài)庫./libpos.so刪除了,再運行上述命令試試。

    # rm libpos.so
            rm: remove regular file `libpos.so'? y
          # LD_LIBRARY_PATH=/root/test/env/lib ./pos /root/test/env/lib
          #

    根據(jù)程序pos的輸出結(jié)果可知,第2個動態(tài)庫搜索的路徑是環(huán)境變量LD_LIBRARY_PATH指定的。我們再把/root/test/env/lib/libpos.so刪除,運行上述命令。

    # rm /root/test/env/lib/libpos.so
            rm: remove regular file `/root/test/env/lib/libpos.so'? y
          # LD_LIBRARY_PATH=/root/test/env/lib ./pos  /root/test/conf/lib
          #

    第3個動態(tài)庫的搜索路徑是配置文件/etc/ld.so.conf指定的路徑。刪除動態(tài)庫/root/test/conf/lib/libpos.so后再運行上述命令。

    # rm /root/test/conf/lib/libpos.so
            rm: remove regular file `/root/test/conf/lib/libpos.so'? y
          # LD_LIBRARY_PATH=/root/test/env/lib ./pos  /lib
          #

    第4個動態(tài)庫的搜索路徑是默認搜索路徑/lib。我們再刪除動態(tài)庫/lib/libpos.so,運行上述命令。

    # rm /lib/libpos.so
            rm: remove regular file `/lib/libpos.so'? y
          # LD_LIBRARY_PATH=/root/test/env/lib ./pos  /usr/lib
          #

    最后的動態(tài)庫搜索路徑是默認搜索路徑/usr/lib。

    綜合以上結(jié)果可知,動態(tài)庫的搜索路徑搜索的先后順序是:

    1.編譯目標代碼時指定的動態(tài)庫搜索路徑;

    2.環(huán)境變量LD_LIBRARY_PATH指定的動態(tài)庫搜索路徑;

    3.配置文件/etc/ld.so.conf中指定的動態(tài)庫搜索路徑;

    4.默認的動態(tài)庫搜索路徑/lib;

    5.默認的動態(tài)庫搜索路徑/usr/lib。

    在上述1、2、3指定動態(tài)庫搜索路徑時,都可指定多個動態(tài)庫搜索路徑,其搜索的先后順序是按指定路徑的先后順序搜索的。對此本文不再舉例說明,有興趣的讀者可以參照本文的方法驗證。

    posted @ 2010-09-14 11:03 xiaoxinchen 閱讀(226) | 評論 (0)編輯 收藏

    序論
    我曾發(fā)表過文件輸入輸出的文章,現(xiàn)在覺得有必要再寫一點。文件 I/O 在C++中比烤蛋糕簡單多了。 在這篇文章里,我會詳細解釋ASCII和二進制文件的輸入輸出的每個細節(jié),值得注意的是,所有這些都是用C++完成的。

    一、ASCII 輸出
    為了使用下面的方法, 你必須包含頭文件<fstream.h>(譯者注:在標準C++中,已經(jīng)使用<fstream>取 代<fstream.h>,所有的C++標準頭文件都是無后綴的。)。這是 <iostream.h>的一個擴展集, 提供有緩沖的文件輸入輸出操作. 事實上, <iostream.h> 已經(jīng)被<fstream.h>包含了, 所以你不必包含所有這兩個文件, 如果你想顯式包含他們,那隨便你。我們從文件操作類的設(shè)計開始, 我會講解如何進行ASCII I/O操作。 如果你猜是"fstream," 恭喜你答對了! 但這篇文章介紹的方法,我們分別使用"ifstream"?和 "ofstream" 來作輸入輸出。
    如果你用過標準控制臺流"cin"?和 "cout," 那現(xiàn)在的事情對你來說很簡單。 我們現(xiàn)在開始講輸出部分,首先聲明一個類對象。

    ofstream fout; 

    這就可以了,不過你要打開一個文件的話, 必須像這樣調(diào)用ofstream::open()。

    fout.open("output.txt"); 

    你也可以把文件名作為構(gòu)造參數(shù)來打開一個文件.

    ofstream fout("output.txt");

      這是我們使用的方法, 因為這樣創(chuàng)建和打開一個文件看起來更簡單. 順便說一句, 如果你要打開的文件不存在,它會為你創(chuàng)建一個, 所以不用擔(dān)心文件創(chuàng)建的問題. 現(xiàn)在就輸出到文件,看起來和"cout"的操作很像。 對不了解控制臺輸出"cout"的人, 這里有個例子。

    int num = 150;char name[] = "John Doe";fout << "Here is a number: " << num << "\n";fout << "Now here is a string: " << name << "\n";

      現(xiàn)在保存文件,你必須關(guān)閉文件,或者回寫文件緩沖. 文件關(guān)閉之后就不能再操作了, 所以只有在你不再操作這個文件的時候才調(diào)用它,它會自動保存文件。 回寫緩沖區(qū)會在保持文件打開的情況下保存文件, 所以只要有必要就使用它。 回寫看起來像另一次輸出, 然后調(diào)用方法關(guān)閉。像這樣:

    fout << flush; fout.close(); 

    現(xiàn)在你用文本編輯器打開文件,內(nèi)容看起來是這樣:

    Here is a number: 150 Now here is a string: John Doe 

      很簡單吧! 現(xiàn)在繼續(xù)文件輸入, 需要一點技巧, 所以先確認你已經(jīng)明白了流操作,對 "<<" 和">>" 比較熟悉了, 因為你接下來還要用到他們。繼續(xù)…

    二、ASCII 輸入
    輸入和"cin" 流很像. 和剛剛討論的輸出流很像, 但你要考慮幾件事情。在我們開始復(fù)雜的內(nèi)容之前, 先看一個文本:

    12 GameDev 15.45 L This is really awesome! 

    為了打開這個文件,你必須創(chuàng)建一個in-stream對象,?像這樣。

    ifstream fin("input.txt"); 

      現(xiàn)在讀入前四行. 你還記得怎么用"<<" 操作符往流里插入變量和符號吧?好,?在 "<<" (插入)?操作符之后,是">>" (提取) 操作符. 使用方法是一樣的. 看這個代碼片段.

    int number; float real; char letter, word[8]; fin >> number; fin >> word; fin >> real; fin >> letter; 

    也可以把這四行讀取文件的代碼寫為更簡單的一行。

    fin >> number >> word >> real >> letter; 

      它是如何運作的呢? 文件的每個空白之后, ">>" 操作符會停止讀取內(nèi)容, 直到遇到另一個>>操作符. 因為我們讀取的每一行都被換行符分割開(是空白字符), ">>" 操作符只把這一行的內(nèi)容讀入變量。這就是這個代碼也能正常工作的原因。但是,可別忘了文件的最后一行。

    This is really awesome! 

      如果你想把整行讀入一個char數(shù)組, 我們沒辦法用">>"?操作符,因為每個單詞之間的空格(空白字符)會中止文件的讀取。為了驗證:

    char sentence[101]; fin >> sentence; 

      我們想包含整個句子, "This is really awesome!" 但是因為空白, 現(xiàn)在它只包含了"This". 很明顯, 肯定有讀取整行的方法, 它就是getline()。這就是我們要做的。

    fin.getline(sentence, 100); 

      這是函數(shù)參數(shù). 第一個參數(shù)顯然是用來接受的char數(shù)組. 第二個參數(shù)是在遇到換行符之前,數(shù)組允許接受的最大元素數(shù)量. 現(xiàn)在我們得到了想要的結(jié)果:“This is really awesome!”。
    你應(yīng)該已經(jīng)知道如何讀取和寫入ASCII文件了。但我們還不能罷休,因為二進制文件還在等著我們。

    三、二進制 輸入輸出
    二進制文件會復(fù)雜一點, 但還是很簡單的。 首先你要注意我們不再使用插入和提取操作符(譯者注:<< 和 >> 操作符). 你可以這么做,但它不會用二進制方式讀寫。你必須使用read() 和write() 方法讀取和寫入二進制文件. 創(chuàng)建一個二進制文件, 看下一行。

    ofstream fout("file.dat", ios::binary); 

      這會以二進制方式打開文件, 而不是默認的ASCII模式。首先從寫入文件開始。函數(shù)write() 有兩個參數(shù)。 第一個是指向?qū)ο蟮腸har類型的指針, 第二個是對象的大小(譯者注:字節(jié)數(shù))。 為了說明,看例子。

    int number = 30; fout.write((char *)(&number), sizeof(number)); 

      第一個參數(shù)寫做"(char *)(&number)". 這是把一個整型變量轉(zhuǎn)為char *指針。如果你不理解,可以立刻翻閱C++的書籍,如果有必要的話。第二個參數(shù)寫作"sizeof(number)". sizeof() 返回對象大小的字節(jié)數(shù). 就是這樣!
    二進制文件最好的地方是可以在一行把一個結(jié)構(gòu)寫入文件。 如果說,你的結(jié)構(gòu)有12個不同的成員。 用ASCII?文件,你不得不每次一條的寫入所有成員。 但二進制文件替你做好了。 看這個。

    struct OBJECT { int number; char letter; } obj; obj.number = 15;obj.letter = ‘M’; fout.write((char *)(&obj), sizeof(obj)); 

      這樣就寫入了整個結(jié)構(gòu)! 接下來是輸入. 輸入也很簡單,因為read()?函數(shù)的參數(shù)和 write()是完全一樣的, 使用方法也相同。

    ifstream fin("file.dat", ios::binary); fin.read((char *)(&obj), sizeof(obj)); 

      我不多解釋用法, 因為它和write()是完全相同的。二進制文件比ASCII文件簡單, 但有個缺點是無法用文本編輯器編輯。 接著, 我解釋一下ifstream 和ofstream 對象的其他一些方法作為結(jié)束.

    四、更多方法
    我已經(jīng)解釋了ASCII文件和二進制文件, 這里是一些沒有提及的底層方法。

    檢查文件

    你已經(jīng)學(xué)會了open() 和close() 方法, 不過這里還有其它你可能用到的方法。
    方法good() 返回一個布爾值,表示文件打開是否正確。
    類似的,bad() 返回一個布爾值表示文件打開是否錯誤。 如果出錯,就不要繼續(xù)進一步的操作了。
    最后一個檢查的方法是fail(), 和bad()有點相似, 但沒那么嚴重。

    讀文件
    方法get() 每次返回一個字符。
    方法ignore(int,char) 跳過一定數(shù)量的某個字符, 但你必須傳給它兩個參數(shù)。第一個是需要跳過的字符數(shù)。 第二個是一個字符, 當遇到的時候就會停止。 例子,

    fin.ignore(100, ‘\n’); 

    會跳過100個字符,或者不足100的時候,跳過所有之前的字符,包括 ‘\n’。
    方法peek() 返回文件中的下一個字符, 但并不實際讀取它。所以如果你用peek() 查看下一個字符, 用get() 在peek()之后讀取,會得到同一個字符, 然后移動文件計數(shù)器。
    方法putback(char) 輸入字符, 一次一個, 到流中。我沒有見到過它的使用,但這個函數(shù)確實存在。

    寫文件
    只有一個你可能會關(guān)注的方法.?那就是 put(char), 它每次向輸出流中寫入一個字符。

    打開文件
    當我們用這樣的語法打開二進制文件:

    ofstream fout("file.dat", ios::binary); 

      "ios::binary"是你提供的打開選項的額外標志. 默認的, 文件以ASCII方式打開, 不存在則創(chuàng)建, 存在就覆蓋. 這里有些額外的標志用來改變選項。

    ios::app 添加到文件尾
    ios::ate 把文件標志放在末尾而非起始。
    ios::trunc 默認. 截斷并覆寫文件。
    ios::nocreate 文件不存在也不創(chuàng)建。
    ios::noreplace    文件存在則失敗。

    文件狀態(tài)
    我用過的唯一一個狀態(tài)函數(shù)是eof(), 它返回是否標志已經(jīng)到了文件末尾。 我主要用在循環(huán)中。 例如, 這個代碼斷統(tǒng)計小寫‘e’ 在文件中出現(xiàn)的次數(shù)。

    ifstream fin("file.txt"); char ch; int counter; while (!fin.eof()) {      ch = fin.get();       if (ch == ‘e’) counter++; }fin.close(); 

      我從未用過這里沒有提到的其他方法。 還有很多方法,但是他們很少被使用。參考C++書籍或者文件流的幫助文檔來了解其他的方法。

    posted @ 2010-08-08 17:37 xiaoxinchen 閱讀(190) | 評論 (0)編輯 收藏

    什么是Socket
    Socket接口是TCP/IP網(wǎng)絡(luò)的API,Socket接口定義了許多函數(shù)或例程,程序員可以用它們來開發(fā)TCP/IP網(wǎng)絡(luò)上的應(yīng)用程序。要學(xué)Internet上的TCP/IP網(wǎng)絡(luò)編程,必須理解Socket接口。
    Socket接口設(shè)計者最先是將接口放在Unix操作系統(tǒng)里面的。如果了解Unix系統(tǒng)的輸入和輸出的話,就很容易了解Socket了。網(wǎng)絡(luò)的 Socket數(shù)據(jù)傳輸是一種特殊的I/O,Socket也是一種文件描述符。Socket也具有一個類似于打開文件的函數(shù)調(diào)用Socket(),該函數(shù)返 回一個整型的Socket描述符,隨后的連接建立、數(shù)據(jù)傳輸?shù)炔僮鞫际峭ㄟ^該Socket實現(xiàn)的。常用的Socket類型有兩種:流式Socket (SOCK_STREAM)和數(shù)據(jù)報式Socket(SOCK_DGRAM)。流式是一種面向連接的Socket,針對于面向連接的TCP服務(wù)應(yīng)用;數(shù)據(jù) 報式Socket是一種無連接的Socket,對應(yīng)于無連接的UDP服務(wù)應(yīng)用。

    Socket建立
    為了建立Socket,程序可以調(diào)用Socket函數(shù),該函數(shù)返回一個類似于文件描述符的句柄。socket函數(shù)原型為:
    int socket(int domain, int type, int protocol);
    domain指明所使用的協(xié)議族,通常為PF_INET,表示互聯(lián)網(wǎng)協(xié)議族(TCP/IP協(xié)議族);type參數(shù)指定socket的類型: SOCK_STREAM 或SOCK_DGRAM,Socket接口還定義了原始Socket(SOCK_RAW),允許程序使用低層協(xié)議;protocol通常賦值"0"。 Socket()調(diào)用返回一個整型socket描述符,你可以在后面的調(diào)用使用它。
    Socket描述符是一個指向內(nèi)部數(shù)據(jù)結(jié)構(gòu)的指針,它指向描述符表入口。調(diào)用Socket函數(shù)時,socket執(zhí)行體將建立一個Socket,實際上"建立一個Socket"意味著為一個Socket數(shù)據(jù)結(jié)構(gòu)分配存儲空間。Socket執(zhí)行體為你管理描述符表。
    兩個網(wǎng)絡(luò)程序之間的一個網(wǎng)絡(luò)連接包括五種信息:通信協(xié)議、本地協(xié)議地址、本地主機端口、遠端主機地址和遠端協(xié)議端口。Socket數(shù)據(jù)結(jié)構(gòu)中包含這五種信息。

    Socket配置
    通過socket調(diào)用返回一個socket描述符后,在使用socket進行網(wǎng)絡(luò)傳輸以前,必須配置該socket。面向連接的socket客戶端通過 調(diào)用Connect函數(shù)在socket數(shù)據(jù)結(jié)構(gòu)中保存本地和遠端信息。無連接socket的客戶端和服務(wù)端以及面向連接socket的服務(wù)端通過調(diào)用 bind函數(shù)來配置本地信息。
    Bind函數(shù)將socket與本機上的一個端口相關(guān)聯(lián),隨后你就可以在該端口監(jiān)聽服務(wù)請求。Bind函數(shù)原型為:
    int bind(int sockfd,struct sockaddr *my_addr, int addrlen);
    Sockfd是調(diào)用socket函數(shù)返回的socket描述符,my_addr是一個指向包含有本機IP地址及端口號等信息的sockaddr類型的指針;addrlen常被設(shè)置為sizeof(struct sockaddr)。
    struct sockaddr結(jié)構(gòu)類型是用來保存socket信息的:
    struct sockaddr {
    unsigned short sa_family; /* 地址族, AF_xxx */
    char sa_data[14]; /* 14 字節(jié)的協(xié)議地址 */
    };
    sa_family一般為AF_INET,代表Internet(TCP/IP)地址族;sa_data則包含該socket的IP地址和端口號。
    另外還有一種結(jié)構(gòu)類型:
    struct sockaddr_in {
    short int sin_family; /* 地址族 */
    unsigned short int sin_port; /* 端口號 */
    struct in_addr sin_addr; /* IP地址 */
    unsigned char sin_zero[8]; /* 填充0 以保持與struct sockaddr同樣大小 */
    };
    這個結(jié)構(gòu)更方便使用。sin_zero用來將sockaddr_in結(jié)構(gòu)填充到與struct sockaddr同樣的長度,可以用bzero()或memset()函數(shù)將其置為零。指向sockaddr_in 的指針和指向sockaddr的指針可以相互轉(zhuǎn)換,這意味著如果一個函數(shù)所需參數(shù)類型是sockaddr時,你可以在函數(shù)調(diào)用的時候?qū)⒁粋€指向 sockaddr_in的指針轉(zhuǎn)換為指向sockaddr的指針;或者相反。
    使用bind函數(shù)時,可以用下面的賦值實現(xiàn)自動獲得本機IP地址和隨機獲取一個沒有被占用的端口號:
    my_addr.sin_port = 0; /* 系統(tǒng)隨機選擇一個未被使用的端口號 */
    my_addr.sin_addr.s_addr = INADDR_ANY; /* 填入本機IP地址 */
    通過將my_addr.sin_port置為0,函數(shù)會自動為你選擇一個未占用的端口來使用。同樣,通過將my_addr.sin_addr.s_addr置為INADDR_ANY,系統(tǒng)會自動填入本機IP地址。
    注意在使用bind函數(shù)是需要將sin_port和sin_addr轉(zhuǎn)換成為網(wǎng)絡(luò)字節(jié)優(yōu)先順序;而sin_addr則不需要轉(zhuǎn)換。
    計算機數(shù)據(jù)存儲有兩種字節(jié)優(yōu)先順序:高位字節(jié)優(yōu)先和低位字節(jié)優(yōu)先。Internet上數(shù)據(jù)以高位字節(jié)優(yōu)先順序在網(wǎng)絡(luò)上傳輸,所以對于在內(nèi)部是以低位字節(jié)優(yōu)先方式存儲數(shù)據(jù)的機器,在Internet上傳輸數(shù)據(jù)時就需要進行轉(zhuǎn)換,否則就會出現(xiàn)數(shù)據(jù)不一致。
    下面是幾個字節(jié)順序轉(zhuǎn)換函數(shù):
    ·htonl():把32位值從主機字節(jié)序轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)序
    ·htons():把16位值從主機字節(jié)序轉(zhuǎn)換成網(wǎng)絡(luò)字節(jié)序
    ·ntohl():把32位值從網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換成主機字節(jié)序
    ·ntohs():把16位值從網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換成主機字節(jié)序
    Bind()函數(shù)在成功被調(diào)用時返回0;出現(xiàn)錯誤時返回"-1"并將errno置為相應(yīng)的錯誤號。需要注意的是,在調(diào)用bind函數(shù)時一般不要將端口號置為小于1024的值,因為1到1024是保留端口號,你可以選擇大于1024中的任何一個沒有被占用的端口號。

    連接建立
    面向連接的客戶程序使用Connect函數(shù)來配置socket并與遠端服務(wù)器建立一個TCP連接,其函數(shù)原型為:
    int connect(int sockfd, struct sockaddr *serv_addr,int addrlen);
    Sockfd 是socket函數(shù)返回的socket描述符;serv_addr是包含遠端主機IP地址和端口號的指針;addrlen是遠端地質(zhì)結(jié)構(gòu)的長度。 Connect函數(shù)在出現(xiàn)錯誤時返回-1,并且設(shè)置errno為相應(yīng)的錯誤碼。進行客戶端程序設(shè)計無須調(diào)用bind(),因為這種情況下只需知道目的機器 的IP地址,而客戶通過哪個端口與服務(wù)器建立連接并不需要關(guān)心,socket執(zhí)行體為你的程序自動選擇一個未被占用的端口,并通知你的程序數(shù)據(jù)什么時候到 打斷口。
    Connect函數(shù)啟動和遠端主機的直接連接。只有面向連接的客戶程序使用socket時才需要將此socket與遠端主機相連。無連接協(xié)議從不建立直接連接。面向連接的服務(wù)器也從不啟動一個連接,它只是被動的在協(xié)議端口監(jiān)聽客戶的請求。
    Listen函數(shù)使socket處于被動的監(jiān)聽模式,并為該socket建立一個輸入數(shù)據(jù)隊列,將到達的服務(wù)請求保存在此隊列中,直到程序處理它們。
    int listen(int sockfd, int backlog);
    Sockfd 是Socket系統(tǒng)調(diào)用返回的socket 描述符;backlog指定在請求隊列中允許的最大請求數(shù),進入的連接請求將在隊列中等待accept()它們(參考下文)。Backlog對隊列中等待 服務(wù)的請求的數(shù)目進行了限制,大多數(shù)系統(tǒng)缺省值為20。如果一個服務(wù)請求到來時,輸入隊列已滿,該socket將拒絕連接請求,客戶將收到一個出錯信息。
    當出現(xiàn)錯誤時listen函數(shù)返回-1,并置相應(yīng)的errno錯誤碼。
    accept()函數(shù)讓服務(wù)器接收客戶的連接請求。在建立好輸入隊列后,服務(wù)器就調(diào)用accept函數(shù),然后睡眠并等待客戶的連接請求。
    int accept(int sockfd, void *addr, int *addrlen);
    sockfd是被監(jiān)聽的socket描述符,addr通常是一個指向sockaddr_in變量的指針,該變量用來存放提出連接請求服務(wù)的主機的信息(某 臺主機從某個端口發(fā)出該請求);addrten通常為一個指向值為sizeof(struct sockaddr_in)的整型指針變量。出現(xiàn)錯誤時accept函數(shù)返回-1并置相應(yīng)的errno值。
    首先,當accept函數(shù)監(jiān)視的 socket收到連接請求時,socket執(zhí)行體將建立一個新的socket,執(zhí)行體將這個新socket和請求連接進程的地址聯(lián)系起來,收到服務(wù)請求的 初始socket仍可以繼續(xù)在以前的 socket上監(jiān)聽,同時可以在新的socket描述符上進行數(shù)據(jù)傳輸操作。

    數(shù)據(jù)傳輸
    Send()和recv()這兩個函數(shù)用于面向連接的socket上進行數(shù)據(jù)傳輸。
    Send()函數(shù)原型為:
    int send(int sockfd, const void *msg, int len, int flags);
    Sockfd是你想用來傳輸數(shù)據(jù)的socket描述符;msg是一個指向要發(fā)送數(shù)據(jù)的指針;Len是以字節(jié)為單位的數(shù)據(jù)的長度;flags一般情況下置為0(關(guān)于該參數(shù)的用法可參照man手冊)。
    Send()函數(shù)返回實際上發(fā)送出的字節(jié)數(shù),可能會少于你希望發(fā)送的數(shù)據(jù)。在程序中應(yīng)該將send()的返回值與欲發(fā)送的字節(jié)數(shù)進行比較。當send()返回值與len不匹配時,應(yīng)該對這種情況進行處理。
    char *msg = "Hello!";
    int len, bytes_sent;
    ……
    len = strlen(msg);
    bytes_sent = send(sockfd, msg,len,0);
    ……
    recv()函數(shù)原型為:
    int recv(int sockfd,void *buf,int len,unsigned int flags);
    Sockfd是接受數(shù)據(jù)的socket描述符;buf 是存放接收數(shù)據(jù)的緩沖區(qū);len是緩沖的長度。Flags也被置為0。Recv()返回實際上接收的字節(jié)數(shù),當出現(xiàn)錯誤時,返回-1并置相應(yīng)的errno值。
    Sendto()和recvfrom()用于在無連接的數(shù)據(jù)報socket方式下進行數(shù)據(jù)傳輸。由于本地socket并沒有與遠端機器建立連接,所以在發(fā)送數(shù)據(jù)時應(yīng)指明目的地址。
    sendto()函數(shù)原型為:
    int sendto(int sockfd, const void *msg,int len,unsigned int flags,const struct sockaddr *to, int tolen);
    該函數(shù)比send()函數(shù)多了兩個參數(shù),to表示目地機的IP地址和端口號信息,而tolen常常被賦值為sizeof (struct sockaddr)。Sendto 函數(shù)也返回實際發(fā)送的數(shù)據(jù)字節(jié)長度或在出現(xiàn)發(fā)送錯誤時返回-1。
    Recvfrom()函數(shù)原型為:
    int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int *fromlen);
    from是一個struct sockaddr類型的變量,該變量保存源機的IP地址及端口號。fromlen常置為sizeof (struct sockaddr)。當recvfrom()返回時,fromlen包含實際存入from中的數(shù)據(jù)字節(jié)數(shù)。Recvfrom()函數(shù)返回接收到的字節(jié)數(shù)或 當出現(xiàn)錯誤時返回-1,并置相應(yīng)的errno。
    如果你對數(shù)據(jù)報socket調(diào)用了connect()函數(shù)時,你也可以利用send()和recv()進行數(shù)據(jù)傳輸,但該socket仍然是數(shù)據(jù)報socket,并且利用傳輸層的UDP服務(wù)。但在發(fā)送或接收數(shù)據(jù)報時,內(nèi)核會自動為之加上目地和源地址信息。

    結(jié)束傳輸
    當所有的數(shù)據(jù)操作結(jié)束以后,你可以調(diào)用close()函數(shù)來釋放該socket,從而停止在該socket上的任何數(shù)據(jù)操作:
    close(sockfd);
    你也可以調(diào)用shutdown()函數(shù)來關(guān)閉該socket。該函數(shù)允許你只停止在某個方向上的數(shù)據(jù)傳輸,而一個方向上的數(shù)據(jù)傳輸繼續(xù)進行。如你可以關(guān)閉某socket的寫操作而允許繼續(xù)在該socket上接受數(shù)據(jù),直至讀入所有數(shù)據(jù)。
    int shutdown(int sockfd,int how);
    Sockfd是需要關(guān)閉的socket的描述符。參數(shù) how允許為shutdown操作選擇以下幾種方式:
    ·0-------不允許繼續(xù)接收數(shù)據(jù)
    ·1-------不允許繼續(xù)發(fā)送數(shù)據(jù)
    ·2-------不允許繼續(xù)發(fā)送和接收數(shù)據(jù),
    ·均為允許則調(diào)用close ()
    shutdown在操作成功時返回0,在出現(xiàn)錯誤時返回-1并置相應(yīng)errno。

    Socket編程實例
    代碼實例中的服務(wù)器通過socket連接向客戶端發(fā)送字符串"Hello, you are connected!"。只要在服務(wù)器上運行該服務(wù)器軟件,在客戶端運行客戶軟件,客戶端就會收到該字符串。
    該服務(wù)器軟件代碼如下:
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    #include <sys/wait.h>
    #define SERVPORT 3333 /*服務(wù)器監(jiān)聽端口號 */
    #define BACKLOG 10 /* 最大同時連接請求數(shù) */
    main()
    {
    int sockfd,client_fd; /*sock_fd:監(jiān)聽socket;client_fd:數(shù)據(jù)傳輸socket */
    struct sockaddr_in my_addr; /* 本機地址信息 */
    struct sockaddr_in remote_addr; /* 客戶端地址信息 */
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    perror("socket創(chuàng)建出錯!"); exit(1);
    }
    my_addr.sin_family=AF_INET;
    my_addr.sin_port=htons(SERVPORT);
    my_addr.sin_addr.s_addr = INADDR_ANY;
    bzero(&(my_addr.sin_zero),8);
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
    perror("bind出錯!");
    exit(1);
    }
    if (listen(sockfd, BACKLOG) == -1) {
    perror("listen出錯!");
    exit(1);
    }
    while(1) {
    sin_size = sizeof(struct sockaddr_in);
    if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size)) == -1) {
    perror("accept出錯");
    continue;
    }
    printf("received a connection from %s\n", inet_ntoa(remote_addr.sin_addr));
    if (!fork()) { /* 子進程代碼段 */
    if (send(client_fd, "Hello, you are connected!\n", 26, 0) == -1)
    perror("send出錯!");
    close(client_fd);
    exit(0);
    }
    close(client_fd);
    }
    }
    }
    服務(wù)器的工作流程是這樣的:首先調(diào)用socket函數(shù)創(chuàng)建一個Socket,然后調(diào)用bind函數(shù)將其與本機地址以及一個本地端口號綁定,然后調(diào)用 listen在相應(yīng)的socket上監(jiān)聽,當accpet接收到一個連接服務(wù)請求時,將生成一個新的socket。服務(wù)器顯示該客戶機的IP地址,并通過 新的socket向客戶端發(fā)送字符串"Hello,you are connected!"。最后關(guān)閉該socket。
    代碼實例中的fork()函數(shù)生成一個子進程來處理數(shù)據(jù)傳輸部分,fork()語句對于子進程返回的值為0。所以包含fork函數(shù)的if語句是子進程代碼部分,它與if語句后面的父進程代碼部分是并發(fā)執(zhí)行的。

    客戶端程序代碼如下:
    #include<stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    #include <netdb.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    #define SERVPORT 3333
    #define MAXDATASIZE 100 /*每次最大數(shù)據(jù)傳輸量 */
    main(int argc, char *argv[]){
    int sockfd, recvbytes;
    char buf[MAXDATASIZE];
    struct hostent *host;
    struct sockaddr_in serv_addr;
    if (argc < 2) {
    fprintf(stderr,"Please enter the server's hostname!\n");
    exit(1);
    }
    if((host=gethostbyname(argv[1]))==NULL) {
    herror("gethostbyname出錯!");
    exit(1);
    }
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
    perror("socket創(chuàng)建出錯!");
    exit(1);
    }
    serv_addr.sin_family=AF_INET;
    serv_addr.sin_port=htons(SERVPORT);
    serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
    bzero(&(serv_addr.sin_zero),8);
    if (connect(sockfd, (struct sockaddr *)&serv_addr, \
    sizeof(struct sockaddr)) == -1) {
    perror("connect出錯!");
    exit(1);
    }
    if ((recvbytes=recv(sockfd, buf, MAXDATASIZE, 0)) ==-1) {
    perror("recv出錯!");
    exit(1);
    }
    buf[recvbytes] = '\0';
    printf("Received: %s",buf);
    close(sockfd);
    }
    客戶端程序首先通過服務(wù)器域名獲得服務(wù)器的IP地址,然后創(chuàng)建一個socket,調(diào)用connect函數(shù)與服務(wù)器建立連接,連接成功之后接收從服務(wù)器發(fā)送過來的數(shù)據(jù),最后關(guān)閉socket。
    函數(shù)gethostbyname()是完成域名轉(zhuǎn)換的。由于IP地址難以記憶和讀寫,所以為了方便,人們常常用域名來表示主機,這就需要進行域名和IP地址的轉(zhuǎn)換。函數(shù)原型為:
    struct hostent *gethostbyname(const char *name);
    函數(shù)返回為hosten的結(jié)構(gòu)類型,它的定義如下:
    struct hostent {
    char *h_name; /* 主機的官方域名 */
    char **h_aliases; /* 一個以NULL結(jié)尾的主機別名數(shù)組 */
    int h_addrtype; /* 返回的地址類型,在Internet環(huán)境下為AF-INET */
    int h_length; /* 地址的字節(jié)長度 */
    char **h_addr_list; /* 一個以0結(jié)尾的數(shù)組,包含該主機的所有地址*/
    };
    #define h_addr h_addr_list[0] /*在h-addr-list中的第一個地址*/
    當 gethostname()調(diào)用成功時,返回指向struct hosten的指針,當調(diào)用失敗時返回-1。當調(diào)用gethostbyname時,你不能使用perror()函數(shù)來輸出錯誤信息,而應(yīng)該使用herror()函數(shù)來輸出。

      無連接的客戶/服務(wù)器程序的在原理上和連接的客戶/服務(wù)器是一樣的,兩者的區(qū)別在于無連接的客戶/服務(wù)器中的客戶一般不需要建立連接,而且在發(fā)送接收數(shù)據(jù)時,需要指定遠端機的地址。

    阻塞和非阻塞
    阻塞函數(shù)在完成其指定的任務(wù)以前不允許程序調(diào)用另一個函數(shù)。例如,程序執(zhí)行一個讀數(shù)據(jù)的函數(shù)調(diào)用時,在此函數(shù)完成讀操作以前將不會執(zhí)行下一程序語句。當 服務(wù)器運行到accept語句時,而沒有客戶連接服務(wù)請求到來,服務(wù)器就會停止在accept語句上等待連接服務(wù)請求的到來。這種情況稱為阻塞 (blocking)。而非阻塞操作則可以立即完成。比如,如果你希望服務(wù)器僅僅注意檢查是否有客戶在等待連接,有就接受連接,否則就繼續(xù)做其他事情,則 可以通過將Socket設(shè)置為非阻塞方式來實現(xiàn)。非阻塞socket在沒有客戶在等待時就使accept調(diào)用立即返回。
    #include <unistd.h>
    #include <fcntl.h>
    ……
    sockfd = socket(AF_INET,SOCK_STREAM,0);
    fcntl(sockfd,F_SETFL,O_NONBLOCK);
    ……
    通過設(shè)置socket為非阻塞方式,可以實現(xiàn)"輪詢"若干Socket。當企圖從一個沒有數(shù)據(jù)等待處理的非阻塞Socket讀入數(shù)據(jù)時,函數(shù)將立即返 回,返回值為-1,并置errno值為EWOULDBLOCK。但是這種"輪詢"會使CPU處于忙等待方式,從而降低性能,浪費系統(tǒng)資源。而調(diào)用 select()會有效地解決這個問題,它允許你把進程本身掛起來,而同時使系統(tǒng)內(nèi)核監(jiān)聽所要求的一組文件描述符的任何活動,只要確認在任何被監(jiān)控的文件 描述符上出現(xiàn)活動,select()調(diào)用將返回指示該文件描述符已準備好的信息,從而實現(xiàn)了為進程選出隨機的變化,而不必由進程本身對輸入進行測試而浪費 CPU開銷。Select函數(shù)原型為:
    int select(int numfds,fd_set *readfds,fd_set *writefds,
    fd_set *exceptfds,struct timeval *timeout);
    其中readfds、writefds、exceptfds分別是被select()監(jiān)視的讀、寫和異常處理的文件描述符集合。如果你希望確定是否可以 從標準輸入和某個socket描述符讀取數(shù)據(jù),你只需要將標準輸入的文件描述符0和相應(yīng)的sockdtfd加入到readfds集合中;numfds的值 是需要檢查的號碼最高的文件描述符加1,這個例子中numfds的值應(yīng)為sockfd+1;當select返回時,readfds將被修改,指示某個文件 描述符已經(jīng)準備被讀取,你可以通過FD_ISSSET()來測試。為了實現(xiàn)fd_set中對應(yīng)的文件描述符的設(shè)置、復(fù)位和測試,它提供了一組宏:
    FD_ZERO(fd_set *set)----清除一個文件描述符集;
    FD_SET(int fd,fd_set *set)----將一個文件描述符加入文件描述符集中;
    FD_CLR(int fd,fd_set *set)----將一個文件描述符從文件描述符集中清除;
    FD_ISSET(int fd,fd_set *set)----試判斷是否文件描述符被置位。
    Timeout參數(shù)是一個指向struct timeval類型的指針,它可以使select()在等待timeout長時間后沒有文件描述符準備好即返回。struct timeval數(shù)據(jù)結(jié)構(gòu)為:
    struct timeval {
    int tv_sec; /* seconds */
    int tv_usec; /* microseconds */
    };

    POP3客戶端實例
    下面的代碼實例基于POP3的客戶協(xié)議,與郵件服務(wù)器連接并取回指定用戶帳號的郵件。與郵件服務(wù)器交互的命令存儲在字符串數(shù)組POPMessage中,程序通過一個do-while循環(huán)依次發(fā)送這些命令。
    #include<stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    #include <netdb.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    #define POP3SERVPORT 110
    #define MAXDATASIZE 4096

    main(int argc, char *argv[]){
    int sockfd;
    struct hostent *host;
    struct sockaddr_in serv_addr;
    char *POPMessage[]={
    "USER userid\r\n",
    "PASS password\r\n",
    "STAT\r\n",
    "LIST\r\n",
    "RETR 1\r\n",
    "DELE 1\r\n",
    "QUIT\r\n",
    NULL
    };
    int iLength;
    int iMsg=0;
    int iEnd=0;
    char buf[MAXDATASIZE];

    if((host=gethostbyname("your.server"))==NULL) {
    perror("gethostbyname error");
    exit(1);
    }
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
    perror("socket error");
    exit(1);
    }
    serv_addr.sin_family=AF_INET;
    serv_addr.sin_port=htons(POP3SERVPORT);
    serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
    bzero(&(serv_addr.sin_zero),8);
    if (connect(sockfd, (struct sockaddr *)&serv_addr,sizeof(struct sockaddr))==-1){
    perror("connect error");
    exit(1);
    }

    do {
    send(sockfd,POPMessage[iMsg],strlen(POPMessage[iMsg]),0);
    printf("have sent: %s",POPMessage[iMsg]);

    iLength=recv(sockfd,buf+iEnd,sizeof(buf)-iEnd,0);
    iEnd+=iLength;
    buf[iEnd]='\0';
    printf("received: %s,%d\n",buf,iMsg);

    iMsg++;
    } while (POPMessage[iMsg]);

    close(sockfd);
    }

    來自:Li

    posted @ 2010-03-21 21:01 xiaoxinchen 閱讀(226) | 評論 (0)編輯 收藏
    總體思路是先打成jar再把jar打成exe。主要看1.3和2.3里的內(nèi)容就可以了。


    1.將項目打成jar:


    1.1 要將項目打包成jar文件,方法很多,可以用Eclipse自帶的打包工具Ant打包,也可以用Eclipse的Export生成jar。經(jīng)過嘗試后,我 不推薦用Ant打包,因為要自己編寫xml腳本語言,還要增加一些外部的jar,所以我打了好幾次都沒打成。


    1.2 在這里介紹兩種方法生成jar,第一種是用Eclpise的Export功能。在要打包的項目上擊右鍵,選擇Export,在窗口中選擇Java里的 JAR file。Next后的窗口中已經(jīng)自動選好了要打包的項目,用戶可以點擊加號查看項目里被打包的內(nèi)容。在下面的JAR file里設(shè)置你打包生成jar文件的輸出目錄,下一步在出現(xiàn)的窗口中選擇Use existing manifest from workspace,在下面的Main class后面直接點Browse,它會自動列出你項目中有主函數(shù)main的類。選擇主類后點Finish即可生成jar文件。在此說明一下,這種打包方 法不能把項目中的外部的jar包打進來,因該是也要編寫一些腳本語言,沒往深研究。所以生成后的jar有些是不能執(zhí)行的。


    1.3 第二種方法是利用Eclipse的一個第三方插件fatjar生成jar文件,也是本人覺得最簡單最方便的一種生成方式。先從網(wǎng)上下載些 插件,解壓后是一個plugins的文件夾,里面只有一個文件夾,我的是“net.sf.fjep.fatjar_0.0.24”將它copy到 Eclipser plugins文件夾下,此插件就安裝成功了,重啟Eclipse在項目上右擊就會看到多出一個“Build Fat Jar”在前面有個綠色的“+”號,這時你就可以用此插件打包你的項目了。進去后第一個界面Jar-Name里增入要生成的jar文件名,我的是 “CAMP_fat.jar”。在Main-Class后點Browse像Export一樣它也會列出你項目中的主類,選擇后其它默認即可,Next后會 列出你要打包的所有內(nèi)容,這個插件的優(yōu)勢就是可以將你項目中的外部jar也打進來,有三個先項,其中Export ANT是生成build.xml腳本文件,方便用戶以后修改腳本,其它兩個按鈕沒用。在這里什么都不點,直接點Finish就可以生成jar文件。


    2.將jar打成.exe文件:


    2.1 雖然此時的jar文件已經(jīng)可以執(zhí)行了。生成.exe的文件我也是用兩種方法實現(xiàn)的,用到的打包工具是j2ewiz和exe4j,它們的不同會在我下面的介 紹中體現(xiàn)出來。


    2.2 首先是j2ewiz,這個軟件是綠色的,不用安裝,解壓后可以直接運行,但這個軟件生成的 .exe文件不是跨平臺的。運行此程序首先就是輸入要打包的jar文件,我們?yōu)g覽JAR選擇我們之前用fatjar生成的“CAMP_fat.jar”項 目文件(詳見1.3),下面那個選項是提示用戶最低要求的JRE版本,一般選1.3。下一步,因為我們的寢室管理系統(tǒng)是圖形界面,所以在這里選 “Windows窗口程序”下一步它也是自動生成要執(zhí)行的主類,你只要選擇就可以。下面的選框可以選擇你啟動程序顯示的圖片。下一步后這個窗可按個人喜好 選擇。下一步,如果你的程序還有什么依賴的外部jar文件,可以從這里加上,但因為之前的fatjar以經(jīng)將我們項目所用的那三個連數(shù)據(jù)庫的外部類打進 CAMP_fat.jar包里了,所以這里不用再添加。如果你之前是用Export打的jar 包,那么這里就需要再把那個三個數(shù)據(jù)庫的包加進來了(詳見1.2)。下一步是添入要生成的.exe文件名,再選一個程序圖標就可以了,下一步后生 成.exe文件,點完成。雙擊生成的.exe文件就能看到運行效果了,這種exe文件還沒有脫離JDK環(huán)境,還不能跨平臺使用,只能用于小組成員測試使 用。


    2.3 下面進入最關(guān)鍵的,如何打包跨平臺的.exe文件。用到的軟件是exe4j,我用的是V4.0版的,此軟件需要破解。安裝后運行左窗窗口標有十步,其實打 包過程也非常簡單。第一步完全略過,直接點Next第二步我們選擇“JAR in EXE mode” 就是選擇我們已經(jīng)有制作好的jar文件。第3步上面是項目名稱,可隨便填寫,下面一個寫出你想要將打包后的exe文件輸出的目錄我的是“桌 面\project\”。第4步,由于我的演示程序是圖形的,所以選第一個,如果你的程序是控制臺的,則選擇第二個,Executable name寫你將要生成的.exe文件的名字,Icon File可以選擇生成文件的圖標。第5步,先別管上面的,先在下面單擊綠色的“+”號,在彈出的窗口中點Archive,然后找到起初已經(jīng)做好的 CAMP_fat.jar(詳見1.3)文件,"OK"后返回,在下面的Class Path里就出現(xiàn)jar文件路徑后,再在上面Main Class欄內(nèi)點擊找到main所在的類。第6步,你系統(tǒng)的JRE版本,一般是填個1.3,下面填1.6在這里單擊advanced options,選擇search sequence。選這個就是因為我們要把JDK環(huán)境也打包進來,好讓程序能跨平臺使用。首先要從你系統(tǒng)的JDK下的JRE目錄copy到你.exe文件 的輸出目錄下“桌面\project\JRE”,然后回到exe4j中在彈出窗口刪除列表中的所有項。我的是三項,一個注冊表的,一個JAVA環(huán)境變量 的,一個JDK環(huán)境變量的,都不要。然后單擊綠“+”,選擇directory并選擇JRE的根目錄,我的是“桌面\project\JRE”就是 copy后的目錄,選完后exe4j彈出窗口中的Directory里會顯示“.\JRE”。點OK關(guān)閉該窗口,返回exe4j的主窗口,你就可以看到剛 加的路徑。再從主窗口左側(cè)窗口中單擊advanced options,并選擇preferred VM,在彈出的窗口中選擇client hostspot VM,單擊next按鈕繼續(xù)。7、8步是一些個性設(shè)置默認即可。第9步編譯完后第10步你點那個“Click Here to Start the Application”按鈕就可以看到程序運行效果了,然后再點”Seave as”保存一個exe4j生成的一個文件,隨便存哪里都行,和我們的.exe程序無關(guān)。全部制作過程就完工了。
    posted @ 2010-03-13 18:06 xiaoxinchen 閱讀(3914) | 評論 (0)編輯 收藏
    首先要弄清楚,在Linux系統(tǒng)中,內(nèi)核為每一個新創(chuàng)建的文件分配一個Inode(索引結(jié)點),每個文件都有一個惟一的inode號。文件屬性保存在索引結(jié)點里,在訪問文件時,索引結(jié)點被復(fù)制到內(nèi)存在,從而實現(xiàn)文件的快速訪問。

    鏈接是一種在共享文件和訪問它的用戶的若干目錄項之間建立聯(lián)系的一種方法。Linux中包括兩種鏈接:硬鏈接(Hard Link)和軟鏈接(Soft Link),軟鏈接又稱為符號鏈接(Symbolic link)。

    一、軟鏈接(符號鏈接)

    軟鏈接克服了硬鏈接的不足,沒有任何文件系統(tǒng)的限制,任何用戶可以創(chuàng)建指向目錄的符號鏈接。因而現(xiàn)在更為廣泛使用,它具有更大的靈活性,甚至可以跨越不同機器、不同網(wǎng)絡(luò)對文件進行鏈接。

    建立軟鏈接,只要在ln后面加上選項 –s。



    二、硬鏈接

    硬鏈接說白了是一個指針,指向文件索引節(jié)點,系統(tǒng)并不為它重新分配inode。可以用:ln命令來建立硬鏈接。語法

    ln [options] existingfile newfile
    ln[options] existingfile-list directory

    用法: 第一種:為”existingfile”創(chuàng)建硬鏈接,文件名為”newfile”。第二種:在”directory”目錄中, 為”existingfile-list”中包含的所有文件創(chuàng)建一個同名的硬鏈接。常用可選[options] –f 無論”newfile”存在與否,都創(chuàng)建鏈接。-n 如果”newfile”已存在,就不創(chuàng)建鏈接。 
    posted @ 2010-03-11 16:07 xiaoxinchen 閱讀(224) | 評論 (0)編輯 收藏
    (1)Jre 是java runtime environment, 是java程序的運行環(huán)境。既然是運行,當然要包含jvm,也就是大家熟悉的虛擬機啦, 還有所有java類庫的class文件,都在lib目錄下打包成了jar。大家可以自己驗證。至于在windows上的虛擬機是哪個文件呢? 學(xué)過MFC的都知道什么是dll文件吧,那么大家看看jre/bin/client里面是不是有一個jvm.dll呢?那就是虛擬機。

    (2)Jdk 是java development kit,是java的開發(fā)工具包,里面包含了各種類庫和工具。當然也包括了另外一個Jre. 那么為什么要包括另外一個Jre呢?而且jdk/jre/bin同時有client和server兩個文件夾下都包含一個jvm.dll。 說明是有兩個虛擬機的。這一點不知道大家是否注意到了呢?
      相信大家都知道jdk的bin下有各種java程序需要用到的命令,與jre的bin目錄最明顯的區(qū)別就是jdk下才有javac,這一點很好理解,因為 jre只是一個運行環(huán)境而已。與開發(fā)無關(guān),正因為如此,具備開發(fā)功能的jdk自己的jre下才會同時有client性質(zhì)的jvm和server性質(zhì)的jvm, 而僅僅作為運行環(huán)境的jre下只需要client性質(zhì)的jvm.dll就夠了。

    (3)記得在環(huán)境變量path中設(shè)置jdk/bin路徑麼?這應(yīng)該是大家學(xué)習(xí)Java的第一步吧, 老師會告訴大家不設(shè)置的話javac和java是用不了的。確實jdk/bin目錄下包含了所有的命令。可是有沒有人想過我們用的java命令并不是 jdk/bin目錄下的而是jre/bin目錄下的呢?不信可以做一個實驗,大家可以把jdk/bin目錄下的java.exe剪切到別的地方再運行 java程序,發(fā)現(xiàn)了什么?一切OK!
      那么有人會問了?我明明沒有設(shè)置jre/bin目錄到環(huán)境變量中啊?
    試想一下如果java為了提供給大多數(shù)人使用,他們是不需要jdk做開發(fā)的,只需要jre能讓java程序跑起來就可以了,那么每個客戶還需要手 動去設(shè)置環(huán)境變量多麻煩啊?所以安裝jre的時候安裝程序自動幫你把jre的java.exe添加到了系統(tǒng)變量中,驗證的方法很簡單,大家看到了系統(tǒng)環(huán)境 變量的 path最前面有“%SystemRoot%\system32;%SystemRoot%;”這樣的配置,那么再去Windows/system32下 面去看看吧,發(fā)現(xiàn)了什么?有一個java.exe。
      如果強行能夠把jdk/bin挪到system32變量前面,當然也可以迫使使用jdk/jre里面的java,不過除非有必要,我不建議大家這么做。使用單獨的jre跑java程序也算是客戶環(huán)境下的一種測試。 
    posted @ 2010-03-11 12:27 xiaoxinchen 閱讀(278) | 評論 (0)編輯 收藏

    關(guān)于2009年12月全國大學(xué)英語四、六級考試成績發(fā)布時間的通知:

    2009年12月全國大學(xué)英語四、六級考試成績將于 2010年3月3日上午9點發(fā)布。

    成績查詢方式

    網(wǎng)上免費查分:

    網(wǎng)址: cet.99sushe.com

    運營商: 99宿舍網(wǎng)

    客服電話: 010-58699163轉(zhuǎn)867

    收費短信查分(2010年3月3日上午9點開始):

    中國移動、聯(lián)通、電信手機用戶:

    發(fā)送A 加 15位準考證號到 1066335577

    如A123456789012345到 1066335577查詢成績(1元/條,不含通信費)

    特別注意:

    河北省的中國移動手機用戶:發(fā)送 8 加 15位準考證號到 10661660

    如8123456789012345到 10661660 查詢成績(1元/條,不含通信費)

    運營商: 空中網(wǎng)

    客服電話: 010-68083018

    注:2009年12月網(wǎng)考成績發(fā)布方式和日期另行通知。

    全國大學(xué)英語四、六級考試委員會辦公室

    2010年2月24日

    posted @ 2010-03-03 00:50 xiaoxinchen 閱讀(237) | 評論 (0)編輯 收藏
    在許多平臺中,Browser控件皆被做為一個必需的控件給出,并提供了DOM接口,用于訪問Browser的內(nèi)容,相對來說SWT中的Browser控件就比較薄弱,沒有提供DOM的可控制接口,那么,如何和控件所加載的頁面進行交互呢?比如需要在集成web應(yīng)用環(huán)境中實現(xiàn)模仿登陸、自動填表等功能
    SWT中對Browser有不同的實現(xiàn),目前實現(xiàn)的有IE和Mozilla。在Browser的構(gòu)造函數(shù)中根據(jù)不同的平臺和不同的style設(shè)置類決定使用哪個類的實現(xiàn)。

    org.eclipse.swt.browser.Mozilla org.eclipse.swt.browser.IE 是已經(jīng)實現(xiàn)的,而其他的 org.eclipse.swt.browser.Safari org.eclipse.swt.browser.Voyager
    來源:www.va1314.com/bc
    則沒有實現(xiàn)。


    public Browser (Composite parent, int style) {

    super (checkParent (parent), checkStyle (style));

    String platform = SWT.getPlatform ();

    Display display = parent.getDisplay ();

    if ("gtk".equals (platform)) display.setData (NO_INPUT_METHOD, null); //$NON-NLS-1$

    String className = null;

    if ((style & SWT.MOZILLA) != 0) {

    className = "org.eclipse.swt.browser.Mozilla"; //$NON-NLS-1$

    } else {

    if ("win32".equals (platform) || "wpf".equals (platform)) { //$NON-NLS-1$ $NON-NLS-2$

    className = "org.eclipse.swt.browser.IE"; //$NON-NLS-1$

    } else if ("motif".equals (platform)) { //$NON-NLS-1$

    className = "org.eclipse.swt.browser.Mozilla"; //$NON-NLS-1$

    } else if ("gtk".equals (platform)) { //$NON-NLS-1$

    className = "org.eclipse.swt.browser.Mozilla"; //$NON-NLS-1$

    } else if ("carbon".equals (platform)) { //$NON-NLS-1$

    className = "org.eclipse.swt.browser.Safari"; //$NON-NLS-1$

    } else if ("photon".equals (platform)) { //$NON-NLS-1$

    className = "org.eclipse.swt.browser.Voyager"; //$NON-NLS-1$

    } else {

    dispose ();

    SWT.error (SWT.ERROR_NO_HANDLES);

    }

    }



    try {

    Class clazz = Class.forName (className);

    webBrowser = (WebBrowser)clazz.newInstance ();

    } catch (ClassNotFoundException e) {

    } catch (IllegalAccessException e) {

    } catch (InstantiationException e) {

    }

    if (webBrowser == null) {

    dispose ();

    SWT.error (SWT.ERROR_NO_HANDLES);

    }



    webBrowser.setBrowser (this);

    webBrowser.create (parent, style);

    }

    public Browser (Composite parent, int style) {

    super (checkParent (parent), checkStyle (style));

    String platform = SWT.getPlatform ();

    Display display = parent.getDisplay ();

    if ("gtk".equals (platform)) display.setData (NO_INPUT_METHOD, null); //$NON-NLS-1$

    String className = null;

    if ((style & SWT.MOZILLA) != 0) {

    className = "org.eclipse.swt.browser.Mozilla"; //$NON-NLS-1$

    } else {

    if ("win32".equals (platform) || "wpf".equals (platform)) { //$NON-NLS-1$ $NON-NLS-2$

    className = "org.eclipse.swt.browser.IE"; //$NON-NLS-1$

    } else if ("motif".equals (platform)) { //$NON-NLS-1$

    className = "org.eclipse.swt.browser.Mozilla"; //$NON-NLS-1$

    } else if ("gtk".equals (platform)) { //$NON-NLS-1$

    className = "org.eclipse.swt.browser.Mozilla"; //$NON-NLS-1$

    } else if ("carbon".equals (platform)) { //$NON-NLS-1$

    className = "org.eclipse.swt.browser.Safari"; //$NON-NLS-1$

    } else if ("photon".equals (platform)) { //$NON-NLS-1$

    className = "org.eclipse.swt.browser.Voyager"; //$NON-NLS-1$

    } else {

    dispose ();

    SWT.error (SWT.ERROR_NO_HANDLES);

    }

    }



    try {

    Class clazz = Class.forName (className);

    webBrowser = (WebBrowser)clazz.newInstance ();

    } catch (ClassNotFoundException e) {

    } catch (IllegalAccessException e) {

    } catch (InstantiationException e) {

    }

    if (webBrowser == null) {

    dispose ();

    SWT.error (SWT.ERROR_NO_HANDLES);

    }



    webBrowser.setBrowser (this);

    webBrowser.create (parent, style);

    }

    其中對IE的實現(xiàn)主要是采用調(diào)用IE的Activex控件,間接加載IE,對Mozilla由于代碼過多,本人沒有具體研究,其本身開源,有興趣能夠參看。

    那么回歸主題,如何實現(xiàn)與Browser控件的交互呢? 其實仔細看Browser控件的API,能夠發(fā)覺一個execute()方法,這個方法適用于在web文檔加載完畢時能夠運行javascript code的。這樣的話,交互就變得簡單了,因為javascript是提供dom的支持的,既然能夠調(diào)用javascript,那么就能夠調(diào)用web頁面 中的每個節(jié)點了。控制的問題處理了,可是另外的問題來了。 如何從javascript的code里邊前往數(shù)據(jù)呢? 比如我需要將一個<input type=text id=textid />的值前往到j(luò)ava code中。其實采用的方法是很投機的,因為execute()方法前往的結(jié)果是true or false,那么對它做文章是沒有用的,我們看其他的api,能夠發(fā)覺:addStatusTextListener()方法。 這個方法能夠監(jiān)聽web頁面對于statusbar文本改變的值,并反映在java code里面,那么我們只需通過javascript把前往的值寫到window.status,那么就能夠在javacode里取到了。 具體代碼請參考下面,對于Browser的承繼重寫,通過getValue能夠取得指定id的html 控件的值,通過setValue能夠設(shè)置值。 view plaincopy to clipboardprint?

    import org.eclipse.swt.browser.Browser;

    import org.eclipse.swt.browser.StatusTextEvent;

    import org.eclipse.swt.browser.StatusTextListener;

    import org.eclipse.swt.widgets.Composite;



    public class CoolBrowser extends Browser implements StatusTextListener {



    private final String DATA = "Browser_Data";



    public CoolBrowser(Composite parent, int style) {

    super(parent, style);

    addStatusTextListener(this);

    }



    @Override

    protected void checkSubclass() {

    }



    /**

    * Get the value of one input control in the web

    * @param id

    * @return

    */

    public String getValue(String id) {

    if (execute("var obj = document.getElementById('" + id + "');"

    + "if( obj != null ) window.status=obj.value;")) {

    return (String) getData(DATA);

    }

    return null;

    }



    /**

    * Set the value of the input control

    * @param id

    * @param value

    */

    public void setValue( String id, Object value ){

    if (execute("var obj = document.getElementById('" + id + "');"

    + "if( obj != null ) obj.value='" + value + "';")) {

    }

    }



    @Override

    public void changed(StatusTextEvent event) {

    setData(DATA, event.text);

    }



    }
    posted @ 2009-12-29 16:28 xiaoxinchen 閱讀(5284) | 評論 (1)編輯 收藏
    下載地址:http://www.iplaysoft.com/windows7-msdn-iso.html
    posted @ 2009-12-20 20:14 xiaoxinchen 閱讀(416) | 評論 (0)編輯 收藏
      Proxy代理模式是一種結(jié)構(gòu)型設(shè)計模式,主要解決的問題是:在直接訪問對象時帶來的問題,比如說:要訪問的對象在遠程的機器上。在面向?qū)ο笙到y(tǒng)中,有些對象由于某些原因(比如對象創(chuàng)建開銷很大,或者某些操作需要安全控制,或者需要進程外的訪問),直接訪問會給使用者或者系統(tǒng)結(jié)構(gòu)帶來很多麻煩,我們可以在訪問此對象時加上一個對此對象的訪問層。如下圖:
       



           比如說C和A不在一個服務(wù)器上,A要頻繁的調(diào)用C,我們可以在A上做一個代理類Proxy,把訪問C的工作交給Proxy,這樣對于A來說,就好像在直接訪問C的對象。在對A的開發(fā)中我們可以把注意力完全放在業(yè)務(wù)的實現(xiàn)上。

           GoF《設(shè)計模式》中說道:為其他對象提供一種代理以控制這個對象的訪問。

           Proxy模式的結(jié)構(gòu):
       



           下面通過一個場景來看看Proxy的實現(xiàn),我們要使用代理類型ProxyClass的對象調(diào)用遠程機器上的一個類型LongDistanceClass的對象。

        首先我們先模擬一個遠程的類型:為了保持對被代理對象使用的透明性,我們使代理類型和被代理類型同時繼承同一個接口IProxy

        接口實現(xiàn):

        interface IProxy

        {

            string Function1();

            string Function2();

        }

        遠程對象實現(xiàn):

        /// <summary>

        /// 模擬的遠程對象

        /// </summary>

        public class LongDistanceClass:IProxy

        {

            #region IProxy 成員

            public string Function1()

            {

                //do someting

                return "LongDistanceClass.Function1";

            }

            public string Function2()

            {

                //do someting

                return "LongDistanceClass.Function2";

            }

            #endregion

        }

        接下來就要實現(xiàn)代理類型,使用代理對象訪問模擬的遠程對象,代理類型實現(xiàn)如下:

        public class ProxyClass:IProxy

        {

            #region IProxy 成員

            public string Function1()

            {

                //to access LongDistanceClass.Function1

                LongDistanceClass obj = new LongDistanceClass();

                return obj.Function1();

            }

            public string Function2()

            {

                //to access LongDistanceClass.Function2

                LongDistanceClass obj = new LongDistanceClass();

                return obj.Function2();

            }

            #endregion

        }

     

        最后實現(xiàn)客戶端代碼:

        class Class1

        {

            [STAThread]

            static void Main(string[] args)

            {

                IProxy pro = new ProxyClass();

                Console.WriteLine(pro.Function1());

                Console.WriteLine(pro.Function2());

                Console.Read();

            }

        }

        運行結(jié)果如下:

        LongDistanceClass.Function1

    LongDistanceClass.Function2

           Proxy模式的要點:

           1、“增加一層間接層”是軟件系統(tǒng)中對許多負責(zé)問題的一種常見解決方法。在面向?qū)ο笙到y(tǒng)中,直接使用某些對象會帶來很多問題,作為間接層的proxy對象便是解決這一問題的常用手段。

           在我們?nèi)粘5墓ぷ髦幸渤3S玫酱砟J剑热鐚τ谌龑咏Y(jié)構(gòu)或者N- tiers結(jié)構(gòu)中DAL數(shù)據(jù)訪問層,它把對數(shù)據(jù)庫的訪問進行封裝。BLL業(yè)務(wù)層的開發(fā)者只是調(diào)用DAL中的方法來獲得數(shù)據(jù)。

           在比如前一段時間看了看AOP和Remoting方面的資料,對于跨越應(yīng)用程序域的訪問,要為客戶應(yīng)用程序提供一個TransparentProxy(透明代理),客戶程序?qū)嶋H上是通過訪問這個代理來訪問實際的類型對象。

    2、具體proxy設(shè)計模式的實現(xiàn)方法、實現(xiàn)粒度都相差很大,有些可能對單個對象作細粒度的控制,有些可能對組件模塊提供抽象代理層,在架構(gòu)層次對對象作proxy。

    3、proxy并不一定要求保持接口的一致性,只要能夠?qū)崿F(xiàn)間接控制,有時候損及一些透明性是可以接受的。例如上面的那個例子,代理類型ProxyClass和被代理類型LongDistanceClass可以不用繼承自同一個接口,正像GoF《設(shè)計模式》中說的:為其他對象提供一種代理以控制這個對象的訪問。代理類型從某種角度上講也可以起到控制被代理類型的訪問的作用。
    posted @ 2009-08-04 14:44 xiaoxinchen 閱讀(149) | 評論 (0)編輯 收藏

    1.策略模式-Strategy

    策略模式
    是對算法的包裝,是把使用算法的責(zé)任和算法本身分割開來,委派給不同的對象管理。
    策略模式通常把一個系列的算法包裝到一系列的策略類里面,作為一個抽象策略類的子類。

    一句話來形容:準備一組算法,并將每一個算法封裝起來,使得他們可以互換


    策略模式的結(jié)構(gòu)
    策略模式涉及到三個角色:
    • 環(huán)境角色:持有一個Strategy類(策略類)的引用
    • 抽象策略角色:策略類,通常由一個接口或者抽象類實現(xiàn)
    • 具體策略角色:包裝了相關(guān)的算法和行為




    《三國演義》中的故事
    諸葛亮的精囊妙計?三條妙計
    走喬國老的后門,求孫國太放人,請孫夫人退兵
    趙云?按計行事
    環(huán)境角色:趙云?由他來決定選擇策略
    抽象策略角色:(接口)精囊妙計?按計行事(抽象方法)
    具體策略角色:三條妙計(單獨使用的)


    例子:一個策略模式的加減乘除
    抽象策略角色: (精囊妙計)? Operation抽象類(oper抽象方法)
    具體策略角色: (三條妙計)? 計算乘積,計算除法,計算加法,計算減法
    環(huán)境角色:  (趙云)?  有一個策略類( Operation )的引用


    策略模式的優(yōu)缺點:
    優(yōu)點:
    1.提供了管理相關(guān)的算法族的辦法。
    2.提供了可以替換繼承關(guān)系的辦法。
    3.避免使用多重條件轉(zhuǎn)移語句

    缺點:
    1.客戶端必須知道所有的策略類,并自行決定使用哪一個策略類。
    2.造成很多的策略類。
    posted @ 2009-08-04 12:21 xiaoxinchen 閱讀(236) | 評論 (0)編輯 收藏
    原則內(nèi)容:OCP原則就是"開-閉原則",一個軟件應(yīng)該對擴展開放,對修改關(guān)閉。
    解釋 :在設(shè)計一個模塊的時候,應(yīng)當使得這個模塊可以在不被修改的前提下面被擴展。換言之,應(yīng)該可以在不必修改源代碼的情況下改變這個
    模塊的行為。這個原則有2點要求:
    ×:擴展開放
    ×:關(guān)閉修改
    滿足OCP原則系統(tǒng)的優(yōu)點:
    ×:通過擴展已有的軟件系統(tǒng),提供新的行為,可以使得軟件系統(tǒng)滿足新需求
    ×:已有的軟件模塊,特別是重要的抽象層模塊不能做變更,這使得變化中的軟件系統(tǒng)有一定的穩(wěn)定性和延續(xù)性。
    如何實現(xiàn)OCP原則:
    1、抽象是關(guān)鍵。
       對需要設(shè)計的系統(tǒng)進行抽象,在此前提下面,讓抽象的實現(xiàn)機制千變?nèi)f化。這個抽象層必須預(yù)見到所有的可能的擴展,任何實現(xiàn)的改變都不會改變該抽象結(jié)構(gòu)。這樣使得系統(tǒng)的抽象層無需修改,從而滿足OCP原則的第二條-關(guān)閉修改。
    2、對可變性的封裝原則
       OCP從另一個角度來說,就是EVP(principle of Encapsulation Variation)原則。即找到系統(tǒng)的可變因素,將之封裝起來。這個原則意味著2點:
    ×:一種可變性不應(yīng)當散落在代碼的很多角落里,而應(yīng)當被封裝到一個對象里面。繼承應(yīng)當被看    做是封裝變化的方法,而不應(yīng)當被認為是從一般的對象生成特殊的對象方法。
    ×:一種可變性不應(yīng)當與另一種可變性混合在一起。所有的類圖的繼承結(jié)構(gòu)一般不會超過兩層,不然就意味著將兩種不同的可變性混合在一起。
    與其他設(shè)計原則的關(guān)系
    LSP原則:這個原則是說任何基類出現(xiàn)的地方,子類一定可以出現(xiàn)。
    這個原則是對OCP原則的補充,基類和子類的關(guān)系就是抽象化的具體體現(xiàn),所以LSP原則是對實現(xiàn)抽象化的具體步驟的規(guī)范。一般來說,違背了LSP原則,一定違反了OCP原則,反之不一定成立。
    CARP原則:這個原則講的是要盡可能的多用合成/聚合,而不是繼承關(guān)系達到復(fù)用的目的。
    CARP原則和LSP原則相輔相成。二者都是對實現(xiàn)OCP原則的具體步驟的規(guī)范。前者要求設(shè)計師首先考慮合成/聚合關(guān)系;后者要求在使用繼承關(guān)系的時候, 必須確定這個關(guān)系是符合一定條件的。CARP原則是OCP原則的必要條件,違反了這個原則,就無法使系統(tǒng)實現(xiàn)OCP原則這個目標。
    DIP原則:這個原則是說要依賴于抽象,不要依賴于實現(xiàn)。
    DIP原則和OCP原則是目標和手段的關(guān)系。OCP是目標,DIP是手段。要想實現(xiàn)OCP原則,必須堅持DIP原則。違反了DIP原則,則不可能達到OCP原則要求。

    LoD原則:這個原則講的是一個軟件實體應(yīng)該盡可能少的和其他實體發(fā)生作用。
    當一個system面臨功能擴展的時候,其中會有一些模塊,他們需要修改的壓力比其他的模塊要大一些,如果這些模塊是相對孤立的,那么他們就不會將修改的 壓力傳遞給其他模塊。根據(jù)LoD原則設(shè)計的系統(tǒng),在功能需要擴展的時候,會相對容易的做到對修改的關(guān)閉。LoD原則是一條通向OCP原則的道路。
    ISP原則:這個原則是說,應(yīng)當為客戶端提供盡可能小的單獨接口,而不要提供大的總接口。ISP原則和LoD原則講的都是一個軟件實體與另一個軟件實體的通訊限制。廣義的LoD原則要求盡可能限制通訊的寬度和深度,ISP原則所限制的是通信寬度。
    一個重構(gòu)方法的討論
    “將條件轉(zhuǎn)移語句改寫成為多態(tài)性”是一條廣為流傳的代碼重構(gòu)做法。

    這一做法本身并不能保證“開-閉”原則,應(yīng)當以“開-閉”原則判斷是否需要改寫成多態(tài)。條件轉(zhuǎn)移并不是錯誤,如果需要,完全可以選擇使用條件轉(zhuǎn)移。

    如果一個條件轉(zhuǎn)移語句確實封裝了某種商務(wù)邏輯的可變性,那么將此種可變性封裝起來就符合“開-閉”原則設(shè)計思想了。如果一個條件轉(zhuǎn)移語句沒有涉及重 要的商務(wù)邏輯,或者不會隨著時間的變化而變化,也不意味著任何的可擴展性,那么它就沒有涉及任何有意義的可變性。這時候?qū)⑦@個條件轉(zhuǎn)移語句改寫成多態(tài)性就 是一種沒有意義的浪費。
    抽象類應(yīng)當擁有盡可能多的共同代碼

     在一個繼承的等級結(jié)構(gòu)中,共同的代碼應(yīng)當盡量向等級結(jié)構(gòu)的上方移動。把重復(fù)的代碼從子類里面移動到超類里面,可以提高代碼的復(fù)用率。在代碼發(fā)生改變時,設(shè)計師之需要修改一個地方。

    抽象類應(yīng)當擁有盡可能少的數(shù)據(jù)

    與代碼的移動方向相反,數(shù)據(jù)的移動方向是從抽象類到具體類,向等級結(jié)構(gòu)的下方移動。一個對象的數(shù)據(jù)不論是否使用都會占用資源,所以應(yīng)當放到等級結(jié)構(gòu)的低端。

     

    什么時候才應(yīng)當使用繼承復(fù)用

    1.子類是超類的一個特殊種類,而不是超類的一個角色,Is-A才符合繼承關(guān)系。

    2.永遠不會出現(xiàn)需要將子類換成另一個類的子類的情況。

    3.子類具有擴展超類的責(zé)任,而不是具有置換掉(Override)和注銷掉(Nullify)超類的責(zé)任。

    4.只有在分類學(xué)角度上有意義時,才可以使用繼承,不要從工具類繼承。

    posted @ 2009-08-03 23:15 xiaoxinchen 閱讀(975) | 評論 (0)編輯 收藏
    什么是內(nèi)聚?什么是耦合?
    內(nèi)聚是從功能角度來度量模塊內(nèi)的聯(lián)系,一個好的內(nèi)聚模塊應(yīng)當恰好做一件事。它描述
    的是模塊內(nèi)的功能聯(lián)系; 耦合是軟件結(jié)構(gòu)中各模塊之間相互連接的一種度量,耦合強弱取決
    于模塊間接口的復(fù)雜程度、進入或訪問一個模塊的點以及通過接口的數(shù)據(jù)。
    耦合性也稱塊間聯(lián)系。指軟件系統(tǒng)結(jié)構(gòu)中各模塊間相互聯(lián)系緊密程度的一種度量。模塊之間聯(lián)系越緊密,其耦合性就越強,模塊的獨立性則越差。模塊間耦合高低取決于模塊間接口的復(fù)雜性、調(diào)用的方式及傳遞的信息。

    2. 內(nèi)聚分為哪幾類?耦合分為哪幾類?
          內(nèi)聚有如下的種類,它們之間的內(nèi)聚度由弱到強排列如下:
    (1) 偶然內(nèi)聚。模塊中的代碼無法定義其不同功能的調(diào)用。但它使該模塊能執(zhí)行不同
    的功能,這種模塊稱為巧合強度模塊。
    (2) 邏輯內(nèi)聚。這種模塊把幾種相關(guān)的功能組合在一起, 每次被調(diào)用時,由傳送給模
    塊參數(shù)來確定該模塊應(yīng)完成哪一種功能
    (3) 時間內(nèi)聚:把需要同時執(zhí)行的動作組合在一起形成的模塊為時間內(nèi)聚模塊。
    (4) 過程內(nèi)聚:構(gòu)件或者操作的組合方式是,允許在調(diào)用前面的構(gòu)件或操作之后,馬上調(diào)用后面的構(gòu)件或操作,即使兩者之間沒有數(shù)據(jù)進行傳遞。
    (5) 通信內(nèi)聚:指模塊內(nèi)所有處理元素都在同一個數(shù)據(jù)結(jié)構(gòu)上操作(有時稱之為信息內(nèi)聚),或者指各處理使用相同的輸入數(shù)據(jù)或者產(chǎn)生相同的輸出數(shù)據(jù)。
    (6) 順序內(nèi)聚:指一個模塊中各個處理元素都密切相關(guān)于同一功能且必須順序執(zhí)行,前一功能元素輸出就是下一功能元素的輸入。
    (7) 功能內(nèi)聚:這是最強的內(nèi)聚,指模塊內(nèi)所有元素共同完成一個功能,缺一不可。
    耦合可以分為以下幾種,它們之間的耦合度由高到低排列如下:
    (1) 內(nèi)容耦合:如果發(fā)生下列情形,兩個模塊之間就發(fā)生了內(nèi)容耦合
    一個模塊直接訪問另一個模塊的內(nèi)部數(shù)據(jù)
    一個模塊不通過正常入口轉(zhuǎn)到另一模塊內(nèi)部;
    兩個模塊有一部分程序代碼重疊(只可能出現(xiàn)在匯編語言中);
    一個模塊有多個入口。
    (2) 公共耦合:若一組模塊都訪問同一個公共數(shù)據(jù)環(huán)境,則它們之間的耦合就稱為公共耦合。公共的數(shù)據(jù)環(huán)境可以是全局數(shù)據(jù)結(jié)構(gòu)、共享的通信區(qū)、內(nèi)存的公共覆蓋區(qū)等。
    (3) 外部耦合:一組模塊都訪問同一全局簡單變量而不是同一全局數(shù)據(jù)結(jié)構(gòu),而且不是通過參數(shù)表傳遞該全局變量的信息,則稱之為外部耦合。
    (4) 控制耦合:如果一個模塊通過傳送開關(guān)、標志、名字等控制信息,明顯地控制選擇另一模塊的功能,就是控制耦合
    (5) 標記耦合:一組模塊通過參數(shù)表傳遞記錄信息,就是標記耦合。這個記錄是某一數(shù)據(jù)結(jié)構(gòu)的子結(jié)構(gòu),而不是簡單變量。其實傳遞的是這個數(shù)據(jù)結(jié)構(gòu)的地址;也就是地址傳遞。
    (6) 數(shù)據(jù)耦合:指兩個模塊之間有調(diào)用關(guān)系,傳遞的是簡單的數(shù)據(jù)值,一個模塊訪問另一個模塊時,彼此之間是通過簡單數(shù)據(jù)參數(shù) (不是控制參數(shù)、公共數(shù)據(jù)結(jié)構(gòu)或外部變量) 來交換輸入、輸出信息的,相當于高級語言的值傳遞。
    (7) 非直接耦合:兩個模塊之間沒有直接關(guān)系,它們之間的聯(lián)系完全是通過主模塊的控制和調(diào)用來實現(xiàn)的。
    耦合強度,依賴于以下幾個因素:
    (1)一個模塊對另一個模塊的調(diào)用;
    (2)一個模塊向另一個模塊傳遞的數(shù)據(jù)量;
    (3)一個模塊施加到另一個模塊的控制的多少;
    (4)模塊之間接口的復(fù)雜程度。


    參考資料:

    http://baike.baidu.com/view/156245.html

    http://www.cnblogs.com/dqshll/articles/1116799.html

    http://blog.zol.com.cn/858/article_857495.html

    posted @ 2009-08-03 23:06 xiaoxinchen 閱讀(1602) | 評論 (0)編輯 收藏

    用 jQuery 的都知道,jQuery 的 get 和 post 方法有三個參數(shù):地址,數(shù)據(jù) 和回調(diào)函數(shù),但我們知道地址也可以跟隨數(shù)據(jù)的(形如:get_data.php?v1=1&v2=2),而且第二個參數(shù)可以省略,即第二個參數(shù)可 以直接寫回調(diào)函數(shù),那么數(shù)據(jù)寫在地址后面和寫在 data 參數(shù)里有什么區(qū)別呢?

    剛剛做了幾個實驗,看看下面的代碼就清楚了:
    以下內(nèi)容需要回復(fù)才能看到

    jquery_data.php

    echo "post: ";
    print_r($_POST);
    echo "get: ";
    print_r($_GET);
    ?>

    jquery_test.html

    實驗1:

    $(function() {
    // post 方法,兩處都有數(shù)據(jù)
    $.post('jquery_data.php?v1=1', {v2: 2}, function(data) {
    $('

    ').append(data).appendTo('body');
    });
    });

    返回結(jié)果:
    post: Array
    (
    [v2] => 2
    )
    get: Array
    (
    [v1] => 1
    )

    實驗2:

    $(function()
    {
    // post 方法,數(shù)據(jù)在地址后面, 第二個參數(shù)為回調(diào)函數(shù)
    $.post('jquery_data.php?v1=1', function(data)
    {
    $('<pre/>').append(data).appendTo('body');
    });
    });

    返回結(jié)果,數(shù)據(jù)在 get 中:
    post: Array
    (
    )
    get: Array
    (
    [v1] => 1
    )

    實驗3:

    $(function()
    {
    // get 方法,用 data 參數(shù)傳值
    $.get('jquery_data.php', {v2: 2}, function(data)
    {
    $('<pre/>').append(data).appendTo('body');
    });
    });

    返回結(jié)果,數(shù)據(jù)在 get 中:
    post: Array
    (
    )
    get: Array
    (
    [v2] => 2
    )

    實驗4:

    $(function()
    {
    // get 方法,兩處都有數(shù)據(jù)
    $.get('jquery_data.php?v1=1', {v2: 2}, function(data)
    {
    $('<pre/>').append(data).appendTo('body');
    });
    });

    返回結(jié)果,兩處數(shù)據(jù)被合并了,都在 get 中:
    post: Array
    (
    )
    get: Array
    (
    [v1] => 1
    [v2] => 2
    )

    實驗5:

    $(function()
    {
    // get 方法,兩處都有數(shù)據(jù),且變量名相同
    $.get('jquery_data.php?v2=1', {v2: 2}, function(data)
    {
    $('<pre/>').append(data).appendTo('body');
    });
    });

    返回結(jié)果,數(shù)據(jù)在 get 中,且 data 參數(shù)中的數(shù)據(jù)覆蓋了地址后面的數(shù)據(jù):
    post: Array
    (
    )
    get: Array
    (
    [v2] => 2
    )

    通過這幾個簡單的小例子不難看出,地址后面的數(shù)據(jù)永遠是以 get 形式傳遞的,無論使用的是 get 方法還是 post 方法;而 data 參數(shù)中的數(shù)據(jù)是根據(jù)方法決定傳遞方式的。

    因此,為了避免混淆,建議大家盡量不要把數(shù)據(jù)寫在地址后面,而是統(tǒng)一放在 data 參數(shù)中。

    當然,如果你想在用 post 方法時,同時利用 get 傳值,那么就可以把要以 get 方式傳遞的數(shù)據(jù)寫在地址后面,把要以 post 方式傳遞的數(shù)據(jù)寫在 data 參數(shù)中。

    總之方法是死的,人是活的,怎么用還要看實際情況。子曾經(jīng)曰過:實踐是檢驗真理的唯一標準。沒事做做實驗,掌握知識更牢固。
    posted @ 2009-07-29 19:22 xiaoxinchen 閱讀(914) | 評論 (1)編輯 收藏

    (zz from http://blog.csdn.net/heiyeshuwu)

    Web Service就是為了異構(gòu)系統(tǒng)的通信而產(chǎn)生的,它基本的思想就是使用基于XML的HTTP的遠程調(diào)用提供一種標準的機制,而省去建立一種新協(xié)議的需求。 目前進行Web Service通信有兩種協(xié)議標準,一種是XML-RPC,另外一種是SOAP。XML-RPC比較簡單,出現(xiàn)時間比較早,SOAP比較復(fù)雜,主要是一些 需要穩(wěn)定、健壯、安全并且復(fù)雜交互的時候使用。

    Web Service介紹

    Web Service就是為了異構(gòu)系統(tǒng)的通信而產(chǎn)生的,它基本的思想就是使用基于XML的HTTP的遠程調(diào)用提供一種標準的機制,而省去建立一種新協(xié)議的需求。 目前進行Web Service通信有兩種協(xié)議標準,一種是XML-RPC,另外一種是SOAP。XML-RPC比較簡單,出現(xiàn)時間比較早,SOAP比較復(fù)雜,主要是一些 需要穩(wěn)定、健壯、安全并且復(fù)雜交互的時候使用。

    PHP中集成了XML-RPC和SOAP兩種協(xié)議的訪問,都是集中在xmlrpc擴 展當中。另外,在PHP的PEAR中,不管是PHP 4還是PHP 5,都已經(jīng)默認集成了XML-RPC擴展,而且該擴展跟xmlrpc擴展無關(guān),能夠獨立實現(xiàn)XML-RPC的協(xié)議交互,如果沒有xmlrpc擴展,建議使 用PEAR::XML-RPC擴展。

    我們這里主要是以XML-RPC來簡單描述Web Service的交互過程,部分內(nèi)容來自PHP手冊,更詳細內(nèi)容,建議參考手冊。

    安裝xmlrpc擴展

    如果你的系統(tǒng)中沒有安裝xmlrpc的php擴展,那么請正確安裝。

    在 Windows平臺下,首先把PHP安裝目錄下的擴展php_xmlrpc.dll放到C:\Windows或者C:\Winnt目錄下, (PHP4的擴展在C:\php\extensions目錄中,PHP5的擴展在C:\php\ext目錄中),同時在C:\Windows \php.ini或者C:\Winnt\php.ini中把extension=php_xmlrpc.dll前面的分號";"去掉,然后重啟Web服務(wù) 器后查看phpinfo()有沒有XML-RPC項目就能夠確定是否已經(jīng)正確安裝xmlrpc擴展。

    在Unix/Linux平臺下,如果沒有安裝xmlrpc擴展,請在重新編譯PHP,在configure的時候請加入 --with-xmlrpc 選項,然后查看phpinfo()看是否正常安裝xmlrpc。

    (注意:以下操作都是建立在xmlrpc擴張正常安裝前提下,請務(wù)必正確安裝。)

    XML-RPC工作原理

    XML-RPC大致就是整個過程就是使用XML來進行通信。首先構(gòu)造一個RPC 服務(wù)器端用來出來從RPC客戶端傳遞過來的使用XML封裝的請求,并且把處理結(jié)果通過XML的形式返回給RPC客戶端,客戶端就去分析XML獲取自己需要的數(shù)據(jù)。

    XML-RPC的服務(wù)器端必須有現(xiàn)成的函數(shù)提供給客戶端調(diào)用,并且客戶端提交的請求中的函數(shù)和方法必須和服務(wù)器端的一致,否則將無法獲取所需要的結(jié)果。

    下面我進行簡單的代碼來描述整個過程。

    XML-RPC實踐

    服務(wù)器端使用xmlrpc_server_create函數(shù)產(chǎn)生一個服務(wù)器端,然后把需要需要暴露的RPC調(diào)用接口進行注冊,接受RPC客戶端POST過來的XML數(shù)據(jù),然后進行處理,處理結(jié)果通過XML的形式顯示給客戶端。

    代碼如下: rpc_server.php

    <?php
    /**
    * 函數(shù):提供給RPC客戶端調(diào)用的函數(shù)
    * 參數(shù):
    * $method 客戶端需要調(diào)用的函數(shù)
    * $params 客戶端需要調(diào)用的函數(shù)的參數(shù)數(shù)組
    * 返回:返回指定調(diào)用結(jié)果
    */
    function rpc_server_func($method, $params) {
    $parameter = $params[0];
    if ($parameter == "get")
    {
    $return = 'This data by get method';
    }
    else
    {
    $return = 'Not specify method or params';
    }
    return $return;
    }

    //產(chǎn)生一個XML-RPC的服務(wù)器端
    $xmlrpc_server = xmlrpc_server_create();

    //注冊一個服務(wù)器端調(diào)用的方法rpc_server,實際指向的是rpc_server_func函數(shù)
    xmlrpc_server_register_method($xmlrpc_server, "rpc_server", "rpc_server_func");

    //接受客戶端POST過來的XML數(shù)據(jù)
    $request = $HTTP_RAW_POST_DATA;

    //執(zhí)行調(diào)用客戶端的XML請求后獲取執(zhí)行結(jié)果
    $xmlrpc_response = xmlrpc_server_call_method($xmlrpc_server, $request, null);

    //把函數(shù)處理后的結(jié)果XML進行輸出
    header('Content-Type: text/xml');
    echo $xmlrpc_response;

    //銷毀XML-RPC服務(wù)器端資源
    xmlrpc_server_destroy($xmlrpc_server);
    ?>

    服務(wù)器端構(gòu)造好了,那么再構(gòu)造我們的RPC客戶端。客戶端大致通過Socket訪問XML-RPC服務(wù)器端的80端口,然后把需要調(diào)用的RPC接口封裝到XML里,通過POST請求提交給RPC服務(wù)器端,最后獲取服務(wù)器端返回結(jié)果。

    代碼如下:rpc_client.php

    <?php
    /**
    * 函數(shù):提供給客戶端進行連接XML-RPC服務(wù)器端的函數(shù)
    * 參數(shù):
    * $host 需要連接的主機
    * $port 連接主機的端口
    * $rpc_server XML-RPC服務(wù)器端文件
    * $request 封裝的XML請求信息
    * 返回:連接成功成功返回由服務(wù)器端返回的XML信息,失敗返回false
    */
    function rpc_client_call($host, $port, $rpc_server, $request) {

    //打開指定的服務(wù)器端
    $fp = fsockopen($host, $port);

    //構(gòu)造需要進行通信的XML-RPC服務(wù)器端的查詢POST請求信息
    $query = "POST $rpc_server HTTP/1.0\nUser_Agent: XML-RPC Client\nHost: ".$host."\nContent-Type: text/xml\nContent-Length: ".strlen($request)."\n\n".$request."\n";

    //把構(gòu)造好的HTTP協(xié)議發(fā)送給服務(wù)器,失敗返回false
    if (!fputs($fp, $query, strlen($query)))
    {
    $errstr = "Write error";
    return false;
    }

    //獲取從服務(wù)器端返回的所有信息,包括HTTP頭和XML信息
    $contents = '';
    while (!feof($fp))
    {
    $contents .= fgets($fp);
    }

    //關(guān)閉連接資源后返回獲取的內(nèi)容
    fclose($fp);
    return $contents;
    }

    //構(gòu)造連接RPC服務(wù)器端的信息
    $host = 'localhost';
    $port = 80;
    $rpc_server = '/~heiyeluren/rpc_server.php';

    //把需要發(fā)送的XML請求進行編碼成XML,需要調(diào)用的方法是rpc_server,參數(shù)是get
    $request = xmlrpc_encode_request('rpc_server', 'get');

    //調(diào)用rpc_client_call函數(shù)把所有請求發(fā)送給XML-RPC服務(wù)器端后獲取信息
    $response = rpc_client_call($host, $port, $rpc_server, $request);

    //分析從服務(wù)器端返回的XML,去掉HTTP頭信息,并且把XML轉(zhuǎn)為PHP能識別的字符串
    $split = '<?xml version="1.0" encoding="iso-8859-1"?>';
    $xml = explode($split, $response);
    $xml = $split . array_pop($xml);
    $response = xmlrpc_decode($xml);

    //輸出從RPC服務(wù)器端獲取的信息
    print_r($response);

    ?>

    大致我們上面的例子就是提交一個叫做rpc_server的方法過去,參數(shù)是get,然后獲取服務(wù)器端的返回,服務(wù)器端返回的XML數(shù)據(jù)是:

    <?xml version="1.0" encoding="iso-8859-1"?>
    <methodResponse>
    <params>
    <param>
    <value>
    <string>This data by get method</string>
    </value>
    </param>
    </params>
    </methodResponse>

    那么我們再通過xmlrpc_decode函數(shù)把這個XML編碼為PHP的字符串,我們就能夠隨意處理了,整個Web Service交互完成。

    結(jié)束語

    不 管是XML-RPC也好,SOAP也罷,只要能夠讓我們穩(wěn)定、安全的進行遠程過程的調(diào)用,完成我們的項目,那么就算整個Web Service就是成功的。另外,如果可以的話,也可以嘗試使用PEAR中的XML-RPC來實現(xiàn)上面類似的操作,說不定會更簡單,更適合你使用。

    參考

    http://phpxmlrpc.sourceforge.net/

    posted @ 2009-07-02 09:42 xiaoxinchen 閱讀(231) | 評論 (0)編輯 收藏
    JPA

    JPA常用標記說明

    Table

    Table用來定義entity主表的name,catalog,schema等屬性。
    元數(shù)據(jù)屬性說明:

    • name: 表名
    • catalog: 對應(yīng)關(guān)系數(shù)據(jù)庫中的catalog
    • schema:對應(yīng)關(guān)系數(shù)據(jù)庫中的schema
    • UniqueConstraints:定義一個UniqueConstraint數(shù)組,指定需要建唯一約束的列
         
    @Entity
    @Table(name="CUST")
    public class Customer { ... }

    SecondaryTable

    一個entity class可以映射到多表,SecondaryTable用來定義單個從表的名字,主鍵名字等屬性。
    元數(shù)據(jù)屬性說明:

    • name: 表名
    • catalog: 對應(yīng)關(guān)系數(shù)據(jù)庫中的catalog
    • schema:對應(yīng)關(guān)系數(shù)據(jù)庫中的schema
    • pkJoin: 定義一個PrimaryKeyJoinColumn數(shù)組,指定從表的主鍵列
    • UniqueConstraints:定義一個UniqueConstraint數(shù)組,指定需要建唯一約束的列

    下面的代碼說明Customer類映射到兩個表,主表名是CUSTOMER,從表名是CUST_DETAIL,從表的主鍵列和主表的主鍵列類型相同,列名為CUST_ID。

                     
    @Entity
    @Table(name="CUSTOMER")
    @SecondaryTable(name="CUST_DETAIL",pkJoin=@PrimaryKeyJoinColumn(name="CUST_ID"))
    public class Customer { ... }

    SecondaryTables

    當一個entity class映射到一個主表和多個從表時,用SecondaryTables來定義各個從表的屬性。
    元數(shù)據(jù)屬性說明:

    • value: 定義一個SecondaryTable數(shù)組,指定每個從表的屬性。
                     
    @Table(name = "CUSTOMER")
    @SecondaryTables( value = {
    @SecondaryTable(name = "CUST_NAME", pkJoin = { @PrimaryKeyJoinColumn(name = "STMO_ID", referencedColumnName = "id") }),
    @SecondaryTable(name = "CUST_ADDRESS", pkJoin = { @PrimaryKeyJoinColumn(name = "STMO_ID", referencedColumnName = "id") }) })
    public class Customer {}

    UniqueConstraint

    UniqueConstraint定義在Table或SecondaryTable元數(shù)據(jù)里,用來指定建表時需要建唯一約束的列。
    元數(shù)據(jù)屬性說明:

    • columnNames:定義一個字符串數(shù)組,指定要建唯一約束的列名。
                     
    @Entity
    @Table(name="EMPLOYEE", uniqueConstraints={@UniqueConstraint(columnNames={"EMP_ID", "EMP_NAME"})})
    public class Employee { ... }

    Column

    Column元數(shù)據(jù)定義了映射到數(shù)據(jù)庫的列的所有屬性:列名,是否唯一,是否允許為空,是否允許更新等。
    元數(shù)據(jù)屬性說明:

    • name:列名。
    • unique: 是否唯一
    • nullable: 是否允許為空
    • insertable: 是否允許插入
    • updatable: 是否允許更新
    • columnDefinition: 定義建表時創(chuàng)建此列的DDL
    • secondaryTable: 從表名。如果此列不建在主表上(默認建在主表),該屬性定義該列所在從表的名字。
             
    public class Person {
    @Column(name = "PERSONNAME", unique = true, nullable = false, updatable = true)
    private String name;

    @Column(name = "PHOTO", columnDefinition = "BLOB NOT NULL", secondaryTable="PER_PHOTO")
    private byte[] picture;

    ...

    JoinColumn

    如果在entity class的field上定義了關(guān)系(one2one或one2many等),我們通過JoinColumn來定義關(guān)系的屬性。JoinColumn的大部分屬性和Column類似。
    元數(shù)據(jù)屬性說明:

    • name:列名。
    • referencedColumnName:該列指向列的列名(建表時該列作為外鍵列指向關(guān)系另一端的指定列)
    • unique: 是否唯一
    • nullable: 是否允許為空
    • insertable: 是否允許插入
    • updatable: 是否允許更新
    • columnDefinition: 定義建表時創(chuàng)建此列的DDL
    • secondaryTable: 從表名。如果此列不建在主表上(默認建在主表),該屬性定義該列所在從表的名字。

    下面的代碼說明Custom和Order是一對一關(guān)系。在Order對應(yīng)的映射表建一個名為CUST_ID的列,該列作為外鍵指向Custom對應(yīng)表中名為ID的列。

                     
    public class Custom {
    @OneToOne
    @JoinColumn(name="CUST_ID", referencedColumnName="ID", unique=true, nullable=true, updatable=true)
    public Order getOrder() {
    return order;
    }

    JoinColumns

    如果在entity class的field上定義了關(guān)系(one2one或one2many等),并且關(guān)系存在多個JoinColumn,用JoinColumns定義多個JoinColumn的屬性。
    元數(shù)據(jù)屬性說明:

    • value: 定義JoinColumn數(shù)組,指定每個JoinColumn的屬性。

    下面的代碼說明Custom和Order是一對一關(guān)系。在Order對應(yīng)的映射表建兩列,一列名為CUST_ID,該列作為外鍵指向Custom對應(yīng)表中名為ID的列,另一列名為CUST_NAME,該列作為外鍵指向Custom對應(yīng)表中名為NAME的列。

                     
    public class Custom {
    @OneToOne
    @JoinColumns({
    @JoinColumn(name="CUST_ID", referencedColumnName="ID"),
    @JoinColumn(name="CUST_NAME", referencedColumnName="NAME")
    })

    public Order getOrder() {
    return order;
    }

    Id

    聲 明當前field為映射表中的主鍵列。id值的獲取方式有五種:TABLE, SEQUENCE, IDENTITY, AUTO, NONE。Oracle和DB2支持SEQUENCE,SQL Server和Sybase支持IDENTITY,mysql支持AUTO。所有的數(shù)據(jù)庫都可以指定為AUTO,我們會根據(jù)不同數(shù)據(jù)庫做轉(zhuǎn)換。 NONE需要用戶自己指定Id的值。元數(shù)據(jù)屬性說明:

    • generate():主鍵值的獲取類型
    • generator():TableGenerator的名字(當generate=GeneratorType.TABLE才需要指定該屬性)

    下面的代碼聲明Task的主鍵列id是自動增長的。(Oracle和DB2從默認的SEQUENCE取值,SQL Server和Sybase該列建成IDENTITY,mysql該列建成auto increment。)

                    
    @Entity
    @Table(name = "OTASK")
    public class Task {
    @Id(generate = GeneratorType.AUTO)
    public Integer getId() {
    return id;
    }
    }

    IdClass

    當entity class使用復(fù)合主鍵時,需要定義一個類作為id class。id class必須符合以下要求:類必須聲明為public,并提供一個聲明為public的空構(gòu)造函數(shù)。必須實現(xiàn)Serializable接,覆寫 equals()和hashCode()方法。entity class的所有id field在id class都要定義,且類型一樣。
    元數(shù)據(jù)屬性說明:

    • value: id class的類名
                     
    public class EmployeePK implements java.io.Serializable{
    String empName;
    Integer empAge;
    public EmployeePK(){}

    public boolean equals(Object obj){ ......}
    public int hashCode(){......}
    }

    @IdClass(value=com.acme.EmployeePK.class)
    @Entity(access=FIELD)
    public class Employee {
    @Id String empName;
    @Id Integer empAge;
    }

    MapKey

    在一對多,多對多關(guān)系中,我們可以用Map來保存集合對象。默認用主鍵值做key,如果使用復(fù)合主鍵,則用id class的實例做key,如果指定了name屬性,就用指定的field的值做key。
    元數(shù)據(jù)屬性說明:

    • name: 用來做key的field名字

    下面的代碼說明Person和Book之間是一對多關(guān)系。Person的books字段是Map類型,用Book的isbn字段的值作為Map的key。

                     
    @Table(name = "PERSON")
    public class Person {
    @OneToMany(targetEntity = Book.class, cascade = CascadeType.ALL, mappedBy = "person")
    @MapKey(name = "isbn")
    private Map books = new HashMap();
    }

    OrderBy

    在一對多,多對多關(guān)系中,有時我們希望從數(shù)據(jù)庫加載出來的集合對象是按一定方式排序的,這可以通過OrderBy來實現(xiàn),默認是按對象的主鍵升序排列。
    元數(shù)據(jù)屬性說明:

    • value: 字符串類型,指定排序方式。格式為"fieldName1 [ASC|DESC],fieldName2 [ASC|DESC],......",排序類型可以不指定,默認是ASC。

    下面的代碼說明Person和Book之間是一對多關(guān)系。集合books按照Book的isbn升序,name降序排列。

                    
    @Table(name = "MAPKEY_PERSON")
    public class Person {
    @OneToMany(targetEntity = Book.class, cascade = CascadeType.ALL, mappedBy = "person")
    @OrderBy(name = "isbn ASC, name DESC")
    private List books = new ArrayList();
    }

    PrimaryKeyJoinColumn

    在三種情況下會用到PrimaryKeyJoinColumn。

    • 繼承。
    • entity class映射到一個或多個從表。從表根據(jù)主表的主鍵列(列名為referencedColumnName值的列),建立一個類型一樣的主鍵列,列名由name屬性定義。
    • one2one關(guān)系,關(guān)系維護端的主鍵作為外鍵指向關(guān)系被維護端的主鍵,不再新建一個外鍵列。

    元數(shù)據(jù)屬性說明:

    • name:列名。
    • referencedColumnName:該列引用列的列名
    • columnDefinition: 定義建表時創(chuàng)建此列的DDL

    下面的代碼說明Customer映射到兩個表,主表CUSTOMER,從表CUST_DETAIL,從表需要建立主鍵列CUST_ID,該列和主表的主鍵列id除了列名不同,其他定義一樣。

                 
    @Entity
    @Table(name="CUSTOMER")
    @SecondaryTable(name="CUST_DETAIL",pkJoin=@PrimaryKeyJoinColumn(name="CUST_ID",referencedColumnName="id"))
    public class Customer {
    @Id(generate = GeneratorType.AUTO)
    public Integer getId() {
    return id;
    }
    }

    下面的代碼說明Employee和EmployeeInfo是一對一關(guān)系,Employee的主鍵列id作為外鍵指向EmployeeInfo的主鍵列INFO_ID。

                 
    @Table(name = "Employee")
    public class Employee {
    @OneToOne
    @PrimaryKeyJoinColumn(name = "id", referencedColumnName="INFO_ID")
    EmployeeInfo info;
    }

    PrimaryKeyJoinColumns

    如果entity class使用了復(fù)合主鍵,指定單個PrimaryKeyJoinColumn不能滿足要求時,可以用PrimaryKeyJoinColumns來定義多個PrimaryKeyJoinColumn。
    元數(shù)據(jù)屬性說明:

    • value: 一個PrimaryKeyJoinColumn數(shù)組,包含所有PrimaryKeyJoinColumn。

    下面的代碼說明了Employee和EmployeeInfo是一對一關(guān)系。他們都使用復(fù)合主鍵,建表時需要在Employee表建立一個外鍵,從Employee的主鍵列id,name指向EmployeeInfo的主鍵列INFO_ID和INFO_NAME.

                 
    @Entity
    @IdClass(EmpPK.class)
    @Table(name = "EMPLOYEE")
    public class Employee {
    private int id;
    private String name;

    private String address;

    @OneToOne(cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumns({
    @PrimaryKeyJoinColumn(name="id", referencedColumnName="INFO_ID"),
    @PrimaryKeyJoinColumn(name="name" , referencedColumnName="INFO_NAME")})
    EmployeeInfo info;
    }

    @Entity
    @IdClass(EmpPK.class)
    @Table(name = "EMPLOYEE_INFO")
    public class EmployeeInfo {

    @Id
    @Column(name = "INFO_ID")
    private int id;

    @Id
    @Column(name = "INFO_NAME")
    private String name;
    }

    Transient

    Transient用來注釋entity的屬性,指定的這些屬性不會被持久化,也不會為這些屬性建表。

         
    @Transient
    private String name;

    Version

    Version指定實體類在樂觀事務(wù)中的version屬性。在實體類重新由EntityManager管理并且加入到樂觀事務(wù)中時,保證完整性。每一個類只能有一個屬性被指定為version,version屬性應(yīng)該映射到實體類的主表上。

    下面的代碼說明versionNum屬性作為這個類的version,映射到數(shù)據(jù)庫中主表的列名是OPTLOCK。

                     
    @Version
    @Column("OPTLOCK")
    protected int getVersionNum() { return versionNum; }

    Lob

    Lob指定一個屬性作為數(shù)據(jù)庫支持的大對象類型在數(shù)據(jù)庫中存儲。使用LobType這個枚舉來定義Lob是二進制類型還是字符類型。
    LobType枚舉類型說明:

    • BLOB 二進制大對象,Byte[]或者Serializable的類型可以指定為BLOB。
    • CLOB 字符型大對象,char[]、Character[]或String類型可以指定為CLOB。

    元數(shù)據(jù)屬性說明:

    • fetch: 定義這個字段是lazy loaded還是eagerly fetched。數(shù)據(jù)類型是FetchType枚舉,默認為LAZY,即lazy loaded.
    • type: 定義這個字段在數(shù)據(jù)庫中的JDBC數(shù)據(jù)類型。數(shù)據(jù)類型是LobType枚舉,默認為BLOB。

    下面的代碼定義了一個BLOB類型的屬性和一個CLOB類型的屬性。

                     
    @Lob
    @Column(name="PHOTO" columnDefinition="BLOB NOT NULL")
    protected JPEGImage picture;

    @Lob(fetch=EAGER, type=CLOB)
    @Column(name="REPORT")
    protected String report;

    JoinTable

    JoinTable在many-to-many關(guān)系的所有者一邊定義。如果沒有定義JoinTable,使用JoinTable的默認值。
    元數(shù)據(jù)屬性說明:

    • table:這個join table的Table定義。
    • joinColumns:定義指向所有者主表的外鍵列,數(shù)據(jù)類型是JoinColumn數(shù)組。
    • inverseJoinColumns:定義指向非所有者主表的外鍵列,數(shù)據(jù)類型是JoinColumn數(shù)組。

    下面的代碼定義了一個連接表CUST和PHONE的join table。join table的表名是CUST_PHONE,包含兩個外鍵,一個外鍵是CUST_ID,指向表CUST的主鍵ID,另一個外鍵是PHONE_ID,指向表PHONE的主鍵ID。

                     
    @JoinTable(
    table=@Table(name=CUST_PHONE),
    joinColumns=@JoinColumn(name="CUST_ID", referencedColumnName="ID"),
    inverseJoinColumns=@JoinColumn(name="PHONE_ID", referencedColumnName="ID")
    )

    TableGenerator

    TableGenerator定義一個主鍵值生成器,在Id這個元數(shù)據(jù)的generate=TABLE時,generator屬性中可以使用生成器的名字。生成器可以在類、方法或者屬性上定義。
    生成器是為多個實體類提供連續(xù)的ID值的表,每一行為一個類提供ID值,ID值通常是整數(shù)。
    元數(shù)據(jù)屬性說明:

    • name:生成器的唯一名字,可以被Id元數(shù)據(jù)使用。
    • table:生成器用來存儲id值的Table定義。
    • pkColumnName:生成器表的主鍵名稱。
    • valueColumnName:生成器表的ID值的列名稱。
    • pkColumnValue:生成器表中的一行數(shù)據(jù)的主鍵值。
    • initialValue:id值的初始值。
    • allocationSize:id值的增量。

    下面的代碼定義了兩個生成器empGen和addressGen,生成器的表是ID_GEN。

                     
    @Entity
    public class Employee {
    ...
    @TableGenerator(
    name="empGen",
    table=@Table(name="ID_GEN"),
    pkColumnName="GEN_KEY",
    valueColumnName="GEN_VALUE",
    pkColumnValue="EMP_ID",
    allocationSize=1
    )
    @Id(generate=TABLE, generator="empGen")
    public int id;
    ...
    }

    @Entity
    public class Address {
    ...
    @TableGenerator(
    name="addressGen",
    table=@Table(name="ID_GEN"),
    pkColumnValue="ADDR_ID"
    )
    @Id(generate=TABLE, generator="addressGen")
    public int id;
    ...
    }

    SequenceGenerator

    SequenceGenerator定義一個主鍵值生成器,在Id這個元數(shù)據(jù)的generator屬性中可以使用生成器的名字。生成器可以在類、方法或者屬性上定義。生成器是數(shù)據(jù)庫支持的sequence對象。
    元數(shù)據(jù)屬性說明:

    • name:生成器的唯一名字,可以被Id元數(shù)據(jù)使用。
    • sequenceName:數(shù)據(jù)庫中,sequence對象的名稱。如果不指定,會使用提供商指定的默認名稱。
    • initialValue:id值的初始值。
    • allocationSize:id值的增量。

    下面的代碼定義了一個使用提供商默認名稱的sequence生成器。

                     
    @SequenceGenerator(name="EMP_SEQ", allocationSize=25)

    DiscriminatorColumn

    DiscriminatorColumn定義在使用SINGLE_TABLE或JOINED繼承策略的表中區(qū)別不繼承層次的列。
    元數(shù)據(jù)屬性說明:

    • name:column的名字。默認值為TYPE。
    • columnDefinition:生成DDL的sql片斷。
    • length:String類型的column的長度,其他類型使用默認值10。

    下面的代碼定義了一個列名為DISC,長度為20的String類型的區(qū)別列。

                     
    @Entity
    @Table(name="CUST")
    @Inheritance(strategy=SINGLE_TABLE, discriminatorType=STRING, discriminatorValue="CUSTOMER")
    @DiscriminatorColumn(name="DISC", length=20)
    public class Customer { ... }
    posted @ 2009-07-02 09:41 xiaoxinchen 閱讀(176) | 評論 (0)編輯 收藏

    web.xml的配置

    在web.xml中添加

    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
    classpath:/applicationContext-resources.xml
    classpath:/applicationContext-dao.xml
    classpath:/applicationContext-service.xml
    classpath*:/applicationContext.xml
    /WEB-INF/applicationContext*.xml
    /WEB-INF/security.xml
    /WEB-INF/dealer-security.xml
    </param-value>
    </context-param>

    <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
    <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
    </listener>
    <listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

    事務(wù)的配置

    <aop:config>
    <aop:advisor id="managerTx" advice-ref="txAdvice" pointcut="execution(* *..service.*Manager.*(..))" order="0" />
    </aop:config>

    <tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
    <tx:method name="find*" read-only="true"/>
    <tx:method name="search*" read-only="true"/>
    <tx:method name="get*" read-only="true"/>
    <tx:method name="*" rollback-for="Throwable"/>
    </tx:attributes>
    </tx:advice>

    ApplicationContext.xml的配置(spring bean 的配置)

    <!--ProductManager-START-->
    <bean id="productManager" class="com.eryiju.service.product.impl.ProductManagerImpl">
    <constructor-arg ref="productDao" />
    <property name="brandDao" ref="brandDao"></property>
    </bean>

    <!--ProductManager-END-->
    <bean id="productDao" class="com.eryiju.dao.product.impl.ProductDaoHibernate">
    <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>

    <bean id="brandDao" class="com.eryiju.dao.product.impl.BrandDaoHibernate">
    <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>

    常見問題

    如何與hibernate整合

    <!-- Hibernate SessionFactory -->
    <bean id="sessionFactory"
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configLocation" value="classpath:hibernate.cfg.xml" />
    <property name="hibernateProperties">
    <value>
    hibernate.dialect=${hibernate.dialect}
    hibernate.query.substitutions=true 'Y', false 'N'
    hibernate.cache.use_second_level_cache=true
    hibernate.cache.use_query_cache=true
    hibernate.cache.provider_class=com.eryiju.util.cache.EhCacheProvider
    hibernate.show_sql=false
    hibernate.connection.release_mode=after_statement
    hibernate.cglib.use_reflection_optimizer=false
    hibernate.search.default.directory_provider=org.hibernate.search.store.FSDirectoryProvider
    hibernate.search.default.indexBase=/opt/dev/static/index
    hibernate.jdbc.batch_size=50
    hibernate.jdbc.fetch_size=50
    </value>
    <!-- Turn batching off for better error messages under PostgreSQL -->
    </property>
    </bean>
    h2. (1)使用spring過濾器解決中文問題

    在web.xml中添加:
    <filter>
    <filter-name>Spring character encoding filter</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>Spring character encoding filter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>

    h2. (2)將applicationContext.xml分解成多個文件

    applicationContext-common.xml
    "dataSource"
    "sessionFactory"
    事務(wù)相關(guān)

    applicationContext-dao.xml
    UserDAO

    applicationContext-biz.xml
    UserManager

    applicationContext-action.xml
    Action

    struts-config.xml中要作修改:
    <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
    <set-property property="contextConfigLocation" value="/WEB-INF/classes/applicationContext-*.xml" />
    </plug-in>
    h2. Spring2.0中的注解實現(xiàn)事務(wù)管理

    第一步:引入<tx:>命名空間 ,在spring的配置文件中修改, beans根元素里多了三行,如下
    Xml代碼

    <?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: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/tx
    http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

    第二步:在spring的配置文件中修改,將所有具有@Transactional 注解的bean自動配置為聲明式事務(wù)支持
    Java代碼

    <!--JDBC事務(wù)管理器,根據(jù)你的情況使用不同的事務(wù)管理器,如果工程中有Hibernate,就用Hibernate的事務(wù)管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource">
    <ref local="dataSource"/>
    </property>
    </bean>

    <!-- 用注解來實現(xiàn)事務(wù)管理 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    第三步: 在接口或類的聲明處 ,寫一個@Transactional. 要是只的接口上寫, 接口的實現(xiàn)類就會繼承下來.
    接口的實現(xiàn)類的具體方法,還可以覆蓋類聲明處的設(shè)置.
    Java代碼

    @Transactional
    public class TestPOAOImpl extends POAOBase implements TestPOAO
    {
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void test1()
    {
    String sql = "INSERT INTO sy_test (NAME,AGE) VALUES('注解趙云',30)";
    execute(sql);

    sql = "INSERT INTO sy_test (NAME,AGE) VALUES('注解張飛',26)";
    execute(sql);

    int a = 9 / 0; //異常

    sql = "INSERT INTO sy_test (NAME,AGE) VALUES('注解關(guān)羽',33)";
    execute(sql);
    System.out.println("走完了");
    }
    //execute() 方法略...
    }

    注意的幾點:

    1 @Transactional 只能被應(yīng)用到public方法上, 對于其它非public的方法,如果標記了@Transactional也不會報錯,但方法沒有事務(wù)功能.
    2 默認情況下,一個有事務(wù)方法, 遇到RuntiomeException 時會回滾 . 遇到 受檢查的異常 是不會回滾 的. 要想所有異常都回滾,要加上 @Transactional( rollbackFor={Exception.class,其它異常}) .
    posted @ 2009-07-02 09:40 xiaoxinchen 閱讀(185) | 評論 (0)編輯 收藏
         摘要: 概述 Maven的目標 對Maven的錯誤理解 Maven的版本 Maven的安裝 Windows 2000/xp下的安裝 基于Unxi-based的操作系統(tǒng)(Linux,Solaris and Mac OS X) 查看依賴庫的位置 http://mvnrepository.com/ Maven主要功能 ...  閱讀全文
    posted @ 2009-07-02 09:39 xiaoxinchen 閱讀(533) | 評論 (0)編輯 收藏

    安裝

    sudo apt-get install mysql

    命令行操作

    登錄

    mysql -u用戶名 -p密碼 -h數(shù)據(jù)庫地址(ip) 數(shù)據(jù)庫名稱

    注意:盡量不要在-p后直接跟密碼,否則其他人很容易通過查閱命令行歷史記錄(比如,history命令)看到你的密碼。

    SQL參考

    MySQL參考

    常見數(shù)據(jù)類型

    integer(11) 11位字節(jié)的整數(shù)
    tinyint(1)
    bigint(20)
    decimal(10,2) 小數(shù)
    varchar(20) 最長為20位字節(jié)的可變字符串
    char(20) 最長為20位字節(jié)的定長字符串(定長指的是存儲空間定長)
    text 文本,用于存大量不固定長度的文本信息
    blob 二級制信息

    常見函數(shù)

    length(str) 字符串的長度
    trim(str) 去掉字符串前后的空格
    substring(str,1) 獲取子串
    convert(str using gbk) 將字符串轉(zhuǎn)化為gbk編碼
    reverse(str) 倒序

    增刪改查

    insert into product (sku,name) values ('123456','productname')

    向表中添加sku=123456,name='productname' 的數(shù)據(jù)

    update product set name='updated product name' where sku='123456'

    將表product中的sku為'123456'的數(shù)據(jù)的name字段的值設(shè)置為'updated product name'

    select sku,name from product where sku='123456'

    從表product 中查詢 sku為'123456'的數(shù)據(jù)

    delete from product where sku='123456'

    其他操作實例

    多表查詢

    select p.sku,b.name from product p,brand b where p.brand_id=b.id and p.sku='123456'

    子查詢

    select p.sku,p.name from product p where p.brand_id in (select id from brand where id=123)

    左連接

    select p.sku,p.name,b.name from product p left join brand b on p.brand_id=b.id

    從一個表導(dǎo)入數(shù)據(jù)到另一個表

    insert into product1 (sku,name,brand_id) (select sku,name,brand_id from product2)

    查找不同的數(shù)據(jù)

    select distinct p.sku from product p

    查詢時按照某個字段排序(asc升序,desc降序)

    select * from product order by name desc

    常見問題

    如何創(chuàng)建表

    CREATE TABLE  product (
    `sku` char(6) NOT NULL COMMENT '商品的唯一標識\n',
    `brand_id` int(11) default NULL,
    `name` varchar(50) default NULL,
    PRIMARY KEY (`sku`),
    CONSTRAINT `brand_fk_constraint` FOREIGN KEY (`brand_id`) REFERENCES `brand` (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8

    如何創(chuàng)建外鍵

    alter table product add CONSTRAINT `brand_fk_constraint` FOREIGN KEY (`brand_id`) REFERENCES `brand` (`id`)

    如何修改表中的字段

    alter table product modify name varchar(200)

    如何向表中添加字段

    alter table product add comment varchar(200)

    如何刪除表中字段

    alter table product drop name

    存儲過程和觸發(fā)器

    h3.mysql創(chuàng)建表

    drop table if exists news;

    /*==========================*/
    /* Table: 消息表 */
    /*==========================*/
    create table news
    (
    NewsId bigint(20) not null unsigned primary key auto_increment,
    NewsContext varchar(50) not null,
    NewsType varchar(50) not null,
    UsersId int(11) not null
    );
    alter table news add constraint FK_Id foreign key (NewsId)
    references users (UsersId);

    資源

    官方參考:http://dev.mysql.com/doc/

    posted @ 2009-07-02 09:38 xiaoxinchen 閱讀(118) | 評論 (0)編輯 收藏

    基本語法

    聲明

    #set ($var=XXX)
    左邊可以是以下的內(nèi)容:
    • Variable reference
    • String literal
    • Property reference
    • Method reference
    • Number literal #set ($i=1)
    • ArrayList #set ($arr=["yt1","t2"])
    • 算術(shù)運算符
    • References 引用的類型

    注釋

    單行:

    ## this is a comment

    多行:

    #* this line
    and this line
    and this line, are comments...*#

    變量 Variables

    以 "$" 開頭,第一個字符必須為字母。character followed by a VTL Identifier. (a .. z or A .. Z).
    變量可以包含的字符有以下內(nèi)容:
    • alphabetic (a .. z, A .. Z)
    • numeric (0 .. 9)
    • hyphen ("-")
    • underscore ("_")

    Properties

    $Identifier.Identifier
    $user.name
    hashtable user中的的name值.類似:user.get("name")

    h2、Methods

    object user.getName() = $user.getName()

    h2、Formal Reference Notation

    用{}把變量名跟字符串分開。如

    #set ($user="csy"}
    ${user}name

    返回csyname

    $與$!的區(qū)別

    當找不到username的時候,$username返回字符串"$username",而$!username返回空字符串""

    雙引號 與 引號

    #set ($var="helo")

    則 test"$var" 返回testhello,test'$var' 返回test'$var'。
    可以通過設(shè)置 stringliterals.interpolate=false改變默認處理方式

    條件語句

    #if( $foo )
    <strong>Velocity!</strong>
    #end
    #if($foo)
    #elseif()
    #else
    #end

    當$foo為null或為Boolean對象的false值執(zhí)行.

    邏輯運算符:

    == && || !

    循環(huán)語句

    #foreach($var in $arrays ) // 集合包含下面三種Vector, a Hashtable or an Array
    #end

    #foreach( $product in $allProducts )
    <li>$product</li>
    #end

    #foreach( $key in $allProducts.keySet() )
    <li>Key: $key -> Value: $allProducts.get($key)</li>
    #end

    #foreach( $customer in $customerList )
    <tr><td>$velocityCount</td><td>$customer.Name</td></tr>
    #end

    velocityCount變量在配置文件中定義

    1. Default name of the loop counter
    2. variable reference.
      directive.foreach.counter.name = velocityCount
    3. Default starting value of the loop
    4. counter variable reference.
      directive.foreach.counter.initial.value = 1

    包含文件

    #include( "one.gif","two.txt","three.htm" )

    Parse導(dǎo)入腳本

    #parse("me.vm" )

    #stop 停止執(zhí)行并返回

    定義宏

    Velocimacros, 相當于函數(shù)支持包含功能:

    #macro( d )
    <tr><td></td></tr>
    #end
    調(diào)用
    #d()

    帶參數(shù)的宏

    #macro( tablerows $color $somelist )
    #foreach( $something in $somelist )
    <tr><td bgcolor=$color>$something</td></tr>
    #end
    #end

    Range Operator

    #foreach( $foo in [1..5] )

    與struts2的整合

    模板裝載位置(按順序依次搜索)

    • Web application 應(yīng)用程序路徑,會覆蓋掉類路徑下的同名配置文件;
    • Class path 類路徑,一般為缺省模板的配置,公共模板位置;

    數(shù)據(jù)來源(按順序依次搜索)

    • The value stack
    • The action context
    • Built-in variables

    Struts2-Velocity集成的一些隱含變量

    • stack - ValueStack自身。調(diào)用方式:${stack.findString('ognl expr')}
    • action - 最新操作的action
    • reponse
    • request
    • session
    • applicaion - 獲得servlet的環(huán)境
    • base - 請求環(huán)境的路徑

    Velocity Result 輸出模板

    模擬jsp執(zhí)行環(huán)境,使用velocity的模板直接顯示到servelet的輸出流。

    location - 模板位置,沒有其它參數(shù)時的缺省配置。
    parse - 默認true ,false將不解析Ognl expressions.

    配置范例:

    <result name="success" type="velocity">
    <param name="location">foo.vm</param>
    </result>

    等價于以下的配置方式:

    <result name="success" type="velocity">
    foo.vm
    </result>

    Velocity語法

    http://blog.csdn.net/alexwan/archive/2007/10/29/1853285.aspx

    Struts 與 Velocity 的集成

    http://www.ibm.com/developerworks/cn/java/j-sr1.html

    posted @ 2009-07-02 09:38 xiaoxinchen 閱讀(161) | 評論 (0)編輯 收藏
    cdn

    介紹

    CDN 的全稱是Content Delivery Network,即內(nèi)容分發(fā)網(wǎng)絡(luò)。其目的是通過在現(xiàn)有的Internet中增加一層新的網(wǎng)絡(luò)架構(gòu), 將網(wǎng)站的內(nèi)容發(fā)布到最接近用戶的網(wǎng)絡(luò)"邊緣", 使用戶可以就近取得所需的內(nèi)容, 解決Internet網(wǎng)絡(luò)擁擠的狀況, 提高用戶訪問網(wǎng)站的響應(yīng)速度。從技術(shù)上全面解決由于網(wǎng)絡(luò)帶寬小, 用戶訪問量大, 網(wǎng)點分布不均等原因所造成的用戶訪問網(wǎng)站響應(yīng)速度慢的問題。

    CDN互聯(lián)網(wǎng)內(nèi)容發(fā)布網(wǎng)絡(luò)(Content Delivery Network)

    CDN 技術(shù)是近年來在美國首先興起并迅速發(fā)展起來的一種解決互聯(lián)網(wǎng)性能不佳問題的有效手段。其基本思路就是盡可能避開互聯(lián)網(wǎng)上有可能影響數(shù)據(jù)傳輸速度和穩(wěn)定性的 瓶頸和環(huán)節(jié),使內(nèi)容傳輸?shù)母臁⒏€(wěn)。通過在網(wǎng)絡(luò)各處放置節(jié)點服務(wù)器所構(gòu)成的在現(xiàn)有的互聯(lián)網(wǎng)基礎(chǔ)之上的一層智能虛擬網(wǎng)絡(luò),cdn系統(tǒng)能夠?qū)崟r地根據(jù)網(wǎng)絡(luò)流 量和各節(jié)點的連接、負載狀況以及到用戶的距離和響應(yīng)時間等綜合信息將用戶的請求重新導(dǎo)向離用戶最近的服務(wù)節(jié)點上。

    實際上,內(nèi)容分發(fā) 布網(wǎng)絡(luò)(CDN)是一種新型的網(wǎng)絡(luò)構(gòu)建方式,它是為能在傳統(tǒng)的IP網(wǎng)發(fā)布寬帶豐富媒體而特別優(yōu)化的網(wǎng)絡(luò)覆蓋層;而從廣義的角度,CDN代表了一種基于質(zhì)量 與秩序的網(wǎng)絡(luò)服務(wù)模式。簡單地說,內(nèi)容發(fā)布網(wǎng)(CDN)是一個經(jīng)策略性部署的整體系統(tǒng),包括分布式存儲、負載均衡、網(wǎng)絡(luò)請求的重定向和內(nèi)容管理4個要件, 而內(nèi)容管理和全局的網(wǎng)絡(luò)流量管理(Traffic Management)是CDN的核心所在。通過用戶就近性和服務(wù)器負載的判斷,CDN確保內(nèi)容以一種極為高效的方式為用戶的請求提供服務(wù)。總的來說,內(nèi) 容服務(wù)基于緩存服務(wù)器,也稱作代理緩存(Surrogate),它位于網(wǎng)絡(luò)的邊緣,距用戶僅有"一跳"(Single Hop)之遙。同時,代理緩存是內(nèi)容提供商源服務(wù)器(通常位于CDN服務(wù)提供商的數(shù)據(jù)中心)的一個透明鏡像。這樣的架構(gòu)使得CDN服務(wù)提供商能夠代表他們 客戶,即內(nèi)容供應(yīng)商,向最終用戶提供盡可能好的體驗,而這些用戶是不能容忍請求響應(yīng)時間有任何延遲的。據(jù)統(tǒng)計,采用CDN技術(shù),能處理整個網(wǎng)站頁面的 70%~95%的內(nèi)容訪問量,減輕服務(wù)器的壓力,提升了網(wǎng)站的性能和可擴展性。

    與目前現(xiàn)有的內(nèi)容發(fā)布模式相比較,CDN強調(diào)了網(wǎng)絡(luò) 在內(nèi)容發(fā)布中的重要性。通過引入主動的內(nèi)容管理層的和全局負載均衡,CDN從根本上區(qū)別于傳統(tǒng)的內(nèi)容發(fā)布模式。在傳統(tǒng)的內(nèi)容發(fā)布模式中,內(nèi)容的發(fā)布由 ICP的應(yīng)用服務(wù)器完成,而網(wǎng)絡(luò)只表現(xiàn)為一個透明的數(shù)據(jù)傳輸通道,這種透明性表現(xiàn)在網(wǎng)絡(luò)的質(zhì)量保證僅僅停留在數(shù)據(jù)包的層面,而不能根據(jù)內(nèi)容對象的不同區(qū)分 服務(wù)質(zhì)量。此外,由于IP網(wǎng)的"盡力而為"的特性使得其質(zhì)量保證是依靠在用戶和應(yīng)用服務(wù)器之間端到端地提供充分的、遠大于實際所需的帶寬通量來實現(xiàn)的。在 這樣的內(nèi)容發(fā)布模式下,不僅大量寶貴的骨干帶寬被占用,同時ICP的應(yīng)用服務(wù)器的負載也變得非常重,而且不可預(yù)計。當發(fā)生一些熱點事件和出現(xiàn)浪涌流量時, 會產(chǎn)生局部熱點效應(yīng),從而使應(yīng)用服務(wù)器過載退出服務(wù)。這種基于中心的應(yīng)用服務(wù)器的內(nèi)容發(fā)布模式的另外一個缺陷在于個性化服務(wù)的缺失和對寬帶服務(wù)價值鏈的扭 曲,內(nèi)容提供商承擔(dān)了他們不該干也干不好的內(nèi)容發(fā)布服務(wù)。

    縱觀整個寬帶服務(wù)的價值鏈,內(nèi)容提供商和用戶位于整個價值鏈的兩端,中間 依靠網(wǎng)絡(luò)服務(wù)提供商將其串接起來。隨著互聯(lián)網(wǎng)工業(yè)的成熟和商業(yè)模式的變革,在這條價值鏈上的角色越來越多也越來越細分。比如內(nèi)容/應(yīng)用的運營商、托管服務(wù) 提供商、骨干網(wǎng)絡(luò)服務(wù)提供商、接入服務(wù)提供商等等。在這一條價值鏈上的每一個角色都要分工合作、各司其職才能為客戶提供良好的服務(wù),從而帶來多贏的局面。 從內(nèi)容與網(wǎng)絡(luò)的結(jié)合模式上看,內(nèi)容的發(fā)布已經(jīng)走過了ICP的內(nèi)容(應(yīng)用)服務(wù)器和IDC這兩個階段。IDC的熱潮也催生了托管服務(wù)提供商這一角色。但 是,IDC并不能解決內(nèi)容的有效發(fā)布問題。內(nèi)容位于網(wǎng)絡(luò)的中心并不能解決骨干帶寬的占用和建立IP網(wǎng)絡(luò)上的流量秩序。因此將內(nèi)容推到網(wǎng)絡(luò)的邊緣,為用戶提 供就近性的邊緣服務(wù),從而保證服務(wù)的質(zhì)量和整個網(wǎng)絡(luò)上的訪問秩序就成了一種顯而易見的選擇。而這就是內(nèi)容發(fā)布網(wǎng)(CDN)服務(wù)模式。CDN的建立解決了困 擾內(nèi)容運營商的內(nèi)容"集中與分散"的兩難選擇,無疑對于構(gòu)建良好的互聯(lián)網(wǎng)價值鏈是有價值的,也是不可或缺的最優(yōu)網(wǎng)站加速服務(wù)。

    目前,國內(nèi)訪問量較高的大型網(wǎng)站如新浪、網(wǎng)易等,均使用CDN網(wǎng)絡(luò)加速技術(shù),雖然網(wǎng)站的訪問巨大,但無論在什么地方訪問都會感覺速度很快。而一般的網(wǎng)站如果服務(wù)器在網(wǎng)通,電信用戶訪問很慢,如果服務(wù)器在電信,網(wǎng)通用戶訪問又很慢。

    它 采取了分布式網(wǎng)絡(luò)緩存結(jié)構(gòu)(即國際上流行的web cache技術(shù)),通過在現(xiàn)有的Internet中增加一層新的網(wǎng)絡(luò)架構(gòu),將網(wǎng)站的內(nèi)容發(fā)布到最接近用戶的cache服務(wù)器內(nèi),通過DNS負載均衡的技 術(shù),判斷用戶來源就近訪問cache服務(wù)器取得所需的內(nèi)容,解決Internet網(wǎng)絡(luò)擁塞狀況,提高用戶訪問網(wǎng)站的響應(yīng)速度,如同提供了多個分布在各地的 加速器,以達到快速、可冗余的為多個網(wǎng)站加速的目的。

    CDN的特點

    1. 本地Cache加速 提高了企業(yè)站點(尤其含有大量圖片和靜態(tài)頁面站點)的訪問速度,并大大提高以上性質(zhì)站點的穩(wěn)定性
    2. 鏡像服務(wù) 消除了不同運營商之間互聯(lián)的瓶頸造成的影響,實現(xiàn)了跨運營商的網(wǎng)絡(luò)加速,保證不同網(wǎng)絡(luò)中的用戶都能得到良好的訪問質(zhì)量。
    3. 遠程加速 遠程訪問用戶根據(jù)DNS負載均衡技術(shù) 智能自動選擇Cache服務(wù)器,選擇最快的Cache服務(wù)器,加快遠程訪問的速度
    4. 帶寬優(yōu)化 自動生成服務(wù)器的遠程Mirror(鏡像)cache服務(wù)器,遠程用戶訪問時從cache服務(wù)器上讀取數(shù)據(jù),減少遠程訪問的帶寬、分擔(dān)網(wǎng)絡(luò)流量、減輕原站點WEB服務(wù)器負載等功能。
    5. 集群抗攻擊 廣泛分布的CDN節(jié)點加上節(jié)點之間的智能冗于機制,可以有效地預(yù)防黑客入侵以及降低各種D.D.o.S攻擊對網(wǎng)站的影響,同時保證較好的服務(wù)質(zhì)量 。

    關(guān)鍵技術(shù)

    1. 內(nèi)容發(fā)布:它借助于建立索引、緩存、流分裂、組播(Multicast)等技術(shù),將內(nèi)容發(fā)布或投遞到距離用戶最近的遠程服務(wù)點(POP)處;
    2. 內(nèi)容路由:它是整體性的網(wǎng)絡(luò)負載均衡技術(shù),通過內(nèi)容路由器中的重定向(DNS)機制,在多個遠程POP上均衡用戶的請求,以使用戶請求得到最近內(nèi)容源的響應(yīng);
    3. 內(nèi)容交換:它根據(jù)內(nèi)容的可用性、服務(wù)器的可用性以及用戶的背景,在POP的緩存服務(wù)器上,利用應(yīng)用層交換、流分裂、重定向(ICP、WCCP)等技術(shù),智能地平衡負載流量;
    4. 性能管理:它通過內(nèi)部和外部監(jiān)控系統(tǒng),獲取網(wǎng)絡(luò)部件的狀況信息,測量內(nèi)容發(fā)布的端到端性能(如包丟失、延時、平均帶寬、啟動時間、幀速率等),保證網(wǎng)絡(luò)處于最佳的運行狀態(tài)。

    P4P與傳統(tǒng)CDN、P2P的對比

    7 月30日消息:德國一個名為iPoque的研究機構(gòu)在2007年研究了一百多萬網(wǎng)民將近 3TB的匿名數(shù)據(jù)流量,調(diào)查地區(qū)包括澳大利亞、東歐、德國、中東和南歐地區(qū)。調(diào)查發(fā)現(xiàn),目前網(wǎng)絡(luò)帶寬“消費大戶”是P2P文件共享,在中東占據(jù)了49%, 東歐地區(qū)占據(jù)了84%。從全球來看,晚上時段的網(wǎng)絡(luò)帶寬有95%被P2P占據(jù)。據(jù)國內(nèi)權(quán)威部門統(tǒng)計,當前P2P流量已經(jīng)占整個互聯(lián)網(wǎng)流量的約70%,并且 正在以每年350%的速度增長。P2P流量消耗了巨大的網(wǎng)絡(luò)帶寬,尤其是國際帶寬,使網(wǎng)絡(luò)基礎(chǔ)設(shè)施不堪重負,運營商苦不堪言。

    問題 的癥結(jié)不在于P2P,而在于交換的機制。P2P過于強調(diào)“對等”,每個節(jié)點之間的交換完全是無序的。一個北京的用戶,既可能和廣州的用戶進行文件片段的交 換,也可能和遠在美國的某用戶進行交換。顯然,無序的交換導(dǎo)致了無謂的跨地區(qū)甚至是跨國的 “流量旅行”,這耗費了寶貴的國內(nèi)和國際帶寬資源,代價巨大。

    如 果正好用戶都在同一個地區(qū),那么,本地化的交換的成本就會大大降低。這也正是P4P的簡單原理——讓P2P也玩“同城”。 P4P全稱是“Proactive network Provider Participation for P2P(電信運營商主動參與P2P網(wǎng)絡(luò))”。與P2P隨機挑選Peer(對等機)不同,P4P協(xié)議可以協(xié)調(diào)網(wǎng)絡(luò)拓撲數(shù)據(jù),能夠有效選擇節(jié)點,從而提高網(wǎng)絡(luò) 路由效率。仍以上述例子來說,北京的用戶就可以優(yōu)先和北京同城的用戶來實現(xiàn)文件片段的交換,再擴展至較遠的地區(qū),有十分的必要時,才會出國進行文件片段交 換。當然,P4P的運行機制,要遠遠超過“同城交換”的概念,它還會根據(jù)用戶的上行、下載帶寬進行綜合判斷,以進行最有效選擇,最大化整體交換的效率。

    舉 幾個例子可以說明CDN的普遍作用。例如2008年,北京奧運會之前,關(guān)于門票網(wǎng)絡(luò)出售,很多國內(nèi)的朋友都去登陸,而大家的登錄的時刻幾乎千篇一律,導(dǎo)致 中國政府的網(wǎng)站服務(wù)器支撐不了這么大的請求,誰都進去不了,都被堵死在門外。這中現(xiàn)象在國內(nèi)許多網(wǎng)站都出現(xiàn)過,比如高考時期,學(xué)生上網(wǎng)填申請,大家都說是 自己網(wǎng)絡(luò)原因,其實不然,這都跟被請求的服務(wù)器有關(guān),來自四面八方的請求去請求他一個網(wǎng)站,他自然接受不了這么大的帶寬,給人一種印象,就是互聯(lián)網(wǎng)太慢, 落后了。這樣的例子很多,我們就不紛紛介紹了。不過互聯(lián)網(wǎng),網(wǎng)聚全球人的智慧。解決方法很多,美國作為世界的互聯(lián)網(wǎng)中心,提供了CDN技術(shù),內(nèi)容網(wǎng)絡(luò)分 發(fā)。美國很多軍方工程都是采用該技術(shù)。我國國內(nèi)的香港海洋科技集團的GTONE產(chǎn)品,專業(yè)為我國國內(nèi)大型公司提供海外服務(wù),在全球都有很廣的資源。國內(nèi)很 多很有實力的公司都和他們合作了。

    新建文件

    posted @ 2009-07-02 09:37 xiaoxinchen 閱讀(119) | 評論 (0)編輯 收藏
    1. 基本命令
    1. 常見文件操作
            建立目錄:mkdir 目錄名
    刪除空目錄:rmdir 目錄名
    無條件刪除子目錄: rm -rf 目錄名
    改變當前目錄:cd 目錄名 (進入用戶home目錄:cd ~;進入上一級目錄:cd -)
    查看自己所在目錄:pwd
    查看當前目錄大小:du
    顯示目錄文件列表:ls -l (-a:增加顯示隱含目錄)
    其中:藍:目錄;綠:可執(zhí)行文件;紅:壓縮文件;淺藍:鏈接文件;灰:其他文件;紅底白字:錯誤的鏈接文件
    瀏覽文件:more 文件名.txt;less 文件名.txt
    復(fù)制文件: cp 源文件 目標文件 (-r:包含目錄)
    查找文件:(1)find (2)locate 命令名
    鏈接:(1)建立hard鏈接:ln 來源文件 鏈接文件(-d:創(chuàng)建目錄鏈接);(2)建立符號鏈接:ln -s 來源文件 鏈接文件
    文本編碼轉(zhuǎn)換工具iconv:iconv -f gb2312 -t utf-8 -o new.txt old.txt
    輸入/輸出格式規(guī)范
    -f, --from-code=NAME 原始文本編碼,
    -t,--to-code=NAME 輸出編碼,信息
    -l, --list 列出所有已知編碼字符集

    輸出控制:

    -c 忽略輸出中的無效字符
    -o, --output=FILE 輸出文件
    -s, --silent suppress warnings
    # 進程管理
            列出當前進程ID:ps -auxw
    終止進程:(1)終止單一進程:kill 進程ID號
    終止該程序所有進程:killall 程序名
    終止X-Window程序:xkill
    查看資源占用情況:(1)top (2)free (3)dmesg
    查看環(huán)境變量值:env
    重啟:(1)reboot (2)Ctrl Alt Del (3)init 6
    關(guān)機:(1)shutdown -h now (2)halt (3)init 0
    # 網(wǎng)絡(luò)管理
            顯示網(wǎng)絡(luò)接口參數(shù):ifconfig
    聯(lián)機狀況:ping xxx.xxx.xxx.xxx
    顯示網(wǎng)絡(luò)狀況:netstat ,其中:options:-a==所有sockets;-l==包含網(wǎng)絡(luò)設(shè)備;-n==數(shù)字IP;-o==其他信息;-r==路由表;-t==只列TCP sockets;-u==只列UDP sockets;-w==只列raw sockets;
    -x==只列Unix Domain sockets

    # 權(quán)限設(shè)定
            (1)chmod -a|u|g|o |-|=r|w|x 文件/目錄名
    其中:a--所有用戶(all);u--本用戶(user);g--用戶組(group);o--其他用戶(other users)
    --增加權(quán)限;---刪除權(quán)限;=--設(shè)置權(quán)限
    文件:r--只讀權(quán)限(read);w--寫權(quán)限(write);x--執(zhí)行權(quán)限(execute)
    目錄:r--允許列目錄下文件和子目錄;w--允許生成和刪除目錄下文件;x--允許訪問該目錄
    (2)chmod xxx 文件/目錄名
    其中:execute=1;write=2;read=4
    x取值:0--沒有任何權(quán)限(常用);1--只能執(zhí)行(不常見);2--只能寫(不常見);3--只能寫和執(zhí)行(不常見);4--只讀(常見);5--只讀和執(zhí)行(常見);6--讀和寫(常見);7--讀.寫和執(zhí)行
    # vim 常見命令
            進入后為命令模式:(1)插入i;(2)打開0;(3)修改c;(4)取代r;(5)替換s
    經(jīng)(1)后進入全屏幕編輯模式。
    命令模式-->編輯模式(a/i);編輯模式-->命令模式(Esc);命令模式-->末行模式(:)。
    :w/w newfile保存
    :q/q!退出iv;:wq保存退出
    http://vimcdoc.sourceforge.net/doc/help.html

    #ln命令

    ln 命令

    用途 : 鏈接文件。

    語法

    1>將某個文件鏈接到一個文件上 ln [ -f | -n] [ -s ] SourceFile [ TargetFile ]

    2>將一個或多個文件鏈接到一個目錄上 ln [ -f | -n] [ -s ] SourceFile ... TargetDirectory

    描述 ln 命令將在 SourceFile 參數(shù)中指定的文件鏈接到在 TargetFile 參數(shù)中指定的文件,或?qū)⑵滏溄拥皆?TargetDirectory 參數(shù)中指定的另一個目錄中的文件。

    在缺省情況下,ln 命令會創(chuàng)建硬鏈接。如果需要使用 ln 命令來創(chuàng)建符號鏈接,請指明 -s 標志。

    符號鏈接是指向文件的一個間接指針;它的目錄項中包含了它所鏈接的文件名。符號鏈接可能會跨越文件系統(tǒng),可能指向目錄。

    如果正在將某個文件鏈接到新的名字,那么只能列出一個文件。如果鏈接到一個目錄,那么可以列出多個文件。

    TargetFile 參數(shù)是可選的。

    如果不指定目標文件,ln 命令會在當前的目錄中創(chuàng)建一個新的文件。新的文件繼承了指定在 SourceFile 參數(shù)中的文件名。

    注意: 如果不使用 -s 標志,就不能在文件系統(tǒng)之間鏈接文件。 如果 TargetDirectory 已經(jīng)是鏈接到目錄上的一個符號鏈接,那么 ln 命令將現(xiàn)有的目標視為文件。 這意味著,類似于 ln -fs somepath/lname symdir 的命令不會遵循現(xiàn)有的 symdir 符號鏈接,作為代替,它會創(chuàng)建一個從 somepath/lname 到 symdir 的新的符號鏈接。

    參數(shù)

    -f 促使 ln 命令替換掉任何已經(jīng)存在的目的路徑。如果目的路徑已經(jīng)存在,而沒有指定 -f 標志,ln 命令不會創(chuàng)建新的鏈接,而是向標準錯誤寫一條診斷消息并繼續(xù)鏈接剩下的 SourceFiles。

    -n 指定,如果鏈接是一個現(xiàn)有的文件,那么不要覆蓋文件的內(nèi)容。 -f 標志重設(shè)了這個標志。這是缺省的行為。

    -s 促使 ln 命令創(chuàng)建符號鏈接。符號鏈接中包含了它所鏈接的文件的名字。當對鏈接執(zhí)行打開操作的時候,會使用到引用文件。對符號鏈接的 stat 調(diào)用會返回鏈接的目標文件;必須完成lstat 調(diào)用來獲取鏈接的信息。可以使用 readlink 調(diào)用來讀取符號鏈接的內(nèi)容。符號鏈接可能跨越文件系統(tǒng),指向目錄。

    注意:當為 -s 標志指定 SourceFile 參數(shù)的時候,必須使用絕對路徑。如果沒有指明絕對路徑,那么當 SourceFile 和 TargetFile 參數(shù)位于不同的目錄中的時候,可能會發(fā)生意外的結(jié)果。在創(chuàng)建符號鏈接之前,不需要存在源文件。

    退出狀態(tài) 此命令返回以下的退出值:

    0 所有指定的文件都成功鏈接上了。

    0 出現(xiàn)一次錯誤。

    示例

    1>為了創(chuàng)建到一個文件的另一個鏈接(別名),請輸入:

    ln -f file1 file2 這會將 file1 鏈接到新的名稱, file2。如果 file2 不存在,那么會創(chuàng)建該文件名。如果 file2 已經(jīng)存在了,那么這個文件會被替換為指向 file1的一個鏈接。然后 file1 和 file2 文件名會指向同一個文件。對其中任何一個的更改都會出現(xiàn)在另一個中。如果一個文件名被 rm 命令刪除,那么該文件并沒有完全被刪除,因為它仍然以其它的名字存在。

    2>為了將文件鏈接為另一個目錄中的相同名字,請輸入:

    ln index dir1 這會將 index 鏈接到新的名稱,dir1/index。

    注意:在示例 1 中的 file2 是一個文件的名稱;在示例 2 中的 dir1 是一個已經(jīng)存在的目錄。

    3>為了將幾個文件鏈接為另一個目錄中的名稱,請輸入:

    ln file2 dir2/file3 /home/dir1 這會將 file2 鏈接到新的名稱 /home/dir1/file2;將 dir2/file3 鏈接到新的名稱 /home/dir1/file3。

    4>如果想要在 ln 命令中使用模式匹配字符,請輸入:

    ln dir1/* . 這會將 dir1 目錄中的所有文件鏈接到當前目錄中, . (點),給他們在 dir1 目錄中同樣的名稱。

    注意: 必須在星號和句點之間輸入一個空格。

    5>為了創(chuàng)建一個符號鏈接,輸入:

    ln -s /tmp/test test

    這會在當前的目錄中創(chuàng)建符號鏈接 test。 test 文件指向 /tmp/test 文件。如果 /tmp/test 文件已經(jīng)存在了,那么 cat test 命令可以列出其內(nèi)容。

    6>如果想要在不指明 TargetFile 參數(shù)的情況下得到相同的結(jié)果,請輸入:

    ln -s /tmp/test

    文件

    /usr/bin/ln 包含了 ln 命令。

    1. 常見配置文件
    posted @ 2009-07-02 09:37 xiaoxinchen 閱讀(126) | 評論 (0)編輯 收藏

    介紹

    入門

    安裝

    不用安裝,直接解壓即可。如果進行JEE開發(fā),可以用eclipse-jee-ganymede-SR2文件,而PHP的話可以直接用PDT。Python可以用基于Apanta的PyDev。

    基本操作

    選項:Windows -> Preference。
    安裝新特性/插件:Help -> SoftwareUpdates

    常用快捷鍵

    快捷鍵的設(shè)置和修改在Windows -> Preference ->General -> Keys;

    我最常用的:
    Ctrl+Space 代碼助手完成一些代碼的插入(但一般和輸入法有沖突,可以Alt+/來代替,在keys里找到command 為Content Assist的,把其Binding改為Alt+/) 這個是我最喜歡的功能,你可以把變量命名的很長,下次引用時只要打首個字母,再打Alt+/,就能寫出變量。
    Ctrl+Q 定位到最后編輯的地方
    Ctrl+Shift+R 全局 打開資源
    Ctrl+E 快速顯示當前Editer的下拉列表(如果當前頁面沒有顯示的用黑體表示)
    Java編輯器 組織導(dǎo)入 Ctrl+Shift+O
    Java編輯器 添加導(dǎo)入 Ctrl+Shift+M
    Alt+← 前一個編輯的頁面
    Alt+→ 下一個編輯的頁面(當然是針對上面那條來說了)
    Ctrl+1 快速修復(fù)
    Ctrl+/ 注釋當前行,再按則取消注釋
    Ctrl+D: 刪除當前行
    Java編輯器 格式化 Ctrl+Shift+F
    Alt+↓ 當前行和下面一行交互位置(特別實用,可以省去先剪切,再粘貼了)
    Alt+↑ 當前行和上面一行交互位置(同上)
    Ctrl+L 定位在某行 (對于程序超過100的人就有福音了)
    Alt+Shift+R 重命名 (是我自己最愛用的一個了,尤其是變量和類的Rename,比手工方法能節(jié)省很多勞動力)
    Alt+Shift+Z 使用try/catch塊來包圍

    下面是網(wǎng)上轉(zhuǎn)過來
    Eclipse快捷鍵大全(轉(zhuǎn)載)
    Ctrl+1 快速修復(fù)(最經(jīng)典的快捷鍵,就不用多說了)
    Ctrl+D: 刪除當前行
    Ctrl+Alt+↓ 復(fù)制當前行到下一行(復(fù)制增加)
    Ctrl+Alt+↑ 復(fù)制當前行到上一行(復(fù)制增加)
    Alt+↓ 當前行和下面一行交互位置(特別實用,可以省去先剪切,再粘貼了)
    Alt+↑ 當前行和上面一行交互位置(同上)
    Alt+← 前一個編輯的頁面
    Alt+→ 下一個編輯的頁面(當然是針對上面那條來說了)
    Alt+Enter 顯示當前選擇資源(工程,or 文件 or文件)的屬性
    Shift+Enter 在當前行的下一行插入空行(這時鼠標可以在當前行的任一位置,不一定是最后)
    Shift+Ctrl+Enter 在當前行插入空行(原理同上條)
    Ctrl+Q 定位到最后編輯的地方
    Ctrl+L 定位在某行 (對于程序超過100的人就有福音了)
    Ctrl+M 最大化當前的Edit或View (再按則反之)
    Ctrl+/ 注釋當前行,再按則取消注釋
    Ctrl+O 快速顯示 OutLine
    Ctrl+T 快速顯示當前類的繼承結(jié)構(gòu)
    Ctrl+W 關(guān)閉當前Editer
    Ctrl+K 參照選中的Word快速定位到下一個
    Ctrl+E 快速顯示當前Editer的下拉列表(如果當前頁面沒有顯示的用黑體表示)
    Ctrl+/(小鍵盤) 折疊當前類中的所有代碼
    Ctrl+×(小鍵盤) 展開當前類中的所有代碼
    Ctrl+Space 代碼助手完成一些代碼的插入(但一般和輸入法有沖突,可以修改輸入法的熱鍵,也可以暫用Alt+/來代替)
    Ctrl+Shift+E 顯示管理當前打開的所有的View的管理器(可以選擇關(guān)閉,激活等操作)
    Ctrl+J 正向增量查找(按下Ctrl+J后,你所輸入的每個字母編輯器都提供快速匹配定位到某個單詞,如果沒有,則在stutes line中顯示沒有找到了,查一個單詞時,特別實用,這個功能Idea兩年前就有了)
    Ctrl+Shift+J 反向增量查找(和上條相同,只不過是從后往前查)
    Ctrl+Shift+F4 關(guān)閉所有打開的Editer
    Ctrl+Shift+X 把當前選中的文本全部變味小寫
    Ctrl+Shift+Y 把當前選中的文本全部變?yōu)樾?br /> Ctrl+Shift+F 格式化當前代碼
    Ctrl+Shift+P 定位到對于的匹配符(譬如{}) (從前面定位后面時,光標要在匹配符里面,后面到前面,則反之)

    下面的快捷鍵是重構(gòu)里面常用的,本人就自己喜歡且常用的整理一下(注:一般重構(gòu)的快捷鍵都是Alt+Shift開頭的了)
    Alt+Shift+R 重命名 (是我自己最愛用的一個了,尤其是變量和類的Rename,比手工方法能節(jié)省很多勞動力)
    Alt+Shift+M 抽取方法 (這是重構(gòu)里面最常用的方法之一了,尤其是對一大堆泥團代碼有用)
    Alt+Shift+C 修改函數(shù)結(jié)構(gòu)(比較實用,有N個函數(shù)調(diào)用了這個方法,修改一次搞定)
    Alt+Shift+L 抽取本地變量( 可以直接把一些魔法數(shù)字和字符串抽取成一個變量,尤其是多處調(diào)用的時候)
    Alt+Shift+F 把Class中的local變量變?yōu)閒ield變量 (比較實用的功能)
    Alt+Shift+I 合并變量(可能這樣說有點不妥Inline)
    Alt+Shift+V 移動函數(shù)和變量(不怎么常用)
    Alt+Shift+Z 重構(gòu)的后悔藥(Undo)

    編輯
    作用域 功能 快捷鍵
    全局 查找并替換 Ctrl+F
    文本編輯器 查找上一個 Ctrl+Shift+K
    文本編輯器 查找下一個 Ctrl+K
    全局 撤銷 Ctrl+Z
    全局 復(fù)制 Ctrl+C
    全局 恢復(fù)上一個選擇 Alt+Shift+↓
    全局 剪切 Ctrl+X
    全局 快速修正 Ctrl1+1
    全局 內(nèi)容輔助 Alt+/
    全局 全部選中 Ctrl+A
    全局 刪除 Delete
    全局 上下文信息 Alt+?
    Alt+Shift+?
    Ctrl+Shift+Space
    Java編輯器 顯示工具提示描述 F2
    Java編輯器 選擇封裝元素 Alt+Shift+↑
    Java編輯器 選擇上一個元素 Alt+Shift+←
    Java編輯器 選擇下一個元素 Alt+Shift+→
    文本編輯器 增量查找 Ctrl+J
    文本編輯器 增量逆向查找 Ctrl+Shift+J
    全局 粘貼 Ctrl+V
    全局 重做 Ctrl+Y

    查看
    作用域 功能 快捷鍵
    全局 放大 Ctrl+=
    全局 縮小 Ctrl+-

    窗口
    作用域 功能 快捷鍵
    全局 激活編輯器 F12
    全局 切換編輯器 Ctrl+Shift+W
    全局 上一個編輯器 Ctrl+Shift+F6
    全局 上一個視圖 Ctrl+Shift+F7
    全局 上一個透視圖 Ctrl+Shift+F8
    全局 下一個編輯器 Ctrl+F6
    全局 下一個視圖 Ctrl+F7
    全局 下一個透視圖 Ctrl+F8
    文本編輯器 顯示標尺上下文菜單 Ctrl+W
    全局 顯示視圖菜單 Ctrl+F10
    全局 顯示系統(tǒng)菜單 Alt+-

    導(dǎo)航
    作用域 功能 快捷鍵
    Java編輯器 打開結(jié)構(gòu) Ctrl+F3
    全局 打開類型 Ctrl+Shift+T
    全局 打開類型層次結(jié)構(gòu) F4
    全局 打開聲明 F3
    全局 打開外部javadoc Shift+F2
    全局 打開資源 Ctrl+Shift+R
    全局 后退歷史記錄 Alt+←
    全局 前進歷史記錄 Alt+→
    全局 上一個 Ctrl+,
    全局 下一個 Ctrl+.
    Java編輯器 顯示大綱 Ctrl+O
    全局 在層次結(jié)構(gòu)中打開類型 Ctrl+Shift+H
    全局 轉(zhuǎn)至匹配的括號 Ctrl+Shift+P
    全局 轉(zhuǎn)至上一個編輯位置 Ctrl+Q
    Java編輯器 轉(zhuǎn)至上一個成員 Ctrl+Shift+↑
    Java編輯器 轉(zhuǎn)至下一個成員 Ctrl+Shift+↓
    文本編輯器 轉(zhuǎn)至行 Ctrl+L

    搜索
    作用域 功能 快捷鍵
    全局 出現(xiàn)在文件中 Ctrl+Shift+U
    全局 打開搜索對話框 Ctrl+H
    全局 工作區(qū)中的聲明 Ctrl+G
    全局 工作區(qū)中的引用 Ctrl+Shift+G

    文本編輯
    作用域 功能 快捷鍵
    文本編輯器 改寫切換 Insert
    文本編輯器 上滾行 Ctrl+↑
    文本編輯器 下滾行 Ctrl+↓

    文件
    作用域 功能 快捷鍵
    全局 保存 Ctrl+X
    Ctrl+S
    全局 打印 Ctrl+P
    全局 關(guān)閉 Ctrl+F4
    全局 全部保存 Ctrl+Shift+S
    全局 全部關(guān)閉 Ctrl+Shift+F4
    全局 屬性 Alt+Enter
    全局 新建 Ctrl+N

    項目
    作用域 功能 快捷鍵
    全局 全部構(gòu)建 Ctrl+B

    源代碼
    作用域 功能 快捷鍵
    Java編輯器 格式化 Ctrl+Shift+F
    Java編輯器 取消注釋 Ctrl+\
    Java編輯器 注釋 Ctrl+/
    Java編輯器 添加導(dǎo)入 Ctrl+Shift+M
    Java編輯器 組織導(dǎo)入 Ctrl+Shift+O
    Java編輯器 使用try/catch塊來包圍 未設(shè)置,太常用了,所以在這里列出,建議自己設(shè)置。
    也可以使用Ctrl+1自動修正。

    運行
    作用域 功能 快捷鍵
    全局 單步返回 F7
    全局 單步跳過 F6
    全局 單步跳入 F5
    全局 單步跳入選擇 Ctrl+F5
    全局 調(diào)試上次啟動 F11
    全局 繼續(xù) F8
    全局 使用過濾器單步執(zhí)行 Shift+F5
    全局 添加/去除斷點 Ctrl+Shift+B
    全局 顯示 Ctrl+D
    全局 運行上次啟動 Ctrl+F11
    全局 運行至行 Ctrl+R
    全局 執(zhí)行 Ctrl+U

    重構(gòu)
    作用域 功能 快捷鍵
    全局 撤銷重構(gòu) Alt+Shift+Z
    全局 抽取方法 Alt+Shift+M
    全局 抽取局部變量 Alt+Shift+L
    全局 內(nèi)聯(lián) Alt+Shift+I
    全局 移動 Alt+Shift+V
    全局 重命名 Alt+Shift+R
    全局 重做 Alt+Shift+Y

    檢出項目

    首先安裝SVN插件(subversive或者subclipse),然后新建Project,從SVN檢出項目。需要特別注意的是,要在general / workspace選項中正確設(shè)置字符編碼,否則可能會出現(xiàn)編譯錯誤。

    用Maven構(gòu)建項目

    安裝IAM之后,在項目的context菜單中選“Maven 2 / Use Maven Dependency Management”,然后就可以管理依賴。

    查看數(shù)據(jù)庫

    打開 Database Perspective 即可。注意要先選擇驅(qū)動程序,即mysql的java connector的jar,然后才是配置各個連接的jdbc地址。

    關(guān)于插件

    插件安裝方法(zz)

    英文教程:http://www.venukb.com/2006/08/20/install-eclipse-plugins-the-easy-way/

    有關(guān)插件安裝問題,四種常用的方法在此特別注明:

    #“幫助”->“軟件更新”->“查找并安裝”->“搜索要安裝的新功能部件”->“新建遠程站點”(此種方式用于在線更新)
    #“幫助”->“軟件更新”->“查找并安裝”->“搜索要安裝的新功能部件”->“新建本地站點”(如果插件已經(jīng)下載到了本地,請不要用第一種方法)
    1. 直接拷貝plugins和features兩個目錄下的內(nèi)容置于$Eclipse_Home$/對應(yīng)的plugins和features下面
    2. 用link外鏈接與外部插件關(guān)聯(lián)

    最菜的,一般用第一種方法,而大部分生手一般選擇第二或者第三種方法,用得習(xí)慣的一般選擇最后一種方式。此四類方法優(yōu)劣勢對比如下:
    前三種方法都會將插件文件拷貝至相$Eclipse_Home$/對應(yīng)的plugins和features目錄下,從本質(zhì)上看,沒多大區(qū)別,并且插件只能 安裝和禁用,不能卸載(當然,如果你對插件對應(yīng)的目錄和文件都很熟悉的話,可以通過直接刪除拷進去的文件來達到卸載插件的目的),但方法一和方法二在安裝 插件的時候很容易出錯或者是產(chǎn)生沖突,特別是當你用了Myeclipse插件、中文包的同時,又想安裝HibernateSynchronizer、 Jode Compiler(Class反編譯工具)、Visual Editor等插件時,及有可能導(dǎo)致Myeclipse插件和中文包失效。

    所以,如果插件已經(jīng)下載到了本地,請直接拷貝至$Eclipse_Home$/對應(yīng)的plugins和features目錄下,也就是用方法三,這樣能避免沖突。

    方 法四是將所有的插件用一個外部目錄存放起來,假如是D:\plug-in,將上面所示的插件目錄文件全部拷貝到該目錄下,比如Tomcat插件,此時的文 件路徑就是D:\plug-in\tomcat_plug\eclipse\plugins \com.sysdeo.eclipse.tomcat_3.1.0.beta(請注意,方法四一定要嚴格這樣的目錄路徑放置文件)。然后 在$Eclipse_Home$下新建一個links目錄,并在links目錄下建立關(guān)聯(lián)文件,假如是tomcat.link,在建立的關(guān)聯(lián)文件中加入如 下語句:

    path=D:/plug-in/tomcat_plug

    還可以寫成相對路徑的形式。剩下的事情,不用我說你肯定都知道了,就是重啟Eclipse,在Dos窗口下進入Eclipse安 裝目錄,鍵入命令eclipse -clean,回車,或者進入$Eclipse_Home$/configuration目錄,刪除org.eclipse.update后再重新啟動 Eclipse。

    QA相關(guān)插件

    參考:http://www.ibm.com/developerworks/cn/java/j-ap01117/

    CheckStyle http://eclipse-cs.sourceforge.net/update/
    Coverlipse http://coverlipse.sf.net/update
    PMD http://pmd.sourceforge.net/eclipse/
    JDepend http://andrei.gmxhome.de/eclipse/
    Metrics http://metrics.sourceforge.net/update
    FindBugs http://findbugs.cs.umd.edu/eclipse

    參考資源

    http://www.ibm.com/developerworks/cn/eclipse/resources.html
    http://www.eclipseplugincentral.com/

    posted @ 2009-07-02 09:36 xiaoxinchen 閱讀(269) | 評論 (0)編輯 收藏

    Web標準

    我理解的Web標準
    web標準就是瀏覽器的開發(fā)廠商和界面開發(fā)人員共同遵循的標準。由萬維網(wǎng)聯(lián)盟W3C(World Wide Web Consortium)組織制定。
    Web標準化無異于工業(yè)標準化,就好像改錐和螺絲一樣,他們都遵循同樣的標準,易用,有效,甚至能贏得戰(zhàn)爭(注1)。
    遵循Web標準的好處
    • 高效率。開發(fā)人員可以更容易地理解彼此的編碼,web開發(fā)的團隊協(xié)作將得到簡化。
    • 易用性。大家都遵循標準,未來也許就不存在跨瀏覽器問題,也可以跨平臺(比如移動電話),另外,標準也可以使殘疾人士更容易地使用web。
    • 利于訪問。更易被搜索引擎訪問,也更易被準確地索引。

    注1:德國的工業(yè)非常發(fā)達,二戰(zhàn)時德國設(shè)計的武器都是標準件,即使一輛趟克被炸爛,其中的零件都還可以再利用,甚至可以應(yīng)用到槍支或其他武器上。

    Acid3

    測試瀏覽器支持Acid3的程度:http://acid3.acidtests.org/

    為什么要使用Web標準(zz)?

    英文版:http://www.webstandards.org/learn/faq/
    中文版:http://www.webstandards.org/learn/faq/faq_zh-simplified/

    posted @ 2009-07-02 09:35 xiaoxinchen 閱讀(109) | 評論 (0)編輯 收藏

    快速入門

    歡迎使用BeanShell.這是一個速成課程。我們將省去一些重要的選項和細節(jié)。要學(xué)習(xí)更多的內(nèi)容請看本User's Guide的其它部分。

    下載和運行BeanShell

    請到http://www.beanshell.org下載最新的JAR文件。你可以用圖形桌面模式和命令行模式起動BeanShell。
    如果你只是要玩一玩BeanShell,你可以在BeanShell的jar文件上雙擊來起動BeanShell的桌面。但不管怎樣,如果你要讓BeanShell與你的類與應(yīng)用程序一起工作就必須將BeanShell的jar文件加到classpath中。
    你可以將BeanShell的jar文件拖到JAVA_HOME的ext目錄也可以直接加到classpath中。

    • windows用戶請將bsh.jar放在JAVA_HOME/jre/lib/ext文件夾,OSX用戶可以放在/Library/Java/Extensions.
      或者增加BeanShell到你的classpath目錄,如:
      unix: export CLASSPATH=$CLASSPATH:bsh-xx.jar
      windows:set classpath %classpath%;bsh-xx.jar

    然后你就可以運行BeanShell在GUI或命令行模式:

    •  java bsh.Console       // run the graphical desktop
      or
           java bsh.Interpreter   // run as text-only on the command line
      or
           java bsh.Interpreter filename [ args ] // run script file

    可以在你的應(yīng)用程序內(nèi)部來運行,也可以作為debug及servlet的遠程服務(wù)器模式,或一個Applet內(nèi)部來運行BeanShell。請參考"BeanShell Modes of Operation"獲得更多詳情。

    BeanShell GUI

    用GUI模式啟動BeanShell后,將打開一個桌面視窗。用鼠標右擊在桌面的背景上,你可以打開另一個控制臺視窗及其它的工具如一個簡單的類游覽器。
    每一個控制臺視窗運行一個獨立的BeanShell解釋器。這個圖形化的控制臺支持基本的歷史命令,行編輯,剪切和粘貼,甚至類和變量名的自動完成功能。從控制臺你能開啟一個簡單的編輯視窗。在它里面,你可以編寫腳本和使用‘eval’選項求表達式的值。

    Java語句和表達式

    BeanShell能理解標準的JAVA語句,表達式,和方法宣告。語句和表達式的內(nèi)容可以是:變量,宣告,賦值,方法調(diào)用,循環(huán),條件等。
    在 Java程序中你必須嚴格的使用它們,但在BeanShell中,你可以用“寬松類型”(loosely typed)的方式來使用它們。也就是說,你可以在寫腳本時偷懶,不進行變量類型的宣告(在原始數(shù)據(jù)類型和對象都可以)。如果你試著用錯變量類 型,BeanShell將會給出一個錯誤。
    這里有一些例子:

    • foo = "Foo";   
      four = (2 + 2)*2/2;
      print( foo + " = " + four );  // print() is a BeanShell command
      // Do a loop
      for (i=0; i<5; i++)
          print(i);  
      // Pop up a frame with a button in it
      button = new JButton( "My Button" );
      frame = new JFrame( "My Frame" );
      frame.getContentPane().add( button, "Center" );
      frame.pack();
      frame.setVisible(true);

    有用的BeanShell命令

    在 剛才那個例子中我們用了一個內(nèi)建在BeanShell中的一個方便的命令print(),來顯示變量的值。print()跟ava的 System.out.println()非常的相像,除非它能保證輸出總是命令行。print()也可以顯示一些對象的類型(如數(shù)組),但比Java的 更詳細。另一個相關(guān)的命令是show(),用來開啟與關(guān)閉顯示你輸入的每一行的結(jié)果。
    這兒是一些其它的BeanShell的命令:
    source(), run() - 將一個bsh腳本讀到解釋器或運行在另一個解釋器。
    frame() - 顯示一個Frame或JFrame的GUI組件.
    load(), save() - 載入和保存一個序列化的對象到一個文件.
    cd(), cat(), dir(), pwd(), etc. - 類unix的shell命令。
    exec() - 運行一個本地的程序。
    javap() - 打印一個對象的方法和字段,類似于Java的javap命令。
    setAccessibility() - 開啟無限制的存取private 和protected的組件。
    要獲得更多的信息請查看BeanShell命令的詳細清單。

    提示:
    BeanShell命令并不是真的"內(nèi)建"其中的,而是作為腳本方法自動從classpath載入的. 你可以擴展基本命令集并加到classpath中作為自訂義的腳本來使用。

    腳本方法

    你可以在bsh中宣告和使用方法,就像在java的類中一樣。

    • int addTwoNumbers( int a, int b ) {
          return a + b;
      }
      sum = addTwoNumbers( 5, 7 );  // 12

    bsh的方法可以有動態(tài)的(寬松的)參數(shù)和返回類型。

    • add( a, b ) {
          return a + b;
      }
      foo = add(1, 2);            // 3
      foo = add("Oh", " baby");   // "Oh baby"

    實現(xiàn)Interface

    注意:如果要BeanShell能實現(xiàn)任意的Interface,必須有jdk1.3及以上支持。
    你可以在腳本中用標準的Java內(nèi)部類的語法來實現(xiàn)Interface.例如:

    • ActionListener scriptedListener = new ActionListener() {
          actionPerformed( event ) { ... }
      }

    你 可以不用實現(xiàn)Interface的所有方法,而只用實現(xiàn)你需要的方法。如果代碼中調(diào)用了未被實現(xiàn)的方法,將丟出異常。如果你想重載大量的方法的行為--例 如為日志生成一個"啞"適配器--你可以在腳本對象中實現(xiàn)一個特殊的方法:invoke(name,args)。invoke()方法用來處理任何未被定 義的方法的調(diào)用:

    • ml = new MouseListener() {
          mousePressed( event ) { ... }
          // handle the rest
          invoke( name, args ) { print("Method: "+name+" invoked!");
      }

    腳本對象

    在 BeanShell中,和在JavaScript與Perl中一樣,腳本對象是用封閉的方法體一構(gòu)成的。通過在方法未尾返回一個特殊值"this",你就 可以像使用方法一樣調(diào)用這個對象了。在這個方法調(diào)用時,你可以給與它任何的值。通常對象內(nèi)部需要包括方法,所以BeanShell的腳本方法在一定程度上 可再包含一些方法以構(gòu)成腳本對象。例如:

    • foo() {
          print("foo");
          x=5;
          bar() {
              print("bar");
          }
          return this;
      }
      myfoo = foo();    // prints "foo"
      print( myfoo.x ); // prints "5"
      myfoo.bar();      // prints "bar"

    如果這些代碼對你來說很陌生,別急,請用戶手冊可得到更透徹的解釋。

    在 你的腳本中,BeanShell腳本對象(也就是先前例子中的"this"參照)能自動實現(xiàn)任何JAVA介面類型。當JAVA代碼調(diào)用相應(yīng)與之通訊的腳本 方法內(nèi)的方法。當你試著將腳本對象作為參數(shù)傳給Java方法時,BeanShell會自動將它造型(cast)為相應(yīng)的類型。如要傳遞BeanShell 外部的對象時,你可以在需要時顯式的進行造型(cast).請看用戶手冊中的詳細內(nèi)容。

    從你的應(yīng)用程序調(diào)用BeanShell

    通過建立一個BeanShell解釋器,使用eval()或source()命令,你可以在你的應(yīng)用程序中求文本表達式的值和運行腳本。如果你希望在你的腳本內(nèi)部使用一個對象,可以用set()方法傳遞對象的變量參照給BeanShell,并通過get()方法取得結(jié)果。

    • import bsh.Interpreter;
      Interpreter i = new Interpreter();  // Construct an interpreter
      i.set("foo", 5);                    // Set variables
      i.set("date", new Date() );
      Date date = (Date)i.get("date");    // retrieve a variable
      // Eval a statement and get the result
      i.eval("bar = foo*10");            
      System.out.println( i.get("bar") );
      // Source an external script file
      i.source("somefile.bsh");

     

    BeanShell將成為Java平臺上的第三種編程語言
    2005-06-08  點擊:8  來源:CSDN  作者:CSDN
    JCP接納了一個新的技術(shù)規(guī)范進入標準化進程,這個編號為JSR-274的技術(shù)規(guī)范將把BeanShell引入為Java平臺上支持的又一種編程語言。

    JSR- 274(http://jcp.org/en/jsr/detail?id=274)是由 Patrick Niemeyer提交的技術(shù)規(guī)范,其目標是將BeanShell腳本語言(http://www.beanshell.org/)規(guī)范化為Java虛擬機 平臺上支持的第三種編程語言。除了Java之外,Java虛擬機還支持Groovy腳本語言。Doug Lea、Apache和Google三個JCP執(zhí)委會成員對此規(guī)范表示了支持。

    按照Java最初的設(shè)計思路,有很多語言都可以在JVM上 運行(詳細列表參見http://en.wikipedia.org/wiki/List_of_Java_scripting_languages), 但這些語言大多沒有流行起來。直到2004年為止,Java平臺事實上只有一種編程語言,也就是Java。2004年3月,Groovy(JSR- 241)成為了Java平臺上的第二種編程語言。

    消息全文請看:http://rmh.blogs.com/weblog/2005/05/beanshell_the_3.html

    http://www.cn-java.com/target/news.php?news_id=2450

    簡介:
    BeanShell是一種腳本語言,一種完全符合java語法的java腳本語言,并且又擁有自己的一些語法和方法,beanShell是一種松散類型的腳本語言(這點和JS類似)。
    下載地址:http://www.beanshell.org

    設(shè)置環(huán)境
    l 把;bsh-xx.jar放到$JAVA_HOME/jre/lib/ext文件夾下
    l unix: export CLASSPATH=$CLASSPATH:bsh-xx.jar
    l windows: set classpath %classpath%;bsh-xx.jar

    運行方式:
    l 界面UI方式 :java bsh.Console
    l 命令行方式 :java bsh.Interpreter
    l 運行腳本文件:java bsh.Interpreter filename [ args ]



    簡單舉例:
    在classpath中設(shè)置好環(huán)境變量,打開dos窗口,鍵入:java bsh.Console命令
    出現(xiàn)BeanShell圖片代表設(shè)置成功,beanshell開始運行





    測試內(nèi)容:
    設(shè)置變量
    foo = "Foo";
    four = (2 + 2)*2/2;
    打印變量
    print( foo + " = " + four );
    循環(huán)
    for (i=0; i<5; i++)
    print(i);
    在窗口中打印按鈕
    button = new JButton( "My Button" );
    frame = new JFrame( "My Frame" );
    frame.getContentPane().add( button, "Center" );
    frame.pack();
    frame.setVisible(true);

    完整代碼:
    foo = "Foo";
    four = (2 + 2)*2/2;
    print( foo + " = " + four );

    for (i=0; i<5; i++)
    print(i);

    button = new JButton( "My Button" );
    frame = new JFrame( "My Frame" );
    frame.getContentPane().add( button, "Center" );
    frame.pack();
    frame.setVisible(true);


    在窗口中輸入上面的代碼

    敲回車執(zhí)行,運行結(jié)果如圖


    說明:
    因為beanshell是松散類型的腳本語言因此可以直接寫
    foo = "Foo";
    four = (2 + 2)*2/2;

    print是beanshell提供一種簡單的打印命令相當于java中的System.out.println()





    其他的beanshell腳本命令
    · source(), run() – 讀取,或者運行一個腳本文件
    · frame() – 顯示一個窗口
    · load(), save() – 讀取或者保存一個腳本對象到文件
    · cd(), cat(), dir(), pwd(), etc. 使用Unix下面的命令
    · exec() – 運行一個本地的方法
    · javap() –使用javap命令.
    · setAccessibility() – 設(shè)置可以接收private和protected類型的變量
    BeanShell命令不一定都是內(nèi)置的腳本命令,腳本方法會自動從classpath中取方法使用,因此你可以添加你自己的腳本到classpath中來擴充基本的命令






    腳本方法
    一般的方法:
    int addTwoNumbers( int a, int b ) {
    return a + b;
    }

    sum = addTwoNumbers( 5, 7 ); // 12
    也可以使用動態(tài)的變量類型(無狀態(tài))方法
    add( a, b ) {
    return a + b;
    }
    foo = add(1, 2); // 3
    foo = add(1, “2”); //”12” 只要有一個為字符串全部按照字符串處理,系統(tǒng)不會根據(jù)1是數(shù)字在前把“2”轉(zhuǎn)換成數(shù)字處理(特別注意)
    foo = add("Oh", " baby"); // "Oh baby"




    實現(xiàn)接口
    實現(xiàn)任何接口需要java1.3或者更高
    可以使用缺省的java匿名類的語法實現(xiàn)一個接口類,例如:
    ActionListener scriptedListener = new ActionListener() {
    actionPerformed( event ) { ... }
    }
    不需要實現(xiàn)接口的所有的方法,只需要實現(xiàn)你使用的方法即可,如果使用你沒有實現(xiàn)的方法,beanshell將拋出一個錯誤,
    ml = new MouseListener() {
    mousePressed( event ) { ... }
    // handle the rest
    invoke( name, args ) { print("Method: "+name+" invoked!");
    }








    腳本對象
    使用特殊的關(guān)鍵字this可以創(chuàng)建一個對象(根JS類似)
    foo() {
    print("foo");
    x=5;

    bar() {
    print("bar");
    }

    return this;
    }

    myfoo = foo(); // prints "foo"
    print( myfoo.x ); // prints "5"
    myfoo.bar(); // prints "bar"

    從應(yīng)用程序中調(diào)用BeanShell
    創(chuàng)建一個BeanShell的解釋器(interpreter)用eval()和source()命令可以對一個字符串求值和運行一個腳本文件
    使用set()方法可以給一個對象傳入一個變量的參考
    使用get()方法可以重新得到一個變量的結(jié)果


    完整代碼:
    package cn.com.sparknet.util;

    import bsh.*;
    import java.util.*;

    public class BeanShell {
    public static void main(String[] args) {
    try {
    Interpreter interpreter = new Interpreter(); // 構(gòu)造一個解釋器
    interpreter.set("foo", 5); // 設(shè)置變量
    interpreter.set("date", new Date()); //設(shè)置一個時間對象
    Date date = (Date) interpreter.get("date"); // 重新得到時間變量
    interpreter.println(date.toString()); //打印時間變量
    interpreter.eval("bar = foo*10"); // 對一段腳本求值,并得到結(jié)果
    System.out.println(interpreter.get("bar")); //打印變量
    interpreter.source("d:\\helloWorld.bsh"); // 導(dǎo)入并執(zhí)行一個腳本文件
    }
    catch (Exception e) {
    //如果發(fā)生異常,寫入日志文件
    Log.error(new BeanShell(), "main", FormatDate.getCurrDate(), e.getMessage());
    }
    }
    }






    BeanShell語法
    BeanShell是一種最原始的java解釋器。
    標準的java語法
    /*
    Standard Java syntax
    */

    // Use a hashtable
    Hashtable hashtable = new Hashtable();
    Date date = new Date();
    hashtable.put( "today", date );

    // Print the current clock value
    print( System.currentTimeMillis() );

    // Loop
    for (int i=0; i<5; i++)
    print(i);

    // Pop up a frame with a button in it
    JButton button = new JButton( "My Button" );
    JFrame frame = new JFrame( "My Frame" );
    frame.getContentPane().add( button, "Center" );
    frame.pack();
    frame.setVisible(true);
    松散類型的java語法
    /*
    Loosely Typed Java syntax
    */

    // Use a hashtable
    hashtable = new Hashtable();
    date = new Date();
    hashtable.put( "today", date );

    // Print the current clock value
    print( System.currentTimeMillis() );

    // Loop
    for (i=0; i<5; i++)
    print(i);

    // Pop up a frame with a button in it
    button = new JButton( "My Button" );
    frame = new JFrame( "My Frame" );
    frame.getContentPane().add( button, "Center" );
    frame.pack();
    frame.setVisible(true);
    異常處理
    標準的java異常
    try {
    int i = 1/0;
    } catch ( ArithmeticException e ) {
    print( e );
    }
    松散的異常處理(類似JS)
    try {
    ...
    } catch ( e ) {
    ...
    }
    松散類型變量的作用范圍
    標 準的java程序的變量作用范圍是在一個模塊中的(在模塊中聲明的變量),而在松散類型的語言中如果在一個模塊中沒有指定一個變量的類型,則認為是一個全 局變量(只有它以后的代碼可以使用該變量,系統(tǒng)在調(diào)用該變量的時候自動生成一個全局變量,也就為什么在調(diào)用模塊之前不能使用該變量的原因)
    // Arbitrary code block
    {
    y = 2; // Untyped variable assigned
    int x = 1; // Typed variable assigned
    }
    print( y ); // 2
    print( x ); // Error! x is undefined.

    // Same with any block statement: if, while, try/catch, etc.
    if ( true ) {
    y = 2; // Untyped variable assigned
    int x = 1; // Typed variable assigned
    }
    print( y ); // 2
    print( x ); // Error! x is undefined.

    同樣也使用于for-loop, if-else等循環(huán)語句
    for( int i=0; i<10; i++ ) { // typed for-init variable
    j=42;
    }
    print( i ); // Error! 'i' is undefined.
    print( j ); // 42

    for( z=0; z<10; z++ ) { } // untyped for-init variable
    print( z ); // 10









    方便靈活的語法
    標準的java語法
    java.awt.Button button = new java.awt.Button();
    button.setLabel(“javaButton”);
    松散的語法
    button = new java.awt.Button();
    button.label = "my button";
    你也可以使用{}來對一個對象設(shè)置屬性
    b = new java.awt.Button();
    b{"label"} = "my button"; // Equivalent to: b.setLabel("my button");

    h = new Hashtable();
    h{"foo"} = "bar"; // Equivalent to: h.put("foo", "bar");




    包裝和未包裝(box和unbox)
    BeanShell自動轉(zhuǎn)為簡單類型
    i=5;
    iw=new Integer(5);
    print( i * iw ); // 25
    導(dǎo)入類和包
    import javax.xml.parsers.*;
    import mypackage.MyClass;
    超級導(dǎo)入法:
    import *;
    BeanShell默認導(dǎo)入下面的包
    · java.lang
    · java.io
    · java.util
    · java.net
    · java.awt
    · java.awt.event
    · javax.swing
    · javax.swing.event
    友好文檔實體
    BeanShell支持特殊的文檔操作類型內(nèi)容
    @gt > @lt <
    @lteq <= @gteq >=
    @or || @and &&
    @bitwise_and & @bitwise_or |
    @left_shift << @right_shift >>
    @right_unsigned_shift >>> @and_assign &=
    @or_assign |= @left_shift_assign <<=
    @right_shift_assign >>= @right_unsigned_shift_assign >>>=
    腳本方法
    你可以定義方法象java中的定義方法一樣
    int addTwoNumbers( int a, int b ) {
    return a + b;
    }
    你可以使用內(nèi)餡的BeanShell方法使用他們
    sum = addTwoNumbers( 5, 7 );
    只有BeanShell變量可以被動態(tài)定義為動態(tài)類型,方法可以有動態(tài)的參數(shù)以及返回類型
    add( a, b ) {
    return a + b;
    }
    在這個方法中,BeanShell將動態(tài)的決定類型當這個方法被調(diào)用時并且能夠準確的計算出你想要的結(jié)果
    foo = add(1, 2);
    print( foo ); // 3

    foo = add("Oh", " baby");
    print( foo ); // Oh baby
    在第一個例子中BeanShell將把參數(shù)定義為數(shù)字型,并返回數(shù)字型
    在第二個例子中BeanShell將把參數(shù)定義為字符型,并返回字符對象
    變量和方法的可見范圍
    就像您所預(yù)期的那樣,在方法內(nèi)您可以參考到上下文中上面的變量和方法
    a = 42;
    someMethod() { ... }

    foo() {
    print( a );
    someMethod(); // invoke someMethod()
    }

    // invoke foo()
    foo(); // prints 42
    如果一個變量只有在方法內(nèi)使用請定義成局部變量,即加上類型,如果是全局變量請在方法外定義
    var = "global";
    foo() {
    print(var);
    String var = "local";
    print(var);
    }
    foo();
    print(var);
    將打印出
    global
    local
    global
    方法內(nèi)的var(第四行)變量屬于局部變量,不會覆蓋全局變量var(第一行)的因此改變var(第四行)變量不會影響到全局變量var(第一行)
    范圍參考:super
    使用super關(guān)鍵字可以在局部參考到全局變量
    var = "global";
    foo() {
    String var = "local";
    print(var);
    print(super.var);
    }
    foo();
    將輸出
    local
    global







    腳本對象
    this對象
    在java標準語言中可以使用this返回一個類的一個實例
    // MyClass.java
    MyClass {
    Object getObject() {
    return this; // return a reference to our object
    }
    }
    在這個例子中g(shù)etObject() 方法是返回MyClass類的一個實例
    在BeanShell中對象中的變量只是局部的變量在對象內(nèi)可以使用,在對象外是不可以使用(不同于前面for-loop,if-else中的使用);
    // Define the foo() method:
    foo() {
    bar = 42;
    print( bar );
    }

    // Invoke the foo() method:
    foo(); // prints 42

    print( bar ); // Error, bar is undefined here
    可以使用this返回對象,使用對象加上“.”運算符參考屬性(類似JS)
    foo() {
    bar = 42;
    return this;
    }

    fooObj = foo();
    print( fooObj.bar ); // prints 42!
    同樣對象中也可以定義一些方法
    foo() {
    bar() {
    ...
    }
    }
    例如
    foo() {
    int a = 42;
    bar() {
    print("The bar is open!");
    }

    bar();
    return this;
    }

    // Construct the foo object
    fooObj = foo(); // prints "the bar is open!"
    // Print a variable of the foo object
    print ( fooObj.a ) // 42
    // Invoke a method on the foo object
    fooObj.bar(); // prints "the bar is open!"
    也可以把bar()和foo也可以代參數(shù)
    foo() {
    return this;
    }
    bar(int a) {
    print("The bar is open!" + a);
    }
    foo().bar(1);
    也可以把bar()方法定義到對象外面

    foo() {
    bar(int a) {
    print("The bar is open!" + a);
    }
    return this;
    }
    foo().bar(1);
    BeanShell一種松散的腳本語言,有很多中聲明的方法可以使用
    This super global
    This是參考當前對象
    Super是參考父親對象
    Global是參考最上層對象
    super.super.super...foo = 42; // Chain super. to reach the top
    global.foo = 42;








    簡單例子:
    文本拖動:

    dragText() {
    f = new Frame("Drag in the box");
    f.setFont( new Font("Serif", Font.BOLD, 24) );
    f.setSize(300, 300);
    f.show();
    gc = f.getGraphics();
    gc.setColor(Color.cyan);
    mouseDragged( e ) {
    gc.drawString("Drag Me!", e.getX(), e.getY());
    }
    mouseMoved( e ) { }
    f.addMouseMotionListener( this );
    }
    簡單畫圖

    import bsh.util.BshCanvas; // BshCanvas simply buffers graphics

    graph( int width, int height ) {
    canvas=new BshCanvas();
    canvas.setSize( width, height );
    frame=frame( canvas );
    graphics=canvas.getBufferedGraphics();
    // draw axis
    graphics.setColor( Color.red );
    graphics.drawLine( 0, height/2, width, height/2 );
    graphics.drawLine( width/2, 0, width/2, height );
    graphics.setColor( Color.black );

    plot(int x, int y) {
    graphics.fillOval( (x+width/2-1), (y+height/2-1), 3, 3);
    canvas.repaint();
    }

    return this;
    }

    drawSin( graph ) {
    for (int x=-100; x<100; x++ ) {
    y=(int)(50*Math.sin( x/10.0 ));
    graph.plot( x, y );
    }
    }
    簡單web瀏覽器

    import javax.swing.*;
    import javax.swing.event.*;
    import javax.swing.text.*;
    import java.awt.event.*;
    import java.awt.*;

    JFrame browser( startingUrl ) {
    invoke( method, args ) {}

    windowClosing(WindowEvent we) {
    we.getWindow().setVisible(false);
    }

    setPage( url ) {
    try {
    pane.setPage( url );
    } catch(Exception e) {
    statusBar.setText("Error opening page: "+url);
    }
    }

    hyperlinkUpdate( HyperlinkEvent he ) {
    type = he.getEventType();
    if (type == HyperlinkEvent.EventType.ENTERED) {
    pane.setCursor(
    Cursor.getPredefinedCursor( Cursor.HAND_CURSOR) );
    statusBar.setText(he.getURL().toString());
    } else
    if (type == HyperlinkEvent.EventType.EXITED) {
    pane.setCursor( Cursor.getDefaultCursor() );
    statusBar.setText(" ");
    } else {
    setPage( he.getURL() );
    if (urlField != null)
    urlField.setText(he.getURL().toString());
    }
    }

    frame = new JFrame("Browser");
    frame.setSize(400,300);
    frame.addWindowListener( this );

    urlPanel = new JPanel();
    urlPanel.setLayout(new BorderLayout());
    urlField = new JTextField(startingUrl);
    urlPanel.add(new JLabel("Site: "), BorderLayout.WEST);
    urlPanel.add(urlField, BorderLayout.CENTER);

    statusBar = new JLabel(" ");
    pane = new JEditorPane();
    pane.setEditable(false);
    setPage( startingUrl );
    jsp = new JScrollPane(pane);

    frame.getContentPane().add(jsp, BorderLayout.CENTER);
    frame.getContentPane().add(urlPanel, BorderLayout.SOUTH);
    frame.getContentPane().add(statusBar, BorderLayout.NORTH);

    // This is the equivalent of an inner class in bsh.
    urlTextHandler() {
    actionPerformed(ActionEvent ae) {
    setPage( ae.getActionCommand() );
    }
    return this;
    }

    urlField.addActionListener( urlTextHandler() );
    pane.addHyperlinkListener( (HyperlinkListener)this );

    return frame;
    }
    browser = browser("http://java.sun.com/");
    browser.show();




    更多的文檔參考BeanShell網(wǎng)站

    http://www.beanshell.org
    posted @ 2008-10-08 14:34 xiaoxinchen 閱讀(2471) | 評論 (0)編輯 收藏
    主站蜘蛛池模板: 野花香高清在线观看视频播放免费 | 18观看免费永久视频| 国产L精品国产亚洲区久久| fc2成年免费共享视频网站| 亚洲国产主播精品极品网红| 日本高清免费中文在线看| 亚洲国产小视频精品久久久三级| 国产高清在线精品免费软件| 亚洲人成网站免费播放| 免费观看的毛片手机视频| 亚洲综合区小说区激情区| 亚洲视频在线免费| 久久成人国产精品免费软件| 全免费一级午夜毛片| 亚洲AV无码一区二区三区鸳鸯影院| 在线免费观看污网站| 亚洲av永久无码精品秋霞电影秋| 热久久精品免费视频| 黄色一级视频免费观看| 一级毛片免费在线| 亚洲国产精品无码专区| 91人人区免费区人人| 亚洲a级成人片在线观看| 日韩免费码中文在线观看| 成年大片免费视频| 亚洲国产综合人成综合网站| 精品亚洲456在线播放| 免费观看的av毛片的网站| 久久久久久久综合日本亚洲| 一级毛片aaaaaa免费看| 亚洲日本VA午夜在线电影| 99在线观看免费视频| 亚洲国产成人高清在线观看| 黄色网页在线免费观看| 免费一级毛片在播放视频| 国产在线播放线91免费| 亚洲男人天堂2018av| 四虎在线成人免费网站| 亚洲精品天天影视综合网| 中文字幕在线免费视频| 亚洲一级特黄无码片|