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

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

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

    2014年12月30日

    執(zhí)行./startup.sh,或者./shutdown.sh的時(shí)候,爆出了Permission denied

    關(guān)于LINUX權(quán)限-bash: ./startup.sh: Permission denied

    <script type="text/javascript"></script><script type="text/javascript"></script>

    在執(zhí)行./startup.sh,或者./shutdown.sh的時(shí)候,爆出了Permission denied,

    其實(shí)很簡(jiǎn)單,就是今天在執(zhí)行tomcat的時(shí)候,用戶沒(méi)有權(quán)限,而導(dǎo)致無(wú)法執(zhí)行,

    用命令chmod 修改一下bin目錄下的.sh權(quán)限就可以了

    如chmod u+x *.sh

    在此執(zhí)行,OK了。

    posted @ 2014-12-30 10:26 liujg 閱讀(289) | 評(píng)論 (0)編輯 收藏

    2011年9月28日

    submit()和onsubmit()的區(qū)別(轉(zhuǎn))

    2011-03-16 10:34

    最近在開(kāi)發(fā)中遇到了表單提交前驗(yàn)證的問(wèn)題,用一個(gè)普通的button按鈕代替submit按鈕,
    在提交前觸發(fā)這個(gè)button的onclick事件,在其事件中觸發(fā)form的submit事件。問(wèn)題出現(xiàn)了:
    以下是出現(xiàn)相關(guān)代碼:
    <form action="http://www.baidu.com/s?wd=this.form.submit%28%29%3B&cl=3" method="post" name="form1" onsubmit="return alert('已提交!'); return false;"> 
        <table align="center" width="420px" cellPadding="2" cellSpacing="1" bgcolor="#A4B6D7"    style="word-wrap:Break-word;">                
            <tr style="cursor: hand;background:#d7e3f6" > 
                <td width="20%" align="right">條型碼</td> 
                <td><input style="width:90%" type="text" name="GOODSNUM"   size="30"  maxlength="8" ></td> 
            </tr> 
            <tr> 
                <td align="center" colspan="2"> 
                    <input type="button" name="save" value="保存" onclick="if((confirm('確定要提交嗎?'))) this.form.submit();"/> 
                </td> 
            </tr>  
        </table> 
    </form> 


    卻發(fā)現(xiàn)并沒(méi)有觸發(fā)form的onsubmit方法,而是直接提交了。奇怪了,難道沒(méi)有這種方式無(wú)法結(jié)合form的onsubmit方法嗎?
    仔細(xì)想了想,既然this.form表示form這個(gè)對(duì)象,那么肯定能獲取到form的屬性和方法的
    ,就改成this.form.onsubmit();  成功!
    我又查了查手冊(cè),原來(lái)submit的方法是這樣解釋的:
      The submit method does not invoke the onsubmit event handler. Call the onsubmit event handler directly. When using Microsoft® Internet Explorer 5.5 and later, you can call the fireEvent method with a value of onsubmit in the sEvent parameter.

    意思是說(shuō)submit這個(gè)方法是不觸發(fā)onsubmit時(shí)間的,如果想要觸發(fā)它,需要調(diào)用
    fireEvent方法。嘗試一下:this.form.fireEvent('onsubmit');哈哈,果然也成功!不過(guò)這樣不是多此一舉嗎?呵呵!

    就這個(gè)小問(wèn)題也搞了我將近一個(gè)小時(shí),不過(guò)為了以后不為這個(gè)問(wèn)題煩惱,這也是值得的。
    this.form.submit(); //直接提交表單
    this.form.onsubmit(); //調(diào)用form的onsubmit方法
    this.form.fireEvent('onsubmit'); //同上,
         PS:又學(xué)到了fireEvent這個(gè)方法,

    2.onsubmit()與submit() :

    <sCript>
    funCtion fun()
    {
       alert("form_submit");
    }
    </sCript>

    <form onsubmit="fun()">
    <input type="submit" id="aaa" value="submit">   <!--能彈出form_submit-->
    <input type="button" id="bbb" value="onCliCk_submit" onCliCk="doCument.forms[0].submit()">
    <!--
    表單會(huì)提交,但是不會(huì)運(yùn)行fun() 原因是 onsubmit事件不能通過(guò)此種方式觸發(fā)(在IE環(huán)境)
    直接用腳本doCumetn.formName.submit()提交表單是不會(huì)觸發(fā)表單的onsubmit()事件的
    -->
        <input type="button" id="bb1" value="onCliCk_onsubmit" onCliCk="doCument.forms[0].onsubmit()">

    <!--會(huì)觸發(fā)fun()參數(shù)-->
    </form>

    posted @ 2011-09-28 15:11 liujg 閱讀(346) | 評(píng)論 (0)編輯 收藏

    2011年5月24日

    doGet()和doPost()的區(qū)別(轉(zhuǎn))

    service()是在javax.servlet.Servlet接口中定義的, 在 javax.servlet.GenericServlet 中實(shí)現(xiàn)了這個(gè)接口, 而 doGet/doPost 則是在 javax.servlet.http.HttpServlet 中實(shí)現(xiàn)的, javax.servlet.http.HttpServlet 是 javax.servlet.GenericServlet 的子類. 所有可以這樣理解, 其實(shí)所有的請(qǐng)求均首先由 service() 進(jìn)行處理, 而在 javax.servlet.http.HttpServlet 的 service() 方法中, 主要做的事情就是判斷請(qǐng)求類型是 Get 還是 Post, 然后調(diào)用對(duì)應(yīng)的 doGet/doPost 執(zhí)行.

    doGet:處理GET請(qǐng)求 doPost:處理POST請(qǐng)求 doPut:處理PUT請(qǐng)求 doDelete:處理DELETE請(qǐng)求 doHead:處理HEAD請(qǐng)求 doOptions:處理OPTIONS請(qǐng)求 doTrace:處理TRACE請(qǐng)求 通常情況下,在開(kāi)發(fā)基于HTTP的servlet時(shí),開(kāi)發(fā)者只需要關(guān)心doGet和doPost方法,其它的方法需要開(kāi)發(fā)者非常的熟悉HTTP編程,因此這些方法被認(rèn)為是高級(jí)方法。 而通常情況下,我們實(shí)現(xiàn)的servlet都是從HttpServlet擴(kuò)展而來(lái)。 doPut和doDelete方法允許開(kāi)發(fā)者支持HTTP/1.1的對(duì)應(yīng)特性; doHead是一個(gè)已經(jīng)實(shí)現(xiàn)的方法,它將執(zhí)行doGet但是僅僅向客戶端返回doGet應(yīng)該向客戶端返回的頭部的內(nèi)容; doOptions方法自動(dòng)的返回servlet所直接支持的HTTP方法信息; doTrace方法返回TRACE請(qǐng)求中的所有頭部信息。 對(duì)于那些僅僅支持HTTP/1.0的容器而言,只有doGet, doHead 和 doPost方法被使用,因?yàn)镠TTP/1.

    下邊是CSDN里邊的一些討論:
    1.doGet和doPost的區(qū)別,在什么時(shí)候調(diào)用,為什么有時(shí)doPost中套用doGet
    2.提交的form     method=Post就執(zhí)行DOPOST,否則執(zhí)行GOGET 套用是不管method是post還是get都執(zhí)行dopost方法
    3.get:你可以通過(guò)URL傳參數(shù)。
    http://www.csdn.net/index.asp?user=1234    , Post不行  
    4.你的表單提交都有方法的,如果提交為get就調(diào)用get方法,用post就調(diào)用post方法.  
        get顯示你傳過(guò)去的參數(shù),post則不顯示.
    5.通常的寫(xiě)法:先用doGet(),然后在doPost()中調(diào)用doGet(),這樣就萬(wàn)無(wú)一失了
    6. 簡(jiǎn)單的說(shuō),get是通過(guò)http     header來(lái)傳輸數(shù)據(jù),有數(shù)量限制,而post則是通過(guò)http     body來(lái)傳輸數(shù)據(jù),沒(méi)有數(shù)量限制。
    7.還有一點(diǎn):get和post提交的數(shù)據(jù)量是不一樣的.  
        get好像最多只能在url后跟64K(?具體多少忘記了),  
        post好像沒(méi)這個(gè)限制,至少我post過(guò)5M以上的文本    
        還有url刷新時(shí)get好像可以不用重復(fù)提交原來(lái)提交的數(shù)據(jù),  
        而post則會(huì)說(shuō)內(nèi)容已提交,想刷新請(qǐng)?jiān)偬峤?

    posted @ 2011-05-24 23:58 liujg 閱讀(479) | 評(píng)論 (0)編輯 收藏

    2011年5月3日

    轉(zhuǎn)載 Vim 基本用法

    這是我總結(jié)的一些基本用法,可能對(duì)初用者會(huì)有幫助,獨(dú)樂(lè)樂(lè)不如眾樂(lè)樂(lè),是吧!

    說(shuō)明:以下黑色為vi和vim均有的一般功能,而紅色為Vim(Vi Improved)所特有功能。Vim一般的Unix和Linux下均有安裝。
    ? 三種狀態(tài)
    Command: 任何輸入都會(huì)作為編輯命令,而不會(huì)出現(xiàn)在屏幕上,任何輸入都引起立即反映
    Insert: 任何輸入的數(shù)據(jù)都置于編輯寄存器,按ESC,可跳回command方式
    Escape: 以“:”或者“/”為前導(dǎo)的指令,出現(xiàn)在屏幕的最下一行,任何輸入都被當(dāng)成特別指令。
    ? 離開(kāi)vi
    :q! 離開(kāi)vi,并放棄剛在緩沖區(qū)內(nèi)編輯的內(nèi)容。
    :wq 將緩沖區(qū)內(nèi)的資料寫(xiě)入磁盤中,并離開(kāi)vi。
    :x 同wq。
    (注意—— :X 是文件加密,一定要與:x存盤退出相區(qū)別)
    ? 進(jìn)入輸入模式
    a (append) 由游標(biāo)之后加入資料。
    A 由該行之末加入資料。
    i (insert) 由游標(biāo)之前加入資料。
    I 由該行之首加入資料。
    o (open) 新增一行於該行之下供輸入資料之用。
    O 新增一行於該行之上供輸入資料之用。
    ? 刪除與修改
    x 刪除游標(biāo)所在該字元。
    X 刪除游標(biāo)所在之前一字元。
    r 用接於此指令之后的字元取代(replace)游標(biāo)所在字元。如:ra將游標(biāo)所在字元以 a 取代之。
    R 進(jìn)入取代狀態(tài),直到《ESC》為止。
    s 刪除游標(biāo)所在之字元,并進(jìn)入輸入模式直到《ESC》。
    S 刪除游標(biāo)所在之該行資料,并進(jìn)入輸入模式直到《ESC》。
    ? 光標(biāo)的移動(dòng)
    m<a-z> 設(shè)置書(shū)簽<a-z>
    ‘<a-z> 移至?xí)?lt;a-z>處
    0 移至該行之首
    $ 移至該行之末。
    e 移動(dòng)到下個(gè)字的最後一個(gè)字母
    w 移動(dòng)到下個(gè)字的第一個(gè)字母。
    b 移動(dòng)到上個(gè)字的第一個(gè)字母。
    ^ 移至該行的第一個(gè)字元處。
    H 移至視窗的第一行。
    M 移至視窗的中間那行。
    L 移至視窗的最后一行。
    G 移至該文件的最后一行。
    + 移至下一列的第一個(gè)字元處。
    - 移至上一列的第一個(gè)字元處。
    :n 移至該文件的第 n 列。
    n+ 移至游標(biāo)所在位置之后的第 n 列。
    n- 移至游標(biāo)所在位置之前的第 n 列。
    <Ctrl><g> 顯示該行之行號(hào)、文件名稱、文件中最末行之行號(hào)、游標(biāo)所在行號(hào)占總行號(hào)之百分比。

    (Vim) 光標(biāo)移動(dòng)基本用法小解:
    (這只要組合上邊的功能就可以明白了,不用再一一講解了吧!)
    ge b w e
    ← ← ---→ --→
    This is-a line, with special/separated/words (and some more).
    ←- ←-- -----------------→ ---→
    GE B W E

    ? 視窗的移動(dòng)
    <Ctrl><f> 視窗往下卷一頁(yè)。
    <Ctrl><b> 視窗往上卷一頁(yè)。
    <Ctrl><d> 視窗往下卷半頁(yè)。
    <Ctrl><u> 視窗往上卷半頁(yè)。
    <Ctrl><e> 視窗往下卷一行。
    <Ctrl><y> 視窗往上卷一行。
    ? 剪切、復(fù)制、刪除
    Operator + Scope = command
    ? Operator
    d 剪切
    y 復(fù)制。
    p 粘帖,與 d 和 y 配和使用。可將最后d或y的資料放置於游標(biāo)所在位置之行列下。
    c 修改,類似delete與insert的組和。刪除一個(gè)字組、句子等之資料,并插入新建資料。
    ? Scope
    e 由游標(biāo)所在位置至該字串的最后一個(gè)字元。
    w 由游標(biāo)所在位置至下一個(gè)字串的第一個(gè)字元。
    b 由游標(biāo)所在位置至前一個(gè)字串的第一個(gè)字元。
    $ 由游標(biāo)所在位置至該行的最后一個(gè)字元。
    0 由游標(biāo)所在位置至該行的第一個(gè)字元。
    ? 整行動(dòng)作
    dd 刪除整行。
    D 以行為單位,刪除游標(biāo)后之所有字元。
    cc 修改整行的內(nèi)容。
    yy 使游標(biāo)所在該行復(fù)制到記憶體緩沖區(qū)。
    ? 取消前一動(dòng)作(Undo)
    u 恢復(fù)最后一個(gè)指令之前的結(jié)果。
    U 恢復(fù)游標(biāo)該行之所有改變。
    (vim) u 可以多次撤消指令,一次撤消一個(gè)操作,直至本次操作開(kāi)始為止。
    (vim) Ctrl+r 可以恢復(fù)撤消前內(nèi)容,按多次可恢復(fù)多次。
    ? 查找與替換
    /字串 往游標(biāo)之后尋找該字串。
    ?字串 往游標(biāo)之前尋找該字串。
    n 往下繼續(xù)尋找下一個(gè)相同的字串。
    N 往上繼續(xù)尋找下一個(gè)相同的字串。
    % 查找“(”,“)”,“{”,“}”的配對(duì)符。
    s 搜尋某行列范圍。
    g 搜尋整個(gè)編輯緩沖區(qū)的資料。
    :1,$s/old/new/g 將文件中所有的『old』改成『new』。
    :10,20s/^/ / 將第10行至第20行資料的最前面插入5個(gè)空白。
    (vim)
    /字符串 后邊輸入查詢內(nèi)容可保存至緩沖區(qū)中,可用↑↓進(jìn)行以往內(nèi)容選擇。
    另外:將光標(biāo)移動(dòng)在選定單詞下方按*,則可以選中此單詞作為查詢字符,可以避免輸入一長(zhǎng)串字符的麻煩。
    ? (vim) 大小寫(xiě)替換
    首先用按v開(kāi)啟選擇功能,然后用↑↓←→鍵來(lái)選定所要替換的字符,若是小寫(xiě)變大寫(xiě),則按U;反之按u;
    如果是選擇單詞,則可以在按v后,按w,最后按U/u,這樣就可以將字符隨意的改變大小寫(xiě)了,而不用刪除后重新敲入。

    ? 資料的連接
    J 句子的連接。將游標(biāo)所在之下一行連接至游標(biāo)該行的后面。
    ? 環(huán)境的設(shè)定
    :set all 可設(shè)置的環(huán)境變量列表
    :set 環(huán)境變量的當(dāng)前值
    :set nu 設(shè)定資料的行號(hào)。
    :set nonu 取消行號(hào)設(shè)定。
    :set ai 自動(dòng)內(nèi)縮。
    :set noai 取消自動(dòng)內(nèi)縮。
    (vim)
    :set ruler 會(huì)在屏幕右下角顯示當(dāng)前光標(biāo)所處位置,并隨光移動(dòng)而改變,占用屏幕空間較小,使用也比較方便,推薦使用。
    :set hlsearch 在使用查找功能時(shí),會(huì)高亮顯示所有匹配的內(nèi)容。
    :set nohlsearch 關(guān)閉此功能。
    :set incsearch 使Vim在輸入字符串的過(guò)程中,光標(biāo)就可定位顯示匹配點(diǎn)。
    :set nowrapscan 關(guān)閉查找自動(dòng)回環(huán)功能,即查找到文件結(jié)尾處,結(jié)束查找;默認(rèn)狀態(tài)是自動(dòng)回環(huán)

    ? ex指令
    ? 讀寫(xiě)資料
    :10,20w test 將第10行至第20行的資料寫(xiě)入test文件。
    :10,20w>>test 將第10行至第20行的資料加在test文件之后。
    :r test 將test文件的資料讀入編輯緩沖區(qū)的最后。
    :e [filename] 編輯新的文件。
    :e! [filename] 放棄當(dāng)前修改的文件,編輯新的文件。
    :sh 進(jìn)入shell環(huán)境,使用exit退出,回到編輯器中。

    :!cmd 運(yùn)行命令cmd后,返回到編輯器中。
    ? 刪除、復(fù)制及搬移
    :10,20d 刪除第10行至第20行的資料。
    :10d 刪除第10行的資料。
    :%d 刪除整個(gè)編輯緩沖區(qū)。
    :10,20co30 將第10行至第20行的資料復(fù)制至第30行之后。
    :10,20mo30 將第10行至第20行的資料搬移至第30行之后。

    本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/jsufcz/archive/2009/02/11/3875956.aspx

    posted @ 2011-05-03 14:25 liujg 閱讀(254) | 評(píng)論 (0)編輯 收藏

    2011年1月30日

    OERR: ORA-12519


    OERR: ORA-12519報(bào)錯(cuò)  
    1、查詢數(shù)據(jù)庫(kù)當(dāng)前的連接數(shù):
    select count(*) from v$process;
    2、查詢數(shù)據(jù)庫(kù)允許的最大連接數(shù):
    select value from v$parameter where name = 'processes';
    3、修改數(shù)據(jù)庫(kù)允許的最大連接數(shù):
    alter system set processes = 300 scope = spfile;
    4、重啟數(shù)據(jù)庫(kù):
    shutdown immediate;
    startup; 

     


    文章出處:飛諾網(wǎng)(www.firnow.com):http://dev.firnow.com/course/7_databases/oracle/oraclejs/20091103/181042.html

    posted @ 2011-01-30 13:36 liujg 閱讀(562) | 評(píng)論 (0)編輯 收藏

    2007年11月29日

    原形設(shè)計(jì)模式,搞不懂

    今天下載了個(gè)設(shè)計(jì)模式看,prototype模式就兩頁(yè)紙,看過(guò)了也沒(méi)看出來(lái)它到底做什么,比較郁悶。我就不清楚那個(gè)copy方法到底做了什么?沒(méi)有copy方法不行嗎?


    定義:

    用原型實(shí)例指定創(chuàng)建對(duì)象的種類,并且通過(guò)拷貝這些原型創(chuàng)建新的對(duì)象. //通過(guò)拷貝創(chuàng)建新的對(duì)象跟通過(guò)繼承創(chuàng)建有什么區(qū)別呢?
    Prototype 模式允許一個(gè)對(duì)象再創(chuàng)建另外一個(gè)可定制的對(duì)象,根本無(wú)需知道任何如何創(chuàng)建的

    細(xì)節(jié),工作原理是:通過(guò)將一個(gè)原型對(duì)象傳給那個(gè)要發(fā)動(dòng)創(chuàng)建的對(duì)象,這個(gè)要發(fā)動(dòng)創(chuàng)建的對(duì)象

    通過(guò)請(qǐng)求原型對(duì)象拷貝它們自己來(lái)實(shí)施創(chuàng)建。

    如何使用?

    因?yàn)镴ava 中的提供clone()方法來(lái)實(shí)現(xiàn)對(duì)象的克隆(具體了解 clone()按這里),所以

    Prototype 模式實(shí)現(xiàn)一下子變得很簡(jiǎn)單.

    以勺子為例:

    public abstract class AbstractSpoon implements Cloneable
    {

        String spoonName;

        public void setSpoonName(String spoonName) {this.spoonName = spoonName;}

        public String getSpoonName() {return this.spoonName;}

        public Object clone()

         {

            Object object = null;

            try {
                object = super.clone();

            } catch (CloneNotSupportedException exception) {

                System.err.println("AbstractSpoon is not Cloneable");

            }

            return object;
        }

    }

    有兩個(gè)具體實(shí)現(xiàn)(ConcretePrototype):

    public class SoupSpoon extends AbstractSpoon

    {

        public SoupSpoon()
         {

            setSpoonName("Soup Spoon");

        }

    }

    public class SaladSpoon extends AbstractSpoon

    {

         public SaladSpoon()

         {
             setSpoonName("Salad Spoon");

         }

    }

    調(diào)用 Prototype 模式很簡(jiǎn)單:

    AbstractSpoon spoon = new SoupSpoon();

    AbstractSpoon spoon = new SaladSpoon();

    posted @ 2007-11-29 16:23 liujg 閱讀(317) | 評(píng)論 (0)編輯 收藏

    2007年10月12日

    java 關(guān)閉IE

    本文代碼來(lái)自以下連接。
    http://www.developer.com/java/other/article.php/10936_2212401_3Introduction to the Java Robot Class in Java
    代碼簡(jiǎn)單說(shuō)明:可以在1024*768的屏幕分辨率下關(guān)掉一個(gè)最大化的IE窗口。


    import java.awt.*;
    import java.awt.event.*;

    /**this class will close an maxmimum IE window in the 1024*768's screen resolution's machine.*/
    public class Robot04{
       public static void main(String[] args)
                                 throws AWTException{
      Robot robot = new Robot();
      robot.mouseMove(1005,10);
      robot.delay(2000);
      robot.mousePress(InputEvent.BUTTON1_MASK);
      robot.delay(2000);
      robot.mouseRelease(InputEvent.BUTTON1_MASK);
       }//end main

    }//end class Robot04

    這個(gè)程序的GUI版本。
    Robot04GUI.java
    /**
     * Robot04GUI.java
     * create by kin. 2004/11/07.
     * Please enjoy this.
     */

    import javax.swing.*;
    import javax.swing.event.*;

    import java.awt.event.*;
    import java.awt.*;

    /**Robot04's GUI version.*/
    public class Robot04GUI extends JFrame {
     
     private JButton b = new JButton("Close IE");
     
     public Robot04GUI() {
      super("Close IE");
      getContentPane().add(b,BorderLayout.CENTER);
      b.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent e) {
        try {
         new Robot04().main(new String[]{}); 
        } catch (Exception ex) {
         ex.printStackTrace();
        }
       } 
      });
     } 
     
     public static void main(String[] args) {
      Robot04GUI r = new Robot04GUI();
      r.setSize(200,200);
      r.setVisible(true);
     } 

    posted @ 2007-10-12 10:06 liujg 閱讀(584) | 評(píng)論 (0)編輯 收藏

    2007年5月24日

    看了下java核心技術(shù)中的代理,還是很暈

    需要記住的東東:
       1.代理類是在程序運(yùn)行過(guò)程中創(chuàng)建的,一旦創(chuàng)建就變成了常規(guī)類,與虛擬機(jī)種的任何其他類沒(méi)有什么區(qū)別.
      2.所有的代理類都擴(kuò)展于Proxy類,一個(gè)代理類只有一個(gè)實(shí)例變量--調(diào)用處理器,它定義在Proxy的超類中,為了履行代理對(duì)象的職責(zé),所需要的任何附加數(shù)據(jù)都必須存儲(chǔ)在調(diào)用處理器中.
       3.所有的代理類都覆蓋了Object中的toString,equals和hashCode,如何所有的代理方法一樣,這些方法僅僅調(diào)用了調(diào)用處理器的invoke.Object中的其他方法clone,getClass沒(méi)有被重新定義.

    感覺(jué)就是把原來(lái)的方法,拿到代理類里面執(zhí)行,在執(zhí)行前后可以加入自己的代碼而已,spring的IOC就是這樣的.
    例子:

    import java.lang.reflect.*;
    import java.util.*;

    public class PorxyTest {

     /**
      * @param args
      */
     public static void main(String[] args) {
      // TODO Auto-generated method stub
      Object[] elements = new Object[1000];
      
      for (int i = 0; i < elements.length; i ++) {
       Integer value = i + 1;
       Class[] interfaces = value.getClass().getInterfaces();
       InvocationHandler handler = new TraceHandler(value);
       Object proxy = Proxy.newProxyInstance(null, interfaces, handler);
       elements[i] = proxy;
      }
      Integer key = new Random().nextInt(elements.length) + 1;
      int result = Arrays.binarySearch(elements, key);
      
      if (result >= 0)
       System.out.println(elements[result]);
     }

    }

    class TraceHandler implements InvocationHandler {
     private Object target;
     public TraceHandler(Object t) {
      target = t;
     }
     
     public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
      System.out.print(target);
      System.out.print("." + m.getName() + "(");
      if (args != null) {
       for (int i = 0; i < args.length; i ++) {
        System.out.print(args[i]);
        if (i < args.length - 1) {
         System.out.print(",");
        }
       }
      }
      System.out.println(")");
      return m.invoke(target, args);
     }
    }

    posted @ 2007-05-24 14:57 liujg 閱讀(396) | 評(píng)論 (0)編輯 收藏

    2006年12月15日

    java程序員的5個(gè)好習(xí)慣()

    http://today.java.net/pub/a/today/2006/08/24/five-habits-of-highly-profitable-developers.html


    Five Habits of Highly Profitable Software Developers Five Habits of Highly Profitable Software Developers

    by Robert J. Miller
    08/24/2006

    Software developers who have the ability to create and maintain quality software in a team environment are in high demand in today's technology-driven economy. The number one challenge facing developers working in a team environment is reading and understanding software written by another developer. This article strives to help software development teams overcome this challenge.

    This article illustrates five habits of software development teams that make them more effective and therefore more profitable. It first will describe the demands the business team puts on its software development team and the software they create. Next it will explain the important differences between state-changing logic and behavior logic. Finally, it will illustrate the five habits using a customer account scenario as a case study.

    Demands Placed on Developers by the Business

    The business team's job is to determine what new value can be added to the software, while ensuring that the new value is most advantageous to the business. Here, "new value" refers to a fresh product or additional enhancement to an existing product. In other words, the team determines what new features will make the business the most money. A key factor in determining what the next new value will be is how much it will cost to implement. If the cost of implementation exceeds the potential revenue, then the new value will not be added.

    The business team demands that the software development team be able to create new value at the lowest possible cost. It also demands that the software development team have the ability to add new value to a product without having the product's implementation costs increase over time. Furthermore, every time the business team requests new value, it demands that value be added without losing any existing value. Over time, the software will accrue enough value that the business team will demand documentation to describe the current value the software provides. Then the business team will use this documentation to help determine what the next new value will be.

    Software development teams can best meet these demands by creating easy-to-understand software. Difficult-to-understand software results in inefficiencies throughout the development process. These inefficiencies increase the cost of software development and can include the unexpected loss of existing value, an increase in developer ramp-up time, and the delivery of incorrect software documentation. These inefficiencies can be reduced by converting the business team's demands, even if complex, into simple, easy-to-understand software.

    Introducing Key Concepts: State and Behavior

    Creating software that is easy to understand starts by creating objects that have state and behavior. "State" is an object's data that persists between method calls. A Java object can hold its state temporarily in its instance variables and can persist it indefinitely by saving it into a permanent data store. Here, a permanent data store can be a database or Web service. "State-changing methods" typically manage an object's data by retrieving it and persisting it to and from a remote data store. "Behavior" is an object's ability to answer questions based on state. "Behavior methods" answer questions consistently without modifying state and are often referred to as the business logic in an application.

    Case Study: CustomerAccount object

    The following ICustomerAccount interface defines methods an object must implement to manage a customer's account. It defines the ability to create a new active account, to load an existing customer's account status, to validate a prospective customer's username and password, and to validate that an existing account is active for purchasing products.

    public interface ICustomerAccount {
    //State-changing methods
    public void createNewActiveAccount()
    throws CustomerAccountsSystemOutageException;
    public void loadAccountStatus()
    throws CustomerAccountsSystemOutageException;
    //Behavior methods
    public boolean isRequestedUsernameValid();
    public boolean isRequestedPasswordValid();
    public boolean isActiveForPurchasing();
    public String getPostLogonMessage();
    }

    Habit 1: Constructor Performs Minimal Work

    The first habit is for an object's constructor to do as little work as possible. Ideally, its constructor will only load data into its instance variables using the constructor's parameters. In the following example, creating a constructor that performs minimal work makes the object easier to use and understand because the constructor performs only the simple task of loading data into the object's instance variables:

    public class CustomerAccount implements ICustomerAccount{
    //Instance variables.
    private String username;
    private String password;
    protected String accountStatus;
    //Constructor that performs minimal work.
    public CustomerAccount(String username, String password) {
    this.password = password;
    this.username = username;
    }
    }

    A constructor is used to create an instance of an object. A constructor's name is always the same as the object's name. Since a constructor's name is unchangeable, its name is unable to communicate the work it is performing. Therefore, it is best if it performs as little work as possible. On the other hand, state-changing and behavior method names use descriptive names to convey their more complex intent, as described in "Habit 2: Methods Clearly Convey Their Intent." As this next example illustrates, the readability of the software is high because the constructor simply creates an instance of the object, letting the behavior and state-changing methods do the rest.

    Note: The use of "..." in the examples represents code that is necessary to run in a live scenario but is not relevant to the example's purpose.

    String username = "robertmiller";
    String password = "java.net";
    ICustomerAccount ca = new CustomerAccount(username, password);
    if(ca.isRequestedUsernameValid() && ca.isRequestedPasswordValid()) {
    ...
    ca.createNewActiveAccount();
    ...
    }

    On the other hand, objects with constructors that do more than just load instance variables are harder to understand and more likely to be misused because their names do not convey their intent. For example, this constructor also calls a method that makes a remote call to a database or Web service in order to pre-load an account's status:

    //Constructor that performs too much work!
    public CustomerAccount(String username, String password)
    throws CustomerAccountsSystemOutageException {
    this.password = password;
    this.username = username;
    this.loadAccountStatus();//unnecessary work.
    }
    //Remote call to the database or web service.
    public void loadAccountStatus()
    throws CustomerAccountsSystemOutageException {
    ...
    }

    A developer can use this constructor and, not realizing it is making a remote call, end up making two remote calls:

    String username = "robertmiller";
    String password = "java.net";
    try {
    //makes a remote call
    ICustomerAccount ca = new CustomerAccount(username, password);
    //makes a second remote call
    ca.loadAccountStatus();
    } catch (CustomerAccountsSystemOutageException e) {
    ...
    }

    Or a developer can reuse this constructor to validate a prospective customer's desired username and password and be forced to make an unnecessary remote call since these behavior methods (isRequestedUsernameValid(), isRequestedPasswordValid()) don't need the account status:

    String username = "robertmiller";
    String password = "java.net";
    try {
    //makes unnecessary remote call
    ICustomerAccount ca = new CustomerAccount(username, password);
    if(ca.isRequestedUsernameValid() && ca.isRequestedPasswordValid()) {
    ...
    ca.createNewActiveAccount();
    ...
    }
    } catch (CustomerAccountsSystemOutageException e){
    ...
    }

    Habit 2: Methods Clearly Convey Their Intent

    The second habit is for all methods to clearly convey their intent through the names they are given. For example, isRequestedUsernameValid() lets the developer know that this method determines whether or not the requested username is valid. In contrast, isGoodUser() can have any number of uses: it can determine if the user's account is active, determine if the requested username and/or password are valid, or determine if the user is a nice person. Since this method is less descriptive, it is more difficult for a developer to figure out what its purpose is. In short, it is better for the method names to be long and descriptive than to be short and meaningless.

    Long and descriptive method names help developer teams quickly understand the purpose and function of their software. Moreover, applying this technique to test method names allows the tests to convey the existing requirements of the software. For example, this software is required to validate that requested usernames and passwords are different. Using the method name testRequestedPasswordIsNotValidBecauseItMustBeDifferentThanTheUsername() clearly conveys the intent of the test and, therefore, the requirement of the software.

    import junit.framework.TestCase;
    public class CustomerAccountTest extends TestCase{
    public void testRequestedPasswordIsNotValid
    BecauseItMustBeDifferentThanTheUsername(){
    String username = "robertmiller";
    String password = "robertmiller";
    ICustomerAccount ca = new CustomerAccount(username, password);
    assertFalse(ca.isRequestedPasswordValid());
    }
    }

    This test method could have easily been named testRequestedPasswordIsNotValid() or even worse testBadPassword(), both of which would make it hard to determine the precise intention of the test. Unclear or ambiguously named test methods result in a loss of productivity. The loss in productivity can be caused by an increase in ramp-up time used to understand the tests, the unnecessary creation of duplicated or conflicting tests, or the destruction of existing value in the object being tested.

    Finally, descriptive method names reduce the need for both formal documentation and Javadoc comments.

    Habit 3: An Object Performs a Focused Set of Services

    The third habit is for each object in the software to be focused on performing a small and unique set of services. Objects that perform a small amount of work are easier to read and more likely to be used correctly because there is less code to digest. Moreover, each object in the software should perform a unique set of services because duplicating logic wastes development time and increases maintenance costs. Suppose in the future, the business team requests an update to the isRequestedPasswordValid() logic and two different objects have similar methods that perform the same work. In this case, the software development team would spend more time updating both objects than they would have had to spend updating just one.

    As the case study illustrates, the purpose of the CustomerAccount object is to manage an individual customer's account. It first creates the account and later can validate that the account is still active for purchasing products. Suppose in the future, this software will need to give discounts to customers who have purchased more than ten items. Creating a new interface, ICustomerTransactions, and object, CustomerTransactions, to implement these new features will facilitate the ongoing goal of working with easy-to-understand software:

    public interface ICustomerTransactions {
    //State-changing methods
    public void createPurchaseRecordForProduct(Long productId)
    throws CustomerTransactionsSystemException;
    public void loadAllPurchaseRecords()
    throws CustomerTransactionsSystemException;
    //Behavior method
    public void isCustomerEligibleForDiscount();
    }

    This new object holds state-changing and behavior methods that store customer transactions and determine when a customer gets its ten-product discount. It should be easy to create, test, and maintain since it has a simple and focused purpose. The less effective approach is to add these new methods to the existing ICustomerAccount interface and CustomerAccount object, as seen below:

    public interface ICustomerAccount {
    //State-changing methods
    public void createNewActiveAccount()
    throws CustomerAccountsSystemOutageException;
    public void loadAccountStatus()
    throws CustomerAccountsSystemOutageException;
    public void createPurchaseRecordForProduct(Long productId)
    throws CustomerAccountsSystemOutageException;
    public void loadAllPurchaseRecords()
    throws CustomerAccountsSystemOutageException;
    //Behavior methods
    public boolean isRequestedUsernameValid();
    public boolean isRequestedPasswordValid();
    public boolean isActiveForPurchasing();
    public String getPostLogonMessage();
    public void isCustomerEligibleForDiscount();
    }

    As seen above, allowing objects to become large repositories of responsibility and purpose makes them harder to read and more likely to be misunderstood. Misunderstandings result in a loss in productivity, costing the business team time and money. In short, it is better for objects and their methods to be focused on performing a small unit of work.

    Habit 4: State-Changing Methods Contain Minimal Behavior Logic

    The fourth habit is for state-changing methods to contain a minimal amount of behavior logic. Intermixing state-changing logic with behavior logic makes the software more difficult to understand because it increases the amount of work happening in one place. State-changing methods typically retrieve or send data to a remote data store and, therefore, are prone to have problems in the production system. Diagnosing a system problem within a state-changing method is easier when the remote call is isolated and it has zero behavior logic. Intermixing also inhibits the development process because it makes it harder to unit test the behavior logic. For example, getPostLogonMessage() is a behavior method with logic based on the accountStatus's value:

    public String getPostLogonMessage() {
    if("A".equals(this.accountStatus)){
    return "Your purchasing account is active.";
    } else if("E".equals(this.accountStatus)) {
    return "Your purchasing account has " +
    "expired due to a lack of activity.";
    } else {
    return "Your purchasing account cannot be " +
    "found, please call customer service "+
    "for assistance.";
    }
    }

    loadAccountStatus() is a state-changing method that loads the accountStatus's value from a remote data store:

    public void loadAccountStatus()
    throws CustomerAccountsSystemOutageException {
    Connection c = null;
    try {
    c = DriverManager.getConnection("databaseUrl", "databaseUser",
    "databasePassword");
    PreparedStatement ps = c.prepareStatement(
    "SELECT status FROM customer_account "
    + "WHERE username = ? AND password = ? ");
    ps.setString(1, this.username);
    ps.setString(2, this.password);
    ResultSet rs = ps.executeQuery();
    if (rs.next()) {
    this.accountStatus=rs.getString("status");
    }
    rs.close();
    ps.close();
    c.close();
    } catch (SQLException e) {
    throw new CustomerAccountsSystemOutageException(e);
    } finally {
    if (c != null) {
    try {
    c.close();
    } catch (SQLException e) {}
    }
    }
    }

    Unit testing the getPostLogonMessage() method can easily be done by mocking the loadAccountStatus() method. Each scenario can then be tested without making a remote call to a database. For example, if the accountStatus is "E" for expired, then getPostLogonMessage() should return "Your purchasing account has expired due to a lack of activity," as follows:

    public void testPostLogonMessageWhenStatusIsExpired(){
    String username = "robertmiller";
    String password = "java.net";
    class CustomerAccountMock extends CustomerAccount{
    ...
    public void loadAccountStatus() {
    this.accountStatus = "E";
    }
    }
    ICustomerAccount ca = new CustomerAccountMock(username, password);
    try {
    ca.loadAccountStatus();
    }
    catch (CustomerAccountsSystemOutageException e){
    fail(""+e);
    }
    assertEquals("Your purchasing account has " +
    "expired due to a lack of activity.",
    ca.getPostLogonMessage());
    }

    The inverse approach is to put both the getPostLogonMessage() behavior logic and the loadAccountStatus() state-changing work into one method. The following example illustrates what not to do:

    public String getPostLogonMessage() {
    return this.postLogonMessage;
    }
    public void loadAccountStatus()
    throws CustomerAccountsSystemOutageException {
    Connection c = null;
    try {
    c = DriverManager.getConnection("databaseUrl", "databaseUser",
    "databasePassword");
    PreparedStatement ps = c.prepareStatement(
    "SELECT status FROM customer_account "
    + "WHERE username = ? AND password = ? ");
    ps.setString(1, this.username);
    ps.setString(2, this.password);
    ResultSet rs = ps.executeQuery();
    if (rs.next()) {
    this.accountStatus=rs.getString("status");
    }
    rs.close();
    ps.close();
    c.close();
    } catch (SQLException e) {
    throw new CustomerAccountsSystemOutageException(e);
    } finally {
    if (c != null) {
    try {
    c.close();
    } catch (SQLException e) {}
    }
    }
    if("A".equals(this.accountStatus)){
    this.postLogonMessage = "Your purchasing account is active.";
    } else if("E".equals(this.accountStatus)) {
    this.postLogonMessage = "Your purchasing account has " +
    "expired due to a lack of activity.";
    } else {
    this.postLogonMessage = "Your purchasing account cannot be " +
    "found, please call customer service "+
    "for assistance.";
    }
    }

    In this implementation the behavior method getPostLogonMessage() contains zero behavior logic and simply returns the instance variable this.postLogonMessage. This implementation creates three problems. First, it makes it more difficult to understand how the "post logon message" logic works since it is embedded in a method performing two tasks. Second, the getPostLogonMessage() method's reuse is limited because it must always be used in conjunction with the loadAccountStatus() method. Finally, in the event of a system problem the CustomerAccountsSystemOutageException will be thrown, causing the method to exit before it sets this.postLogonMessage's value.

    This implementation also creates negative side effects in the test because the only way to unit test this getPostLogonMessage() logic is to create a CustomerAccount object with a username and password for an account in the database with an accountStatus set to "E" for expired. The result is a test that makes a remote call to a database. This causes the test to run slower and to be prone to unexpected failures due to changes in the database. This test has to make a remote call to a database because the loadAccountStatus() method also contains the behavior logic. If the behavior logic is mocked, then the test is testing the mocked object's behavior instead of the real object's behavior.

    Habit 5: Behavior Methods Can Be Called in Any Order

    The fifth habit is to ensure that each behavior method provides value independent of any other behavior method. In other words, an object's behavior methods can be called repeatedly and in any order. This habit allows the object to deliver consistent behavior. For example, CustomerAccount's isActiveForPurchasing() and getPostLogonMessage() behavior methods both use the accountStatus's value in their logic. Each of these methods should be able to function independently of the other. For instance, one scenario can require that isActiveForPurchasing() be called, followed by a call to getPostLogonMessage():

    ICustomerAccount ca = new CustomerAccount(username, password);
    ca.loadAccountStatus();
    if(ca.isActiveForPurchasing()){
    //go to "begin purchasing" display
    ...
    //show post logon message.
    ca.getPostLogonMessage();
    } else {
    //go to "activate account" display
    ...
    //show post logon message.
    ca.getPostLogonMessage();
    }

    A second scenario can require that getPostLogonMessage() is called without isActiveForPurchasing() ever being called:

    ICustomerAccount ca = new CustomerAccount(username, password);
    ca.loadAccountStatus();
    //go to "welcome back" display
    ...
    //show post logon message.
    ca.getPostLogonMessage();

    The CustomerAccount object will not support the second scenario if getPostLogonMessage() requires isActiveForPurchasing() to be called first. For example, creating the two methods to use a postLogonMessage instance variable so that its value can persist between method calls supports the first scenario but not the second:

    public boolean isActiveForPurchasing() {
    boolean returnValue = false;
    if("A".equals(this.accountStatus)){
    this.postLogonMessage = "Your purchasing account is active.";
    returnValue = true;
    } else if("E".equals(this.accountStatus)) {
    this.postLogonMessage = "Your purchasing account has " +
    "expired due to a lack of activity.";
    returnValue = false;
    } else {
    this.postLogonMessage = "Your purchasing account cannot be " +
    "found, please call customer service "+
    "for assistance.";
    returnValue = false;
    }
    return returnValue;
    }
    public String getPostLogonMessage() {
    return this.postLogonMessage;
    }

    On the other hand, if both methods derive their logic independently of each other, then they will support both scenarios. In this preferred example, postLogonMessage is a local variable created exclusively by the getPostLogonMessage() method:

    public boolean isActiveForPurchasing() {
    return this.accountStatus != null && this.accountStatus.equals("A");
    }
    public String getPostLogonMessage() {
    if("A".equals(this.accountStatus)){
    return "Your purchasing account is active.";
    } else if("E".equals(this.accountStatus)) {
    return "Your purchasing account has " +
    "expired due to a lack of activity.";
    } else {
    return "Your purchasing account cannot be " +
    "found, please call customer service "+
    "for assistance.";
    }
    }

    An added benefit of making these two methods independent of each other is that the methods are easier to comprehend. For example, isActiveForPurchasing() is more readable when it is only trying to answer the "is active for purchasing" question as opposed to when it is also trying to set the "post logon message". Another added benefit is that each method can be tested in isolation, which also makes the tests easier to comprehend:

    public class CustomerAccountTest extends TestCase{
    public void testAccountIsActiveForPurchasing(){
    String username = "robertmiller";
    String password = "java.net";
    class CustomerAccountMock extends CustomerAccount{
    ...
    public void loadAccountStatus() {
    this.accountStatus = "A";
    }
    }
    ICustomerAccount ca = new CustomerAccountMock(username, password);
    try {
    ca.loadAccountStatus();
    } catch (CustomerAccountsSystemOutageException e) {
    fail(""+e);
    }
    assertTrue(ca.isActiveForPurchasing());
    }
    public void testGetPostLogonMessageWhenAccountIsActiveForPurchasing(){
    String username = "robertmiller";
    String password = "java.net";
    class CustomerAccountMock extends CustomerAccount{
    ...
    public void loadAccountStatus() {
    this.accountStatus = "A";
    }
    }
    ICustomerAccount ca = new CustomerAccountMock(username, password);
    try {
    ca.loadAccountStatus();
    } catch (CustomerAccountsSystemOutageException e) {
    fail(""+e);
    }
    assertEquals("Your purchasing account is active.",
    ca.getPostLogonMessage());
    }
    }

    Conclusion

    Following these five habits will help development teams create software that everyone on the team can read, understand, and modify. When software development teams create new value too quickly and without consideration for the future, they tend to create software with increasingly high implementation costs. Inevitably, bad practices will catch up to these teams when they have to revisit the software for future comprehension and modification. Adding new value to existing software can be very expensive if the software is difficult to comprehend. However, when development teams apply these best practices, they will provide new value at the lowest possible cost to their business team.

     


    posted @ 2006-12-15 17:27 liujg 閱讀(804) | 評(píng)論 (0)編輯 收藏

    僅列出標(biāo)題  
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    導(dǎo)航

    統(tǒng)計(jì)

    常用鏈接

    留言簿(1)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    相冊(cè)

    收藏夾

    boddiy

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 久久久久久久岛国免费播放 | 国产精品无码免费专区午夜| 亚洲av片在线观看| 亚洲成AV人片高潮喷水| 亚洲AV噜噜一区二区三区| 久久精品国产亚洲av瑜伽| 相泽南亚洲一区二区在线播放| 亚洲AV成人精品日韩一区| 色偷偷亚洲第一综合网| 免费一级做a爰片久久毛片潮| 成在线人直播免费视频| 久久免费99精品国产自在现线 | 亚洲国产中文在线视频| 亚洲综合无码无在线观看| 亚洲欧洲日本在线观看| 亚洲爆乳精品无码一区二区| 免费大片黄在线观看| 三级黄色片免费看| 久久综合给合久久国产免费| av大片在线无码免费| 免费看片免费播放| 亚洲日本va午夜中文字幕久久| 亚洲精品乱码久久久久久按摩 | 又粗又大又硬又爽的免费视频| 亚洲中文字幕视频国产| 亚洲成色www久久网站夜月| 亚洲视屏在线观看| 亚洲AV永久无码精品一福利 | 亚洲一区二区无码偷拍| 美女羞羞视频免费网站| 中文字幕无码毛片免费看| 美女内射毛片在线看免费人动物 | 手机看片国产免费永久| 最好看最新的中文字幕免费| 99精品全国免费观看视频| 成人伊人亚洲人综合网站222| 亚洲av永久无码精品国产精品| 亚洲人和日本人jizz| 永久免费观看黄网站| 一级成人a毛片免费播放| 日韩伦理片电影在线免费观看|