每日一得

          不求多得,只求一得 about java,hibernate,spring,design,database,Ror,ruby,快速開發
          最近關心的內容:SSH,seam,flex,敏捷,TDD
          本站的官方站點是:顛覆軟件

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            220 隨筆 :: 9 文章 :: 421 評論 :: 0 Trackbacks

          #

          碰到一個奇怪的問題,Spring在啟動的時候得listener提示啟動失敗,打開log也沒有任何信息,最后把log4j打開 :

          <?xml?version="1.0"?encoding="UTF-8"??>
          <!DOCTYPE?log4j:configuration?SYSTEM?"log4j.dtd">

          <log4j:configuration?xmlns:log4j="http://jakarta.apache.org/log4j/">

          ????
          <appender?name="CONSOLE"?class="org.apache.log4j.ConsoleAppender">
          ????????
          <layout?class="org.apache.log4j.PatternLayout">
          ????????????
          <param?name="ConversionPattern"
          ???????????????????value
          ="%p?-?%C{1}.%M(%L)?|?%m%n"/>
          ????????
          </layout>
          ????
          </appender>

          ????
          <logger?name="org.apache">
          ????????
          <level?value="WARN"/>
          ????
          </logger>


          ????
          <logger?name="net.sf.hibernate">
          ????????
          <level?value="WARN"/>
          ????
          </logger>

          ????
          <logger?name="org.springframework">
          ????????
          <level?value="DEBUG"/>
          ????
          </logger>
          ????
          <!--
          ????<logger?name="org.appfuse">
          ????????<level?value="DEBUG"/>
          ????</logger>
          -->
          ????
          <root>
          ????????
          <level?value="DEBUG"/>
          ????????
          <appender-ref?ref="CONSOLE"/>
          ????
          </root>

          </log4j:configuration>

          提示說applicationContext.xml的編碼有問題,最后改為UTF-8解決
          posted @ 2006-10-23 10:57 Alex 閱讀(1389) | 評論 (0)編輯 收藏

          打印可以用控件實現,保存為excel也可以用POI實現,不過如果僅僅是對當前頁面的指定區域作打印或者Excel導出可以用js實現,還是挺簡單的.

          保存為Excel:

          function?saveAsExcel(HeadName,?DivName)?{
          ????????????
          var?s?=?"<center>"?+?HeadName?+?"</center>"?+?"\r\n";
          ????????????s?
          +=?DivName.innerHTML;
          ????????????
          var?xlsWindow?=?window.open("",?"_blank",?"width=1,height=1,scrollbars=no,toolbar=no");
          ????????????xlsWindow.document.write(s);
          ????????????xlsWindow.document.close();
          ????????????xlsWindow.document.execCommand('Saveas',?
          true,?'%homeDrive%\\Data.xls')
          ????????????xlsWindow.close();
          ????????}


          打印當前頁面:

          function?PrintDataSoure(HeadName1,HeadName2,HeadName3,DivName,TailName1)?{
          ??
          var?oldBody=document.body.innerHTML;
          ??
          var?Div1=DivName.innerHTML;
          ??
          var?css?=?'<style?type="text/css"?media=all>'?+
          ??'p?{?line
          -height:?120%}'?+
          ??'.fhead?{???font
          -size:?9pt;?text-decoration:?none;?color:?104A7B}'?+
          ??'.ftitle?{?line
          -height:?120%;?font-size:?18px;?color:?#000000}'?+
          ??'td?{?font
          -size:?10px;?color:?#000000}'?+
          ??'
          </style>'?;

          ??
          var?body?='<table?width="640"?border="0"?cellspacing="0"?cellpadding="5">'?+
          ??'?
          <tr>?'?+
          ??'?
          <td?class="fbody">'?+
          ??'?
          <b><div?align="center">'+'<font?size="+1"?class=fhead>'+?HeadName1?+?'</div>'+'</font></b>'+
          ??'?
          <b><div?align="center">'+'<font?size="+1"?class=fhead>'+?HeadName2?+?'?????'?+?HeadName3?+'</div></font></b>'+
          ??'?
          </td>'?+
          ??'?
          </tr>'?+
          ??'?
          <tr>?'?+
          ??'?
          <td?class="fbody">'?+
          ??'?
          <div?align="center"?class=ftitle>'?+?Div1?+?'</div>'+
          ??'?
          <b><div?align="right">'+'<font?size="+1"?class=fhead>'+?'??????</div>'+'</font></b>'+
          ??'?
          <b><div?align="right">'+'<font?size="+1"?class=fhead>'+?TailName1?+?'</div>'+'</font></b>'+
          ??'?
          </td>'?+
          ??'?
          </tr>'?+
          ??'
          </table>';
          document.body.innerHTML?
          =?'<center>'?+?css?+?body?+'<OBJECT?classid="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2"?height=0?id=wb?name=wb?width=0></OBJECT>'+'</center>';
          wb.execwb(
          6,6);
          document.body.innerHTML
          =oldBody;
          }




          posted @ 2006-10-21 12:19 Alex 閱讀(3147) | 評論 (0)編輯 收藏

               摘要: key words:Spring,jdbcTemplate 注:因為Spring是以后的一個趨勢,Hibernate的集成已經很好了,對于單獨的jdbc的操作用DBUtils感覺已經沒有什么必要,不如全部轉到Spring的jdbc支持,從成本來考慮似乎更合適。 本文轉自 這里 ...  閱讀全文
          posted @ 2006-10-16 16:28 Alex 閱讀(2752) | 評論 (0)編輯 收藏

               摘要:   閱讀全文
          posted @ 2006-10-10 11:09 Alex 閱讀(2064) | 評論 (3)編輯 收藏

          Facade用的非常的廣了,以前剛接觸的時候有個誤解,總覺得Facade是簡單的,而它后面的支撐服務是復雜的,對于客戶來說卻是簡單的,現在來看,不完全對,或者說只是說對了一半,因為有時候恰恰是Facade是復雜的.

          我們舉一個例子,比如發送短信,我們一般就定義一個MessageService的服務類,里面只提供一個方法就行了,sendToUser(String phone,String content)
          但是到了客戶端的時候有了自己的 "方言",比如它不是關心一個抽象的用戶,它只知道向教師發送短信,或者向學生發送短信,或者向家長發送短信。

          示例如下:

          facade.png
          由圖中可以看到,Facade的內容非常豐富,而支撐它的服務類卻很簡單,在開發過程中我們一般先實現通用的ServiceA,然后根據進一步的需求做一個面向具體復雜的Facade.



          在Spring提供的sample里發現一個小技巧,就是Facade和ServiceA都是接口,然后提供一個實現二者的支撐類:


          public?class?PetStoreAnnotationImpl?implements?PetStoreFacade,?OrderService?{

          ????
          private?AccountDao?accountDao;

          ????
          private?CategoryDao?categoryDao;

          ????
          private?ProductDao?productDao;

          ????
          private?ItemDao?itemDao;

          ????
          private?OrderDao?orderDao;


          ????
          //-------------------------------------------------------------------------
          ????
          //?Setter?methods?for?dependency?injection
          ????
          //-------------------------------------------------------------------------

          ????
          public?void?setAccountDao(AccountDao?accountDao)?{
          ????????
          this.accountDao?=?accountDao;
          ????}

          ????
          public?void?setCategoryDao(CategoryDao?categoryDao)?{
          ????????
          this.categoryDao?=?categoryDao;
          ????}

          ????
          public?void?setProductDao(ProductDao?productDao)?{
          ????????
          this.productDao?=?productDao;
          ????}

          ????
          public?void?setItemDao(ItemDao?itemDao)?{
          ????????
          this.itemDao?=?itemDao;
          ????}

          ????
          public?void?setOrderDao(OrderDao?orderDao)?{
          ????????
          this.orderDao?=?orderDao;
          ????}


          ????
          //-------------------------------------------------------------------------
          ????
          //?Operation?methods,?implementing?the?PetStoreFacade?interface
          ????
          //-------------------------------------------------------------------------

          ????
          public?Account?getAccount(String?username)?{
          ????????
          return?this.accountDao.getAccount(username);
          ????}

          ????
          public?Account?getAccount(String?username,?String?password)?{
          ????????
          return?this.accountDao.getAccount(username,?password);
          ????}

          ????
          public?void?insertAccount(Account?account)?{
          ????????
          this.accountDao.insertAccount(account);
          ????}

          ????
          public?void?updateAccount(Account?account)?{
          ????????
          this.accountDao.updateAccount(account);
          ????}

          ????
          public?List?getUsernameList()?{
          ????????
          return?this.accountDao.getUsernameList();
          ????}

          ????
          public?List?getCategoryList()?{
          ????????
          return?this.categoryDao.getCategoryList();
          ????}

          ????
          public?Category?getCategory(String?categoryId)?{
          ????????
          return?this.categoryDao.getCategory(categoryId);
          ????}

          ????
          public?List?getProductListByCategory(String?categoryId)?{
          ????????
          return?this.productDao.getProductListByCategory(categoryId);
          ????}

          ????
          public?List?searchProductList(String?keywords)?{
          ????????
          return?this.productDao.searchProductList(keywords);
          ????}

          ????
          public?Product?getProduct(String?productId)?{
          ????????
          return?this.productDao.getProduct(productId);
          ????}

          ????
          public?List?getItemListByProduct(String?productId)?{
          ????????
          return?this.itemDao.getItemListByProduct(productId);
          ????}

          ????
          public?Item?getItem(String?itemId)?{
          ????????
          return?this.itemDao.getItem(itemId);
          ????}

          ????
          public?boolean?isItemInStock(String?itemId)?{
          ????????
          return?this.itemDao.isItemInStock(itemId);
          ????}

          ????
          public?void?insertOrder(Order?order)?{
          ????????
          this.orderDao.insertOrder(order);
          ????????
          this.itemDao.updateQuantity(order);
          ????}

          ????
          public?Order?getOrder(int?orderId)?{
          ????????
          return?this.orderDao.getOrder(orderId);
          ????}

          ????
          public?List?getOrdersByUsername(String?username)?{
          ????????
          return?this.orderDao.getOrdersByUsername(username);
          ????}

          }


          看起來似乎不錯,不過仔細想想個人認為還是不是太好,總的感覺就是層次不清晰,因為很多時候Facade和Service之間是被服務與服務的關系,所以理當分開。 同時,這個類有點傾向于"萬能類"了,能分還是分開好.這和我們以前提到的dao又背離過來了(以前我們提倡一個業務一個dao,現在覺得只用一個通用的dao更合適),這個并不矛盾,具體問題具體看待.

          歡迎各位拍磚.
          posted @ 2006-10-09 22:27 Alex 閱讀(1380) | 評論 (2)編輯 收藏

          設計模式之Visitor

          板橋里人 http://www.jdon.com 2002/05/05(轉載請保留)

          模式實戰書籍《Java實用系統開發指南》

          Visitor訪問者模式定義
          作用于某個對象群中各個對象的操作. 它可以使你在不改變這些對象本身的情況下,定義作用于這些對象的新操作.

          在Java中,Visitor模式實際上是分離了collection結構中的元素和對這些元素進行操作的行為.

          為何使用Visitor?
          Java的Collection(包括Vector和Hashtable)是我們最經常使用的技術,可是Collection好象是個黑色大染缸,本來有 各種鮮明類型特征的對象一旦放入后,再取出時,這些類型就消失了.那么我們勢必要用If來判斷,如:


          Iterator iterator = collection.iterator()
          while (iterator.hasNext()) {
             Object o = iterator.next();
             if (o instanceof Collection)
                messyPrintCollection((Collection)o);
             else if (o instanceof String)
                System.out.println("'"+o.toString()+"'");
             else if (o instanceof Float)
                System.out.println(o.toString()+"f");
             else
                System.out.println(o.toString());
          }
          在上例中,我們使用了 instanceof來判斷 o的類型.

          很顯然,這樣做的缺點代碼If else if 很繁瑣.我們就可以使用Visitor模式解決它.

          如何使用Visitor?
          針對上例,定義接口叫Visitable,用來定義一個Accept操作,也就是說讓Collection每個元素具備可訪問性.

          被訪問者是我們Collection的每個元素Element,我們要為這些Element定義一個可以接受訪問的接口(訪問和被訪問是互動的,只有訪問者,被訪問者如果表示不歡迎,訪問者就不能訪問),取名為Visitable,也可取名為Element。

          public interface Visitable
          {
             public void accept(Visitor visitor);
          }

          被訪問的具體元素繼承這個新的接口Visitable:

          public class StringElement implements Visitable
          {
             private String value;
             public StringElement(String string) {
                value = string;
             }

             public String getValue(){
                return value;
             }


             //定義accept的具體內容 這里是很簡單的一句調用
             public void accept(Visitor visitor) {
                visitor.visitString(this);
             }
          }


          上面是被訪問者是字符串類型,下面再建立一個Float類型的:

          public class FloatElement implements Visitable
          {
             private Float value;
             public FloatElement(Float value) {
                this.value = value;
             }

             public Float getValue(){
                return value;
             }


             //定義accept的具體內容 這里是很簡單的一句調用
             public void accept(Visitor visitor) {
                visitor.visitFloat(this);
             }
          }


          我 們設計一個接口visitor訪問者,在這個接口中,有一些訪問操作,這些訪問操作是專門訪問對象集合Collection中有可能的所有類,目前我們假 定有三個行為:訪問對象集合中的字符串類型;訪問對象集合中的Float類型;訪問對象集合中的對象集合類型。注意最后一個類型是集合嵌套,通過這個嵌套 實現可以看出使用訪問模式的一個優點。

          接口visitor訪問者如下:

          public interface Visitor
          {

             public void visitString(StringElement stringE);
             public void visitFloat(FloatElement floatE);
             public void visitCollection(Collection collection);

          }

          訪問者的實現:

          public class ConcreteVisitor implements Visitor
          {
             //在本方法中,我們實現了對Collection的元素的成功訪問
             public void visitCollection(Collection collection) {
                Iterator iterator = collection.iterator()
                while (iterator.hasNext()) {
                   Object o = iterator.next();
                   if (o instanceof Visitable)
                      ((Visitable)o).accept(this);
                }
             }

             public void visitString(StringElement stringE) {
                System.out.println("'"+stringE.getValue()+"'");
             }
             public void visitFloat(FloatElement floatE){
                System.out.println(floatE.getValue().toString()+"f");
             }

          }

          在上面的visitCollection我們實現了對Collection每個元素訪問,只使用了一個判斷語句,只要判斷其是否可以訪問.

          StringElement只是一個實現,可以拓展為更多的實現,整個核心奧妙在accept方法中,在遍歷Collection時,通過相應的accept方法調用具體類型的被訪問者。這一步確定了被訪問者類型,

          如果是StringElement,而StringElement則回調訪問者的visiteString方法,這一步實現了行為操作方法。

          客戶端代碼:

          Visitor visitor = new ConcreteVisitor();

          StringElement stringE = new StringElement("I am a String");
          visitor.visitString(stringE);

          Collection list = new ArrayList();
          list.add(new StringElement("I am a String1"));
          list.add(new StringElement("I am a String2"));
          list.add(new FloatElement(new Float(12)));
          list.add(new StringElement("I am a String3"));
          visitor.visitCollection(list);

          客戶端代碼中的list對象集合中放置了多種數據類型,對對象集合中的訪問不必象一開始那樣,使用instance of逐個判斷,而是通過訪問者模式巧妙實現了。

          至此,我們完成了Visitor模式基本結構.

          使用Visitor模式的前提
          使用訪問者模式是對象群結構中(Collection) 中的對象類型很少改變。

          在兩個接口Visitor和Visitable中,確保Visitable很少變化,也就是說,確保不能老有新的Element元素類型加進來,可以變化的是訪問者行為或操作,也就是Visitor的不同子類可以有多種,這樣使用訪問者模式最方便.

          如果對象集合中的對象集合經常有變化, 那么不但Visitor實現要變化,Visistable也要增加相應行為,GOF建議是,不如在這些對象類中直接逐個定義操作,無需使用訪問者設計模式。

          但是在Java中,Java的Reflect技術解決了這個問題,因此結合reflect反射機制,可以使得訪問者模式適用范圍更廣了。

          Reflect技術是在運行期間動態獲取對象類型和方法的一種技術,具體實現參考Javaworld的英文原文.
          posted @ 2006-09-28 09:30 Alex 閱讀(537) | 評論 (0)編輯 收藏

          key words:軟件設計 建模 UML

          這篇文章以前就看到了,后來再想看的時候居然找不到了,感覺寫的不錯,作為想把軟件開發往深里整地朋友有借鑒作用。

          轉自這里

          前段時間把一個界面框架完成了,今天基于這個框架開發一個小模塊,在這里把這個模塊設計的全過程記錄下來,希望大家討論并指正。

          一、起因

          公 司交給我一個任務,為測試員寫一個手機模擬界面,以方便她們的手機短信測試。過去她們都是用MC4J直接調用公司服務器的MBean服務來模擬進行測試, 以驗證我們整個系統平臺。這種測試主要是檢查收發短信是否正常,而我的要做的工作就是,讓她們在測試的時候更方便更直觀。

          二、需求

          我和測試員陳MM(也就是軟件的使用者)約定了一個時間,大家一起來討論這個軟件的需求。

          1、首先,我大概了解了一下她們的測試工作,知道我要做個什么東東。

          2、然后我回去思考了一下,再次找她詳細了解其測試的具體步驟,并在一張白紙上以UML用例圖的方式,記錄下需求的功能。用例是什么?用例就是需求,就是你的軟件應該具有的功能,當然用例圖只是概括性的對功能進行了描述。

          3、最后,我坐在我的電腦前開始用MagicDraw UML來畫用例圖(我不喜歡用Rose,那玩意太笨重了,界面友好性也不好)。在畫用例圖的時候,我發現了一些隱含的功能,這些是陳MM在和我做需求時沒有考慮到的(注:開發者應該為用戶挖掘隱含需求)。我和陳MM一一確定了這些我新發現的需求,最后得到如下的用例圖。

          (1)手機前臺測試操作的用例圖(說明:include是指某用例包含(include)子用例)

          [用例]手機.jpg
          ?(2)后臺管理
          [用例]后臺管理.jpg


          三、界面設計

          接下來是界面設計。既然是手機模擬,我很自然就拿我的motorola手機的操作界面來做參考。不過這里應該注意到,手機操作環境和電腦操作環境不盡相同(比如說電腦有鼠標,還有鍵盤可以輸入文字),所以沒有必要唯妙唯肖的完全模枋,還是以使用者操作方便為主。

          界 面設計是很重要的一步,不要一上來就寫程序,一定要先做到心中有個大概,否則返工的可能性就很大。而且,把界面拿出來給客戶看,客戶也就能做到心中有數, 還能盡早提出一些新需求和意見來。千萬不要等到軟件做完了再拿給客戶看,到時客戶看了如果要修改,那就做太多白費工了。

          由于軟件界面相對簡單,陳MM基本沒有提修改意見,但這不是個好兆頭。不過極限編程就是要擁抱變化不是^_^。咱不怕她改,只要大致的界面她能定下來就行了。

          界面我喜歡用Visio來畫,當然也聽說有人喜歡用VB來快速構建界面原型的,看個人喜好了。整個界面如下:
          [界面設計]手機.jpg



          這個是后臺管理界面
          [界面設計]號碼管理.jpg



          四、類圖

          類圖反映了軟件的數據模型。在設計數據模型,我參考了界面設計圖和用例圖,找出一個個的類。然后參照用例圖的一個個功能,設計出了各類的屬性和方法。設計初始的類圖當然不可能很詳細,但至少應該看到個大概。有錯誤不要緊,后期可以慢慢修正,但大體關系就算定下來了。

          Neil(公司CTO,一個40歲左右的真正的資深程序員)說:看一個軟件的設計主要看兩個類:類圖和時序圖。類圖確定了軟件數據模型的靜態關型,時序圖則是數據模型的動態關系。

          類圖如下,看英文大致可以知道類/屬性/方法的含義和作用了,就不一一介紹了。


          [類圖].jpg



          五、時序圖

          時序圖是本文最后一個圖,時序圖表明了用例圖中各功能的實現方案,同時也反應了類圖中各類的交互關系。以后程序的邏輯和時序圖基本一致。不過,有些人會去畫得很詳細的時序圖,詳細到都快趕上偽代碼級別了,我覺得這沒必要。我把時序圖看做反映自己思路的大概過程,所以也就畫個大概。

          我認為時序圖要簡潔易懂,這樣以后你的后繼維護者,拿到這個軟件的時序圖(當然也包括用例圖、類圖),就能明白你的大概設計思路。另外,畫時序圖也能整理自己的思路,同時還可以對類圖的設計進行驗證。在畫這個時序圖的過程中,我就糾正了在類圖中的幾處考慮不周的地方。

          總結:時序圖可以(1)整理思路(2)驗證類的設計(3)是很好的軟件文檔,對維護者理解代碼很有幫助。

          這里僅給出其中幾個時序圖(實際上我也沒有把用例都畫完,有些類似的簡單的,就忽略了)

          (1)新增一個手機號碼
          [時序圖]add phone number.jpg

          (2)關機
          [時序圖]power off.jpg
          (3)開機
          [時序圖]power on.jpg
          (4)發送短信
          [時序圖]send message.jpg



          到這里設計階段就完成了,用時一天。下一步是編碼,將應用TDD先寫測試代碼的方式來寫代碼,下次再介紹了。


          作者簡介

          陳剛,廣西桂林人,著作有《Eclipse從入門到精通》
          您可以通過其博客了解更多信息和文章:http://www.ChenGang.com.cn
          版權聲明:本博客所有文章僅適用于非商業性轉載,并請在轉載時注明出處及作者的署名。

          posted @ 2006-09-22 13:16 Alex 閱讀(950) | 評論 (0)編輯 收藏

          key words:軟件架構師
          轉自here

          現在軟件架構師滿天飛,是個寫代碼的都稱自己為軟件架構師,就象開個公司管上四五號人就給自己按個CEO頭銜一樣,著實讓人好笑。于是到網上GOOGLE了一下看看軟件構架師具體是個啥東東,有想做貨真價實的構架師,就朝著那方向努力吧。網摘如下:

          軟件架構師的職責:將客戶的需求轉換為規范的開發計劃及文本,并制定這個項目的總體架構,指導整個開發團隊完成這個計劃。

          軟件架構師的具體工作:
          ????(
          1)在需求階段,軟件架構師主要負責理解和管理非功能性系統需求,比如軟件的可維護性、性能、復用性、可靠性、有效性和可測試性等等,此外,架構師還要經常審查和客戶及市場人員所提出的需求,確認開發團隊所提出的設計;
          ????(
          2)在需求越來越明確后,架構師的關注點開始轉移到組織開發團隊成員和開發過程定義上;
          ????(
          3)在軟件設計階段,架構師負責對整個軟件體系結構、關鍵構件、接口和開發政策的設計;
          ????(
          4)在編碼階段,架構師則成為詳細設計者和代碼編寫者的顧問,并且經常性地要舉行一些技術研討會、技術培訓班等;
          ????(
          5)隨著軟件開始測試、集成和交付,集成和測試支持將成為軟件架構師的工作重點;
          ????(
          6)在軟件維護開始時,軟件架構師就開始為下一版本的產品是否應該增加新的功能模塊進行決策。
          ?
          軟件架構師的要求
          ??????(
          1)必須對開發技術非常了解,具有豐富的軟件設計與開發經驗,關鍵時候能對技術的選擇作出及時、有效的決定。
          ??????(
          2)有良好的組織管理能力:溝通、領導、團隊協作
          ??????(
          3)構件通信機制方面的知識:遠程調用、JAVARMI、CORBA、COM/DCOM、各種標準的通信協議、網絡服務、面對對象數據庫、關系數據庫等等

          成長為軟件架構師的幾個階段:
          ??????(
          1)構架師胚胎(程序員):語言基礎、設計基礎、通信基礎等,內容包括java、c、c++、uml、RUP、XML、socket通信(通信協議)
          ??????(
          2)構架師萌芽(高級程序員):分布式系統組建等內容,包括分布式系統原理、ejb、corba、com/com+、webservice、網絡計算機、高性能并發處理等
          ??????(
          3)構架師幼苗(設計師):透徹掌握設計模式,包括設計模式(c++版本、java版本)、ejb設計模式、J2EE構架、UDDI、軟件設計模式等。此期間,最好能夠了解軟件工程在實際項目中的應用以及小組開發、團隊管理
          posted @ 2006-09-22 13:14 Alex 閱讀(657) | 評論 (0)編輯 收藏

          key words: DAO模式

          今天在看一篇文章時提到了DAO,這個東西以前也經常接觸,突然想回顧一下,于是打開Appfuse里看看dao模式(記憶中appfuse里就是很多的dao)

          截圖如下:
          appfusedao.png

          很清楚,左邊的部分是基礎模塊,原意是想讓右邊的DAO和實現能夠重用左邊的,可是我找了半天也沒看到需要重用左邊的東西,因為在client調用的所有方法中都是明確的getUser或removeUser,就是沒有getObject或者removeObject,那么不禁要問,左邊的基礎dao和它的實現還有什么意義呢?所以我的第一想法就是把左邊的去掉得了,還好,果然有支持我想法的做法,打開springside,我們看到如下的結構:
          截圖2
          springside.png
          這里的做法更厲害,連interface也不要了,不過效果確實是很簡潔,在bookmanager里完全重用了左邊的基本方法 :
          public?Book?get(Integer?id)?{
          ????????
          return?(Book)?super.get(id);
          ????}

          ????
          public?void?save(Book?book)?{
          ????????
          super.save(book);
          ????????logger.info(
          "保存圖書.圖書詳情:"?+?book.toString());
          ????}

          ????
          public?void?remove(Integer?id)?{
          ????????
          super.remove(id);
          ????????logger.info(
          "刪除圖書.圖書ID:"?+?id);
          ????}

          這是一個更務實的做法,如果你的項目并不是那么那么的復雜完全可以這么做,當然要說其有什么缺點顯然和沒有了interface的天生屬性決定了的,不可強求,若你對測試隔離面向接口以及你能想到的所有關于interface的好處,那就用你自己的方式吧。

          現在我在想一個問題,難道appfuse里的繼承的基本關于object的做法就沒有地方可用了么?


          其時正好碰到java視線這一篇文章有點相關,你可以參考一下:
          用DAO模式有什么好處?


          ps:
          以前是一個基本的dao,然后n個業務dao繼承于這個基本dao,現在提供一個通用dao,每個要用到的地方直接繼承用就是了,更務實了!
          不過,有一個小小的瑕疵,就是對于service中類似getUserByName或者getPeopleByEmail方法中需要提供給dao一個sql語句,從mvc的角度看,在service中看到了db層,有點不雅,不過綜合來看這個還是可以或略,不要專牛角尖嘛? :)

          posted @ 2006-09-21 16:05 Alex 閱讀(2450) | 評論 (0)編輯 收藏

          key words: VSS IDEA

          vss實在是太惡心了,提交各東西還不支此右鍵,要是要在開發一段時間后提交多個不同的目錄下的文件費死勁了,我壓根不知道哪個文件還沒有提交,Fuck Microsoft!

          至少,我們還有IDEA? :)? 在開發工具里提交的一個好處就是直觀和簡便.Let's go!

          具體指導請看這里
          你需要填寫關于VSS的相關信息 ,截圖如下:
          vss.png

          其中的vss project可能有點困難,屬于vss自己的術語,你自己實際上是不知道的,方法是打開vss客戶端,通過這個工具查找到你所在的項目的vss project到底是什么,右鍵項目名稱,出現如下dialog
          vss2.png

          OK了

          在IDEA里看看效果,截圖如下:
          vss3.png


          Fine.
          posted @ 2006-09-21 11:40 Alex 閱讀(3033) | 評論 (3)編輯 收藏

          key words :Oracle分頁 視圖

          google了一下關于Oracle的分頁方法,方法還不少,大多數效果差不多-有點惡心. 惡心也要作,不過后來就是大家都用得這種方式在我這里出現了新問題,奇怪的是怎么沒有別人碰到?

          String condition?=?"?teacher_id?=?"?+?userId?+?"?and?school_id="+siteId;
          sql?
          =
          ???
          "?select * "?+
          ???
          "?from your_table where?"?+?condition?+
          ???
          "?and?rowid?not?in?(?select?rowid?from your_table where"?+?condition?+
          ???
          "?and?rownum?<=?"?+?(pageIndex?-?1)?*?Constants.PAGE_NUMS +?")?"?+
          ???
          "?and?rownum?<=?"?+?Constants.PAGE_NUMS ;

          現在的問題是我需要按照table的某個字段排序,于是改成如下:
          String?condition?=?"?teacher_id?=?"?+?userId?+?"?and?school_id="+siteId;
          sql?
          =
          ????
          "?select?*?"?+
          ????
          "?from?your_table?where?"?+?condition?+
          ????
          "?and?rowid?not?in?(?select?rowid?from?your_table?where"?+?condition?+
          ????
          "?and?rownum?<=?"?+?(pageIndex?-?1)?*?Constants.PAGE_NUMS?+?"order by id desc)?"?+
          ????
          "?and?rownum?<=?"?+?Constants.PAGE_NUMS + " order by id desc";

          這個sql有問題么?
          答案是可能有問題,也可能沒有問題,因為據說在8i的Oracle版本之前都不行,實際上也不盡然,在我的9i和10g我得到的是同樣的錯誤 "missing right parenthesis",還有一位兄弟估計是DBA建議我去metalink打一個patch,埃,動作太大了,不敢動。

          問題還是要解決,試了下類似于select a.*,rownum r from (select * from table where ...) a where rownum < 10 等的方法,效果一樣,就是不能加嵌套的order by
          最后,用視圖的方法間接解決問題,因為我要解決的問題實際就是按某個字段排序,那么在視圖里先對table進行排序,再在視圖的基礎上作操作就OK了.

          另,還有一種不錯的實現方法,即用OracleCachedRowSet,分頁也比較簡單,有點類似于hibernate,由于時間關系沒有時間去看,感興趣的朋友可以看一下.


          BTW: 對于視圖可能rowid有問題,可以改成視圖的某個主鍵替換

          String?condition?=?"?teacher_id?=?"?+?userId?+?"?and?school_id="+siteId;
          sql?
          =
          ????
          "?select?*?"?+
          ????
          "?from?your_table?where?"?+?condition?+
          ????
          "?and?id?not?in?(?select?id?from?your_table?where"?+?condition?+
          ????
          "?and?rownum?<=?"?+?(pageIndex?-?1)?*?Constants.PAGE_NUMS?+?"order?by?id?desc)?"?+
          ????
          "?and?rownum?<=?"?+?Constants.PAGE_NUMS?+?"?order?by?id?desc";



          posted @ 2006-09-20 15:36 Alex 閱讀(1697) | 評論 (3)編輯 收藏

          轉自 robin

          Java本身是一種設計的非常簡單,非常精巧的語言,所以Java背后的原理也很簡單,歸結起來就是兩點:

          1、JVM的內存管理

          理解了這一點,所有和對象相關的問題統統都能解決

          2、JVM Class Loader

          理解了這一點,所有和Java相關的配置問題,包括各種App Server的配置,應用的發布問題統統都能解決

          就像張無忌學太極劍,本質就是一圈一圈的畫圓,你要是懂得了太極劍的本質,那么太極劍就那么一招而已,本身是很容易學的,只是難度在于你要能夠舉一 反三,化一式劍意為無窮無盡的劍招,這就需要一點悟性和不斷的實踐了;反過來說,如果學劍不學本質,光學劍招,你就是學會了1萬招,碰到了第1萬零1招, 還是不會招架,敗下陣來。

          技術世界本來就是豐富多彩,企圖統一標準,實際上也做不到,但是世界本質其實并不復雜。學習技術,特別是某種具體的軟件工具的時候,應該學會迅速把 握事物的本質,不要過多攪纏細節。軟件工具應該為我所用,而不是我被工具所駕馭。當你具備了對整個J2EE架構的設計和實施的能力,你還會被具體的工具束 縛嗎?哪種工具適合你的架構,你就用什么,哪種不適合你,你就拋棄它,軟件皆臣服于你的腳下,而不是你被什么軟件牽著鼻子走,到了這種程度,你難道還害怕 學習什么新的軟件?

          我自己也在一直朝著這個方向努力,在我心中,設計軟件,架構是第一位的,采用什么技術要為架構服務。如果我發現什么技術對我的架構來說很重要,那么 我會花時間去學習,去鉆研,就像我花時間去鉆研ORM一樣,如果我覺得什么技術對我的架構來說沒有用,即使技術再火爆,我也不去碰它

          總之要學會抓住本質,駕馭技術,而不是被技術所駕馭。當你掌握了本質原理,其實學什么都很快,畢竟都是相通的,我先看JDO,后看 Hibernate,其實兩者就很類似,所以學得很快,以后如果有工作需要,要我學習別的ORM,那我也不會覺得有什么困難的,一樣手到拿來。

          更有說服力的是Unix類的操作系統,那就更相似了,只要抓住了Unix最本質的幾點,例如shell命令和編程,文件系統結構和配置,系統啟動原 理和過程,所有的Unix都是無師自通的。我自己會用Linux,FreeBSD,SCO Unix, Solaris,HP-UX 和 AIX等6種Unix,更體會到一通百通的道理。

          拿剛出了光明頂密道的張無忌來說吧,(我很喜歡張無忌這個角色),他也沒有練過什么武功,但是他已經把天下武學之本質:九陽神功 + 乾坤大挪移學會了,所以不管什么功夫,他都是看一遍就會,馬上為我所用,看了空性用了一遍龍爪手,就會用龍爪手來破對方;和昆侖派打了一架,就會用昆侖劍 法和滅絕師太過招;七傷拳更是無師自通;太極拳也是看一遍就會。

          總之,學習方法還是很重要,別被五花八門的技術給搞不清學習方向了。

          posted @ 2006-09-20 12:12 Alex 閱讀(470) | 評論 (1)編輯 收藏

          轉自portian

          基本上一個應用程序里面的領域相關的模型里面需要3種對象:
          1。值對象(Value Object),沒有身份,內容表示一切,譬如我和weihello都去銀行里面存取100大洋,那這個100RMB是一個值對象

          2。實體對象(Entity),需要持久,不是按照內容,而是按照它的身份來區分,也就是說即使內容完全一樣,也不是同一個對象。這個身份在內存 里面是它的實例地址,在數據庫里面是關鍵字,最常見的就是OID.這個實體對象并不是純數據,它處理本身的實體模型,例如Accout,它的 withDraw,它的子Account等等,它也處理自己和其他實體對象之間的關系,例如訂單里面的訂單行,都是應該在這個Account里面實現的, 而不應該有一個什么控制類。在一個Web應用程序里面,涉及到對象關系的一般只需要一個(或幾個)DTOFactory負責所有對象的DTO和 Entity之間的組裝和拆份,不需要專門的管理,這一部分也是和數據建模最相近的地方。
          ?
          3。服務對象(Service),這是為我們提供服務的類,譬如銀行里面服務員,她幫助我們把錢從一個賬戶轉到另外一個賬戶,并記錄相應的交易。

          對象的作用是對它自己的內部狀態負責,如果它需要存取很多其它對象的狀態進行運算,那叫做特性忌妒,是要重構的。應該把這些代碼移到那個持有這些狀態的類里面



          辨別一些名詞:
          1。VO:實際上很模糊,通常指ValueObject和ViewObject
          2. ViewObject,界面展現需要的對象,如Struts的FormBean
          3。Value Object,早期被作為ValueObject和Transfer Object的總稱。實際上Value Object的真正意義在于它的內容,而不是身份
          4。Transfer Object:數據傳輸對象,在應用程序不同層次之間傳書對象,在一個分布式應用程序中,通常可以提高整體的性能
          5。PO:也許就是Persistent Object,基本上就是Entity了
          在不同的體系結構和實現方式里面,這些對象有可能重復,也有可能不重疊。如果你要做一個對所有的體系都能夠方便移植的框架,那么每一種對象都需要 嚴格區分。例如JDO的PO不能作為TO,應為它不能脫離PM,譬如你可以選擇用ViewObject(如Struts的FOrmBean)直接作為 TO,但在tapestry和Webwork里面就不合適了。但在很多時候,能夠方便實用是最重要的,不要過度設計就是了。
          posted @ 2006-09-20 09:53 Alex 閱讀(427) | 評論 (1)編輯 收藏

          key words: 如何做設計 設計步驟
          轉自robin

          一。需求分析(抽象Use case + 分析Use case之間的關系)

          分析軟件需求,以用戶的角度來使用軟件,找出發生的scenerio,抽象成為一個一個Use Case,分析出Use Case之間的關系,這一步是非常重要的,這一步做好了,設計就成功了一半。Use Case的抽象有一些可以遵循的原則,這里不詳細談。

          然后用語言描述每一個Use Case,描述用戶使用一個Use Case發生的主事件流以及異常流。

          這樣就完成了需求分析階段。

          二。概要設計(找出實體 + 分析實體類之間的關系 + 提取控制類 + 畫序列圖)

          接下來做概要設計,針對每個Use Case,讀Use Case的描述,看事件流,找出所有的實體類,這也有一些可以遵循的原則,例如找出所有的名詞,畫表格排除等等方法。

          然后分析實體類之間的關系,是包含,聚合還是依賴,是1:1,還是1:n,還是其他....,根據這些關系,就可以得出實體類和別的實體類想關聯的屬性,然后再找出每個實體類本身重要的屬性。

          然后再次分析Use Case的事件流,一方面check實體類的設計是否合理,另一方面你可以找出動詞,分析對實體類的控制邏輯,這樣就可以可以設計出業務控制類,一般你可 以一個實體類一個控制類,也可以業務邏輯相關的實體類由一個Facade Session Bean(非EJB含義)來統一控制,這里面的控制類的顆粒度就由你自己來掌握了。一般來說先可以設計一些細顆粒度的控制類,然后再按照模塊,用粗粒度封 裝細顆粒度的控制類,提供給Web層一個Facade。

          然后你可以畫序列圖,就是用序列圖來表達事件流,在這個過程中,你需要不斷回到類圖,給控制類添加方法,而序列圖就是控制類的方法調用。

          至此,你已經在Rose里面完成了概要設計,當然你不可能一次設計完善,會有很多次迭代,因此你不能一開始把類設計的太詳細,只抓住主要的屬性和方法,特別需要注意的是,是抽象的設計,不要用具體的編程語言來表達類。

          三。實施(結合xdoclet和Schema工具自動生成代碼)

          然后你就可以拋開Rose了,轉到Eclipse+Togehter里面,根據那些類,規劃一下package層次,然后在Together里面進行類的詳細設計,所有需要的屬性一一寫上,當然你還是不可能一下把所有的屬性方法寫全,不過沒有關系,把重要的寫好就行了。

          然后類框架已經生成好了,給所有的實體類加上xdoclet,然后生成hbm,然后用Hibernate的ExportScheme生成DDL,運行一遍自動創建好所有的表。這樣所有的實體相關類全部做好了。

          你現在就集中精力把控制類那些方法里面的代碼填寫上就OK了,在這個過程,你會發現有些實體類缺屬性,沒有關系,加上屬性,然后寫好xdoclet,運行一遍,自動生成hbm,自動創建好表,然后繼續寫你的方法,也有可能你發現控制類缺方法,那么就加上。

          基本上實體類就是getter/setter,和少量的實體相關方法,所有的控制邏輯都寫在控制類里面。

          最后你的軟件就基本寫好了,用Eclipse生成好一堆你的testCase運行測試,反復修改,除bug。

          看看使用OOAD的設計思路,是多么的爽的事情阿!你只需要把精力放到Use Case的抽象,實體類的關系總結,控制類的歸納。而當你使用Eclipse+Together之后,你所需要寫的代碼只不過是控制類的方法實現代碼,其 他的都已經生成好了。另外可能需要寫少量工具類。


          posted @ 2006-09-20 09:02 Alex 閱讀(961) | 評論 (1)編輯 收藏

          注:關于跨域登陸cookie的問題在網上搜索了一下,沒看到有java下的示例,這個asp的也可以參照一下,有空再在java下測一下.

          key words:單點登陸 SSO 跨域cookie


          摘要:當你有一個Cookie組(或叫Cookie字典)使用Domain屬性指定域名之后,當你在對該組的成員進行修改或新增的時候,一定要在操 作之后加上Resonse.Cookies(CookieName).Domain屬性。如果沒有必要,請不要修改已設置Domain的Cookie組.
          關鍵字:
          正文:
          ????Cookie跨域操作看來是個簡單的問題,因為只要指定Domain屬性為指定網站的根域名就可以了.但是筆者在實際使用過程中卻遇到了一些問題,的確值得注意.?   環境介紹   cookie在www主域名下創建,并寫入Domain屬性,如:(為方便調試以下代碼皆為asp代碼)   Write.asp <%
          Response.Cookies(CookieName)("UserName")?=?"SunBird"
          Response.Cookies(CookieName)("Password")?=?"xyz1234"
          Response.Cookies(CookieName).Domain?=?"xxxx.com"
          %>
            上面文件放在www主域名下,同時在同目錄下放置一個讀取cookie的Read.asp   Read.asp <%
          Response.Write?Request.Cookies(CookieName)("UserName")
          Response.Write?Request.Cookies(CookieName)("Password")
          %>
            再放一個Read.asp文件到另外一個子域名站點里,代碼同上。最后我們再做一個清除cookie的Clear.asp放在主域名下   Clear.asp <%
          Response.Cookies(CookieName)("UserName")?=?""
          Response.Cookies(CookieName)("Password")?=?""
          Response.Cookies(CookieName).Domain?=?"xxxx.com"
          %>
            現在可以通過下面的執行順序來測試,Write.asp-->主域名的Read.asp-->子域名的Read.asp?所有 Read.asp頁面都可以讀取到Write.asp創建的cookie的值,然后再運行Clear.asp進行清除,一切都Ok,看上去沒有什么問題。   但是把這種方法運用到實際的站點時卻出現問題了。   問題描述:   第一次登錄一切ok,所有子域名都可以訪問到主域名存儲的cookie,但是,一旦退出之后,子域名的cookie被清除了,但是主域名的 cookie仍然保留著,強行清除主域名的cookie之后,無論怎樣登錄主域名下都無法保存cookie了,除非關掉瀏覽器重新打開。   經過多次嘗試之后,無意中發現問題所在,以下是測試經過。   創建一個Write2.asp的頁面放在主域名下 <%
          Response.Cookies(CookieName)("TEST_COOKIE")?=?"TEST_COOKIE"
          %>
            第一步:關閉瀏覽器后,按以下順序執行,Write.asp-->主域名的Read.asp-->子域名的Read.asp?到這里所有Read.asp讀取正常。   第二步:Clear.asp-->主域名的Read.asp-->子域名的Read.asp?到這里清除操作是成功的。   第三步:Write.asp-->?Write2.asp?-->?主域名Read.asp?-->?子域名Read.asp?到這里兩個Read.asp都可以讀取到cookie的值。   第四步:重新執行第二步,發現主域名Read.asp仍然輸出了值,而子域名下的Read.asp的值已經被清空了。   根據以上測試總結以下幾點再跨域使用cookie時需要注意的地方   1、當你有一個Cookie組(或叫Cookie字典)使用Domain屬性指定域名之后,當你在對該組的成員進行修改或新增的時候,一定要在操作之后加上Resonse.Cookies(CookieName).Domain屬性。   2、如果沒有必要,請不要修改已設置Domain的Cookie組,直接使用Response.Cookies("CookieText")?=?CookieValue?來創建一個新的Cookie。
          posted @ 2006-09-18 20:59 Alex 閱讀(2493) | 評論 (0)編輯 收藏

          僅列出標題
          共15頁: First 上一頁 2 3 4 5 6 7 8 9 10 下一頁 Last 
          主站蜘蛛池模板: 堆龙德庆县| 扶沟县| 山西省| 容城县| 定兴县| 凤翔县| 临安市| 大方县| 柘城县| 八宿县| 读书| 平陆县| 黄山市| 姜堰市| 凌云县| 八宿县| 宁乡县| 永兴县| 永安市| 临汾市| 南郑县| 电白县| 蚌埠市| 唐山市| 犍为县| 勃利县| 桑日县| 上虞市| 临泽县| 锦屏县| 鹤壁市| 吉木萨尔县| 依安县| 毕节市| 柳林县| 公主岭市| 洞口县| 德保县| 凭祥市| 晴隆县| 江川县|