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

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

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

    nighty

    折騰的年華
    posts - 37, comments - 143, trackbacks - 0, articles - 0

    2008年5月30日

    系統為ubuntu server,二臺機器A和B,IP為A 192.168.1.111,B 192.168.1.222
    A為rsync server,啟動為守護進程,B為備份機,做為rsync client,最后用crontab做一個簡單的作業,定時在B上執行同步文件的功能
    A的安裝和配置如下:
    1.  apt-get install rsync   可能提示系統已經安裝有了
    2. 配置文件/etc/rsyncd.conf
        默認安裝時是不會有這個配置文件的,但是可以 cp /usr/share/doc/rsync/examples/rsyncd.conf /etc  把它示例中的配置文件拷貝過來
        vi /etc/rsyncd.conf    這里參數有點多,但是有些可以先不管,關注重點的
        [ftp]  這里是模塊,可以配置多個,這個是系統默認給出的一個配置,下面給一個本機上的配置示例:
    --------------------------------------------------------------------------------------------------
    # so omit the "pid file" line completely in that case.
    pid file=/var/run/rsyncd.pid
    #syslog facility=daemon
    #socket options=
    # MODULE OPTIONS
    [share]
    comment = public archive
    path = /var/www/pub
    use chroot = no
    max connections=2
    # lock file = /var/lock/rsyncd
    # the default for read only is yes...
    read only = no
    list = yes
    uid = nobody
    gid = nogroup
    # exclude = 
    # exclude from = 
    # include =
    # include from =
    auth users = rsync
    secrets file = /etc/rsyncd.secrets
    strict modes = yes
    hosts allow = 192.168.1.222
    # hosts deny =
    ignore errors = yes
    ignore nonreadable = yes
    transfer logging = yes
    log format = %t: host %h (%a) %o %f (%l bytes). Total %b bytes.
    timeout = 600
    refuse options = checksum dry-run
    dont compress = *.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz
    ---------------------------------------------------------------------------------------------
    這里,最上面的是pid文件位置。然后配置了一個模塊名叫做share,最大連接數是2,read only = no,指定為非只讀(不然同步時會有權限問題)
    而后面的auth users = rsync 是指定一個同步的賬戶名叫做rsync,這個賬戶的認證文件是/etc/rsyncd.secrets,當然我們要創建這個文件

    3.  創建 /etc/rsyncd.secrets文件,內容為: rsync:123  表示rsync這個用戶的密碼是123 然后修改文件的權限 chmod 600 /etc/rsyncd.secrets

    4.  rsync server做為守護進程
         vi /etc/default/rsync
         可以看到開頭處這樣聲明:
    ------------------------------------
    # start rsync in daemon mode from init.d script?
    #  only allowed values are "true", "false", and "inetd"
    #  Use "inetd" if you want to start the rsyncd from inetd,
    #  all this does is prevent the init.d script from printing a message
    #  about not starting rsyncd (you still need to modify inetd's config yourself).
    RSYNC_ENABLE=inetd
    -------------------------------------------
       做為守護進程,可以設置為true或是xinetd方式來啟動。于是我們安裝inetd   sudo apt-get install xinetd
       安裝好后配置inetd的配置文件  vi /etc/xinetd.d/rsync ,輸入如下內容:
    ---------------------------------------------------
    service rsync
    {
        disable = no
        socket_type = stream
        wait = no
        user = root
        server = /usr/bin/rsync
        server_args = --daemon
        log_on_failure += USERID
    }
    -------------------------------------------------------
    然后啟動xinetd,/etc/init.d/xinetd restart,A服務器的rsyncd server就完成了!

    5.  B服務器由于是client,不需要配置,也不需要安裝xinetd,直接可以通過命令行執行
    rsync --delete -azvv rsync@192.168.1.111::share /var/www/pub/
    這個命令就可以直接連接到192.168.111的rsync賬戶,它會提示你輸入密碼,就是A中的secrets文件中的密碼,然后同步share模塊到本機的/var/www/pub目錄,你可以事前在A機器上創建一個文件如test.txt,隨便寫點內容,然后執行些命令,看是不是B上多了這樣一個文件?如果是,則表示已經連接成功。你接下來就可以做crontab了!

    posted @ 2013-04-12 12:23 寒武紀 閱讀(1345) | 評論 (0)編輯 收藏

    二臺服務器,A的內網IP為192.168.1.111,B的內網IP為192.168.1.222,A做為master,B做為Slave
    1.  配置A的Mysql
         (1)  vim /etc/mysql/my.cnf
               去掉[mysqld]段中 server_id =1 和log_bin=/var/log/mysql/mysql-bin.log的#注釋
               加上  binlog-do-db = s3     s3就是要同步的數據庫的名稱,如果沒有這一行,表示同步所有的數據,另外 binlog_ignore_db = mysql。要表示忽略同步的數據庫名稱為mysql,如果有多個要指定同步或是忽略同步的數據,就配置多行,保存退出。
         (2) 創建一個復制用的賬戶(名稱為repl,允許從遠程連接,密碼為123456):
              GRANT REPLICATION SLAVE, RELOAD,SUPER, NO *.* TO repl@'%' IDENTIFIED BY '123456';
            FLUSH PRIVILEGES;
         (3) 重啟mysql服務,或是直接reboot機器也可以
         (4) 進入mysql,然后用 show master status\G  查看二進制日志的狀態,看到類似以下的結果:
              +------------------+----------+--------------+------------------+
              | File                      | Position  | Binlog_Do_DB | Binlog_Ignore_DB |
              +------------------+----------+--------------+------------------+
              | mysql-bin.000003 |     1376  | s3                  |                           |
              +------------------+----------+--------------+------------------+
    2.  配置B的Mysql
          (1) vim /etc/mysql/my.cnf
               去掉[mysqld]段中 server_id =1 和log_bin=/var/log/mysql/mysql-bin.log的#注釋,把server_id改為2,要和master機器的不一樣。并增加以下內容:
               binlog_do_db=s3
               log-slave-updates
              保存退出
         (2) 重啟mysql服務
         (3) 進入mysql,執行
              CHANGE MASTER TO MASTER_HOST='192.168.1.111', MASTER_USER='repl',Master_Port=3306,MASTER_PASSWORD='123456',MASTER_LOG_FILE='mysql-bin.000003',MASTER_LOG_POS=1376;
              SLAVE START;
              注意上面的CHANGE語句中,MASTER_LOG_FILE和MASTER_LOG_POS就是上面1.4中提到的show master status命令得到的結果,指定二進制文件的名稱和開始同步的位置。
         (4) 查看SLAVE狀態:    show slave status\G
    *************************** 1. row ***************************
                   Slave_IO_State: Waiting for master to send event
                      Master_Host: 192.168.1.111
                      Master_User: repl
                      Master_Port: 3306
                    Connect_Retry: 60
                  Master_Log_File: mysql-bin.000003
              Read_Master_Log_Pos: 1376
                   Relay_Log_File: mysqld-relay-bin.000002
                    Relay_Log_Pos: 1355
            Relay_Master_Log_File: mysql-bin.000003
                 Slave_IO_Running: Yes
                Slave_SQL_Running: Yes
                  Replicate_Do_DB: 
              Replicate_Ignore_DB: 
               Replicate_Do_Table: 
           Replicate_Ignore_Table: 
          Replicate_Wild_Do_Table: 
      Replicate_Wild_Ignore_Table: 
                       Last_Errno: 0
                       Last_Error: 
                     Skip_Counter: 0
              Exec_Master_Log_Pos: 1376
                  Relay_Log_Space: 1512
                  Until_Condition: None
                   Until_Log_File: 
                    Until_Log_Pos: 0
               Master_SSL_Allowed: No
               Master_SSL_CA_File: 
               Master_SSL_CA_Path: 
                  Master_SSL_Cert: 
                Master_SSL_Cipher: 
                   Master_SSL_Key: 
            Seconds_Behind_Master: 0
    Master_SSL_Verify_Server_Cert: No
                    Last_IO_Errno: 0
                    Last_IO_Error: 
                   Last_SQL_Errno: 0
                   Last_SQL_Error: 
      Replicate_Ignore_Server_Ids: 
                 Master_Server_Id: 1
        上面的紅色二行如果為YES則表示已經正常連接,可以進行復制了。

    posted @ 2013-04-09 20:33 寒武紀 閱讀(1735) | 評論 (0)編輯 收藏

        許久沒用服務器上裝的那個postgresql,其實是用來做redmine的數據庫的,考慮到mysql可能經常升級,而rails的連接組件在安裝上有點麻煩,所以當初就裝成postgresql。
        今天準備備份一下,用的phppgadmin,剛開始是提示其中的pg_dump執行路徑沒有配置,重新配置好后,導出的結果卻是空的損壞文件。于是想算了,還是轉到pg的安裝目錄下執行pg_dump.
        服務器裝的是centos 6.2,忘了當初是建了一個用戶postgres.postgres進行安裝的,用其它用戶切換到pg的安裝目錄下bin/pg_dump是執行不了的,提示在指定目標下生成導出文件。故猜測應該是postgres這個用戶的權限不足!
        cat /etc/passwd查看一下當前有多少用戶,的確有postgres.postgres用戶,密碼多少?忘了!反正有root,直接passwd修改成新的密碼吧,于是就立馬修改了該用戶的密碼,可以正確切換到postgres用戶了,還需要root為postgres指定一個目錄有操作權限
        chown -R postgres.postgres /var/xxxx   
        然后再回到pg的bin目錄下,執行pg_dump redmine > /var/xxx/redmine.bak
        這下終于正常了,別忘了還得去redmine安裝目錄下,備份下files文件夾。
        
        僅以此為筆記,以后可以查閱使用

    posted @ 2013-03-27 22:39 寒武紀 閱讀(1400) | 評論 (0)編輯 收藏

          用Flex做企業應用將近有一年時間了,這個過程很累,在國內這方面的積累不多,真正有參考意義的資料的確非常少。經過一段長時間的摸索后,多少也積累了一點經驗,就最近的關于單元測試的想法做一點總結,由于涉及的知識較多,這里也只是給出個人的一種思路。
         眾所周知,Flex的缺點是開發調試效率較低,而且它只是表現層的一種解決方案。在企業應用中最需要解決的是編譯生成的swf體積問題,我想任何客戶都很難接受一個企業應用全部打包在一個swf里,幾MB甚至幾十MB的初始化過程誰都無法接受,所以都必不可少地采用Module的加載方式,把不同的業務功能編譯成獨立的swf,需要用的時候再去加載。把核心功能、通信機制、公共組件設計成庫項目,編譯成swc做為RSL讓業務模塊共享調用,達到盡量減少業務模塊編譯體積的目的。在這方面如果用心優化的話,基本上可以控制到每個swf體積大概在200KB以內,這樣就算是互聯網方式部署,客戶訪問仍是可以接受的。
        

         該結構圖給出了一種整體的設計方案,Flex的啟動肯定得有Application,這個是用戶初登錄后第一個加載的swf(登錄就不要用flex了,用jsp或是模板實現吧)。所以它負責加載你設計的整個框架,包含模塊加載機制、通信代理方式、基礎庫初始化等等,而和Java端的通信目前比較有效的仍然是blazeds,這個技術需要的介紹內容不在本文的范圍之內。關于通信接口的實現有一種非常有用的方式就是借用Java的動態代理理念,Spring有一個flex的擴展子項目叫做springactionscript,而這個項目又引用了as3commons的庫(類似于apache commons的一些公共組件)。為什么提及這個,因為flex本身的反射功能api非常難用,所以as3commons就做了擴展,它大大簡化了反射的使用,而且提供了一個bytecode的工具用于操作字節碼,它是實現動態代理的關鍵。至于為什么要動態代理?目的就是達到在寫和Java對接的接口時,可以只聲明接口,不需要實現類(得減少多少重復代碼呀?),而和Java對接接口我們又可以開發一個工具讓java code 自動轉成 as code,如果懂得Eclipse插件開發的話還可以進一步做一個插件,達到Java只寫一次就可以自動生成對應的flex接口,提高開發效率。
         轉入正題,關于單元測試的概念,Flash Builder在4.5已經把flex unit作為內置庫了,這點和Eclipse把junit內置類似,而flex unit的使用網上有大量的資料介紹,這里也不多說。flex unit在測試as代碼還是不錯的,和junit測試一樣,提供了一些簡單的Assert斷言,但是你最痛苦的卻不是as的測試。企業開發的特點就是數據量不大,但是需求坑爹,經常變來變去,而且結構復雜,往往一張表很多字段,關聯子表,層級屬性多。而你如果選擇了Flex做了展示層的技術,那必定是看中它比HTML + CSS + JS更強的界面交互功能。的確,這點不容質疑,Flex Spark的皮膚機制的確提供了很多優秀的特點,不過如果你想純熟掌握它的整個機制,恐怕得花很多時間閱讀源代碼才行,而皮膚的制作整對別想讓美工獨自實現,它同樣是需要技術積累的,介紹它需要用幾個篇幅才足夠。任何技術方案都一樣,BS、CS、AIR在實現復雜界面時,對于開發人員來說,最痛苦的莫過于界面的單元測試。
         痛苦在哪里?回看上面那幅架構圖,業務功能界面實現在Flex,業務邏輯在后臺Java,那么當二個團隊同時進行工作的時候,溝通就是最大的成本。解決溝通的問題就必須在先前設計時約定好接口和數據結構,那是會影響雙方團隊協調的關鍵因素。當雙方同時進行開發的時候,勢必存在前臺依賴后臺的情況,因為它能到達界面的前提得在整個框架載入后(并且可以初始化一堆數據,發生了通信),Java后臺還好說,依賴于spring和junit可以做到很好的單元測試。而flex就痛苦了,我沒有通訊啥都做不了呀!
         如何設計單元測試?最大的出發點就是如何切掉和后臺通信連接,看下面的簡單結構圖

         實現思路介紹:
         1.  簡化Application加載過程   --   可以套用你主程序中的加載過程,但是不需要你的主界面其它多余的元素,達到減少到達測試界面的多余步驟(盡可能少地減少鼠標和鍵盤操作)
         2.  定義測試配置   --   測試哪個模塊?哪個工作流程?你得通過配置的方式來定義,而不是每次都手寫代碼,才能方便你的成員使用你這個工具
         3.  模擬后臺接口實現  --  記得上面說的動態代理嗎?其實是為接口動態生成一個實現類,然后注入真正通信的實現代碼,例如WebService、HTTP,既然可以注入這些通信渠道,當然就可以注入本地實現類啦
         4.  對象查看器    --   這個是神馬?因為你都不要Java后臺了,每次操作一個界面后得提交數據吧?沒有后臺了,提交到哪里?你得必須把你的提交對象用界面展示出來吧?好吧,這個可是個難點!

         我想這四個方面的原則無非就是:減少單元測試需要進行的步驟(最快到達測試界面),脫離后臺依賴(自己簡單模擬后臺實現,可惜flex沒有類似java的mock庫,悲?。。绾尾榭刺峤坏胶笈_的結果。 單元測試的目標:界面能正常加載、提交數據正常,如果二者都沒問題,那么聯調的時候就可以非常容易定位到是Flex的問題還是Java的問題!達到介分責任的目標,當然,如果你所在團隊是按模塊分的,也就是說flex和java都是同一個人做,那么就不存在責任問題。

         怎么實現上面的四個步驟呢?簡要地介紹一下吧。
         第1簡化application加載,其實你可以把第一張圖中的application加載機制拷貝過來,只是主界面可以做得非常簡單,比如不需要多余的控件(比如過長的菜單、當前登錄人、時間、一陀設置按鈕等),只留下最核心的能到達你測試界面的入口,至于怎么設計這個簡化版的application,那得發揮你本人的創造力,另外還得看具體的業務。

        第2定義測試配置。模塊如何加載?通信接口本地模擬實現類定義?通過配置顯示在appliation做為觸發控件,這些你都得自定義一套xml之類的文件來配置吧,這個就需要技巧了,不能設計得太復雜,因為你的開發人員需要沿用你定義的規范來定義它需要測試的模塊,關于這方面的知識,可以參考spring加載配置文件方式、struts2加載定義文件等理念,有一個概念我比較推薦,就是struts2中的include配置文件,允許配置文件分散,讓大家提供代碼和文件時減少沖突,又可以套用你正常的加載機制。

        第3模擬后臺接口實現。這個是比較煩的,模擬機制本身通過動態代理倒是不難實現,惡心的是你得自己動手用flex簡單實現一次后臺生成數據、處理數據的邏輯。這里我有個實踐的總結經驗分享,在前期你調試完的后臺接口證明是沒有問題的,那么可以混合使用,一部分調試過的接口可以直接用后臺,而新接口才本地模擬。一個原則就是后臺有的,已經證明穩定的就用后臺,沒有的或是后臺還沒有完成的你就自己模擬。

        第4對象查看器。想想flex不能操作數據庫、由于安全限制不允許直接操作文件、無法讀取本地文件目錄。而你的測試數據也許會有關聯(特別是在工作流方面),所以你得想一個方案來保存你的對象結果,而且得以一種人性化的方式查看對象內容。且拋開數據存儲的問題,這個對象查看器如何設計就夠你頭疼的了,首先是對象得定義成一種格式,一種人可以看得懂的格式,比如xml,可以支持序列化和反序列化,你得去掉多余的無用屬性和訪問器。又得回到反射機制上了,序列化其實不難,難的是反序列化時如何正確地轉成原來的對象。列一種本人設計的結構:
         <xxx   type="com.xx.oo.XXClass">
              <aa type="String">aaa</aa>
              <bb type="Boolean">true</bb>
              <list type="mx.collection.ArrayCollenction">
                  ....
              </list>
         </xxx>
         對象分簡單對象、復雜對象、動態對象等,如何表達這種結構和保證序列化時不丟失數據需要細心考慮。那么最后如何實現查看器呢?其實有一個參考的范例,就是Eclipse的“大綱”視圖,經過實踐的擴展,把樹視圖換成表格樹(這種控件原生沒有,有第三方的可以拿來修改),看個樣圖吧!
     
         因為你關注的對象內容無法就是這三個方面,屬性名、值、和類型,又支持以樹方式導航對象,已經足夠你人眼分辯內容了。至于如何有效的保存測試數據,并且組織好結構,這個方面我目前也仍在思考中,未有較好的思路。
         以上內容僅是出于本人的一種方案,也許有更好的實現方案,只是水平不足以超過這種認識,希望后續能進一步思考能實現更加完美的單元測試框架。
         ST測試更關注的界面的自動化測試,這方面涉及的知識更多,一般公司是很難有財力和技術去支持做自動化測試,屬于比較高端的范圍,實現是很多回歸都靠測試團隊人肉在實現。

    posted @ 2012-04-28 12:03 寒武紀 閱讀(1539) | 評論 (1)編輯 收藏

          采用Spark進行Flex的Web應用開發的時候,往往會用一個固定欄,比如說類似Windows的任務欄,我們想把它固定在頂部或是底部,用于某些場景存放一些控件。<s:Application>組件中有一個<s:controlBarContent>屬性和<s:controlBarLayout>,用于設置Application的一個組件區域(我猜官方起的這個名稱大概用意在于此吧),下面這段話就是官方的中文注釋:
    Title包含在 Application 容器控件欄區域中的組件集。Application 容器控件欄區域的位置和外觀由 spark.skins.spark.ApplicationSkin 類確定。默認情況下,ApplicationSkin 類定義以灰色背景顯示在 Application 容器內容區域頂部的控件欄區域。創建自定義外觀以更改控件欄的默認外觀。
          于是可以簡單的給<s:controlBarContent>區域添加各種控件,以及設置它內在的布局(controlBarLayout)。但是,發現它只能顯示在Application的頂部!
          這是怎么回事,根據上面的注釋,感覺應該原因在它的皮膚,得跟進代碼,看一下究竟。
          首先找到<s:Application>控件的標準Skin,可以在Flash Builder中直接查看。
          
          雙擊打開ApplicationSkin,里面的代碼包含了各種SVG圖形學的實現api調用,flex管這些庫叫FVG,大意就是SVG的Flex實現版本,該庫實現得還算簡潔!
          Application標準皮膚的就是先畫一個矩形,然后用一個Group來包含不同的形狀,最后一段<s:Group id="contentGroup" width="100%" height="100%" minWidth="0" minHeight="0" />,代表Application的內容區域,Flex從設計上區分了控件樹和布局樹,有些復雜,可以參考官方的文檔。因為Application是屬于容器,所以必須在皮膚中包含這一句,不然程序運行時就看不到它包含的子控件。
         而前面長長一串<s:Group id="topGroup">中是畫了頂欄的外觀,它用FVG庫畫了四層:
         <!-- layer 0: control bar highlight -->     底部高亮線(用畫筆填充一個矩形)
         <!-- layer 1: control bar fill -->              背景填充線性漸變顏色
         <!-- layer 2: control bar divider line -->  分割線
         <!-- layer 3: control bar -->                  controlBar的具體內容容器
         當然這個controlBar不是自己會出現的,只有當你填充了內容控件的時候它才顯示,所以有includeIn="normalWithControlBar, disabledWithControlBar",表示在這二個State下才顯示,什么時候State才包含這二個呢?當然,就得去看Application.as的實現原理,具體篇幅就不描述。
         那么回到最初的問題:我想改變controlBar的位置在下方怎么處理?
         從上面的分析可知其實controlBar的擺放位置是在Skin中定義的,而它是什么布局,它顯示不顯示是通過Application.as本身的代碼控制的,那么我們就只要自定義Application.as的皮膚就可以,新建一個外觀mxml,直接復制官方的ApplicationSkin.mxml的代碼,然后,把<s:Group id="contentGroup" width="100%" height="100%" minWidth="0" minHeight="0" />代碼移到<s:Group id="topGroup">代碼的上面,在你的Application中強制指定skinClass為你自定義的ApplicationSkin,或是通過css設定即可。
         再擴展思維一下,其實我們完全可以把controlBar放到左邊或是右邊,甚至任何位置,都取決你在Skin的定義和Application.as的邏輯控制(你可以繼承Application擴展)。
         那么controlBar有什么作用?其實spark的Panel從及它的子類TitleWindow都有controlBar的概念,它能獨立于你容器外的區域,對于你容器本身包含的組件和布局不會產生干擾,以及你設置了width、height為100%時也不產生影響。如果你不要controlBar,直接在Application中用布局添加一個Group也是可以實現,但是它從根本上是屬于布局樹中contentGroup的內容,會受限于布局。
         Spark Skin的設計的確有高明的地方,對比Flex3的外觀,它提供給設計人員的空間實在大得多,你可以組合圖片和FVG庫的功能自定義各種外觀,當然,我就建議你多熟悉一下FVG庫的應用,畢竟從外加載圖片對flex來說是一個消耗,你的程序也會增肥。

    posted @ 2011-10-13 18:14 寒武紀 閱讀(2480) | 評論 (0)編輯 收藏

          問題描述:
              服務器操作系統是Centos5.5,此前已經有多套系統跑在上面,且裝有PHP5.2.10。Centos5.X系統的穩定yum安裝源版本是5.1.6,并不符合最新版本的phpmyadmin(5.2以上版本),下載了最新版本phpmyadmin安裝后提示缺少mysql支持模塊。
    查看了一下發現的確是安裝php的時候沒有裝上php-mysql模塊。直接重新編譯php源碼安裝比較麻煩。
         一個比較方便的方法:
        為yum添加第三方的源,然后直接用yum -y install php-mysql進行安裝
        以下方法為從網絡搜索到的,做個記錄,方面須用之時查閱。
              導入地址:    rpm --import http://www.jasonlitka.com/media/RPM-GPG-KEY-jlitka
              編輯yum源: vi  /etc/yum.repos.d/CentOS-Base.repo
              在最下面添加如下信息:
                       [utterramblings]
                       name=Jason's Utter Ramblings Repo
                       baseurl=http://www.jasonlitka.com/media/EL$releasever/$basearch/
                       enabled=1
                       gpgcheck=1
                       gpgkey=http://www.jasonlitka.com/media/RPM-GPG-KEY-jlitka

          
        然后執行安裝命令: yum -y install php-mysql    系統就會自動從上面添加的源中讀取合適該版本的php-mysl模塊,安裝完成后重啟httpd服務,再訪問就OK了。
        該方法同樣適合于默認安裝的php5.1.6版本安裝成功后再進行升級到 5.2版本。

    posted @ 2011-08-14 15:53 寒武紀 閱讀(2100) | 評論 (2)編輯 收藏

        freemarker幾天前才發布了2.3.17版本,5月21號又發布了2.3.18,距2.3.16已經一年多了。老的編輯器已經不能安裝在新版本的eclipse和myeclipse上面了,最新的官方編輯器仍在開發階段,有網友貌似知道最新的源代碼鏈接位置,不過肯定是不穩定的。
        另一個可選的編輯器就是JBoss Tools 3.2中的FreeMarker編輯器,值得安慰,啟動MyEclipse9.0后進入MyEclipse Configuration Center --> Software --> add site,輸入Name: freemarker,    
        URL:   http://download.jboss.org/jbosstools/updates/stable/helios/  然后在All JBoss Tools 3.2.0下選擇FreeMarker IDE,其它的大概你不需要都不用管,也不影響下載時間,然后一路確認安裝就OK!

    posted @ 2011-05-22 22:15 寒武紀 閱讀(2837) | 評論 (0)編輯 收藏

           上周服務器的一個PHP軟件不能訪問,查看原因是CentOS的PCRE模塊未用utf-8編碼引起的,由是搜索了一些資料照著變更,沒有效果。
           當時和另一個朋友L共同嘗試刪除后重裝,由于對Linux系統不熟悉,只會使用常規的命令進行一些皮毛的操作,就直接用yum remove進行刪除,系統當時還提示是否remove掉相關聯的700多個組件或模塊。當時也沒有多想就直接回車!結果------悲劇了,屏幕狂刷,我意識到pcre是基礎模塊,所有關聯它的或是它關聯都刪除掉,系統將遭遇一個災難式的破壞。等刷完屏幕的字符,最終發現:所有的bin目錄下的命令全部不見了?。。√炷?,連ls命令都沒有,唯獨剩下一個cd命令。幸運的是,當時運行在服務器的幾個應用還能訪問,比如說phpmyadmin。

            而后想了想,嘗試了各種方式去恢復,都沒有辦法,那么,唯一的辦法就是盡量備份原有的數據和文件,重裝系統進行環境的重新搭建。還好有其它方式,可以先把里面重要的文件都提取了出來。然后在幸存的phpmyadmin上趕緊進行mysql相關數據庫的備份。(注:因為是個人的服務器,所以并沒有像公司一樣做好運營和備份計劃)

            第二天決定重裝系統了,管理員用了3個小時才搭建起CentOS5.5和SSH遠程服務端。輪到我和L需要用SSH進行遠程的環境搭建。接下來的三天晚上,真是折騰又折騰。計劃安裝的幾個主要軟件是:Mysql、PHP、Apache、JDK、Tomcat、Ruby on Rails、Redmine、PHPMyAdmin等。

            第一個晚上,災難之前裝在上面的上述各種軟件版本都有點低,所以想干脆直接上最新的,而CentOS5.5的yum庫是取不到這些最新的軟件的。所以朋友 L 大量地采用了make install和rpm方式來安裝,而CentOS本身集成的就只有Apache的版本滿足。裝了MySQL5.5+phpMyAdmin3.4,運行起來了卻發現和MySQL5.5和redmine1.1.1有沖突,主要是RoR環境的Mysql驅動有問題,在網上能找到的都是從http://www.tmtm.org/en/ruby/mysql/ 下載的0.2.6版本,這個版本我只試在MySQL5.0情況下正常連接?,F在換成5.5,就無法運行了,為此我還特地把Ruby環境從1.8.6提高到1.8.7,同樣裝了redmine官網要求的各種Ruby工具和Rails組件,折騰無果!最后,我還把異常信息拿出來,給ruby-mysql的日本作者發了一個email,第二天作者回復我,原來ruby-mysql已經掛到GitHub去了,而且現在已經是3.0alpha狀態了,但是他不確定能否工作在ruby1.8.6下。 最后感覺還是不行,切換回MySQL5.0,同樣高版本的ruby-mysql驅動也無法連接低版本的MySQL。第一天以失敗告終!

           第二天晚上繼續折騰,再不停地重新安裝,這時才想起一個問題:應該退回到系統宕機前的所有軟件版本狀態,這樣原先備份的數據才能正?;謴停粫眍~外的版本沖突麻煩。于是折騰到接近晚上12:00時發覺方向錯了,無奈,和 L 打了個招呼,計劃明天讓管理員再重裝一次系統,現在目前的系統又被我們搞亂了!

           第三天。就著原來的思路,重裝恢復到以前的版本,又用yum的原來方式裝回原來的版本,這次進行順利。用了二個小時,就把常用的軟件恢復了,同時恢復了數據庫。最后只剩下一個問題,redmine的密鑰恢復后,仍然無法連接原來的用戶密碼,我想可能得去查閱redmine的用戶管理模塊,看看它究竟是怎么生成密碼和檢驗登錄的,有趣的事是發現網友找到另一個方法,就是直接在redmine下建ruby腳本,調用ActiveReord的User.save(),存一個自己的新密碼,不曉得可不可行,找個時間做個實驗看看。

          回頭一想。其實規劃、整理、理清服務器的管理工作,比精通Linux系統、各種軟解決技術更為重要!

    posted @ 2011-05-20 09:24 寒武紀 閱讀(7796) | 評論 (2)編輯 收藏

        Phusion Passenger模塊使得Rails應用可以像PHP模塊一樣運行在Apache上,非常方便。
       準備條件:CentOS服務器已經裝好了Apache2.2和Redmine應用        

        1. 安裝Passenger模塊
                gem install passenger
                passenger-install-apache2-module
            
                第二個命令是安裝passenger的apache2模塊,它已經做得很智能,會提示你確認安裝以及最后怎么配置模塊到apache中。
                摘出配置段的內容如下:
                    Please edit your Apache configuration file, and add these lines:

                    LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-3.0.7/ext/apache2/mod_passenger.so
                    PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-3.0.7
                    PassengerRuby /usr/bin/ruby

                把紅色字體部分拷貝到apache的配置文件,可以是主配置文件/etc/httpd/conf/httpd.conf,也可以是在/etc/httpd/conf.d/目錄下新建一個子文件命名為ruby.conf,推薦第二種方式,更為簡潔,不會影響主文件的配置。
          
        2. 先測試一下passenger是否安裝正常

                切換到redmine的安裝目錄下,passenger start  命令嘗試一下是否正常能以paasenger方式啟動,如果沒有異常,恭喜,已經安裝完成,剩下的工作就是配置一個虛擬主機和子給你的redmine,這樣可以轉到更為常用的80端口上。

        3. 配置rails應用做為sub URI模式
                 在passenger的官方文檔中其實有好幾種配置的方式,可以是域名、域名子URI等,很多時候你可能只有一個域名,那么利用sub URI來掛不同的應用就顯得比較
                首先配置一段虛擬主機如下:

            <VirtualHost *:80>
                ServerName www.phusion.nl
                DocumentRoot /websites/phusion
                <Directory /websites/phusion>
            Allow from all
                </Directory>
            </VirtualHost>

               解釋一下過程大致是先創建一個硬鏈接,如下:

            ln -s /webapps/mycook/public /websites/phusion/rails 
     
         /webapps/mycook/public是你的rails的應用目錄下面的public目錄,例如你的redmine安裝在/var/www/html,這個目錄就是
    /var/www/html/redmine/public,后面就是你Apache主目錄下的創建的一個鏈接地址rails,意思就是把/var/www/html/redmine/public
    鏈接到/var/www/html/rails,而/var/www/html/rails是實際上不存在的。
    然后再配置子目錄如下:

    <VirtualHost *:80> ServerName www.phusion.nl DocumentRoot /websites/phusion <Directory /websites/phusion> Allow from all </Directory>
    RailsBaseURI /rails # <-- These lines have <Directory /websites/phusion/rails> # <-- been added. Options -MultiViews # <-- </Directory> # <-- </VirtualHost>

     最后四句帶#注釋說明是重點,應用RailsBaseURI命令把rails子URI指定到rails的應用目錄,而rails目錄就是我們上面鏈接的目錄,而實際上會跳到我們的直接redmine目錄。

     

    posted @ 2011-05-19 15:10 寒武紀 閱讀(2543) | 評論 (1)編輯 收藏

            引言:最近又用到dbutils,之前一直用Map映射的方式取出select的結果再手工做轉換。有寫過一篇文章說MapHandler方式的一個缺陷:關于commons dbutils組件的一個小缺陷分析 ,用這種方式,在項目不大的情況下,寫一些Map到JavaBean的轉換代碼工作量不大,但是在數據庫表過多并且表中的字段過多的情況下,這種重復的setter感覺有點煩。于是又重新思考了BeanHandler和BeanListHandler的情況,dbutils底層映射用的反射,性能上肯定有損失,不過在大多數項目規模不是很大的情況下,這點損失可以忽略,帶來的代碼減少卻是比較可觀。
            問題在哪里?先看一段官方的示例代碼:

    QueryRunner run = new QueryRunner(dataSource);

    // Use the BeanHandler implementation to convert the first
    // ResultSet row into a Person JavaBean.
    ResultSetHandler<Person> h = new BeanHandler<Person>(Person.class);

    // Execute the SQL statement with one replacement parameter and
    // return the results in a new Person object generated by the BeanHandler.
    Person p = run.query(
        
    "SELECT * FROM Person WHERE name=?", h, "John Doe");

            這里有個地方有約束,就是要求示例中的JavaBean類Person中的字段定義要和數據庫的字段定義一致。Java的命名習慣一般是駱峰寫法,例如userId,那么數據庫中就必須定義為userId,而問題在于:有時候我們需要數據庫中字段的定義格式與JavaBean的命名不一樣,比如數據庫定義為:user_id,而JavaBean則定義為userId
            看源代碼可能有點費時間,在官方的example頁面的最下面果然有一段關于自定義BeanProcessor的指引。摘錄出來:

          BasicRowProcessor uses a BeanProcessor to convert ResultSet columns into JavaBean properties. You can subclass and override processing steps to handle datatype mapping specific to your application. The provided implementation delegates datatype conversion to the JDBC driver.
          BeanProcessor maps columns to bean properties as documented in the BeanProcessor.toBean() javadoc. Column names must match the bean's property names case insensitively. For example, the firstname column would be stored in the bean by calling its setFirstName() method. However, many database column names include characters that either can't be used or are not typically used in Java method names. You can do one of the following to map these columns to bean properties:
          1. Alias the column names in the SQL so they match the Java names: select social_sec# as socialSecurityNumber from person
          2. Subclass BeanProcessor and override the mapColumnsToProperties() method to strip out the offending characters.


          大概意思就是提供二種方式:一種就是最直接的,用as關鍵字把colName重命名,另一種方式就是繼承BeanProcessor類,重寫mapColumnsToProperties()方法。
          那當然是第二種方式更加具有代表性。嘗試了一下。代碼如下:
        
     1public class CustomBeanProcessor extends BeanProcessor {
     2    
     3    @Override
     4    protected int[] mapColumnsToProperties(ResultSetMetaData rsmd,
     5            PropertyDescriptor[] props) throws SQLException {
     6        int cols = rsmd.getColumnCount();
     7        int columnToProperty[] = new int[cols + 1];
     8        Arrays.fill(columnToProperty, PROPERTY_NOT_FOUND);
     9
    10        for (int col = 1; col <= cols; col++{
    11            String columnName = rsmd.getColumnLabel(col); 
    12            if (null == columnName || 0 == columnName.length()) {
    13              columnName = rsmd.getColumnName(col);
    14            }

    15            columnName = colNameConvent(columnName); // 在這里進行數據庫表columnName的特殊處理
    16            for (int i = 0; i < props.length; i++{
    17
    18                if (columnName.equalsIgnoreCase(props[i].getName())) {
    19                    columnToProperty[col] = i;
    20                    break;
    21                }

    22            }

    23        }

    24        return columnToProperty;
    25    }

    26
    27    /**
    28     * 數據庫列名重新約定
    29     * @param columnName
    30     * @return
    31     */

    32    private String colNameConvent(String columnName) {
    33        String[] strs = columnName.split("_");
    34        String conventName = "";
    35        for (int i = 0; i < strs.length; i++{
    36            conventName += StringUtils.capitalize(strs[i]);
    37        }

    38        StringUtils.uncapitalize(conventName);
    39        return conventName;
    40    }

    41}

            注意mapColumnsToProperties方法的邏輯是從父類的方法中直接復制出來的,然后在第15行那里變了個戲法,這里的columnName就是從數據庫中讀出來的,自定義一個private方法用于轉換命名,這里你就可以添加自己的命名約束。例如上面就是把 user_id 轉化為Java的駱峰寫法:userId
           再深入一層思考,你可以在這里進行更多擴展,以便讓自己可以選擇不同的命名轉換方式。定義了這個Processor之后,下面看看如何調用:
    Connection conn = ConnectionManager.getInstance().getConnection();
    QueryRunner qr 
    = new QueryRunner();
    CustomBeanProcessor convert 
    = new CustomBeanProcessor();
    RowProcessor rp 
    = new BasicRowProcessor(convert);
    BeanHandler
    <User> bh = new BeanHandler<User>(User.class, rp);
    User u 
    = qr.query(conn, sql, bh, params);
    DbUtils.close(conn);
          是不是非常靈活?如果是想返回List結果的,就把BeanHandler替換成BeanListHander類,還可以再進一步封裝這些操作,抽象到公共模塊中去,讓外部直接傳入sql語句和Class就能直接返回想要的結果,當然你得增加泛型的定義。同樣舉一個封裝的例子:
     1protected <T> List<T> selectBeanList(Connection conn, String sql, Class<T> type,
     2            Object[] params) throws Exception {
     3        log.debug("select sql:[" + sql + "]");
     4        QueryRunner qr = new QueryRunner();
     5        CustomBeanProcessor convert = new CustomBeanProcessor();
     6        RowProcessor rp = new BasicRowProcessor(convert);
     7        ResultSetHandler<List<T>> bh = new BeanListHandler<T>(type, rp);
     8        List<T> list = qr.query(conn, sql, bh, params);
     9        return list;
    10    }

            至于為什么擴展這個方法就可以實現這個邏輯就得去跟源代碼看它的內部實現,用了一些JavaBean的處理和反映的技巧來做的。具體就不說。
            總結:commons組件都設計得非常好,可擴展性和實用性都非常高。雖然上面舉例實現了轉換邏輯的替換,但是仍然需要開發人員在設計數據庫的時候和寫JavaBean時都要嚴格做好規范,避免產生不必要的問題。這方面Ruby On Rails就直接內部實現,動態語言的優點特別能體現,同時強制你在設計時必須用這種方式,典型的約定優于配置原則。當然,在dbutils里你愿意二種字段名都一樣也無可厚非。
           缺點:BeanProcessor是不支持關聯查詢的,所以上面的方式也只能局限于單表的轉換,這點就不如myBatis和Hibernate,當然用這二個就引入了一些復雜性,如何權衡需要自己衡量,哪個用得好都一樣。本人就不喜歡myBatis那種把SQL寫到XML中的方式,見過太復雜的SQL最終在XML里面變得面目全非,如果是接手別人的代碼,是很痛苦的,而且你無法避免只修改XML而不改Java,既然二者都要改,那直接寫Java里又有什么區別?簡單就是美。格式和注釋寫好一點同樣很容易理解!

    posted @ 2011-04-26 16:41 寒武紀 閱讀(4266) | 評論 (0)編輯 收藏

    posted @ 2011-03-09 16:48 寒武紀 閱讀(13765) | 評論 (4)編輯 收藏

    1.  Redmine安裝前提條件

    官方的安裝指南:http://www.redmine.org/projects/redmine/wiki/RedmineInstall

    Notes:

    Ruby 1.9 is not supported yet. You have to use Ruby 1.8.x as stated above.
    RubyGems 1.3.1 or higher is required (Rails 2.3.5 will fail with RubyGems 1.5.0 and later, stick to previous versions of RubyGems)
    Rake 0.8.3 or higher is required
    Rack 1.0.1 is required. If you don't have this exact version, database migration would fail.
    I18n 0.4.2 is required for Redmine >= 1.0.5

     安裝主要版本選擇:ruby 1.8.6,rubygems1.3.5,rake 0.8.3rack 1.0.1,I18n 0.4.2,rails 2.3.5

         
    2.  yum安裝ruby

    使用yum安裝ruby相關的軟件

    yum -y install ruby ruby-devel ruby-libs ruby-irb ruby-rdoc ruby-mysql

    如果沒有ruby-mysql,則從http://www.tmtm.org/en/ruby/mysql/ 下載手動安裝

    3.
    升級ruby
    1.8.6版本

    /etc/yum.repos.d/ 目錄下創建yum源文件ruby.repo,內容如下:

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

    [ruby] 
    name=ruby 
    baseurl=http://repo.premiumhelp.eu/ruby/ 
    gpgcheck=0 
    enabled=0 

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

    升級ruby

    yum --enablerepo=ruby update ruby

    4.  安裝rubygems1.3.5

    因為直接通過yum安裝的rubygems0.9.4,所以選擇手工下載安裝的方式

    wget http://rubyforge.org/frs/download.php/60718/rubygems-1.3.5.tgz
    tar xzvf rubygems-1.3.5.tgz
    cd rubygems-1.3.5
    ruby setup.rb

    安裝完后運行gem –v檢查一下版本是否正常,(當然還可以直接用yum安裝,然后通過gem本身的更新來實現,那從rubyforge下載的就應該是.gem結束的升級文件)

    5.  安裝rails 2.3.5

    gem install rails –v=2.3.5

    6.  安裝Rack 1.0.1

    gem install rack –v=1.0.1

    7.  安裝Rake 0.8.3

    gem install rake –v=0.8.3

    8. 安裝I18n 0.4.2

    gem install -v=0.4.2 i18n

    9.  下載和安裝redmine1.1.1

    wget http://rubyforge.org/frs/download.php/74128/redmine-1.1.1.tar.gz

    拷貝壓縮文件到要安裝的目錄,比如 /var/www目錄下,解壓

    tar xzvf redmine-1.1.1.tar.gz

    cd redmine-1.1.1

    配置數據庫連接yml文件(redmine目錄下進行如下操作)

    cd config

    cp database.yml.example database.yml

    vi database.yml

    添加如下內容:

    production:
    adapter: mysql
    database: redmine
    host: localhost
    username: root
    password: xxx
    socket: /var/lib/mysql/mysql.sock

    數據庫要預先創建好,如果你裝好了mysql,直接運行mysql -uroot -p 登錄,然后create database redmine,主機名、用戶名、密碼也要寫對。

    10.   生成會話密鑰

     rake config/initializers/session_store.rb

    11.  rails數據庫生成和數據初始化

    rake db:migrate RAILS_ENV=production
    rake redmine:load_default_data RAILS_ENV=production

    12.  運行測試

    如果沒有異常,在redmine安裝目錄下執行啟動服務器的命令:

    ruby script/server -e production &

    這樣redmine就會偵聽本機IP3000端口,輸入URLhttp://IP:3000 就可以看到登陸界面,如果是本機就直接 http://localhost:3000。

    但這樣只是以獨立的方式啟動redmine的服務器,在后臺執行,有些不足,因為客戶端的訪問日志會在終端上直接顯示。并且你退出終端時,服務器進程也會跟著關閉,后面再介紹啟動和關閉腳本的編寫,以及如何用nginx做反向代理,或是用Apache也可以,這個網上可以搜索到很多資料。

    13.  附注:redmine默認端口是3000,如果你是遠程操作,直接訪問主機的IP或是域名是無法打開主頁的,因為centosiptables默認是沒有開通3000端口的,所以需要開放端口。

    打開iptablesvi /etc/sysconfig/iptables

    添加下面一行到文件里面

    -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 3000 -j ACCEPT

    然后重啟iptables

    /sbin/service iptables restart

    到此為止就完成redmine的安裝,過程比較繁瑣,主要是各種組件和模塊的版本匹配問題。大多數情況下根據安裝的錯誤提示和Google就可以解決滴。

     

    posted @ 2011-03-01 09:47 寒武紀 閱讀(3096) | 評論 (1)編輯 收藏

            非常喜歡這種輕量級的JDBC封裝,比起Hibernate和iBatis,可以非常自由和靈活地運用和自行二次封裝,由于dbutils的BeanHandler轉換方式采取了反射技術,在性能上肯定有所損失,所以項目中基本上都使用MapHandler方式來轉換數據,當然就是自己寫的代碼多一點,也無所謂。一般的查詢、子查詢、聯合查詢、包括視圖查詢等等都很正常,但是發現一個比較小的問題,就是在使用聚合函數的場所,例如:select user_type, count(*) as count from `user` group by user_type這種類型查詢的時候,MapHandler方式不起作用,as列都變成key為空串的K-V對,導致有許多地方使用map.get("")代碼的情況出現,這種寫法當然是不太好的,容易出問題。
            鑒于前面沒有時間了解,就都粗略使用了上面那種粗暴的map.get("")來處理,最好的情況是讓dbutils組件能自動識別到as類型的列名。于是有空了就專門看了看它的源代碼,發現最主要的一段代碼如下:
     1public Map<String, Object> toMap(ResultSet rs) throws SQLException {
     2        Map<String, Object> result = new CaseInsensitiveHashMap();
     3        ResultSetMetaData rsmd = rs.getMetaData();
     4        int cols = rsmd.getColumnCount();
     5
     6        for (int i = 1; i <= cols; i++{
     7            result.put(rsmd.getColumnName(i), rs.getObject(i));
     8        }

     9
    10        return result;
    11    }
            CaseInsensitiveHashMap是dbutils自定義的一個Map,忽略鍵大小寫的K-V字典,但是key使用的是ResultSetMetaData.getColumnName(),我想問題大概出在這里,于是認真翻了翻java的api文檔(開發做久了容易遺忘基礎),果然,原來getColumnName()是:獲取指定列的名稱;而as關鍵字之后,使列名稱變成用于顯示的意義,這個時候應該使用getColumnLabel():獲取用于打印輸出和顯示的指定列的建議標題。建議標題通常由 SQL AS 子句來指定。如果未指定 SQL AS,則從 getColumnLabel 返回的值將和 getColumnName 方法返回的值相同。自己手動試驗了一下,果然如所料,問題就出在這里。
            所以呢,如果想要dbutils在自動轉換Map及MapList時能識別聚合函數的列名,那么最好的做法就是重載這種方式,懶一點的,你就干脆修改上面那段代碼,讓它判斷是否使用了as關鍵字。個人暫時搞不清楚官方為什么沒有考慮這一步,有時間再思考一下!

    posted @ 2011-02-12 17:33 寒武紀 閱讀(3028) | 評論 (7)編輯 收藏

        在項目中剛好有一個地方需要在服務器端處理一個請求后,重定向到另一個Action,這樣瀏覽器的url才會變成另一個url,用戶重新刷新時,才不會彈出一個對話框問你是不是要重新提交form。于是就自然而然地用了redirectAction。大概如下:
       
    1<result name="myInfoSuccess" type="redirectAction">
    2    myapp_myInfo.action?msg=${msg}
    3</result>

        因為重定義會丟失所有的請求參數和值棧,所以這里轉向時,加了一個請求參數msg,msg在要重定向的action中設置。
        問題來了,重定向到myapp_myInfo.action時,這個Action里面取出msg參數時變成亂碼?。?! 不論中文或是英語還是數字,全是亂碼,折騰了一翻,URLEncoder、URLDEncoder進行URL Base64編碼和解碼處理,包括new String(msg.getBtye("ISO-8859-1"), "UTF-8")這種處理方式仍無法奏效。google了一下并且抱起書本認真看了看struts2重定向問題后。大概有了個思路。
        所有的重定向操作都會丟失所有的請求參數、請求屬性等,當然包括Action的處理結果也會丟失。 
        首先搞清楚redirect、redirectAction的區別:
        1. redirect類型struts2是調用HttpServletResponse的sendRedirect(String)方法來重定向到指定的資源,可以是一個視圖結果,也可以是其它類型的Action;
        2. redirectAction同樣是重新生成一個全新的請求。但是struts2內部卻是使用ActionMapperFactory提供的ActionMapper來重定向,它只能跳轉到另外一個Action;

             由于redirectAction使用的是ActionMapper來重定向,也就同時使用ActionMapper的編碼方式重新進行編碼,這就導致了后面在取出參數時變成亂碼,沒有具體閱讀它的源代碼,但是多次不同的編碼再想重新還原出來就有點麻煩了。而redirect是使用HttpServletResponse來重定向,就不存在上面的問題。最后改為redirect來重定向,結果如下:
    1<result name="myInfoSuccess" type="redirect">
    2    <param name="location">myapp_myInfo.action?msg=${msg}</param>
    3    <param name="encode">true</param>
    4</result>
            注意:在myapp_myInfo.action對應的Action必須對msg參數做一次轉碼,因為前面的Action過來時就做了URL base64編碼,如果直接發給瀏覽器,就會在瀏覽器看到一串帶%的URL base64編碼字符,所以要加上
    1String msg = URLDecoder.decode(getMsg(), "UTF-8");
    2setMsg(msg);
           把它設置回為中文,瀏覽器才能正常。

           還得提到另一個重定向類型chain,它是Action鏈,還能維持當前的值棧不變。不過用它重定向后,雖然跳到其它Action,但是在瀏覽器端的URL是不會變化的,這樣開頭提到的那個問題仍是無法解決的!

    posted @ 2011-01-14 16:41 寒武紀 閱讀(6770) | 評論 (3)編輯 收藏

         摘要: 項目中使用了FreeMarker做為視圖技術,相對來說因為freemarker在視圖上有一些邏輯處理功能,某些地方就顯得比較方便,特別是macro的使用,當然也不是說JSP就沒有這個功能,只是以前用JSP寫起來沒有這么順手.......  閱讀全文

    posted @ 2010-11-10 15:43 寒武紀 閱讀(3092) | 評論 (3)編輯 收藏

         摘要: 都說roller在國外是二次開發博客系統的首選,但是下載源代碼之后發現是它是基于netbeans項目結構開發的。平時用習慣了Eclipse,所以想搬到MyEclipse上面,但沒有想到居然那么不容易,折騰了整整一天,才最終跑起來。網上的參考信息太少,大概都是那二三篇的轉貼,全部結合起來就差不多可以解決,借此總結一下,希望用到的朋友有參考作用!  閱讀全文

    posted @ 2009-11-22 21:04 寒武紀 閱讀(2256) | 評論 (2)編輯 收藏

         摘要:   閱讀全文

    posted @ 2009-10-14 17:41 寒武紀 閱讀(2173) | 評論 (1)編輯 收藏

        最近的二個項目,由于規模較小,都是十張表之內,而且表關聯非常少。所以用了一下iBatis做為數據庫關系映射,本著減少手寫JDBC代碼的目的,想著可以減少工作量。但是卻遇到了二個令人郁悶的問題。由于環境的限制,使用了jdk1.4.x編譯的iBatis2.3版本,沒有使用最近的。

        第一問題:  其中的一個項目,有一個表為它配置了sql Map的一個delete操作,非常簡單,大概就是delete from xxx where id=#value#這樣的語句,然后用sqlMapClient進行操作,日志打印完全正常,沒有報任何Exception,返回影響記錄數也是正確的。但是進數據庫一看,巍然不動!左查查,右查查,查不出任何毛病。更奇怪的是,數據庫表之間的所有關聯和索引全部取消,還是存在這問題。其它的三個字段比較少的表,這樣配置,同樣的api調用卻正常!這個出問題的數據庫表字段大概20+個左右。

        第二個問題:另一個項目,是二期重構,本來一期也不復雜,全部是使用JDBC實現的,只是有些表的字段太多,JDBC寫到煩,特別是處理一些NULL的插入,還有批處理時異常日志的詳細處理也有點煩。近期做二期升級,就算采用iBatis來減少一些代碼量,于于喜涮涮地搞上去了,代碼的確減少了許多。單元測試也能通過,后來就設置了比較復雜的數據。發現問題的現場如下:在一個業務接口中,一個事務中包含了許多SQL操作,有delete,也有insert,大概十個sql語句左右,全部放在一個batch中執行,整個batch提交一個事務。測試環境提供了31個類似的業務數據,總共執行31個事務,采用for的循環執行調用,每逢索引 i = 10*n  的時候就會卡住,這個操作得花很長時間,最后能通過。后來進行跟蹤,發現是在執行第一個語句delete一個記錄(delete from xxx where id='xx')同樣也是單表刪除。搜索了google,baidu,沒有任何資源,翻遍了文檔沒有任何說明,查了網站FAQ也沒有辦法。于是,只能.......郁悶!

       為什么遇到delete都會有這個問題?不曉得有沒有高手遇到同樣的問題,這里算是總結的同時也提問,希望有遇到相同類型的高手給個解決的方案。如果不行,就得倒回去用JDBC實現,就此iBatis的體驗使用也就擱置,估計以后也不會碰它了。Hibernate就不用了,有點小題大作。
       google了才知道,原來iBatis的書籍、論壇、資料、討論等等相比Hibernate要少很多。學習是很簡單,但是遇到這種細節的時候,又不太愿意花時間去研究源代碼(都是現實所逼,有個球時間呀?)。所以選框架要慎重?。。?

    posted @ 2009-08-21 16:52 寒武紀 閱讀(4324) | 評論 (24)編輯 收藏

         摘要:   閱讀全文

    posted @ 2009-07-31 15:58 寒武紀 閱讀(2159) | 評論 (6)編輯 收藏

    Java環境安裝
        1.  從sun主頁下載JDK for Linux版本。這里下載的是jdk-6u6-linux-i586.bin。
        2. 用root用戶登錄ubuntu,或是在普通用戶下用su命令切換用戶。切換到所需的安裝目錄。類型:cd <目錄路徑名>   例如,要在 /usr/java/ 目錄中  安裝軟件,請鍵入:cd /usr/java/,把jdk-6u6-linux-i586.bin文件拷貝這個目錄里面,設置權限為可執行類型:chmod a+x jre-6u6-linux-i586.bin
        3. 啟動安裝過程。鍵入:./jre-6u<version>-linux-i586.bin。接下來會提示二進制的許可協議,鍵入yes回車即可。安裝過程如果遇到一些問題,都同樣鍵入yes就可以。
        4. 一路下來,最后看到Done字樣,就完成了Java環境的安裝。安裝的位置就是當前目錄 /usr/java,當然你可以選擇在別的位置??梢杂胠s命令查看一下是否正常。

    環境變量配置
       上面安裝完畢后,直接在shell里面輸入java是不起作用的,需要先配置一下環境變量。一般都會用export命令,不過這樣設置只對當前shell起作用,重啟或是切換到別的shell會話就不起作用了??梢赃x擇配置 .bashr文件。用vi或是gedit打開,在末尾添加下面的內容
       export JAVA_HOME=/usr/java/jdk1.6.0_06
       export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
       export PATH=$PATH:$JAVA_HOME/bin
       然后保存。再在shell里面試驗一下是否安裝成功。echo一下各個變量是否正常,然后輸入java -version看看。
      還有一種方式是修改/etc/profile,這樣相當于修改系統配置文件,對所有用戶都有影響,我在嘗試的過程可能輸入了一些異常字符,導致整個ubuntu無法用GUI登錄,無奈只能用文本登錄,然后再次把profile改回來才正常。
       好了之后可以先試一下用vi新建一個Hello的Java文件,然后編譯一下試運行。

    Eclipse安裝
       Linux下面的Eclipse在ubuntu的界面渲染下看起來非常漂亮。先從Eclipse社區下載一個Linux版本的,這里下載的是europa版本的gz包。只要解壓到一個目錄就可以,這里選擇/opt/eclipse下面。Eclipse是解壓就可以使用的。不過為了方便,我們在桌面做一個啟動器把啟動目標指向到Eclipse的安裝目的地,選擇里面已有的圖標文件,這樣就完成了。不過默認Eclipse是找不到Java執行路徑的,有網友寫了這樣一個腳本eclipse.sh 放到/usr/local/bin目錄下,記得加上775權限。然后把啟動器位置指到這里eclispe.sh。下面是eclipse.sh的內容:
        #!/bin/bash
        #
        # 執行 eclipse 2.1.1
        #
        export JAVA_HOME=/usr/java/XXX
        export CLASSPATH=/usr/java/XXX/lib
        /opt/eclipse/eclipse -vm /usr/java/XXX/bin/java -data ~/workspace &
        # -vm 參數用以指定使用哪一個 jvm 來執行Eclipse,
        # -date參數用以指定Eclipse的數據目錄。在此指定其存在用戶根目錄(~)下的workspace目錄中
      
       還有一個比較笨的方法,Eclipse默認會去找它自己目錄下是不是有jre存在,如果有,它就可以啟動,那么你可以直接把先前安裝好的JDK里面的JRE目錄整個復制到Eclipse里面。然后就可以直接運行了。下面看一下效果
      

    posted @ 2008-08-29 17:07 寒武紀 閱讀(38192) | 評論 (6)編輯 收藏

        ActionSet是Eclipse RCP里面一非常重要的概念,因為菜單、工具欄、上下文菜單、狀態欄很多操作都是共享的,所以Action就是用來處理重復出現的東西。至于Eclipse里面定義ActionSet有非常多的技巧,可能無法一一列舉,而且使用方法也多種多樣。下面介紹的是RssOwl2項目的ui源代碼部分的一小塊。
       1.  菜單的插入點 -- GroupMarker和Separator的使用
            ApplicationActionBarAdvisor類是定義全局所有Action插入點和入口,查看fillMenuBar(IMenuManager)方法,為了簡化,以其中的輔助方法createFileMenu(IMenuManager)為例,講述一下實現菜單“文件”的內容,先看一下菜單的結構

           像Close,Import...之類的非常簡單,看一下它是如何實現New這個子菜單的。首先看一下它的源代碼如何定義插入點
         
    /* Menu: File */
      
    private void createFileMenu(IMenuManager menuBar) {
        MenuManager fileMenu 
    = new MenuManager("&File", IWorkbenchActionConstants.M_FILE);
        menuBar.add(fileMenu);

        fileMenu.add(
    new GroupMarker(IWorkbenchActionConstants.FILE_START));
        fileMenu.add(
    new GroupMarker(IWorkbenchActionConstants.NEW_EXT));
        fileMenu.add(
    new Separator());

        fileMenu.add(getAction(ActionFactory.CLOSE.getId()));
        fileMenu.add(getAction(ActionFactory.CLOSE_ALL.getId()));
        fileMenu.add(
    new GroupMarker(IWorkbenchActionConstants.CLOSE_EXT));
        fileMenu.add(
    new Separator());
        fileMenu.add(getAction(ActionFactory.SAVE_AS.getId()));
        fileMenu.add(
    new GroupMarker(IWorkbenchActionConstants.SAVE_EXT));
        fileMenu.add(
    new Separator());
        fileMenu.add(getAction(ActionFactory.PRINT.getId()));

        fileMenu.add(
    new Separator());
        fileMenu.add(
    new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));

        fileMenu.add(fReopenEditors); 
    // TODO Consider moving into a "Go" Menu!

        fileMenu.add(
    new Separator());
        fileMenu.add(
    new GroupMarker(IWorkbenchActionConstants.FILE_END));
        fileMenu.add(
    new Separator());

        fileMenu.add(getAction(ActionFactory.QUIT.getId()));
      }
           其中有一行fileMenu.add(new GroupMarker(IWorkbenchActionConstants.NEW_EXT)); 這里是定義一個GroupMarker作為組標記,把子菜單New容納進來。這個NEW_EXT的值是:new.ext
          現在跳回到plugin.xml去看一下它的ActionSet定義,結構如下:
    ,點擊New(menu),它的path值為:file/new.ext,這個路徑就是在createFileMenu方法定義的路徑,第一個是“File”本身的ID。也就是把子菜單New(menu)插入到指定的那個GroupMarker,ID為new.ext。然后定義了三個ID分別為bookmark,newsbin,searchmark,的groupmarker和一個folder的separator,這個三ID分別就對應上面actionSet定義的三個action,以其中的Bookmark(action)為例,它的menubarPath為:file/new_sub/bookmark,代表插入到"File"主菜單中定義的new_sub子菜單中,new_sub是New(menu)的ID。因為folder是定義為separator,所以它會有一條分隔線。這只是RssOwl的定義方法,其實以前自己做開發的時候是沒有這樣定義的,而且把子菜單New也寫在方法fillMenuBar中的,菜單把ID都寫在里面,ActionSet的配置就沒有子菜單出現了,但是這樣定義看起來就比較亂。采用這種寫法感覺比較簡潔。
        2.  Action的實現
           仍以bookmark為例,它的實現類是NewBookMarkAction,實現了IWorkbenchWindowActionDelegate, IObjectActionDelegate二個接口,第一個是ActionSet指定實現接口,第二個是對象操作菜單要求實現的接口(但事實發現沒有再定義它的配置,可能是internal版本的原因),也就是說這個Action是多功能,它將會出現在主菜單,工具欄,和局部的右鍵菜單上。主菜單和工具欄的位置都在ActionSet配置定義了,看看它的右鍵菜單實現是在哪里的,這個右鍵是在視圖Bookmarks定義的,那么跳轉到org.rssowl.ui.internal.views.explorer.BookMarkExplorer類去看看。里面有一個hookContextualMenu()方法,就是定義它的右鍵菜單的,看一下代碼實現:
    private void hookContextualMenu() {
        MenuManager manager 
    = new MenuManager();

        
    /* New Menu */
        MenuManager newMenu 
    = new MenuManager("New");
        manager.add(newMenu);

        
    /* New BookMark */
        newMenu.add(
    new Action("Bookmark"{
          @Override
          
    public void run() {
            IStructuredSelection selection 
    = (IStructuredSelection) fViewer.getSelection();
            IFolder parent 
    = getParent(selection);
            IMark position 
    = (IMark) ((selection.getFirstElement() instanceof IMark) ? selection.getFirstElement() : null);
            
    new NewBookMarkAction(fViewSite.getShell(), parent, position).run(null);
          }


          @Override
          
    public ImageDescriptor getImageDescriptor() {
            
    return OwlUI.BOOKMARK;
          }

        }
    );

       
    //其它定義
    }
         原來實現也很簡單,只是往MenuManager里面添加一個Action而已,而且run方法就是直接調用定義好的NewBookMarkAction的run方法,但是把選中對象做為參數傳進去,因為這個new是涉及當前上下文選擇對象的。
        3. 下拉類型的工具按鈕定義
        非常常見的Dropdown類型的工具欄按鈕可以把功能類型的按鈕歸為一類,做成一個下拉菜單形式,有默認的按下功能,也有可以選擇其它類似功能的下三角形式,樣子如下:

        這個dropdown的Action是定義在ActionSet配置里的。style是pulldown類型的,所以實現類NewTypeDropdownAction實現了IWorkbenchWindowPulldownDelegate接口,它的run方法就是定義默認點擊不做選擇時的事情,這個下拉菜單是實現getMenu(Control parent)方法而來,它定義了如何生成這個菜單,這就用到了最原始的SWT中的MenuItem了,并且為它們添加SelectionListener,方法實現,不用說都知道了,又是New一個先前定義好的NewBookMarkAction類,然后又是調用它的run方法。所以總結一下,Action的重用不一定是這個類的重用,關鍵是它的run方法的重用,在不同的場景下它的外在表現形式可能會多種多樣,但是它的run內容是一致的。像添加這種添加的run大部分時候都是彈出一個對話框,而對話框大都又是Winzard類型的,因為Winzard可以共享放到dialog里面。所以這種復用的思想在Eclipse里面隨處可見。
       歸結一下,其實這些技巧都是次要的,因為做GUI一個比較痛苦的事情就是經常要寫很多重復類似的代碼,抽取的不好,可能就變得不倫不類了。怎么利用它的這種思想,把復用的代碼都抽取在一起,而閱讀起來又比較輕松才是關鍵。
       知道的就這些,先介紹到這里,下次再談談其它新的發現。

    posted @ 2008-08-21 11:29 寒武紀 閱讀(1798) | 評論 (0)編輯 收藏

         摘要:     許久沒有弄RCP了,剛好近來閑暇一點,找來個RSSOwl的源代碼看看,有點收獲。RssOwl非常出名,只是可能很多人不知道它是用Java做的。以前看過RssOwl第一版的源碼,沒有詳細研究,down下來之后放上公司的共享CVS服務器,倒是幾個同事饒有興趣地研究起來。第一個版本寫得較早,可能Eclipse的RCP框架都還沒有出來,所以全部采用的SWT/JFace...  閱讀全文

    posted @ 2008-07-31 15:13 寒武紀 閱讀(2086) | 評論 (5)編輯 收藏

        最近一個程序出了點問題,對于中文參數的GET請求,服務器無法解析出正確的參數。剛好服務器的那端是另一個項目組負責,是異構系統,當初測試的時候也是走流程化,涉及到很多工作上的協調就比較麻煩,測試也不充分,像趕鴨子上架一樣就上線了,催說是項目緊急。當然這是話外,不多廢話。
        httpClient的GetMethod類加入參數的方法是如下:
    void setQueryString(NameValuePair[] params)
              Sets the query string of this HTTP method.
     void setQueryString(String queryString)
       跟蹤一下httpClient的GetMethod的源代碼,繼承自HttpMethodBase,源碼如下:
      
    public void setQueryString(String queryString) {
       
    this.queryString = queryString;
    }

        
    public void setQueryString(NameValuePair[] params) {
       LOG.trace(
    "enter HttpMethodBase.setQueryString(NameValuePair[])");
       queryString 
    = EncodingUtil.formUrlEncode(params, "UTF-8");
    }
       EncodingUtil是httpClient定義的一個編碼工具類,由于默認設置的是UTF-8,所以對于一些系統可能就無法識別??梢栽谕獠窟@樣更改:
    method.setQueryString(EncodingUtil.formUrlEncode(pair, "GB2312"));另外,注意請求頭也要修改為對應的一致編碼方式,method.addRequestHeader("Content-type" , "text/html; charset=GB2312");如果這二個編碼不一致,就會引起亂碼。
       剛開始的時候嘗試過都使用一致的UTF-8,但是發現還是亂碼,這應該是服務器的原因。IE默認的就是采用操作系統Windows的中文編碼去進行Encoder的,服務器原先基本上都為IE服務的,所以改為GB2312就能正常識別得到。
       另外,上面提到的EncodingUtil這個工具是從apache的另一個組件codec包裝而來的,而非SUN的URLEncoder。有興趣的可以研讀一下源代碼。

    posted @ 2008-07-16 10:31 寒武紀 閱讀(5207) | 評論 (2)編輯 收藏

    Jakarta的httpclient3.1是最新版本,項目中需要用程序模擬瀏覽器的GET和POST動作。在使用過程中遇到不少問題。
    1. 帶附件的POST提交
        最開始都是使用MultipartPostMethod這個類,現在已經廢棄這個類了。API說明:Deprecated. Use MultipartRequestEntity in conjunction with PostMethod instead.   使用PostMethod可以實現的功能,就沒有必要再弄一個MultipartPostMethod了。下面是一段最簡單的示例:

    PostMethod post = new PostMethod();
            NameValuePair[] pairs 
    = new NameValuePair[2];
            pairs[
    0= new NameValuePair("para1""value1");
            pairs[
    0= new NameValuePair("para2""value2");
            post.setRequestBody(pairs);
            HttpClient client 
    = new HttpClient();
            
    try {
                client.executeMethod(post);
            }
     catch (HttpException e) {
                e.printStackTrace();
            }
     catch (IOException e) {
                e.printStackTrace();
            }
       這是針對一般的form形式的提交,而且這個form里面不帶附件的。如果帶附件,那么這種方法就不起作用,附件上傳的參數和普通參數無法一同在服務器獲取到。org.apache.commons.httpclient.methods.multipart 這個包就是為處理文件上傳這種多形式參數的情況的。最主要的類是Part(代表一種post object),它有二個比較重要的子類:FilePart和StringPart,一個是文件的參數,另一個就是普通的文本參數。它的典型使用方法如下:
    String url = "http://localhost:8080/HttpTest/Test";
             PostMethod postMethod 
    = new PostMethod(url);
             
             StringPart sp 
    = new StringPart("TEXT""testValue");
             FilePart fp 
    = new FilePart("file""test.txt"new File("./temp/test.txt"));
             
             MultipartRequestEntity mrp
    = new MultipartRequestEntity(new Part[]{sp, fp}, postMethod
                     .getParams());
             postMethod.setRequestEntity(mrp);
             
             
    //執行postMethod
             HttpClient httpClient = new HttpClient();
             
    try {
                httpClient.executeMethod(postMethod);
            }
     catch (HttpException e) {
                e.printStackTrace();
            }
     catch (IOException e) {
                e.printStackTrace();
            }
        在第二行PostMethod postMethod = new PostMethod();后面,有人說需要使用postMehtod.setRequestHeader("Content-type", "multipart/form-data"); Content-type的請求類型進行更改。但是我在使用過程沒有加上這一句,查了一下httpCleint的默認Content-type是application/octet-stream。應該是沒有影響的。對于MIME類型的請求,httpclient建議全用MulitPartRequestEntity進行包裝,就是上面的用法。

    2.  參數中文的處理問題
        httpclient的默認編碼都是ISO-8859-1,那肯定就無法支持中文參數了。引用一下這篇文章:http://thinkbase.net/w/main/Wiki?HttpClient+POST+%E7%9A%84+UTF-8+%E7%BC%96%E7%A0%81%E9%97%AE%E9%A2%98 ,按照作者的說法,就可以正常解決中文編碼的問題。其中最關鍵的是修改EncodingUtil這個類的一個方法實現。另外,FilePart和StringPart的構造方法都有一個帶編碼指定的參數,為了減少問題的出現,建議所有的都帶上統一的編碼,包括postMethod.getParams()。示例如下:
    String url = "http://localhost:8080/HttpTest/Test";
             PostMethod postMethod 
    = new PostMethod(url);
             
             StringPart sp 
    = new StringPart("TEXT""testValue""GB2312");
             FilePart fp 
    = new FilePart("file""test.txt"new File("./temp/test.txt"), null"GB2312");
             
             postMethod.getParams().setContentCharset(
    "GB2312");
             MultipartRequestEntity mrp
    = new MultipartRequestEntity(new Part[]{sp, fp}, postMethod
                     .getParams());
             postMethod.setRequestEntity(mrp);
             
             
    //執行postMethod
             HttpClient httpClient = new HttpClient();
             
    try {
                httpClient.executeMethod(postMethod);
            }
     catch (HttpException e) {
                e.printStackTrace();
            }
     catch (IOException e) {
                e.printStackTrace();
            }

    posted @ 2008-06-11 15:18 寒武紀 閱讀(6927) | 評論 (8)編輯 收藏

       1. 先下載VMWare Tools for linux,下面是一個下載鏈接 http://vmware.cn/Soft/UploadSoft9f4/VMware%20Workstation%206.02%C2%CC%C9%AB%BE%AB%BC%F2%D3%A2%CE%C4%B0%E6/vmware_tools_linux.rar
       2. 解壓出一個linux.iso文件,這個就是tools工具的安裝光盤鏡像。事先你必須正確安裝了Linux,我安裝的ubuntu8.04,在VM上點擊“編輯虛擬機設置”,CD-ROM方式改為“使用ISO鏡像”,選擇linux.iso,確定
       3. 啟動你的虛擬機操作系統,然后切換出來鼠標,選擇主菜單“虛擬機”--> “安裝VMware Tools”,ubuntu會自動搜索到該CDROM,直接打個桌面的圖標即可。可以看到二個文件:VMwareTools-xxx-i386.rpm和VMwareTools- xxx.tar.gz。rpm是RedHat的安裝包,這里我們應該使用gz文件,把這個gz文件直接復制到桌面,解壓,生成一個-tools-distrib 目錄。
       4. 打開終端,跳桌面這個-tools-distrib 目錄。輸入下面的命令:$ sudo ./-install.pl(回車后會提示輸入你的密碼,并且密碼不會顯示出來,表明你將以更高級權限執行一個動作——安裝軟件;再次回車后安裝開始)
       5. 安裝過程會有一系列的問題確認,類似windows的安裝向導提示,一路回車下去,采用默認方式就可以。
       6. 最后安裝成功會提示選擇桌面環境的默認分辨率。分辨率可以以后再調整。
       7. 安裝后鼠標的滑輪可能不好使了。我們這樣解決這個問題,還是打開終端,輸入:$ sudo gedit /etc/X11/xorg.conf   這個命令使系統以root權限打開鼠標配置文件/etc/X11/xorg.conf。把文件中的 Option “Protocol” “ps/2”改成 Option “Protocol” “IMPS/2” 。保存,然后重新啟動ubuntu。

       補充:關于VMware安裝ubuntu8.04和VMware tools以后,真實系統和虛擬系統的文件共享仍存在問題的,無法直接從外部的windows拖文件放入虛擬系統里面。掛載U盤或是分區也比較麻煩。后來想可以利用光驅,自己把要共享的文件制作成Windows下面的ISO文件,然后裝截入光驅,直接在虛擬光驅里面打開,就可以直接操作。

    posted @ 2008-06-03 17:27 寒武紀 閱讀(6868) | 評論 (3)編輯 收藏

       Eclipse3.3出來很久了,一直都使用英文版,剛好看到有網友介紹Eclipse的一個Project,叫Babel,官方的描述這樣:Eclipse is a global community. It is in everyone's interest to ensure that Eclipse is available and translated in as many locales as possible. 項目的主頁地址是:http://www.eclipse.org/babel/ 。按照說明從這里可以下載安裝到語言包。
       直接從Eclipse3.3的菜單"Help --> Software Updates --> Find and Insatll...",新建一個遠程站點,URL為 http://download.eclipse.org/technology/babel/update-site/ ,然后直接在線安裝。在彈出的語言選擇界面上選擇中文簡體。如下圖:
       

        網絡情況如果正常的話,安裝應該不會有問題的,中間可能會彈出幾次下載jar文件失敗的對話框,繼續retry就行。
       
        最后重啟一下,可以看到都變成中文界面的。
       
     
      原來是3.3的Eclipse,怎么變成3.2呢?原因估計是語言插件的版本是3.2的導致的,所以你看到有一些地方漢化并不完全,像Error Log視圖的標題,項目右鍵菜單,以及一些頂級菜單都沒有完全漢化。
      希望以后Babel項目后面更新跟得上主版本的變化,不過習慣了英文版的,其實也是差不多的。

    posted @ 2008-05-30 15:44 寒武紀 閱讀(13944) | 評論 (13)編輯 收藏

    主站蜘蛛池模板: 国产人成网在线播放VA免费| 免费福利在线观看| 亚洲成AV人片在WWW| 国产99久久亚洲综合精品| 一个人免费观看www视频| 中文字幕久精品免费视频| 亚洲电影免费观看| 日韩成人免费在线| 2022中文字字幕久亚洲| 亚洲午夜视频在线观看| 国产成人亚洲综合网站不卡| 日日摸夜夜添夜夜免费视频| 久久aa毛片免费播放嗯啊| 日本成年免费网站| 亚洲成?Ⅴ人在线观看无码| 久久亚洲AV无码精品色午夜麻| 91免费国产视频| 8888四色奇米在线观看免费看| 九九九国产精品成人免费视频| 亚洲国产成人精品久久| 久久亚洲AV成人无码国产最大| 亚洲一区二区三区四区视频| 久久人午夜亚洲精品无码区| 免费看成人AA片无码视频吃奶| 黄视频在线观看免费| 久久免费视频精品| 成人超污免费网站在线看| 亚洲精品国精品久久99热| 亚洲高清视频在线播放| 久久精品国产亚洲av品善| 伊人免费在线观看| 成年女性特黄午夜视频免费看| 好大好深好猛好爽视频免费| 亚洲一区日韩高清中文字幕亚洲 | 亚洲成AⅤ人影院在线观看| 亚洲AV无码一区东京热久久 | 国产精品国产自线拍免费软件| 成人午夜18免费看| 亚洲国产精品久久久天堂| 亚洲av日韩aⅴ无码色老头| 午夜爽爽爽男女免费观看影院|