<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

    2011年1月14日

    系統(tǒng)為ubuntu server,二臺機(jī)器A和B,IP為A 192.168.1.111,B 192.168.1.222
    A為rsync server,啟動為守護(hù)進(jìn)程,B為備份機(jī),做為rsync client,最后用crontab做一個簡單的作業(yè),定時在B上執(zhí)行同步文件的功能
    A的安裝和配置如下:
    1.  apt-get install rsync   可能提示系統(tǒng)已經(jīng)安裝有了
    2. 配置文件/etc/rsyncd.conf
        默認(rèn)安裝時是不會有這個配置文件的,但是可以 cp /usr/share/doc/rsync/examples/rsyncd.conf /etc  把它示例中的配置文件拷貝過來
        vi /etc/rsyncd.conf    這里參數(shù)有點多,但是有些可以先不管,關(guān)注重點的
        [ftp]  這里是模塊,可以配置多個,這個是系統(tǒng)默認(rèn)給出的一個配置,下面給一個本機(jī)上的配置示例:
    --------------------------------------------------------------------------------------------------
    # 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,最大連接數(shù)是2,read only = no,指定為非只讀(不然同步時會有權(quán)限問題)
    而后面的auth users = rsync 是指定一個同步的賬戶名叫做rsync,這個賬戶的認(rèn)證文件是/etc/rsyncd.secrets,當(dāng)然我們要創(chuàng)建這個文件

    3.  創(chuàng)建 /etc/rsyncd.secrets文件,內(nèi)容為: rsync:123  表示rsync這個用戶的密碼是123 然后修改文件的權(quán)限 chmod 600 /etc/rsyncd.secrets

    4.  rsync server做為守護(hù)進(jìn)程
         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
    -------------------------------------------
       做為守護(hù)進(jìn)程,可以設(shè)置為true或是xinetd方式來啟動。于是我們安裝inetd   sudo apt-get install xinetd
       安裝好后配置inetd的配置文件  vi /etc/xinetd.d/rsync ,輸入如下內(nèi)容:
    ---------------------------------------------------
    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服務(wù)器的rsyncd server就完成了!

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

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

    二臺服務(wù)器,A的內(nèi)網(wǎng)IP為192.168.1.111,B的內(nèi)網(wǎng)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就是要同步的數(shù)據(jù)庫的名稱,如果沒有這一行,表示同步所有的數(shù)據(jù),另外 binlog_ignore_db = mysql。要表示忽略同步的數(shù)據(jù)庫名稱為mysql,如果有多個要指定同步或是忽略同步的數(shù)據(jù),就配置多行,保存退出。
         (2) 創(chuàng)建一個復(fù)制用的賬戶(名稱為repl,允許從遠(yuǎn)程連接,密碼為123456):
              GRANT REPLICATION SLAVE, RELOAD,SUPER, NO *.* TO repl@'%' IDENTIFIED BY '123456';
            FLUSH PRIVILEGES;
         (3) 重啟mysql服務(wù),或是直接reboot機(jī)器也可以
         (4) 進(jìn)入mysql,然后用 show master status\G  查看二進(jìn)制日志的狀態(tài),看到類似以下的結(jié)果:
              +------------------+----------+--------------+------------------+
              | 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機(jī)器的不一樣。并增加以下內(nèi)容:
               binlog_do_db=s3
               log-slave-updates
              保存退出
         (2) 重啟mysql服務(wù)
         (3) 進(jìn)入mysql,執(zhí)行
              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命令得到的結(jié)果,指定二進(jìn)制文件的名稱和開始同步的位置。
         (4) 查看SLAVE狀態(tài):    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則表示已經(jīng)正常連接,可以進(jìn)行復(fù)制了。

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

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

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

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

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

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

         我想這四個方面的原則無非就是:減少單元測試需要進(jìn)行的步驟(最快到達(dá)測試界面),脫離后臺依賴(自己簡單模擬后臺實現(xiàn),可惜flex沒有類似java的mock庫,悲劇!),如何查看提交到后臺的結(jié)果。 單元測試的目標(biāo):界面能正常加載、提交數(shù)據(jù)正常,如果二者都沒問題,那么聯(lián)調(diào)的時候就可以非常容易定位到是Flex的問題還是Java的問題!達(dá)到介分責(zé)任的目標(biāo),當(dāng)然,如果你所在團(tuán)隊是按模塊分的,也就是說flex和java都是同一個人做,那么就不存在責(zé)任問題。

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

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

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

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

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

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

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

          問題描述:
              服務(wù)器操作系統(tǒng)是Centos5.5,此前已經(jīng)有多套系統(tǒng)跑在上面,且裝有PHP5.2.10。Centos5.X系統(tǒng)的穩(wěn)定yum安裝源版本是5.1.6,并不符合最新版本的phpmyadmin(5.2以上版本),下載了最新版本phpmyadmin安裝后提示缺少mysql支持模塊。
    查看了一下發(fā)現(xiàn)的確是安裝php的時候沒有裝上php-mysql模塊。直接重新編譯php源碼安裝比較麻煩。
         一個比較方便的方法:
        為yum添加第三方的源,然后直接用yum -y install php-mysql進(jìn)行安裝
        以下方法為從網(wǎng)絡(luò)搜索到的,做個記錄,方面須用之時查閱。
              導(dǎo)入地址:    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

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

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

        freemarker幾天前才發(fā)布了2.3.17版本,5月21號又發(fā)布了2.3.18,距2.3.16已經(jīng)一年多了。老的編輯器已經(jīng)不能安裝在新版本的eclipse和myeclipse上面了,最新的官方編輯器仍在開發(fā)階段,有網(wǎng)友貌似知道最新的源代碼鏈接位置,不過肯定是不穩(wěn)定的。
        另一個可選的編輯器就是JBoss Tools 3.2中的FreeMarker編輯器,值得安慰,啟動MyEclipse9.0后進(jìn)入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,其它的大概你不需要都不用管,也不影響下載時間,然后一路確認(rèn)安裝就OK!

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

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

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

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

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

           第二天晚上繼續(xù)折騰,再不停地重新安裝,這時才想起一個問題:應(yīng)該退回到系統(tǒng)宕機(jī)前的所有軟件版本狀態(tài),這樣原先備份的數(shù)據(jù)才能正常恢復(fù),不會帶來額外的版本沖突麻煩。于是折騰到接近晚上12:00時發(fā)覺方向錯了,無奈,和 L 打了個招呼,計劃明天讓管理員再重裝一次系統(tǒng),現(xiàn)在目前的系統(tǒng)又被我們搞亂了!

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

          回頭一想。其實規(guī)劃、整理、理清服務(wù)器的管理工作,比精通Linux系統(tǒng)、各種軟解決技術(shù)更為重要!

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

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

        1. 安裝Passenger模塊
                gem install passenger
                passenger-install-apache2-module
            
                第二個命令是安裝passenger的apache2模塊,它已經(jīng)做得很智能,會提示你確認(rèn)安裝以及最后怎么配置模塊到apache中。
                摘出配置段的內(nèi)容如下:
                    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方式啟動,如果沒有異常,恭喜,已經(jīng)安裝完成,剩下的工作就是配置一個虛擬主機(jī)和子給你的redmine,這樣可以轉(zhuǎn)到更為常用的80端口上。

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

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

               解釋一下過程大致是先創(chuàng)建一個硬鏈接,如下:

            ln -s /webapps/mycook/public /websites/phusion/rails 
     
         /webapps/mycook/public是你的rails的應(yīng)用目錄下面的public目錄,例如你的redmine安裝在/var/www/html,這個目錄就是
    /var/www/html/redmine/public,后面就是你Apache主目錄下的創(chuàng)建的一個鏈接地址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>

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

     

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

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

    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中的字段定義要和數(shù)據(jù)庫的字段定義一致。Java的命名習(xí)慣一般是駱峰寫法,例如userId,那么數(shù)據(jù)庫中就必須定義為userId,而問題在于:有時候我們需要數(shù)據(jù)庫中字段的定義格式與JavaBean的命名不一樣,比如數(shù)據(jù)庫定義為:user_id,而JavaBean則定義為userId
            看源代碼可能有點費時間,在官方的example頁面的最下面果然有一段關(guān)于自定義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關(guān)鍵字把colName重命名,另一種方式就是繼承BeanProcessor類,重寫mapColumnsToProperties()方法。
          那當(dāng)然是第二種方式更加具有代表性。嘗試了一下。代碼如下:
        
     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); // 在這里進(jìn)行數(shù)據(jù)庫表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     * 數(shù)據(jù)庫列名重新約定
    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方法的邏輯是從父類的方法中直接復(fù)制出來的,然后在第15行那里變了個戲法,這里的columnName就是從數(shù)據(jù)庫中讀出來的,自定義一個private方法用于轉(zhuǎn)換命名,這里你就可以添加自己的命名約束。例如上面就是把 user_id 轉(zhuǎn)化為Java的駱峰寫法:userId
           再深入一層思考,你可以在這里進(jìn)行更多擴(kuò)展,以便讓自己可以選擇不同的命名轉(zhuǎn)換方式。定義了這個Processor之后,下面看看如何調(diào)用:
    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結(jié)果的,就把BeanHandler替換成BeanListHander類,還可以再進(jìn)一步封裝這些操作,抽象到公共模塊中去,讓外部直接傳入sql語句和Class就能直接返回想要的結(jié)果,當(dāng)然你得增加泛型的定義。同樣舉一個封裝的例子:
     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    }

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

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

    posted @ 2011-03-09 16:48 寒武紀(jì) 閱讀(13764) | 評論 (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.6rubygems1.3.5rake 0.8.3rack 1.0.1I18n 0.4.2rails 2.3.5

         
    2.  yum安裝ruby

    使用yum安裝ruby相關(guān)的軟件

    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/ 目錄下創(chuàng)建yum源文件ruby.repo,內(nèi)容如下:

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

    [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

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

    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

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

    cd config

    cp database.yml.example database.yml

    vi database.yml

    添加如下內(nèi)容:

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

    數(shù)據(jù)庫要預(yù)先創(chuàng)建好,如果你裝好了mysql,直接運(yùn)行mysql -uroot -p 登錄,然后create database redmine,主機(jī)名、用戶名、密碼也要寫對。

    10.   生成會話密鑰

     rake config/initializers/session_store.rb

    11.  rails數(shù)據(jù)庫生成和數(shù)據(jù)初始化

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

    12.  運(yùn)行測試

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

    ruby script/server -e production &

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

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

    13.  附注:redmine默認(rèn)端口是3000,如果你是遠(yuǎn)程操作,直接訪問主機(jī)的IP或是域名是無法打開主頁的,因為centosiptables默認(rèn)是沒有開通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的安裝,過程比較繁瑣,主要是各種組件和模塊的版本匹配問題。大多數(shù)情況下根據(jù)安裝的錯誤提示和Google就可以解決滴。

     

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

            非常喜歡這種輕量級的JDBC封裝,比起Hibernate和iBatis,可以非常自由和靈活地運(yùn)用和自行二次封裝,由于dbutils的BeanHandler轉(zhuǎn)換方式采取了反射技術(shù),在性能上肯定有所損失,所以項目中基本上都使用MapHandler方式來轉(zhuǎn)換數(shù)據(jù),當(dāng)然就是自己寫的代碼多一點,也無所謂。一般的查詢、子查詢、聯(lián)合查詢、包括視圖查詢等等都很正常,但是發(fā)現(xiàn)一個比較小的問題,就是在使用聚合函數(shù)的場所,例如:select user_type, count(*) as count from `user` group by user_type這種類型查詢的時候,MapHandler方式不起作用,as列都變成key為空串的K-V對,導(dǎo)致有許多地方使用map.get("")代碼的情況出現(xiàn),這種寫法當(dāng)然是不太好的,容易出問題。
            鑒于前面沒有時間了解,就都粗略使用了上面那種粗暴的map.get("")來處理,最好的情況是讓dbutils組件能自動識別到as類型的列名。于是有空了就專門看了看它的源代碼,發(fā)現(xiàn)最主要的一段代碼如下:
     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(),我想問題大概出在這里,于是認(rèn)真翻了翻java的api文檔(開發(fā)做久了容易遺忘基礎(chǔ)),果然,原來getColumnName()是:獲取指定列的名稱;而as關(guān)鍵字之后,使列名稱變成用于顯示的意義,這個時候應(yīng)該使用getColumnLabel():獲取用于打印輸出和顯示的指定列的建議標(biāo)題。建議標(biāo)題通常由 SQL AS 子句來指定。如果未指定 SQL AS,則從 getColumnLabel 返回的值將和 getColumnName 方法返回的值相同。自己手動試驗了一下,果然如所料,問題就出在這里。
            所以呢,如果想要dbutils在自動轉(zhuǎn)換Map及MapList時能識別聚合函數(shù)的列名,那么最好的做法就是重載這種方式,懶一點的,你就干脆修改上面那段代碼,讓它判斷是否使用了as關(guān)鍵字。個人暫時搞不清楚官方為什么沒有考慮這一步,有時間再思考一下!

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

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

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

             由于redirectAction使用的是ActionMapper來重定向,也就同時使用ActionMapper的編碼方式重新進(jìn)行編碼,這就導(dǎo)致了后面在取出參數(shù)時變成亂碼,沒有具體閱讀它的源代碼,但是多次不同的編碼再想重新還原出來就有點麻煩了。而redirect是使用HttpServletResponse來重定向,就不存在上面的問題。最后改為redirect來重定向,結(jié)果如下:
    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對應(yīng)的Action必須對msg參數(shù)做一次轉(zhuǎn)碼,因為前面的Action過來時就做了URL base64編碼,如果直接發(fā)給瀏覽器,就會在瀏覽器看到一串帶%的URL base64編碼字符,所以要加上
    1String msg = URLDecoder.decode(getMsg(), "UTF-8");
    2setMsg(msg);
           把它設(shè)置回為中文,瀏覽器才能正常。

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

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

    主站蜘蛛池模板: 中文国产成人精品久久亚洲精品AⅤ无码精品 | 亚洲∧v久久久无码精品| 婷婷久久久亚洲欧洲日产国码AV| 久久精品亚洲一区二区| 久久亚洲精品成人av无码网站| 亚洲性猛交xx乱| 久久久国产亚洲精品| 美女无遮挡免费视频网站| 国产精品视频全国免费观看| 99久久精品国产免费| 欧美好看的免费电影在线观看| 免费在线观看亚洲| caoporm超免费公开视频| 一级毛片aaaaaa免费看| 成年性生交大片免费看| 国产成人亚洲精品影院| 亚洲精品免费观看| 亚洲av午夜电影在线观看| 中文字幕免费观看视频| 国产高清免费视频| 亚洲成年看片在线观看| 亚洲av日韩av高潮潮喷无码| 亚洲中文字幕乱码熟女在线| 亚洲天堂免费在线视频| 亚洲高清免费在线观看| 波多野结衣免费视频观看 | 亚洲福利精品一区二区三区| 亚洲AV无码成人网站久久精品大| 久久乐国产综合亚洲精品| WWW免费视频在线观看播放| 日本精品人妻无码免费大全 | 亚洲M码 欧洲S码SSS222| 亚洲日本中文字幕区| 久久久久亚洲AV无码去区首| 无码少妇精品一区二区免费动态 | 日韩毛片在线免费观看| 美女视频黄.免费网址| 99精品在线免费观看| 免费国产综合视频在线看| 亚洲精品中文字幕麻豆| www.av在线免费观看|