隨筆-19  評論-128  文章-1  trackbacks-0
            2010年7月11日
               摘要: 一、分布式實現(xiàn)原理               如上圖所示,主要通過Apache-Server作為中轉(zhuǎn)服務(wù)器,實現(xiàn)多個tomcat服務(wù)器之間的分布式處理,用戶直接請求Apache-Server,然后Apache-Server會將請求分發(fā)到具體的tomcat-server,之...  閱讀全文
          posted @ 2011-06-22 16:09 obpm 閱讀(8213) | 評論 (4)編輯 收藏
          從設(shè)計理念層面看abstract class和interface

          上面主要從語法定義和編程的角度論述了abstract class和interface的區(qū)別,這些層面的區(qū)別是比較低層次的、非本質(zhì)的。本小節(jié)將從另一個層面:abstract class和interface所反映出的設(shè)計理念,來分析一下二者的區(qū)別。作者認為,從這個層面進行分析才能理解二者概念的本質(zhì)所在。

          前面已經(jīng)提到過,abstarct class在Java語言中體現(xiàn)了一種繼承關(guān)系,要想使得繼承關(guān)系合理,父類和派生類之間必須存在"is a"關(guān)系,即父類和派生類在概念本質(zhì)上應(yīng)該是相同的(參考文獻〔3〕中有關(guān)于"is a"關(guān)系的大篇幅深入的論述,有興趣的讀者可以參考)。對于interface 來說則不然,并不要求interface的實現(xiàn)者和interface定義在概念本質(zhì)上是一致的,僅僅是實現(xiàn)了interface定義的契約而已。為了使論述便于理解,下面將通過一個簡單的實例進行說明。

          考慮這樣一個例子,假設(shè)在我們的問題領(lǐng)域中有一個關(guān)于Door的抽象概念,該Door具有執(zhí)行兩個動作open和close,此時我們可以通過abstract class或者interface來定義一個表示該抽象概念的類型,定義方式分別如下所示:

          使用abstract class方式定義Door:

          abstract class Door {
          abstract void open();
          abstract void close();
          }


          使用interface方式定義Door:


          interface Door {
          void open();
          void close();
          }


          其他具體的Door類型可以extends使用abstract class方式定義的Door或者implements使用interface方式定義的Door。看起來好像使用abstract class和interface沒有大的區(qū)別。

          如果現(xiàn)在要求Door還要具有報警的功能。我們該如何設(shè)計針對該例子的類結(jié)構(gòu)呢(在本例中,主要是為了展示abstract class和interface反映在設(shè)計理念上的區(qū)別,其他方面無關(guān)的問題都做了簡化或者忽略)?下面將羅列出可能的解決方案,并從設(shè)計理念層面對這些不同的方案進行分析。

          解決方案一:

          簡單的在Door的定義中增加一個alarm方法,如下:

          abstract class Door {
          abstract void open();
          abstract void close();
          abstract void alarm();
          }


          或者

          interface Door {
          void open();
          void close();
          void alarm();
          }


          那么具有報警功能的AlarmDoor的定義方式如下:

          class AlarmDoor extends Door {
          void open() { … }
          void close() { … }
          void alarm() { … }
          }


          或者

          class AlarmDoor implements Door {
          void open() { … }
          void close() { … }
          void alarm() { … }


          這種方法違反了面向?qū)ο笤O(shè)計中的一個核心原則ISP(Interface Segregation Priciple),在Door的定義中把Door概念本身固有的行為方法和另外一個概念"報警器"的行為方法混在了一起。這樣引起的一個問題是那些僅僅依賴于Door這個概念的模塊會因為"報警器"這個概念的改變(比如:修改alarm方法的參數(shù))而改變,反之依然。

          解決方案二:

          既然open、close和alarm屬于兩個不同的概念,根據(jù)ISP原則應(yīng)該把它們分別定義在代表這兩個概念的抽象類中。定義方式有:這兩個概念都使用abstract class方式定義;兩個概念都使用interface方式定義;一個概念使用abstract class方式定義,另一個概念使用interface方式定義。

          顯然,由于Java語言不支持多重繼承,所以兩個概念都使用abstract class方式定義是不可行的。后面兩種方式都是可行的,但是對于它們的選擇卻反映出對于問題領(lǐng)域中的概念本質(zhì)的理解、對于設(shè)計意圖的反映是否正確、合理。我們一一來分析、說明。

          如果兩個概念都使用interface方式來定義,那么就反映出兩個問題:1、我們可能沒有理解清楚問題領(lǐng)域,AlarmDoor在概念本質(zhì)上到底是Door還是報警器?2、如果我們對于問題領(lǐng)域的理解沒有問題,比如:我們通過對于問題領(lǐng)域的分析發(fā)現(xiàn)AlarmDoor在概念本質(zhì)上和Door是一致的,那么我們在實現(xiàn)時就沒有能夠正確的揭示我們的設(shè)計意圖,因為在這兩個概念的定義上(均使用interface方式定義)反映不出上述含義。

          如果我們對于問題領(lǐng)域的理解是:AlarmDoor在概念本質(zhì)上是Door,同時它有具有報警的功能。我們該如何來設(shè)計、實現(xiàn)來明確的反映出我們的意思呢?前面已經(jīng)說過,abstract class在Java語言中表示一種繼承關(guān)系,而繼承關(guān)系在本質(zhì)上是"is a"關(guān)系。所以對于Door這個概念,我們應(yīng)該使用abstarct class方式來定義。另外,AlarmDoor又具有報警功能,說明它又能夠完成報警概念中定義的行為,所以報警概念可以通過interface方式定義。如下所示:

          abstract class Door {
          abstract void open();
          abstract void close();
          }
          interface Alarm {
          void alarm();
          }
          class AlarmDoor extends Door implements Alarm {
          void open() { … }
          void close() { … }
          void alarm() { … }
          }


          這種實現(xiàn)方式基本上能夠明確的反映出我們對于問題領(lǐng)域的理解,正確的揭示我們的設(shè)計意圖。其實abstract class表示的是"is a"關(guān)系,interface表示的是"like a"關(guān)系,大家在選擇時可以作為一個依據(jù),當然這是建立在對問題領(lǐng)域的理解上的,比如:如果我們認為AlarmDoor在概念本質(zhì)上是報警器,同時又具有Door的功能,那么上述的定義方式就要反過來了。

          轉(zhuǎn)載人員-Nicholas
          posted @ 2010-11-07 13:57 obpm 閱讀(574) | 評論 (4)編輯 收藏
          可關(guān)閉的TabbedPane結(jié)構(gòu):


          測試代碼:

          package cn.demo.test;

          import java.awt.Component;

          import javax.swing.JFrame;
          import javax.swing.JLabel;
          import javax.swing.UIManager;

          /**
           * Test
           * 
          @author Tom
           *
           
          */
          public class TestDemo {

              
          public static void main(String[] args) {
                  
          try {
                      String feel 
          = UIManager.getSystemLookAndFeelClassName();
                      UIManager.setLookAndFeel(feel);
                  } 
          catch (Exception e) {
                      e.printStackTrace();
                  } 
                  
                  JFrame frame 
          = new JFrame();
                  frame.setTitle(
          "可關(guān)閉Tab測試");
                  frame.setSize(
          300400);
                  frame.setLocationRelativeTo(
          null);
                  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                  
                  TabbedPane tabbedPane 
          = new TabbedPane();
                  tabbedPane.setCloseButtonEnabled(
          true);
                  tabbedPane.addTab(
          "測試一"nullnew JLabel("測試一"));
                  tabbedPane.addTab(
          "測試二"nullnew JLabel("測試二"));
                  tabbedPane.addTab(
          "測試三"nullnew JLabel("測試三"));
                  tabbedPane.addTab(
          "測試四"nullnew JLabel("測試四"));
                  tabbedPane.addTabbedPaneListener(
          new TabbedPaneListener(){
                      @Override
                      
          public void allTabsRemoved() {
                          
          // TODO Auto-generated method stub
                          
                      }
                      @Override
                      
          public boolean canTabClose(Tab tab, Component component) {
                          
          // TODO Auto-generated method stub
                          return false;
                      }
                      @Override
                      
          public void tabAdded(Tab tab, Component component, int index) {
                          
          // TODO Auto-generated method stub
                          
                      }
                      @Override
                      
          public void tabRemoved(Tab tab, Component component, int index) {
                          
          // TODO Auto-generated method stub
                          System.out.println("close");
                      }
                      @Override
                      
          public void tabSelected(Tab tab, Component component, int index) {
                          
          // TODO Auto-generated method stub
                          
                      }
                  });
                  
                  frame.add(tabbedPane);
                  frame.setVisible(
          true);
              }
              
          }

           測試效果:

               

          源碼下載:TabbedPane.rar

          發(fā)表人: Tom


          posted @ 2010-10-24 16:44 obpm 閱讀(6136) | 評論 (2)編輯 收藏

          在數(shù)據(jù)庫層使用SQL分頁可以很大程度增加平臺系統(tǒng)程序運行速度與效率。本人只是初入手半數(shù)據(jù)庫半程序的開發(fā),所以對數(shù)據(jù)庫研究不深。于是要收集下列代碼以作參考,同時也Post出來可以讓需要的人參考一下,高手就請見笑了。說轉(zhuǎn)載說不上,說原創(chuàng)也... 國慶期間在家家里的機子跑DB比較困難,做不了過多測試。不過語句或函數(shù)方面本人都仔細看過抄回來的SQL的網(wǎng)頁里示例,感覺基本上大同小異,如果有錯誤查下做相應(yīng)的修改或百度Google一下應(yīng)該沒什么大問題,也請多多包涵。當然,有機會就會對下列SQL做測試,然后會進行修正。至于每個數(shù)據(jù)庫分頁在這就不進行深究,只是列出個可用的方法。

          ##########
          # MySQL#
          ##########

          select * from tlk_buginfo limit startPos, pageSize

          startPos: 定義當前頁起始位置(不包括startPos)
          pageSize: 每頁顯示數(shù)據(jù)的條數(shù)

          ##########
          # MSSQL#(2005的row_number,暫無2000)
          ##########

          1、
          --返回第20-40行數(shù)據(jù)
          select top 20 * from (select row_number() over (order by EmployeeID) as RowNumber, * from HumanResources.Employee) TableNickname where RowNumber>=20

          2、
          --返回第20-40行數(shù)據(jù)
          select * from (select row_number() over (order by EmployeeID) as RowNumber, * from HumanResources.Employee) TableNickname where RowNumber between 20 and 40

          3、
          --返回第20-40行數(shù)據(jù)
          with OrderedResults as
          (select *, ROW_NUMBER() OVER (order by EmployeeID) as RowNumber FROM HumanResources.Employee)
          select * from OrderedResults where RowNumber between 20 and 40

          ##########
          # Oracle#
          ##########

          ①采用rownum關(guān)鍵字(三層嵌套)
          --返回第5-15行數(shù)據(jù)
          select * from (select row_.*, rownum num from (select * from tlk_buginfo) row_ where rownum<=15) where num>=5

          ②采用row_number解析函數(shù)進行分頁(效率更高)
          --返回第5-15行數(shù)據(jù)
          select tab.* from (select t.*, row_number() over (order by lastmodified) as num from tlk_buginfo t) tab where num between 5 and 15

          ##########
          # DB2#
          ##########

          select * from (select *, rownumber() over(order by 排序字段 asc ) as rowid  from 表名 )as a where a.rowid >= startPage AND a.rowid <endPage

          ##########
          # Hsqldb#
          ##########

          select LIMIT 0 10 表名


          收集資料:(allen)
          posted @ 2010-10-10 21:32 obpm 閱讀(397) | 評論 (1)編輯 收藏
          jbpm4.3API(chn)下載
          (denny)
          posted @ 2010-10-08 00:11 obpm 閱讀(1467) | 評論 (1)編輯 收藏
          HTML5 是近十年來 Web 標準最巨大的飛躍。和以前的版本不同,HTML 5 并非僅僅用來表示 Web 內(nèi)容,它的使命是將 Web 帶入一個成熟的應(yīng)用平臺,在這個平臺上,視頻,音頻,圖象,動畫,以及同電腦的交互都被標準化。盡管 HTML 5 的實現(xiàn)還有很長的路要走,但 HTML 5 正在改變 Web。
          HTML 最近的一次升級是1999年12月發(fā)布的 HTML 4.01。自那以后,發(fā)生了很多事。最初的瀏覽器戰(zhàn)爭已經(jīng)結(jié)束,Netscape 灰飛煙滅,IE5 作為贏家后來又發(fā)展到 IE6, IE7到IE8。Mozilla Firefox 從 Netscape 的死灰中誕生,并躍居第二位。蘋果和 Google 各自推出自己的瀏覽器,而小家碧玉的 Opera 仍然嚶嚶嗡嗡地活著,并以推動 Web 標準為己命。我們甚至在手機和游戲機上有了真正的 Web 體驗,感謝 Opera,iPhone 以及 Google 已經(jīng)推出的 Android。
          然而這一切,僅僅讓 Web 標準運動變得更加混亂,HTML 5 和其它標準被束之高閣,結(jié)果,HTML 5 一直以來都是以草案的面目示人。
          于是,一些公司聯(lián)合起來,成立了一個叫做 Web Hypertext Application Technology Working Group (Web 超文本應(yīng)用技術(shù)工作組 - WHATWG) 的組織,他們將重新揀起 HTML 5。這個組織獨立于 W3C,成員來自 Mozilla, KHTML/Webkit 項目組,Google,Apple,Opera 以及微軟。盡管 HTML 5 草案不會在短期內(nèi)獲得認可,但 HTML 5 總算得以延續(xù)。
          HTML 5 將帶來什么?以下是 HTML 5 草案中最激動人心的部分:
          全新的,更合理的 Tag,多媒體對象將不再全部綁定在 object 或 embed Tag 中,而是視頻有視頻的 Tag,音頻有音頻的 Tag。本地數(shù)據(jù)庫。這個功能將內(nèi)嵌一個本地的 SQL 數(shù)據(jù)庫,以加速交互式搜索,緩存以及索引功能。同時,那些離線 Web 程序也將因此獲益匪淺。不需要插件的富動畫。Canvas 對象將給瀏覽器帶來直接在上面繪制矢量圖的能力,這意味著我們可以脫離 Flash 和 Silverlight,直接在瀏覽器中顯示圖形或動畫。一些最新的瀏覽器,除了 IE,已經(jīng)開始支持 Canvas。瀏覽器中的真正程序。將提供 API 實現(xiàn)瀏覽器內(nèi)的編輯,拖放,以及各種圖形用戶界面的能力。內(nèi)容修飾 Tag 將被剔除,而使用 CSS。理論上講,HTML 5 是培育新 Web 標準的土壤,讓各種設(shè)想在他的組織者之間分享,但 HTML 5 目前仍處于試驗階段。
          Mozilla 的技術(shù)副總裁 Mike Shaver 說,HTML 5 是一個被寄予厚望的概念,它既是 WHATWG 組織的實驗田,又是 W3C 的標準之路。
          Shaver 認為,Mozilla 的興趣和 WHATWG 實驗相吻合,Mozilla 在 HTML 5 工作組中非常活躍,我們對一些早期的細則進行實驗并將成熟的結(jié)果提交 W3C。
          在過去的幾年,Mozilla 隨著各種出現(xiàn)的新標準,推出多個富有前瞻性的項目,包括 Prism,一個用于離線運行 Web 程序的系統(tǒng),以及 Weave,一個數(shù)據(jù)存儲框架。
          Shaver 說,HTML 5 運動肇始于對 W3C 的不耐煩,Web 標準中的很多進展都因 W3C 將重點從 HTML 轉(zhuǎn)移到 XML 而停滯不前。
          很多基于 XML 架構(gòu)的新技術(shù)被設(shè)計出來替代 HTML,Shaver 說,這不是一條正確的道路,人們不應(yīng)象黑瞎子掰玉米把樣一邊掰一邊丟。
          HTML 5 的新實驗在 Firefox 以及 基于 Webkit 的 Safari 和 Chrome 瀏覽器中逐漸得到強化,但仍有不少問題。
          Chrome 的開發(fā)者 Darin Fisher 說,Chrome 仍在襁褓中時,就不得不面臨幾個問題,盡管使用的是最新的 Webkit,HTML 5 的本地數(shù)據(jù)庫功能在 Chrome 的初期版本中并沒有實現(xiàn)。因為 Chrome 的沙箱機制和 Webkit 的數(shù)據(jù)庫功能有沖突。
          而由于 Chrome 屬于秘密開發(fā),Chrome 的開發(fā)人員也不便參與 Webkit 的開發(fā)。
          我們要想保守 Chrome 的秘密,就無法參與 Webkit 社區(qū)。Fisher 說,我們很希望可以在某些方面給 Webkit 以幫助,我們擁有眾多經(jīng)驗豐富的開發(fā)者,我們很想知道人們目前遇到的挑戰(zhàn)并樂意提供幫助。
          隨著 Chrome 的發(fā)布,F(xiàn)isher 說他的團隊成員有時會和 Webkit 的人一起吃飯,有些人私下里還成了好朋友。Fisher 稱,他們迫切地想同其他 Webkit 開發(fā)組一起工作解決離線數(shù)據(jù)庫的問題。
          Chrome 里面還包含Google 的開源 Gears 技術(shù),用來實現(xiàn)與 HTML 5 類似的離線功能。
          Gears 可以看作已有 API 的替代品,F(xiàn)isher 說,HTML 5 對新瀏覽器來說是非常好的東西,但絕大多數(shù)用戶還使用舊瀏覽器。Gears 可以讓那些舊瀏覽器也獲得這樣的 API,我們正在為 HTML 5 版 API 提供兼容。
          Gears 兼容性非常好,它正成為將 HTML 5 帶向人們桌面的另外一條途徑。
          目前,絕大多數(shù)工作由 Apple,Mozilla, Opera, Google 以及 Trolltech 展開。微軟在干什么?IE 因其對 Web 標準的遲鈍而聞名,更不要說 HTML 5。但 IE8 可能會做出改變。
          微軟 IE 平臺與 WHAT 工作組主席 Chris Wilson 在郵件中稱,我們希望我們現(xiàn)在開始的工作可以在 HTML 工作組創(chuàng)建一套測試系統(tǒng)。Wilson 說,IE 開發(fā)組仍然對 HTML 5 的一些提議感到擔憂。我覺得工作組的所有成員都會承認我們還有很多事要做。
          目前處于 Beta 版的 IE9,已經(jīng)包含 HTML 5 的諸多新功能。它擁有一個跨文檔消息系統(tǒng),本地存儲,以及一些離線事件來檢測網(wǎng)絡(luò)的中斷。但還有些功能還未提上議程,如 Canvas。
          HTML 5 非常龐大,仍處在開發(fā)階段,我認為瀏覽器廠商應(yīng)當盡快達成一致,而每個瀏覽器的具體實現(xiàn)時間可以自己選擇。Web 開發(fā)者和瀏覽器廠商會同意 Wilson 的下面這句話,這確切無疑是一個激動人心的時刻,我們希望看到 Web 成為新的應(yīng)用平臺。
          HTML5寫的例子(IE9或google瀏覽器才有效果):
           
          Google Gravity
          http://mrdoob.com/projects/chromeexperiments/google_gravity/
          BallDropping
          http://balldroppings.com/js/
          Animated Harmonograph
          http://hernan.amiune.com/labs/harmonograph/animated-harmonograph.html
          Canopy
          http://onecm.com/projects/canopy/
          Ball Pool
          http://mrdoob.com/projects/chromeexperiments/ball_pool/
          Browser Ball
          http://experiments.instrum3nt.com/markmahoney/ball/parent.html
          Wavy Scrollbars
          http://the389.com/experiment/
          Twitch
          http://reas.com/twitch/window0.html
          Colorscube
          http://www.canvasdemos.com/2009/04/03/colorscube/
          InterNetris
          http://internetris.net/
          CanvasPaint
          http://canvaspaint.org/
          HTML5學習資料:
          http://www.chinabyte.com/bang/html5/
          收集資料:(denny)
          posted @ 2010-10-07 21:46 obpm 閱讀(2113) | 評論 (1)編輯 收藏
          首先,在jbpm4中,流程定義相關(guān)的部署信息就存在JBPM4_DEPLOYMENTJBPM4_DEPLOYPROPJBPM4_LOB (存放當發(fā)布一個png和xml文件后的流程定義后的記錄)。中。

          JBPM4_HIST_PROCINSTJBPM4_HIST_ACTINST兩張表中,分別存放的是process Instance、Activity Instance的歷史記錄,Activity Instance是指流程定義中各個步驟:task descition等存放Process Instance、Activity Instance歷史記錄的表有了,那他們的當前記錄存在什么地方呢?這就需要弄清楚jBPM的另外幾個概念。一般而言,在jBPM中,“a process instance is the root of a tree of executions”。因此,當一個流程實例Split出兩個并行步驟的時候,在JBPM4_EXECUTION表中將有三筆相關(guān)記錄,一筆是代表流程實例的Root Execution,另外兩筆是關(guān)于上述兩個并行步驟的Child Execution。

          此外,在jbpm中,Activity的種類是很豐富的,可以是Control Flow Activities,如sub-process,decision等,也可以是Automatic Activity,如java、script、sql等,其中需要人來參與完成的Activity被稱為Task,待辦任務(wù)放在JBPM4_TASK表中,而歷史任務(wù)放在JBPM4_HIST_TASK表中。

          對一個Task而言,它可能會有多個Participation(swim lane 同樣會有多個Participation),Participation的種類有Candidate、client、owner、Replaced Assignee和viewer,而具體的Participation既可以是單一用戶,也可以是用戶組,Participation的信息存放在JBPM4_PARTICIPATION中。

          Swim Lane是一種Runtime Process Role,通過Swim Lane,多個Task可以一次分配到同一Actor身上,存放這些信息是表JBPM4_PARTICIPATION

          JBPM4_ID_GROUPJBPM4_ID_MEMBERSHIPJBPM4_ID_USER這是基本的權(quán)限控制,建議關(guān)于用戶認證方面還是自己開發(fā)一套,這個功能太簡單了,難以滿足需求。

          JBPM4_JOB存放的是Timer的定義。

          JBPM4_PROPERTY這是jbpm引擎參數(shù)表。

          JBPM4_VAR表存放流程臨時變量,當流程實例結(jié)束后,表中內(nèi)容清除。

          JBPM4_HIST_VAR表存放歷史臨時變量,但是jbpm4好像還沒有對這張表進行利用。

          JBPM4_HIST_DETAIL表保存變量變更記錄。



          了解jbpm4.3以上這18張表后,我們應(yīng)該在流程運行中,詳細觀察jbpm是如何對這些表進行操作,以及進行什么樣的操作的。

          發(fā)布一個流程定義后:

          JBPM4_DEPLOYMENT新增一條記錄

          JBPM4_DEPLOYPROP新增三條記錄

          JBPM4_LOB新增兩條記錄



          開始一個流程startProcessInstanceByKey后:

          JBPM4_EXECUTION新增一條記錄

          JBPM4_TASK新增一條記錄

          JBPM4_HIST_PROCINSTJBPM4_HIST_ACTINST分別新增一條記錄

          JBPM4_HIST_TASK新增一條記錄



          當執(zhí)行taskService.setVariables(task.getId(), map);時,JBPM4_VARIABLES中添加變量記錄
           
          轉(zhuǎn)載人員:Nicholas
          posted @ 2010-09-16 19:51 obpm 閱讀(1265) | 評論 (0)編輯 收藏

          權(quán)限分析文檔

          基于RBAC的權(quán)限設(shè)計模型:

          1 RBAC 介紹

          RBAC 模型作為目前最為廣泛接受的權(quán)限模型。

          NIST (The National Institute of Standards and Technology,美國國家標準與技術(shù)研究院)標準RBAC模型由4個部件模型組成,這4個部件模型分別是基本模型RBAC0(Core RBAC)、角色分級模型RBAC1(Hierarchal RBAC)、角色限制模型RBAC2(Constraint RBAC)和統(tǒng)一模型RBAC3(Combines RBAC)[1]。RBAC0模型如圖1所示。

          clip_image001.jpg
          圖表 1 RBAC 0 模型

          l RBAC0 定義了能構(gòu)成一個RBAC控制系統(tǒng)的最小的元素集合

          在RBAC之中,包含用戶users(USERS)、角色roles(ROLES)、目標objects(OBS)、操作operations(OPS)、許可權(quán)permissions(PRMS)五個基本數(shù)據(jù)元素,權(quán)限被賦予角色,而不是用戶,當一個角色被指定給一個用戶時,此用戶就擁有了該角色所包含的權(quán)限。會話sessions是用戶與激活的角色集合之間的映射。RBAC0與傳統(tǒng)訪問控制的差別在于增加一層間接性帶來了靈活性,RBAC1、RBAC2、RBAC3都是先后在RBAC0上的擴展。

          l RBAC1 引入角色間的繼承關(guān)系

          角色間的繼承關(guān)系可分為一般繼承關(guān)系和受限繼承關(guān)系。一般繼承關(guān)系僅要求角色繼承關(guān)系是一個絕對偏序關(guān)系,允許角色間的多繼承。而受限繼承關(guān)系則進一步要求角色繼承關(guān)系是一個樹結(jié)構(gòu)。

          l RBAC2 模型中添加了責任分離關(guān)系

          RBAC2 的約束規(guī)定了權(quán)限被賦予角色時,或角色被賦予用戶時,以及當用戶在某一時刻激活一個角色時所應(yīng)遵循的強制性規(guī)則。責任分離包括靜態(tài)責任分離和動態(tài)責任分離。約束與用戶-角色-權(quán)限關(guān)系一起決定了RBAC2模型中用戶的訪問許可。

          l RBAC3 包含了RBAC1和RBAC2

          既提供了角色間的繼承關(guān)系,又提供了責任分離關(guān)系。

          建立角色定義表。定出當前系統(tǒng)中角色。

          因為有繼承的問題,所以角色體現(xiàn)出的是一個樹形結(jié)構(gòu)。

          test.bmp

          2 權(quán)限設(shè)計:

          配置資源以及資源的操作 : 這里資源可以定義為一個通用的資源模型。提供通用的資源統(tǒng)一接口。

          數(shù)據(jù)庫 ER 圖:

          clip_image002.gif

          關(guān)系圖:

          clip_image003.gif

          未命名.bmp

          3 分析:

          根據(jù)以上的類關(guān)系圖和ER圖可以看出。整個權(quán)限可以抽象為五個對象組成。

          OrgBean : 用于描述org模型。

          Role : 用于描述角色。

          Permission : 用于描述權(quán)限。

          Resource : 用于描述資源。

          Operation : 用于描述操作。

          其中Permission中有Resource , Operation 的聚合,資源和操作組成權(quán)限。

          Role 和 Permission 都有自包含。因為設(shè)計到權(quán)限的繼承。

          資源Resource 也可能出現(xiàn)一顆樹形結(jié)構(gòu),那資源也要有自包含。

          思想 :

          權(quán)限系統(tǒng)的核心由以下三部分構(gòu)成: 1. 創(chuàng)造權(quán)限, 2. 分配權(quán)限, 3. 使用權(quán)限,然后,系統(tǒng)各部分的主要參與者對照如下: 1. 創(chuàng)造權(quán)限 -Creator 創(chuàng)造, 2. 分配權(quán)限 - Administrator 分配, 3. 使用權(quán)限 - User :

          1. Creator 創(chuàng)造 Privilege , Creator 在設(shè)計和實現(xiàn)系統(tǒng)時會劃分,一個子系統(tǒng)或稱為模塊,應(yīng)該有哪些權(quán)限。這里完成的是 Privilege 與Resource 的對象聲明,并沒有真正將 Privilege 與具體 Resource 實例聯(lián)系在一起,形成 Operator 。

          2. Administrator 指定 Privilege 與 Resource Instance 的關(guān)聯(lián) 。在這一步, 權(quán)限真正與資源實例聯(lián)系到了一起, 產(chǎn)生了 Operator (Privilege Instance )。 Administrator 利用 Operator 這個基本元素,來創(chuàng)造他理想中的權(quán)限模型。如,創(chuàng)建角色,創(chuàng)建用戶組,給用戶組分配用戶,將用戶組與角色關(guān)聯(lián)等等 ... 這些操作都是由 Administrator 來完成的。

          3. User 使用 Administrator 分配給的權(quán)限去使用各個子系統(tǒng)。 Administrator 是用戶,在他的心目中有一個比較適合他管理和維護的權(quán)限模型。于是,程序員只要回答一個問題,就是什么權(quán)限可以訪問什么資源,也就是前面說的 Operator 。程序員提供 Operator 就意味著給系統(tǒng)穿上了盔甲。 Administrator 就可以按照他的意愿來建立他所希望的權(quán)限框架 可以自行增加,刪除,管理 Resource 和 Privilege 之間關(guān)系。可以自行設(shè)定用戶 User 和角色 Role 的對應(yīng)關(guān)系。 ( 如果將 Creator 看作是 Basic 的發(fā)明者, Administrator 就是 Basic 的使用者,他可以做一些腳本式的編程 ) Operator 是這個系統(tǒng)中最關(guān)鍵的部分,它是一個紐帶,一個系在 Programmer , Administrator , User 之間的紐帶。

          4 權(quán)限API

          getPermissionByOrgGuid(String orgGuid )

          通過傳入一個org的Guid , 拿到當前這個org對象都具有那些訪問權(quán)限。

          getSourcePermissionByOrgGuid(String orgGuid , String resouceGuid)

          通過傳入一個org的Guid 和 一個資源的Guid , 返回改Org對當前這個資源的訪問權(quán)限。

          getPermissionByResourceGuid(String resource)

          通過傳入一個資源的Guid , 得到當前資源下都有那些權(quán)限定義。

          havingHeritPermission(String orgGuid , String resouceGuid) : Boolean

          傳入一個orgGuid, 資源GUID ,查看改OrgGuid下對資源是否有向下繼承的權(quán)限。這里繼承是資源的繼承。即對父欄目有權(quán)限,可以繼承下去對父欄目下的子欄目同樣有權(quán)限。

          havingPermission(String orgGuid , String resourceGuid) : Boolean

          判斷某Org對某一資源是否用權(quán)限。

          以上是粗粒度的權(quán)限API 。 以下為細粒度的權(quán)限:

          getOperationByPermission(String permissionGuid)

          通過permission 的Guid 得到該permission 的所有有效操作。

          getOperationByGuid(String permissionGuid , String resourceGuid)

          通過permision的Guid , 資源的Guid 得到該資源下所有的有效操作。

          screeningOpreationByGuid (String permissionGuid , String resourceGuid , String orgGuid)

          通過permission , resource , org的Guid 得到改Org對這一資源的有效操作。

          hasOperation(String operationGuid) : boolean

          通過傳入的operationGuid 返回是否具有操作權(quán)限。

          5 權(quán)限的實現(xiàn):

          1 .表單式認證,這是常用的,但用戶到達一個不被授權(quán)訪問的資源時, Web 容器就發(fā)

          出一個 html 頁面,要求輸入用戶名和密碼。

          2 .用 Filter 防止用戶訪問一些未被授權(quán)的資源, Filter 會截取所有 Request/Response ,

          然后放置一個驗證通過的標識在用戶的 Session 中,然后 Filter 每次依靠這個標識來決定是否放行 Response 。

          這個模式分為:

          Gatekeeper :采取 Filter 或統(tǒng)一 Servlet 的方式。

          Authenticator : 在 Web 中使用 JAAS 自己來實現(xiàn)。

          Filter 攔截只是攔截該用戶是否有訪問這個頁面,或這一資源的權(quán)限。真正做到顯示后攔截是在應(yīng)用程序內(nèi)部去做。

          做顯示攔截提供API , 標簽這兩種方式

           

          轉(zhuǎn)載人員:Happy

          原文地址 http://blog.csdn.net/huanghanzzz2006/archive/2006/12/04/1429666.aspx

          posted @ 2010-09-14 13:30 obpm 閱讀(941) | 評論 (0)編輯 收藏

          flex4幫助文檔大小有34M(網(wǎng)頁版),上傳不了。需要該文檔的,請留下你的郵箱地址。
          115共享地址:
          http://u.115.com/file/f8c22d4e48
          flex4api.zip   提取碼:f8c22d4e48


          原創(chuàng)人員:denny

          posted @ 2010-09-03 08:50 obpm 閱讀(4603) | 評論 (104)編輯 收藏
          圖片剪切功能:

          效果圖:






          flex代碼:

           

          <?xml version="1.0" encoding="utf-8"?>
          <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="init()" xmlns:local="astion.*">
           
          <mx:Script>
            
          <![CDATA[
             import mx.controls.Image;
             import mx.graphics.ImageSnapshot;
             import flash.net.FileReference;
             import mx.graphics.codec.JPEGEncoder;
             import mx.managers.PopUpManager;
             import mx.containers.TitleWindow;
             import mx.controls.Alert;
             import mx.events.CloseEvent;
             import mx.core.IFlexDisplayObject;
             import mx.utils.*;
             import mx.core.Application;
             import astion.Dot;
             import astion.ScaleBox;
             
             public static const LINE_WIDTH:Number = 1;//縮放邊框?qū)挾?br />    private var file:FileReference;
             public var IMAGE_URL:String="http://localhost:8080/cutPicuter/aa/aa.jpg";
             private var loader:Loader;
             private var bmp:Bitmap;
                      private var stream:URLStream;
                      public var realPath:String="D:\myWorkSpace\cutPicuter\WebRoot\aa\aa.jpg";
             
             //初始化數(shù)據(jù)
             private function init():void{
              this.loader = new Loader();
                          this.stream = new URLStream();
                          this.loader.contentLoaderInfo.addEventListener(Event.COMPLETE,this.onComplete);
                          this.loader.load(new URLRequest(encodeURI(this.IMAGE_URL)));//解決中文亂碼
                          this.stream.load(new URLRequest(encodeURI(this.IMAGE_URL)));
                          this.stream.addEventListener(Event.COMPLETE,this.onLoaded);
             }
             private function onLoaded(e:Event):void
                      {                                
                          var bytearray:ByteArray = new ByteArray();    
                          this.stream.readBytes(bytearray);
                          
                          if(this.stream.connected)
                              this.stream.close();
                              
                          this.loader.loadBytes(bytearray);
                      }
                      private function onComplete(e:Event):void
                      {
                          try
                          {
                              this.bmp = this.loader.content as Bitmap;
                              var showImage:Image= new Image();
                              showImage.source=this.loader.content;
                              canvas.addChild(showImage);
                              canvas.setChildIndex(box,1);
                              canvas.setChildIndex(showImage,0);
                          }
                          catch(e:Error)
                          {
                              
                          }
                      }
             
             //截圖,顯示縮放選擇框
             private function doCapture():void{
              box.x = 100;
              box.y = 100;
              box.visible = true;
             }
             
             //獲取縮放選擇框內(nèi)的圖像
             private function getImg():BitmapData{
              //截取整個區(qū)域
              box.scaleEnable = false;
              var bmp:BitmapData = ImageSnapshot.captureBitmapData(canvas);
              box.scaleEnable = true;
              
              //矩形為要截取區(qū)域                
                          var re:Rectangle = new Rectangle(box.x+LINE_WIDTH,box.y+LINE_WIDTH,box.boxWidth-LINE_WIDTH,box.boxHeight-LINE_WIDTH); 
                          var bytearray:ByteArray = new ByteArray();   
                          //截取出所選區(qū)域的像素集合                        
                          bytearray = bmp.getPixels(re); 
                          
                          
                          var imgBD:BitmapData = new BitmapData(box.boxWidth-LINE_WIDTH,box.boxHeight-LINE_WIDTH);       
                          //當前的bytearray.position為最大長度,要設(shè)為從0開始讀取       
                          bytearray.position=0;            
                          var fillre:Rectangle = new Rectangle(0,0,box.boxWidth-LINE_WIDTH,box.boxHeight-LINE_WIDTH);
                          //將截取出的像素集合存在新的bitmapdata里,大小和截取區(qū)域一樣
                          imgBD.setPixels(fillre,bytearray);
                          
                          return imgBD;
             }
             
             //預(yù)覽圖片
             private function doScan():void{
              var t:TitleWindow = new TitleWindow();
              t.showCloseButton=true;
              t.addEventListener(CloseEvent.CLOSE,closeWindow);
              t.width = box.boxWidth+t.getStyle("borderThickness");
              t.height =box.boxHeight+t.getStyle("borderThickness")+t.getStyle("headerHeight");
              var img:Image = new Image();
              img.width = box.boxWidth;
              img.height = box.boxHeight; 
              img.source = new Bitmap(getImg());
              t.addChild(img);
              PopUpManager.addPopUp(t,this,true);
              PopUpManager.centerPopUp(t);
             }
             
             private function closeWindow(e:CloseEvent):void{            
                          var t:TitleWindow = e.currentTarget as TitleWindow;                    
                          PopUpManager.removePopUp(t);                
                      }
                      
                      //保存圖片到本地
             private function downloadPicture():void{
              file=new FileReference();
              file.addEventListener(Event.COMPLETE,downloadComplete);
              file.save(new JPEGEncoder(80).encode(getImg()),"default.jpg");
             }
             
             private function downloadComplete(event:Event):void{
              Alert.show("成功保存圖片到本地!","提示");
             }
             
             //保存圖片到服務(wù)器即覆蓋原來的圖片
             private function save():void{
              Alert.show("是否保存剪切圖片?","提示",3, this, function(event:CloseEvent):void {
                    if (event.detail==Alert.YES){
                     var request:URLRequest = new URLRequest("http://localhost:8080/cutPicuter/servlet/FileManagerSaveFileServlet?realPath="+encodeURIComponent(StringUtil.trim(realPath)));
               request.method=URLRequestMethod.POST;
               request.contentType = "application/octet-stream";
               request.data = new JPEGEncoder(80).encode(getImg());
               var loader:URLLoader = new URLLoader();
               loader.load(request);
               loader.addEventListener(Event.COMPLETE,saveResult);

                    }});
             }
             
             private function saveResult(event:Event):void{
              Application.application.reLoadFolderFiles(realPath.substr(0,realPath.lastIndexOf("\\")));
              Alert.show("保存剪切圖片成功","提示");
             }
            
          ]]>
           
          </mx:Script>
           
          <mx:HBox x="0" y="0">
                  
          <mx:LinkButton label="剪裁" click="doCapture();" icon="@Embed('assets/cut.png')"/>
                  
          <mx:LinkButton label="預(yù)覽" click="doScan();" icon="@Embed('assets/ok.png')"/>
                  
          <mx:VRule height="22"/>
                  
          <mx:LinkButton label="保存"  click="save()"  icon="@Embed('assets/save.png')"/>
                  
          <mx:LinkButton label="另存為" click="downloadPicture();" icon="@Embed('assets/saveAs.png')"/>
              
          </mx:HBox>
           
          <mx:Canvas id="canvas" y="23" x="1">
           
          <local:ScaleBox id="box" visible="false" y="0" x="0" width="100" height="100"/>
           
          </mx:Canvas>
          </mx:Application>



          java代碼:

           

          package com;


          import java.io.DataOutputStream;
          import java.io.File;
          import java.io.FileOutputStream;
          import java.io.IOException;
          import java.io.InputStream;

          import javax.servlet.ServletException;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;

          /**
           * Servlet implementation class FileManagerSaveFileServlet
           
          */
          public class FileManagerSaveFileServlet extends HttpServlet {
           
           
          private int len=0;//處理流
           private int mm=0;//重命名
           private String fileName="";//文件原名
           private String extName="";//文件擴展名
           private String tempFileName="";//文件名加擴展名
           
           
          public void doGet(HttpServletRequest request, HttpServletResponse response)    
           
          throws ServletException, IOException {    
           processRequest(request, response);    
           }    
             
           
          public void doPost(HttpServletRequest request, HttpServletResponse response)    
            
          throws ServletException, IOException {    
           processRequest(request, response);    
           }    
           
           
          public void processRequest(HttpServletRequest request, HttpServletResponse response)

              
          throws ServletException, IOException {
            request.setCharacterEncoding(
          "utf-8");
            String realPath
          =request.getParameter("realPath");
            
          //System.out.println("FMSFS-->realPath:"+realPath);
            response.setContentType("application/octet-stream");
            InputStream is 
          = request.getInputStream();
            
          try {
            
          int size = 0;
            
          byte[] tmp = new byte[100000];
            
            tempFileName
          =realPath.substring(realPath.lastIndexOf("\\")+1);//切割獲得文件名加擴展名
            fileName=tempFileName.substring(0,tempFileName.lastIndexOf("."));//切割獲得文件名
            
          //確保獲得真實的文件名如:1(1)可以獲得真實為1,
            if(fileName.indexOf("(")!=-1){
             fileName
          =fileName.substring(0,fileName.indexOf("("));
            }
            
            extName
          =tempFileName.substring(tempFileName.lastIndexOf("."));//切割獲得擴展名
            
            
          //調(diào)用遞歸方法
            fileName+=reNameFile(realPath.substring(0,realPath.lastIndexOf("\\")+1),fileName,extName);
            
          // 創(chuàng)建一個文件夾用來保存發(fā)過來的圖片;
            File f = new File(realPath.substring(0,realPath.lastIndexOf("\\")+1)+fileName+extName);
            DataOutputStream dos 
          = new DataOutputStream(new FileOutputStream(f));
            
          while ((len = is.read(tmp)) != -1) {
            dos.write(tmp, 
          0, len);
            size 
          += len;
            }
            dos.flush();
            dos.close();
            } 
          catch (IOException e) {
            e.printStackTrace();
            }
           }
           
           
          //遞歸來重命名文件名
           String str="";
           
          public String reNameFile(String realPath,String filename,String extName){
            File file 
          =new File(realPath+"\\"+filename+extName);
            str
          ="";
                  
          if(file.exists()){
                   mm
          ++;
                   str
          ="_"+mm;
                   reNameFile(realPath,fileName
          +str,extName);
                  }
          else{
                   
          if(mm!=0){
                str
          ="_"+mm;
                   }
                  }
            
          return str;
           }
          }

           


           

          源碼: flex圖片剪切示例


          原創(chuàng)人員:Denny

          posted @ 2010-09-01 09:55 obpm 閱讀(8609) | 評論 (6)編輯 收藏

          James Gosling : Java之父
          文/陶文

          作為Java之父,James Gosling的名字可謂是耳熟能詳。當人們評論一種編程語言時,總喜歡捎帶著把下蛋的母雞一起帶上。Java做為中國的編程語言學習者餐桌上有限的那么幾樣餐點中的流行款式,自然是讓James Gosling風光不已。雖然James Gosling現(xiàn)在已經(jīng)不是領(lǐng)導Java發(fā)展潮流的領(lǐng)軍人物了,做為Sun的開發(fā)者產(chǎn)品組的CTO,怎么算來也是身居高位了,俗事纏身吧,但是這并不妨礙其對于Java一如既往的愛護,表達著各式各樣鮮明的觀點,引發(fā)一場又一場的爭論。
          James Gosling是很愛Java的——是啊,哪有當父母的不愛自己的孩子的呢。James Gosling也是很愛Sun的——是啊,哪有當領(lǐng)導的不愛自己的公司的呢。于是我們在批評.NET的安全性的隊伍前頭,在褒揚Java性能的隊伍前頭,在抨擊SWT開倒車的隊伍前頭,在給NetBeans大唱贊歌的隊伍前頭,我們都看到了James Gosling的身影。無論對錯、偏見或者固執(zhí),至少說明了Gosling的鮮明個性絲毫沒有受到年齡的影響。也許也只有這種天才而偏執(zhí)的人物才能創(chuàng)造出Java這般偉大的語言來吧。

          Bill Joy : 軟件業(yè)的愛迪生
          文/徐昊

          Joy生于1954年,1982年與Vinod Khosla, Scott McNealy和Andy Bechtolsheim一起創(chuàng)建了Sun Microsystems,并從那時起擔任首席科學家,直到2003年離開。他是一位令人崇敬的軟件天才,他在軟件和硬件的歷史上留下了無數(shù)令人仰止的傳奇。
          在上個世紀80年代早期,DARPA與BBN達成協(xié)議,準備將Vinton Cerf和Bob Kahn設(shè)計的TCP/IP協(xié)議添加到Berkeley UNIX中。Bill Joy被委派來完成這項任務(wù),然而他卻拒絕將BBN的TCP/IP協(xié)議棧添加到BSD中,因為在他的眼中BBN的TCP/IP實現(xiàn)還遠不夠好,于是他就寫了一個高性能的TCP/IP協(xié)議棧。John Gage回憶道,“BBN和DARPA簽署了巨額合同來實現(xiàn)TCP/IP協(xié)議,然而他們的員工所編寫的代碼遠沒有一個研究生所做的好。于是他們邀請Bill Joy參加他們的一個會議,這位研究生穿著一件T-Shirt就出現(xiàn)了,他們詢問他,‘你是如何做到的呢?’Bill回答說,‘這是非常簡單的一件事,你讀一下協(xié)議然后就可以編碼了’”。除了TCP/IP協(xié)議,基于分頁的虛擬內(nèi)存系統(tǒng)最早也是由Bill Joy添加到Berkeley UNIX內(nèi)核當中的。同時他還是vi、csh、早期Pascal編譯器的作者。
          關(guān)于Bill Joy驚人的軟件才能流傳最廣的一個傳奇是,據(jù)說他在上研究生的時候,想看看自己能不能寫一個操作系統(tǒng)出來,于是就在三天里寫了一個非常簡陋,但是可以使用的Unix系統(tǒng), 傳說就是BSD的前身。雖然如此夸張的才情令人難以置信,但是考慮到主角是Bill Joy,還是有一定的可信度的。Bill Joy碩士畢業(yè)之后,決定到工業(yè)界發(fā)展,于是就到了當時只有一間辦公室的Sun, 他作為主要設(shè)計者參與了SPARC微處理器的設(shè)計,負責設(shè)計最為關(guān)鍵的一部分電路。這樣兼精軟硬件的天才實在是讓人不得不佩服啊。1995年,Sun發(fā)布了轟動世界的Java語言。當然,Bill Joy對Java也作出了不少的貢獻,首先是JINI——一種針對分布式服務(wù)的基礎(chǔ)連接技術(shù)。任何可以內(nèi)嵌JVM的電子設(shè)備都可以通過JINI相互連接;JXTA是基于Java的P2P協(xié)議,允許互聯(lián)網(wǎng)上的軟件進行點對點交流和協(xié)作。
          這個其貌不揚的瘦高個,有著凌亂的亞麻色頭發(fā),被《財富》雜志譽為“網(wǎng)絡(luò)時代的愛迪生”的技術(shù)狂人,在短短的二十年間,創(chuàng)造了無數(shù)令人心動的軟件。在MIT的BBS上曾有一個帖子,說微軟電話面試有一道題,問“Who do you think is the best coder, and why?”雖然回復的帖子中大家都聲明列舉的best coder排名不分先后,然而大多數(shù)人仍把Bill Joy列在第一位,或許可以從一個側(cè)面驗證Bill Joy在廣大Programmer心目中的地位吧。

          Joshua Bloch : Java 2 元勛

          早在1996年,適逢Java剛剛嶄露頭角,年內(nèi)好事連連。先是1月份發(fā)布JDK 1.0,然后是5月底在舊金山召開首屆JavaOne大會,年末又是JDK 1.1緊跟其后。正是在Java技術(shù)如火如荼、大展拳腳的背景之下,Joshua Bloch來到了Sun,開始了他帶領(lǐng)Java社區(qū)步入“迦南美地”的漫長歷程。
          很快,他被從安全組調(diào)入核心平臺組,從事底層API設(shè)計。至此以后,每逢JDK的重大版本發(fā)布,總能在其中見到Joshua的“妙筆”。JDK 1.1中的java.math、1.4中的assertions,還有大家所熟識的Collections Framework皆是Joshua一手打造。其中的Collections Framework還獲得了當年的Jolt大獎。到了J2SE 5.0研發(fā)階段,身為平臺組構(gòu)架師的Joshua接掌了Tiger大旗,其核心地位已然無人可以替代。作為Tiger的代言人和領(lǐng)路人,沒有誰比Joshua更清楚Tiger。相信大家一定還記得Joshua當年仿效英國詩人William Blake所做的詠Tiger詩八首,優(yōu)雅的筆調(diào),透出大師深厚底蘊的同時,也道出了Tiger的幾大重要特性,這些特性是自JDK 1.1引入Inner Class以來,Java最大的語法改進。
          Java風雨十年,從JDK 1.1到J2SE 5.0,Joshua實在功不可沒。難怪有人戲言,假如將James Gosling比作Java之父,那么Joshua就是一手將Java “哺育”成人的Java之母。Joshua對Java的貢獻還不止于JDK,提起他的大作《Effective Java》(Addison Wesley, 2001),相信Java粉絲們一定耳熟能詳。該書榮膺2002年度Jolt大獎,且備受James Gosling推崇。書中57條頗具實用價值的經(jīng)驗規(guī)則,來自Joshua多年來在JDK開發(fā)工作中,尤其是Collections Framework設(shè)計中的實踐心得,各個有理有據(jù),剖析深入,也足見其深厚功力。該書對Java社群的影響,猶如C++社群中的《Effective C++》。Joshua對JCP的貢獻也不小。他是JSR201和JSR175的領(lǐng)導者,前者包含了Tiger四大語言特性,后者則為Java提供了元數(shù)據(jù)支持。此外,他還是JSR166的發(fā)起人之一(該JSR由Doug Lea領(lǐng)導),并且是許多其他JSR的參與者。Joshua目前是JCP為數(shù)不多的幾個執(zhí)行委員會成員之一。
          Joshua Bloch給人的印象是謙遜平和,行事低調(diào)而不喜拋頭露面,一個典型的技術(shù)人員和實干家。不過即便如此,也絲毫不會減弱他對Java技術(shù)的卓越貢獻和對Java社區(qū)的絕對影響力。有人說,如果他能更彰顯一些,就很有可能成為Java開發(fā)者中的領(lǐng)軍人物,就有如Don Box之于微軟社群。
          2004年7月初,就在Tiger發(fā)布在即之時,就在Jusha Bloch剛剛榮獲Sun“杰出工程師(Distinguished Engineer)”的稱號之時,他突然離開Sun而去了正值發(fā)展態(tài)勢迅猛的Google。當他離開Sun的消息在TSS發(fā)布之后,眾多擁躉表達了懷念與不舍之情。一年過去了,我們還沒有獲知Joshua的任何近聞,似乎又是他行事低調(diào)的一貫作風所致,不知他在Google狀況如何。希望Joshua依然能繼續(xù)“摩西未盡的事業(yè)”,以他的影響力推動Java社群繼續(xù)前行。據(jù)稱,《Effective Java》的下一版會加入Java 5.0的部分,讓我們翹首以待吧。


          Bruce Eckel : 功勛卓著的機會主義分子

          Bruce Eckel原本是一位普通的匯編程序員。不知道是什么因緣際會,他轉(zhuǎn)行去寫計算機技術(shù)圖書,卻在此大紅大紫。他成功的秘訣不外乎兩點:超人的表達能力和捕捉機會的能力。他最早的一本書是1990年代初期的《C++ Inside & Out》,隨后,在1995年他寫出了改變自己命運的《Thinking in C++》。如果說這本書充分表現(xiàn)了他作為優(yōu)秀技術(shù)作家的一面,那么隨后他寫作《Thinking in Java》并因此步入頂級技術(shù)作家行列,則體現(xiàn)了他作為優(yōu)秀的機會主義分子善于捕捉機會的另一面。寫作中擅長舉淺顯直接的小例子來說明問題,語言生動,娓娓道來,特別適合于缺乏實踐經(jīng)驗的初學者。因此《Thinking in Java》儼然成為天字第一號的Java教科書,對Java的普及與發(fā)展發(fā)揮著不可忽略的作用。不過公允地說,Bruce Eckel的書欠深刻。比如在“Thinking in…”系列中對設(shè)計模式的解說就有失大師水準。這一方面是因為書的定位非常清晰,另一方面也是因為Bruce太過分心趕潮流,未能深入之故。TIJ之后,他預(yù)言Python將火,就匆匆跑去寫了半本《Thinking in Python》。后來Python并未如期而旺,于是他也就把書稿撂在那里不過問了,機會主義的一面暴露無遺。我們也可以善意的猜測一下,他的下一個投機對象會是什么呢?Ruby?.NET?MDA?總之,是什么我都不奇怪。


          Rickard Oberg :J2EE奇才

          Oberg的作品很多,流行的代碼生成工具XDoclet和MVC框架WebWork都出自他的手筆。這兩個框架有一個共同的特點,即它們的功能雖然簡單,但設(shè)計都非常優(yōu)雅靈活,能夠很方便地擴展新功能甚至移植到新環(huán)境下使用。優(yōu)雅的設(shè)計源自O(shè)berg的過人才華,簡單的功能則折射出他玩世不恭的人生態(tài)度。正是這兩種特質(zhì)的融合,才造就了這個不世出的奇才。
          1999年,JDK 1.3發(fā)布,其中帶來了一個重要的新特性:動態(tài)代理(Dynamic Proxy)。當所有人都還在對這項新技術(shù)的用途感到迷惑時,Oberg發(fā)現(xiàn)用它便可以輕松攻克EJB容器實現(xiàn)中的一些難關(guān)。這一發(fā)現(xiàn)的產(chǎn)物就是一本《Mastering RMI》,以及大名鼎鼎的JBoss應(yīng)用服務(wù)器。但Oberg很快又讓世人見識了他的玩世不恭。由于和總經(jīng)理Marc Fleury在經(jīng)營理念上不合,Oberg抱怨“法國的天空總讓我感到壓抑”,甩手離開了自己一手打造的JBoss。此后的幾年里,他和老友Hani Suleiman不斷地對JBoss的“專業(yè)開源”模式和Marc Fleury的商人味道冷嘲熱諷,讓眾人為他的孩子氣扼腕嘆息。
          2002年10月,微軟推出Petstore示例應(yīng)用的.NET版本,并宣稱其性能比Java Petstore高出數(shù)倍。正是Oberg深入分析這個示例應(yīng)用的源代碼,在第一時間指出它大量運用了SQL Server專有的特性,性能對比根本不具參考價值。后來Oberg又先后關(guān)注了AOP和IoC容器,兩者都成為了J2EE架構(gòu)的新寵。

          Doug Lea : 世界上對Java影響力最大的個人
          文/KIT

          如果IT的歷史,是以人為主體串接起來的話,那么肯定少不了Doug Lea。這個鼻梁掛著眼鏡,留著德王威廉二世的胡子,臉上永遠掛著謙遜靦腆笑容,服務(wù)于紐約州立大學Oswego分校計算器科學系的老大爺。
          說他是這個世界上對Java影響力最大的個人,一點也不為過。因為兩次Java歷史上的大變革,他都間接或直接的扮演了舉足輕重的腳色。一次是由JDK 1.1到JDK 1.2,JDK1.2很重要的一項新創(chuàng)舉就是Collections,其Collection的概念可以說承襲自Doug Lea于1995年發(fā)布的第一個被廣泛應(yīng)用的collections;一次是2004年所推出的Tiger。Tiger廣納了15項JSRs(Java Specification Requests)的語法及標準,其中一項便是JSR-166。JSR-166是來自于Doug編寫的util.concurrent包。
          值得一提的是: Doug Lea也是JCP (Java小區(qū)項目)中的一員。
          Doug是一個無私的人,他深知分享知識和分享蘋果是不一樣的,蘋果會越分越少,而自己的知識并不會因為給了別人就減少了,知識的分享更能激蕩出不一樣的火花。《Effective JAVA》這本Java經(jīng)典之作的作者Joshua Blosh便在書中特別感謝Doug是此書中許多構(gòu)想的共鳴板,感謝Doug大方分享豐富而又寶貴的知識。這位并發(fā)編程的大師級人物的下一步,將會帶給Java怎樣的沖擊,不禁令人屏息以待。

          Scott McNealy :SUN十年來的掌舵者
          文/KIT

          McNealy,Sun的CEO、總裁兼董事長。他曾經(jīng)狂傲的說:“摧毀微軟是我們每個人的任務(wù)。”這位英勇的硅谷英雄,似乎帶頭起義,試圖組織一個反微軟陣線聯(lián)盟,以對抗微軟這股龐大的托拉斯惡勢力。他時常口出驚人之語,在公開場合大肆的批評微軟,并曾經(jīng)說微軟的.NET是.NOT。
          Scott McNealy先后畢業(yè)于哈佛大學及史丹佛大學,分別持有經(jīng)濟學學士學位及企管碩士。1982年MBA畢業(yè)的他和三個同學共同合伙創(chuàng)建了Sun,并于1984年成為Sun的執(zhí)行官。“要么吞了別人,不然就被別人吞了”是Scott McNealy的名言錄之一。他擅長以信念帶動員工,鼓舞士氣。極富自信的他,對于認定的事,總是堅持自己的想法,因此有人形容他是一個剛愎自用的決策者。
          身為Sun這艘船的掌舵者,Scott McNealy能夠看多遠,Sun就能走多遠。Scott McNealy認為將來軟件界是一個只有服務(wù),沒有產(chǎn)品的世代。他希望打造出Sun不是一個純靠硬件賺錢的公司。從Open Source到Open Solaris,Sun希望可以成為提供整合性解決方案的服務(wù)廠商。Solaris 10 + UltraSPARC是否可以像Scott McNealy希望的是下一匹世紀黑馬呢?Sun是否能以股價來證明華爾街分析師及普羅大眾的誹短流長?Scott McNealy是否能帶領(lǐng)著Sun成為繼微軟之后的下一個巨人,一場場IT界的爭霸戰(zhàn)值得我們拭目以待。


          Rod Johnson : 用一本書改變了Java世界的人

          Rod在悉尼大學不僅獲得了計算機學位,同時還獲得了音樂學位。更令人吃驚的是在回到軟件開發(fā)領(lǐng)域之前,他還獲得了音樂學的博士學位。有著相當豐富的C/C++技術(shù)背景的Rod早在1996年就開始了對Java服務(wù)器端技術(shù)的研究。他是一個在保險、電子商務(wù)和金融行業(yè)有著豐富經(jīng)驗的技術(shù)顧問,同時也是JSR-154(Servlet 2.4)和JDO 2.0的規(guī)范專家、JCP的積極成員。
          真正引起了人們的注意的,是在2002年Rod Johnson根據(jù)多年經(jīng)驗撰寫的《Expert One-on-One J2EE Design and Development》。其中對正統(tǒng)J2EE架構(gòu)的臃腫、低效的質(zhì)疑,引發(fā)了人們對正統(tǒng)J2EE的反思。這本書也體現(xiàn)了Rod Johnson對技術(shù)的態(tài)度,技術(shù)的選擇應(yīng)該基于實證或是自身的經(jīng)驗,而不是任何形式的偶像崇拜或者門戶之見。正是這本書真正地改變了Java世界。基于這本書的代碼,Rod Johnson創(chuàng)建了輕量級的容器Spring。Spring的出現(xiàn),使得正統(tǒng)J2EE架構(gòu)一統(tǒng)天下的局面被打破。基于Struts+Hibernate+Spring的J2EE架構(gòu)也逐漸得到人們的認可,甚至在大型的項目架構(gòu)中也逐漸開始應(yīng)用。
          Rod Johnson的新作《Expert One-on-one J2EE Development without JEB》則更讓人吃驚,單單“Without EJB”一詞就會讓大多數(shù)J2EE架構(gòu)師大跌眼鏡了。不過Rod Johnson可能僅僅是想通過“Without EJB”一詞表明應(yīng)該放開門戶之見。這也是Rod Johnson一貫的作風,。也許正是這種思想,促使得Rod Johnson創(chuàng)建了Spring,真正改變了Java世界。

           

          Alan Kay :Java的精神先鋒

          Sun的官方Java教材中有一句話,說Java是“C++的語法與Smalltalk語義的結(jié)合”。而Smalltalk的創(chuàng)造者就是Alan Kay。
          Alan Kay于1970年加入Xerox公司的Palo Alto研究中心。早在70年代初期,Alan Kay等人開發(fā)了世界上第二個面向?qū)ο笳Z言Smalltalk,因此,Alan Kay被譽為Smalltalk之父。2003年,Alan Key因為在面向?qū)ο蟪绦蛟O(shè)計上的杰出貢獻,獲得了有計算機界的諾貝爾獎之稱的ACM Turing Award。
          Alan Kay成名于Smapltalk和OOP,而Java雖然在語言上類似于C,但是在語義上非常接近Smalltalk,很多Java中的設(shè)計思想在Alan Kay的文獻中找到根源,也有些人將Alan Kay尊為Java思想的先驅(qū)。不過遺憾的是似乎Alan Kay老先生對Java并不買賬,反倒攻擊說Java是存在致命缺陷的編程語言,Java的成功不是由于Java本身的內(nèi)在價值,而是其商業(yè)化的成功。Alan Kay欣賞的是Lisp,他認為Lisp是軟件的麥克斯韋方程,其中的許多想法是軟件工程和計算機科學的一部分。看來擁有Alan Kay這樣一位重量級的Java先驅(qū)仍是我們Java一廂情愿的單戀吧。


          Kent Beck : 領(lǐng)導的敏捷潮

          Beck全家似乎都彌漫著技術(shù)的味道。生長在硅谷, 有著一個對無線電癡迷的祖父,以及一個電器工程師父親。從小就引導Kent Beck成為了業(yè)余無線電愛好者。
          在俄勒岡州大學讀本科期間,Kent Beck就開始研究起模式。然而在他最終拿到計算機學位之前,他卻是在計算機和音樂中交替學習。似乎Java大師都能夠有這樣的能耐,另一Java大牛Rod Johnson同樣也擁有音樂學的博士學位。
          Kent Beck一直倡導軟件開發(fā)的模式定義。早在1993年,他就和Grady Booch(UML之父)發(fā)起了一個團隊進行這個方面的研究。雖然著有了《Smalltalk Best Practice Patterns》一書,但這可能并不是Kent Beck最大的貢獻。他于1996年在DaimlerChrysler啟動的關(guān)于軟件開發(fā)的項目,才真正地影響后來的軟件開發(fā)。這次的杰作就是XP(極限編程)的方法學。
          和軟件開發(fā)大師Martin Fowler合著的《Planning Extreme Programming》可謂是關(guān)于XP的奠基之作。從此,一系列的作品如《Test Driven Development: By Example》,《Extreme Programming Explained: Embrace Change》讓更多的人領(lǐng)略到了極限編程的精髓,也逐步導致了極限編程的流行。
          Kent Beck的貢獻遠不僅如此。對于眾多的Java程序員來說,他和Erich Gamma共同打造的JUnit,意義更加重大。也許正式這個簡單而又強大的工具,讓眾多的程序員更加認可和信賴極限編程,從而引起了Java敏捷開發(fā)的狂潮吧。



          轉(zhuǎn)載人員:Nicholas
          posted @ 2010-08-30 11:27 obpm 閱讀(197) | 評論 (0)編輯 收藏

          功能:在線拍照
          簡介:用flex與java結(jié)合實現(xiàn)在線拍照
          需求:為了滿足希望通過攝像頭拍照的圖片,然后通過服務(wù)器來展示需要
          效果:
                      后臺: 

                      前臺:


          實現(xiàn)代碼:
          flex:

          <?xml version="1.0" encoding="utf-8"?>
          <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="388" height="222" creationComplete="initApp()" backgroundColor="#A6C9E2">
               
          <mx:Style>
                   Alert{font-size:12px;}
               
          </mx:Style>
               
          <mx:Script>
                   
          <![CDATA[
                       import mx.events.CloseEvent;
                       import mx.rpc.events.FaultEvent;
                       import mx.rpc.events.ResultEvent;
                       import mx.controls.Alert;
                       import mx.core.Application;
                      
                       private static const DEFAULT_CAMERA_WIDTH:Number = 160; //攝像頭顯示寬度
                       private static const DEFAULT_CAMERA_HEIGHT:Number = 120; //攝像頭顯示高度
                       private var DEFAULT_WEBSERVICE_URL:String = ""; //WebService地址
                       private var str:String;
                      
                       private var m_camera:Camera; //定義一個攝像頭
                       private var m_localVideo:Video; //定義一個本地視頻
                       private var m_pictureBitmapData:BitmapData //定義視頻截圖
                       [Bindable]
                       private var m_pictureData:String;
                      
                       private function initApp():void
                       {
                           t_btn_Shooting.enabled = false;
                           t_ban_Save.enabled = false;
                           initCamera();
                           DEFAULT_WEBSERVICE_URL = Application.application.parameters.contextPath+"/onLineTakePhotoServlet";
                           t_ws_SavePicture.url=DEFAULT_WEBSERVICE_URL;
                       }
                      
                       //初始化攝像頭
                       private function initCamera():void
                       {
                           m_camera = Camera.getCamera();
                           if(m_camera != null)
                           {
                               m_camera.addEventListener(StatusEvent.STATUS,__onCameraStatusHandler);
                              
                               m_camera.setMode(DEFAULT_CAMERA_WIDTH,DEFAULT_CAMERA_HEIGHT,30);
                               m_localVideo = new Video();
                               m_localVideo.width = DEFAULT_CAMERA_WIDTH;
                               m_localVideo.height = DEFAULT_CAMERA_HEIGHT;
                               m_localVideo.attachCamera(m_camera);
                               t_vd_Video.addChild(m_localVideo);
                           }
                           else
                           {
                               Alert.show("沒有找到攝像頭,是否重新查找。","提示:",Alert.OK|Alert.NO,this,__InitCamera);
                               return;
                           }
                       }
                      
                       //拍照按鈕事件,進行視頻截圖
                       private function SnapshotPicture():void
                       {
                           m_pictureBitmapData = new BitmapData(DEFAULT_CAMERA_WIDTH,DEFAULT_CAMERA_HEIGHT);
                           m_pictureBitmapData.draw(t_vd_Video,new Matrix());
                          
                           var m_pictureBitmap:Bitmap = new Bitmap(m_pictureBitmapData);
                           t_img_Picture.addChild(m_pictureBitmap);
                          
                           t_panel_Picture.visible = true;
                           t_ban_Save.enabled = true;
                       }
                      
                       //保存按鈕事件,保存視頻截圖
                       //通過WebService保存
                       private function SavePicture():void
                       {
                           m_pictureData = "";
                           for(var i:int = 0; i < DEFAULT_CAMERA_WIDTH; i++)
                           {
                               for(var j:int = 0; j < DEFAULT_CAMERA_HEIGHT; j++)
                               {
                                   if(m_pictureData.length > 0)
                                   {
                                       m_pictureData += "," + m_pictureBitmapData.getPixel32(i,j).toString();
                                   }
                                   else
                                   {
                                       m_pictureData = m_pictureBitmapData.getPixel32(i,j).toString();
                                   }
                               }
                           }
                           
                           var params:URLVariables = new URLVariables();
               params.width = DEFAULT_CAMERA_WIDTH;
               params.height = DEFAULT_CAMERA_HEIGHT;
               params.bitmap_data = m_pictureData;
               t_ws_SavePicture.send(params);
                       }
                      
                       //檢測攝像頭權(quán)限事件
                       private function __onCameraStatusHandler(event:StatusEvent):void
                       {
                           if(!m_camera.muted)
                           {
                               t_btn_Shooting.enabled = true;
                           }
                           else
                           {
                               Alert.show("無法鏈接到活動攝像頭,是否重新檢測。","提示:",Alert.OK|Alert.NO,this,__InitCamera);
                           }
                           m_camera.removeEventListener(StatusEvent.STATUS,__onCameraStatusHandler);
                       }
                      
                       //當攝像頭不存在,或連接不正常時重新獲取
                       private function __InitCamera(event:CloseEvent):void
                       {
                           if(event.detail == Alert.OK)
                           {
                               initApp();
                           }
                       }
                      
                       //WebService保存圖片成功事件
                       private function __onSavePictureResult(event:ResultEvent):void
                       {
                           //trace(event.result);
                           if(event.result.toString() != "保存失敗")
                           {
                             str = event.result.toString();
                             
                               Alert.show("保存成功,是否關(guān)閉窗口?","提示",3,this,__onAlertCloseHandler);
                           }
                           else
                           {
                               Alert.show(event.result.toString(),"提示",Alert.OK);
                           }
                       }
                      
                       //連接WebService失敗事件
                       private function __onSavePictureFault(event:FaultEvent):void
                       {
                           //Alert.show(event.fault.toString(),"提示",Alert.OK);
                           Alert.show("連接服務(wù)器失敗。","提示",Alert.OK);
                       }
                      
                       //保存圖片成功后的彈出窗口確認事件
                       private function __onAlertCloseHandler(event:CloseEvent):void
                       {
                           if(event.detail == Alert.YES)
                           {
                              ExternalInterface.call("setValueToField",str);
                           }
                       }
                   
          ]]>
               
          </mx:Script>
               
          <mx:HTTPService id="t_ws_SavePicture" showBusyCursor="true" method="POST" useProxy="false" result="__onSavePictureResult(event)" fault="__onSavePictureFault(event)"/>
               
          <mx:Panel x="10" y="10" width="180" height="200" layout="absolute" title="視頻拍照" fontSize="12">
                   
          <mx:VideoDisplay id="t_vd_Video" width="160" height="120"/>
                   
          <mx:ControlBar horizontalAlign="right">
                       
          <mx:Button id="t_btn_Shooting" label="拍照" click="SnapshotPicture()"/>
                   
          </mx:ControlBar>
               
          </mx:Panel>
               
          <mx:Panel id="t_panel_Picture" x="198" y="10" width="180" height="200" layout="absolute" title="拍照圖片" fontSize="12" visible="false">
                   
          <mx:Image id="t_img_Picture" x="0" y="0" width="160" height="120"/>
                   
          <mx:ControlBar   horizontalAlign="right">
                       
          <mx:Button id="t_ban_Save" label="保存" click="SavePicture()" />
                   
          </mx:ControlBar>
               
          </mx:Panel>
          </mx:Application>



          java:

          package cn.myapps.core.onlinetakephoto;

          import java.awt.Color;
          import java.awt.image.BufferedImage;
          import java.io.ByteArrayOutputStream;
          import java.io.DataOutputStream;
          import java.io.File;
          import java.io.FileOutputStream;
          import java.io.IOException;

          import javax.imageio.ImageIO;
          import javax.servlet.ServletException;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;

          import cn.myapps.constans.Environment;
          import cn.myapps.util.sequence.Sequence;

          /**
           * Servlet implementation class onLineTakePhotoServlet
           
          */
          public class onLineTakePhotoServlet extends HttpServlet {
           
          private static final long serialVersionUID = 1L;
              
           
          private Environment env = Environment.getInstance();
           
           
          public void doGet(HttpServletRequest request, HttpServletResponse response)    
           
          throws ServletException, IOException {    
           processRequest(request, response);    
           }    
             
           
          public void doPost(HttpServletRequest request, HttpServletResponse response)    
            
          throws ServletException, IOException {    
           processRequest(request, response);    
           }    
           
           
          public void processRequest(HttpServletRequest request, HttpServletResponse response)

              
          throws ServletException, IOException {
            response.setContentType(
          "text/html;charset=UTF-8");   
                  response.setHeader(
          "Pragma""No-cache");   
                  response.setHeader(
          "Cache-Control""no-cache");   
                  response.setDateHeader(
          "Expires"0);   
            
                  String bitmap_data 
          = request.getParameter("bitmap_data");   
                  
          int width = Integer.parseInt(request.getParameter("width"));   
                  
          int height = Integer.parseInt(request.getParameter("height"));   
                  BufferedImage img 
          = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);   
            
          try {   
                      
          int w = width;   
                      
          int h = height;   
                      
          int[] pixels = new int[w * h];   
                      String[] m_tempPics 
          = bitmap_data.split(",");   
                      
          for (int x = 0; x < w; x++) {   
                          
          for (int y = 0; y < h; y++) {   
                              Long pic_argb 
          = Long.parseLong(m_tempPics[x * h + y]);   
                              
          int a = (int) (pic_argb >> 24 & 0xFF);   
                              
          int r = (int) (pic_argb >> 16 & 0xFF);   
                              
          int g = (int) (pic_argb >> 8 & 0xFF);   
                              
          int b = (int) (pic_argb & 0xFF);   
                              pixels[y 
          * w + x] = new Color(r, g, b, a).getRGB();   
                          }   
                      }   
                      img.setRGB(
          00, w, h, pixels, 0, w);   
                      img.flush();   
                      ByteArrayOutputStream bao 
          = new ByteArrayOutputStream();   
                      ImageIO.write(img, 
          "jpg", bao);   
                      
          byte[] data = bao.toByteArray();  
                      String filePath 
          = env.getRealPath("/uploads/photo");
                      
          //判斷路徑是否存在,若不存在則創(chuàng)建路徑
                      File upDir = new File(filePath);
                      
          if (!upDir.exists())
                      {
                          upDir.mkdir();
                      }
                      
          //生成隨機文件名
                      String saveName = Sequence.getSequence();
                      String fileName 
          = saveName + ".jpg";
                      
          //寫圖片
                      File f = new File(filePath+"\\" + fileName);
                DataOutputStream dos 
          = new DataOutputStream(new FileOutputStream(f));
                dos.write(data);
                dos.flush();
                dos.close();
                response.setContentType(
          "text/xml");   
                      response.getWriter().write(
          "/uploads/photo/" + fileName);   
                  }
                  
          catch(Exception ex)
                  {
                   response.setContentType(
          "text/xml");   
                      response.getWriter().write(
          "保存失敗");   
                  }
           }

          }

           


          源碼:/Files/obpm/onlinetakephoto.rar

           原創(chuàng)人員:Denny

          posted @ 2010-08-29 21:52 obpm 閱讀(5518) | 評論 (5)編輯 收藏

          LDAP快速入門

          1. LDAP簡介

            LDAP(輕量級目錄訪問協(xié)議,Lightweight Directory Access Protocol)是實現(xiàn)提供被稱為目錄服務(wù)的信息服務(wù)。目錄服務(wù)是一種特殊的數(shù)據(jù)庫系統(tǒng),其專門針對讀取,瀏覽和搜索操作進行了特定的優(yōu)化。目錄一般用來包含描述性的,基于屬性的信息并支持精細復雜的過濾能力。目錄一般不支持通用數(shù)據(jù)庫針對大量更新操作操作需要的復雜的事務(wù)管理或回卷策略。而目錄服務(wù)的更新則一般都非常簡單。這種目錄可以存儲包括個人信息、web鏈結(jié)、jpeg圖像等各種信息。為了訪問存儲在目錄中的信息,就需要使用運行在TCP/IP 之上的訪問協(xié)議—LDAP。

           

            LDAP目錄中的信息是是按照樹型結(jié)構(gòu)組織,具體信息存儲在條目(entry)的數(shù)據(jù)結(jié)構(gòu)中。條目相當于關(guān)系數(shù)據(jù)庫中表的記錄;條目是具有區(qū)別名DN (Distinguished Name)的屬性(Attribute),DN是用來引用條目的,DN相當于關(guān)系數(shù)據(jù)庫表中的關(guān)鍵字(Primary Key)。屬性由類型(Type)和一個或多個值(Values)組成,相當于關(guān)系數(shù)據(jù)庫中的字段(Field)由字段名和數(shù)據(jù)類型組成,只是為了方便檢索的需要,LDAP中的Type可以有多個Value,而不是關(guān)系數(shù)據(jù)庫中為降低數(shù)據(jù)的冗余性要求實現(xiàn)的各個域必須是不相關(guān)的。LDAP中條目的組織一般按照地理位置和組織關(guān)系進行組織,非常的直觀。LDAP把數(shù)據(jù)存放在文件中,為提高效率可以使用基于索引的文件數(shù)據(jù)庫,而不是關(guān)系數(shù)據(jù)庫。類型的一個例子就是mail,其值將是一個電子郵件地址。

           

          LDAP的信息是以樹型結(jié)構(gòu)存儲的,在樹根一般定義國家(c=CN)或域名(dc=com),在其下則往往定義一個或多個組織 (organization)(o=Acme)或組織單元(organizational units) (ou=People)。一個組織單元可能包含諸如所有雇員、大樓內(nèi)的所有打印機等信息。此外,LDAP支持對條目能夠和必須支持哪些屬性進行控制,這是有一個特殊的稱為對象類別(objectClass)的屬性來實現(xiàn)的。該屬性的值決定了該條目必須遵循的一些規(guī)則,其規(guī)定了該條目能夠及至少應(yīng)該包含哪些屬性。例如:inetorgPerson對象類需要支持sn(surname)和cn(common name)屬性,但也可以包含可選的如郵件,電話號碼等屬性。

           

          2. LDAP簡稱對應(yīng)

          1. o– organization(組織-公司)
          2. ou – organization unit(組織單元-部門)
          3. c - countryName(國家)
          4. dc - domainComponent(域名)
          5. sn – suer name(真實名稱)
          6. cn - common name(常用名稱)

           

          3. 目錄設(shè)計

          設(shè)計目錄結(jié)構(gòu)是LDAP最重要的方面之一。下面我們將通過一個簡單的例子來說明如何設(shè)計合理的目錄結(jié)構(gòu)。該例子將通過Netscape地址薄來訪文。假設(shè)有一個位于美國US(c=US)而且跨越多個州的名為Acme(o=Acme)的公司。Acme希望為所有的雇員實現(xiàn)一個小型的地址薄服務(wù)器。

           

            我們從一個簡單的組織DN開始: 

              dn: o=Acme, c=US

           

            Acme所有的組織分類和屬性將存儲在該DN之下,這個DN在該存儲在該服務(wù)器的目錄是唯一的。Acme希望將其雇員的信息分為兩類:管理者(ou= Managers)和普通雇員(ou=Employees),這種分類產(chǎn)生的相對區(qū)別名(RDN,relative distinguished names。表示相對于頂點DN)就shi :

           

              dn: ou=Managers, o=Acme, c=US

              dn: ou=Employees, o=Acme, c=US

           

            在下面我們將會看到分層結(jié)構(gòu)的組成:頂點是US的Acme,下面是管理者組織單元和雇員組織單元。因此包括Managers和Employees的DN組成為:

              dn: cn=Jason H. Smith, ou=Managers, o=Acme, c=US

              dn: cn=Ray D. Jones, ou=Employees, o=Acme, c=US

              dn: cn=Eric S. Woods, ou=Employees, o=Acme, c=US

           

            為了引用Jason H. Smith的通用名(common name )條目,LDAP將采用cn=Jason H. Smith的RDN。然后將前面的父條目結(jié)合在一起就形成如下的樹型結(jié)構(gòu):

           

              cn=Jason H. Smith

                  + ou=Managers

                      + o=Acme

                          + c=US

                                         -> dn: cn=Jason H. Smith,ou=Managers,o=Acme,c=US

           

           

            現(xiàn)在已經(jīng)定義好了目錄結(jié)構(gòu),下一步就需要導入目錄信息數(shù)據(jù)。目錄信息數(shù)據(jù)將被存放在LDIF文件中,其是導入目錄信息數(shù)據(jù)的默認存放文件。用戶可以方便的編寫Perl腳本來從例如/etc/passwd、NIS等系統(tǒng)文件中自動創(chuàng)建LDIF文件。

           

            下面的實例保存目錄信息數(shù)據(jù)為testdate.ldif文件,該文件的格式說明將可以在man ldif中得到。

            在添加任何組織單元以前,必須首先定義Acme DN: 

              dn: o=Acme, c=US

              objectClass: organization

           

            這里o屬性是必須的

              o: Acme

           

            下面是管理組單元的DN,在添加任何管理者信息以前,必須先定義該條目。

              dn: ou=Managers, o=Acme, c=US

              objectClass: organizationalUnit

          這里ou屬性是必須的。

           

          ou: Managers

            第一個管理者DN:

              dn: cn=Jason H. Smith, ou=Managers, o=Acme, c=US

              objectClass: inetOrgPerson

            cn和sn都是必須的屬性:

              cn: Jason H. Smith

              sn: Smith

            但是還可以定義一些可選的屬性:

              telephoneNumber: 111-222-9999

              mail: headhauncho@acme.com

              localityName: Houston

           

            可以定義另外一個組織單元:

              dn: ou=Employees, o=Acme, c=US

              objectClass: organizationalUnit

              ou: Employees

           

            并添加雇員信息如下:

              dn: cn=Ray D. Jones, ou=Employees, o=Acme, c=US

              objectClass: inetOrgPerson

              cn: Ray D. Jones

              sn: Jones

              telephoneNumber: 444-555-6767

              mail: jonesrd@acme.com

              localityName: Houston

              dn: cn=Eric S. Woods, ou=Employees, o=Acme, c=US

              objectClass: inetOrgPerson

              cn: Eric S. Woods

              sn: Woods

              telephoneNumber: 444-555-6768

              mail: woodses@acme.com

              localityName: Houston

           

           

          4. 配置OpenLDAP

          本文實踐了在 Windows 下安裝配 openldap,并添加一個條目,LdapBrowser 瀏覽,及 Java 程序連接 openldap 的全過程。

           

          1. 下載安裝 openldap for windows,當前版本2.2.29下載地址:http://download.bergmans.us/openldap/openldap-2.2.29/openldap-2.2.29-db-4.3.29-openssl-0.9.8a-win32_Setup.exe

              相關(guān)鏈接:http://lucas.bergmans.us/hacks/openldap/

             安裝很簡單,一路 next 即可,假設(shè)我們安裝在 c:\openldap

           

          2. 配置 openldap,編輯 sldap.conf 文件

             1) 打開 c:\openldap\sldap.conf,找到

              include  C:/openldap/etc/schema/core.schema,在它后面添加

              include  C:/openldap/etc/schema/cosine.schema

              include  C:/openldap/etc/schema/inetorgperson.schema

           

              接下來的例子只需要用到以上三個 schema,當然,如果你覺得需要的話,你可以把其他的 schema 全部添加進來

              include  C:/openldap/etc/schema/corba.schema

              include  C:/openldap/etc/schema/dyngroup.schema

              include  C:/openldap/etc/schema/java.schema

              include  C:/openldap/etc/schema/misc.schema

              include  C:/openldap/etc/schema/nis.schema

              include  C:/openldap/etc/schema/openldap.schema

           

             2) 還是在 sldap.conf 文件中,找到

              suffix  "dc=my-domain,dc=com"

              rootdn  "cn=Manager,dc=my-domain,dc=com"

              把這兩行改為

              suffix "o=teemlink,c=cn" 

              rootdn "cn=Manager,o=teemlink,dc=cn"

           

              suffix 就是看自己如何定義了,后面步驟的 ldif 文件就必須與它定義了。還要注意到這個配置文件中有一個 rootpw  secret,這個 secret 是 cn=Manager 的密碼,以后會用到,不過這里是明文密碼,你可以用命令: slappasswd -h {MD5} -s secret 算出加密的密碼 {MD5}Xr4ilOzQ4PCOq3aQ0qbuaQ== 取代配置中的 secret。

           

          3. 啟動 openldap

              CMD 進入到 c:\openldap 下,運行命令 sldapd -d 1

              用可以看到控制臺下打印一片信息,openldap 默認是用的 Berkeley DB 數(shù)據(jù)庫存儲目錄數(shù)據(jù)的。

           

          4. 建立條目,編輯導入 ldif 文件

             1) 新建一個 ldif(LDAP Data Interchanged Format) 文件(純文本格式),例如 test.ldif,文件內(nèi)容如下:

             

          dn: o=teemlink

          objectclass: top

          objectclass: organization

          o: develop

           

             2) 執(zhí)行命令:ldapadd -l test.ldif

           

          5. 使用LDAP Browser進行訪問

                 5.1安裝LDAP Browser2.6軟件,進行如下操作:

             

            

           

          5.2顯示效果

           

           

          5. Java操作LDAP

           

          5.1 用JNDI進訪問

          package cn.myapps.test;

          import java.util.Hashtable;
          import javax.naming.Context;
          import javax.naming.NamingException;
          import javax.naming.directory.Attributes;
          import javax.naming.directory.DirContext;
          import javax.naming.directory.InitialDirContext;

          public class LdapTest {
          public void JNDILookup() {
          String root
          = "o=teemlink,c=cn";
          Hashtable env
          = new Hashtable();
          env.put(Context.INITIAL_CONTEXT_FACTORY,
          "com.sun.jndi.ldap.LdapCtxFactory");
          env.put(Context.PROVIDER_URL,
          "ldap://192.168.0.30/" + root);
          env.put(Context.SECURITY_AUTHENTICATION,
          "simple");
          env.put(Context.SECURITY_PRINCIPAL,
          "cn=Nicholas,ou=develop,o=teemlink,c=cn");
          env.put(Context.SECURITY_CREDENTIALS,
          "123456");
          DirContext ctx
          = null;

          try {
          ctx
          = new InitialDirContext(env);
          Attributes attrs
          = ctx.getAttributes("cn=Nicholas,ou=develop");
          System.out.println(
          "Last Name: " + attrs.get("sn").get());
          System.out.println(
          "認證成功");
          }
          catch (javax.naming.AuthenticationException e) {
          e.printStackTrace();
          System.out.println(
          "認證失敗");
          }
          catch (Exception e) {
          System.out.println(
          "認證出錯:");
          e.printStackTrace();
          }
          if (ctx != null) {
          try {
          ctx.close();
          }
          catch (NamingException e) {
          // ignore
          }
          }
          }

          public static void main(String[] args) {
          LdapTest LDAPTest
          = new LdapTest();
          LDAPTest.JNDILookup();
          }
          }

           

          5.2 用JLDAP進訪問

          訪問地址:http://www.openldap.org/jldap/ 并下載相關(guān)lib

           

          import com.novell.ldap.*;

          import java.io.UnsupportedEncodingException;

          public class List

          {

          public static void main(String[] args)

          {
          int ldapPort = LDAPConnection.DEFAULT_PORT;
          int searchScope = LDAPConnection.SCOPE_ONE;
          int ldapVersion = LDAPConnection.LDAP_V3;
          boolean attributeOnly = false;
          String attrs[]
          = null;
          String ldapHost
          = "192.168.0.30";
          String loginDN
          = "cn=Manager,o=teemlink,c=cn";
          String password
          = "secret";
          String searchBase
          = "ou=develop,o=teemlink,c=cn";
          String searchFilter
          = "objectClass=*";

          LDAPConnection lc
          = new LDAPConnection();
          try {
          // connect to the server
          lc.connect(ldapHost, ldapPort);

          // bind to the server
          lc.bind(ldapVersion, loginDN, password.getBytes("UTF8"));

          LDAPSearchResults searchResults
          =

          lc.search(searchBase,
          // container to search
          searchScope, // search scope
          searchFilter, // search filter
          attrs, // "1.1" returns entry name only
          attributeOnly); // no attributes are returned

          // print out all the objects
          while (searchResults.hasMore()) {
          LDAPEntry nextEntry
          = null;
          try {
          nextEntry
          = searchResults.next();
          System.out.println(
          "\n" + nextEntry.getDN());
          System.out.println(nextEntry.getAttributeSet());
          }
          catch (LDAPException e) {
          System.out.println(
          "Error: " + e.toString());
          // Exception is thrown, go for next entry
          continue;
          }
          }

          // disconnect with the server
          lc.disconnect();

          }
          catch (LDAPException e) {
          System.out.println(
          "Error: " + e.toString());
          }
          catch (UnsupportedEncodingException e) {
          System.out.println(
          "Error: " + e.toString());
          }
          System.exit(
          0);
          }
          }

           

          5.3 用JDBC-LDAP進訪問

          訪問地址:http://www.openldap.org/jdbcldap/ 并下載相關(guān)lib

           

          package jdbcldap;

          import java.sql.Connection;
          import java.sql.DriverManager;
          import java.sql.ResultSet;
          import java.sql.Statement;

          public class JdbcLdap {

          /**
          *
          @param args
          *
          @throws Exception
          */
          public static void main(String[] args) throws Exception {
          Class.forName(
          "com.octetstring.jdbcLdap.sql.JdbcLdapDriver");
          String ldapConnectString
          = "jdbc:ldap://192.168.0.30/o=teemlink,c=cn?SEARCH_SCOPE:=subTreeScope";
          Connection con
          = DriverManager.getConnection(ldapConnectString, "cn=Manager,o=teemlink,c=cn", "secret");

          String sql
          = "SELECT * FROM ou=develop,o=teemlink,c=cn";

          Statement sat
          = con.createStatement();
          ResultSet rs
          = sta.executeQuery(sql);
          while (rs.next()) {
          System.out.println(rs.getString(
          1));
          }

          if (con != null)
          con.close();
          }
          }

           

          原創(chuàng)人員:Nicholas

           

           


          文章來源:http://www.cnblogs.com/obpm/archive/2010/08/28/1811065.html
          posted @ 2010-08-28 14:38 obpm 閱讀(1932) | 評論 (0)編輯 收藏

          以子類取代類型編碼

           Replace Type Code with Subclasses

          1. 何謂重構(gòu)

           

          1.1名詞解釋

            對軟件內(nèi)部結(jié)構(gòu)的一種調(diào)整,目的是在不改變「軟件之可察行為」前提下,提高其可理解性,降低其修改成本。

            

          1.2動詞解釋

            使用一系列重構(gòu)準則(手法),在不改變「軟件之可察行為」前提下,調(diào)整其結(jié)構(gòu)。

           

          2. 為何重構(gòu)

           

          2.1「重構(gòu)」改進軟件設(shè)計

            同樣完成一件事,設(shè)計不良的程序往往需要更多代碼,這常常是因為代碼在不同的方使用完全相同的語句做同樣的事。因此改進設(shè)計的一個重要方向就是消除重復代碼(Duplicate Code)

           

          2.2「重構(gòu)」使軟件更易被理解

            你的源碼還有其它讀者:數(shù)個月之后可能會有另一位程序員嘗試讀懂你的代碼并做一些修改。我們很容易忘記這第二位讀者,但他才是最重要的。計算器是否多花了數(shù)個鐘頭進行編譯,又有什么關(guān)系呢?如果一個程序員花費一周時間來修改某段代碼,那才關(guān)系重大— 如果他理解你的代碼,這個修改原本只需一小時

           

          2.3「重構(gòu)」助你找到臭蟲 ( bugs)

            Kent Beck 經(jīng)常形容自己的一句話:『我不是個偉大的程序員;我只是個有著些優(yōu)秀習慣的好程序員而已。』重構(gòu)能夠幫助我更有效地寫出強固穩(wěn)健(robust)的代碼。 

           

          2.4「重構(gòu)」助你提高編程速度

            終于,前面的一切都歸結(jié)到了這最后一點:重構(gòu)幫助你更快速地開發(fā)程序。聽起來有違反直覺。當我談到重構(gòu),人們很容易看出它能夠提高質(zhì)量。改善設(shè)計、提升可讀性、減少錯誤,這些都是提高質(zhì)量。但這難道不會降低開發(fā)速度嗎?我強烈相信:良好設(shè)計是快速軟件開發(fā)的根本。事實上擁有良好設(shè)計才可能達成快速的開發(fā)。如果沒有良好設(shè)計,或許某段時間內(nèi)你的進展迅速,但惡劣的設(shè)計很快就讓你的速度慢來。你會把時間花在調(diào)試面,無法添加新功能。修改時間愈來愈長,因為你必須花愈來愈多的時間去理解系統(tǒng)、尋找重復代碼。隨著你給最初程序打上一個又一個的補丁(patch),新特性需要更多代碼才能實現(xiàn)。真是個惡性循環(huán)。

           

          3.何時重構(gòu)?

            重構(gòu)本來就不是一件「特別撥出時間做」的事情,重構(gòu)應(yīng)該隨時隨地進行。你不應(yīng)該為重構(gòu)而重構(gòu),你之所以重構(gòu),是因為你想做別的什么事,而重構(gòu)可以幫助你把那些事做好

           

          3.1三次法則(The Rule of Three)

            Don Roberts 給了我一條準則:第一次做某件事時只管去做;第二次做類似的事會產(chǎn)生反感,但無論如何還是做了;第三次再做類似的事,你就應(yīng)該重構(gòu)。

            ☆ 事不過則重構(gòu)。(Three strikes and you refactor.

           

          3.2重構(gòu)時機

            添加功能時一并重構(gòu)

            修補錯誤時一并重構(gòu)

            復審代碼時一并重構(gòu)

           

          -以上章節(jié)摘抄自《重構(gòu)-改善既有代碼的設(shè)計

           

          4.平臺重構(gòu)案例

           

          4.1重構(gòu)動機

            1. 實例模塊為View,重構(gòu)元素為ViewAction、ViewProcessBean、View,以下為關(guān)系圖。

            

            2. 由于View存在多種editMode(編輯模式),而每個調(diào)用的地方都需要進行type code(類型碼)判斷,然后再進行相應(yīng)的業(yè)務(wù)邏輯處理,最終在每個調(diào)用的地方都形成了大量的if-else代碼,大大減弱了代碼的可讀性,和邏輯清晰度。

           

            3. 調(diào)用的地方:

            

          4.2重構(gòu)作法

            

           

          如上圖所示,將每種type code重構(gòu)成subclass,加強了每種類型處理業(yè)務(wù)邏輯的能力。

           

          View-版本1566代碼片段:

           

          public EditMode getEditModeType() {
          if (EDIT_MODE_CODE_DQL.equals(getEditMode())) {
          return new DQLEditMode(this);
          }
          else if (EDIT_MODE_CODE_SQL.equals(getEditMode())) {
          return new SQLEditMode(this);
          }
          else if (EDIT_MODE_DESIGN.equals(getEditMode())) {
          return new DesignEditMode(this);
          }

          return new NullEditMode(this);
          }

          說明:調(diào)用者無需了解具體的類型,由View自身作判斷,返回EditMode接口,從而實現(xiàn)多態(tài)調(diào)用。

           

           

          ViewProcessBean代碼片段:

          重構(gòu)前-版本1503:

           

          public String expDocToExcel(String viewid, WebUser user, ParamsTable params) throws Exception {
          if (view.getEditMode().equals(View.EDIT_MODE_DESIGN)) {
          datas
          = dp.queryBySQLPage(sql, params, tempPage, LINES, user.getDomainid());
          }
          else if (view.getEditMode().equals(View.EDIT_MODE_CODE_DQL)) {
          datas
          = dp.queryByDQLPage(dql, params, tempPage, LINES, user.getDomainid());
          }
          else if (view.getEditMode().endsWith(View.EDIT_MODE_CODE_SQL)) {
          datas
          = dp.queryBySQLPage(sql, params, tempPage, LINES, user.getDomainid());
          }
          }

           

          重構(gòu)后-版本1566:

           

          public String expDocToExcel(String viewid, WebUser user, ParamsTable params) throws Exception {
          datas
          = view.getEditModeType().getDataPackage(params, tempPage, LINES, user, currdoc);
          //其他業(yè)務(wù)邏輯
          }

           

           

          5.結(jié)語

            由上述案例可看到,引入subclass代替type code可以大大減少if-else判斷,而且可以把責任內(nèi)聚到每種type中,使代碼結(jié)構(gòu)更清晰易懂。

           

          6.其他

                 在本案例中引入了空類型概念,即NullEditMode,代碼如下:

            

          /**
          *
          *
          @author nicholas zhen
          *
          */
          public class NullEditMode extends AbstractEditMode implements EditMode {

          public NullEditMode(View view) {
          super(view);
          }

          public String getQueryString(ParamsTable params, WebUser user, Document sDoc) {
          return "";
          }

          public DataPackage getDataPackage(ParamsTable params, WebUser user, Document doc) throws Exception {
          return new DataPackage();
          }

          public DataPackage getDataPackage(ParamsTable params, int page, int lines, WebUser user, Document doc) throws Exception {
          return new DataPackage();
          }

          public long count(ParamsTable params, WebUser user, Document doc) throws Exception {
          return 0;
          }
          }

          說明:空類型保證了調(diào)用每個方法都有默認值返回,而不需要進行非空判斷,當View沒有類型時,即返回默認的空類型

           

          原創(chuàng)人員:Nicholas


          文章來源:http://www.cnblogs.com/obpm/archive/2010/07/13/1776856.html
          posted @ 2010-07-13 23:22 obpm 閱讀(231) | 評論 (0)編輯 收藏

          不會畫流程圖的,看了這個就懂了,絕對經(jīng)典!

           

           

           

           

          轉(zhuǎn)載人員:Nicholas


          文章來源:http://www.cnblogs.com/obpm/archive/2010/07/12/1776058.html
          posted @ 2010-07-12 21:34 obpm 閱讀(269) | 評論 (0)編輯 收藏
          創(chuàng)建型模式

          1、FACTORY —追MM少不了請吃飯了,麥當勞的雞翅和肯德基的雞翅都是MM愛吃的東西,雖然口味有所不同,但不管你帶MM去麥當勞或肯德基,只管向服務(wù)員說“來四個雞翅”就行了。麥當勞和肯德基就是生產(chǎn)雞翅的Factory

          工廠模式:客戶類和工廠類分開。消費者任何時候需要某種產(chǎn)品,只需向工廠請求即可。消費者無須修改就可以接納新產(chǎn)品。缺點是當產(chǎn)品修改時,工廠類也要做相應(yīng)的修改。如:如何創(chuàng)建及如何向客戶端提供。

          2、BUILDER  —MM最愛聽的就是“我愛你”這句話了,見到不同地方的MM,要能夠用她們的方言跟她說這句話哦,我有一個多種語言翻譯機,上面每種語言都有一個按鍵,見到MM我只要按對應(yīng)的鍵,它就能夠用相應(yīng)的語言說出“我愛你”這句話了,國外的MM也可以輕松搞掂,這就是我的“我愛你”builder。(這一定比美軍在伊拉克用的翻譯機好賣)

          建造模式:將產(chǎn)品的內(nèi)部表象和產(chǎn)品的生成過程分割開來,從而使一個建造過程生成具有不同的內(nèi)部表象的產(chǎn)品對象。建造模式使得產(chǎn)品內(nèi)部表象可以獨立的變化,客戶不必知道產(chǎn)品內(nèi)部組成的細節(jié)。建造模式可以強制實行一種分步驟進行的建造過程。

          3、FACTORY METHOD —請MM去麥當勞吃漢堡,不同的MM有不同的口味,要每個都記住是一件煩人的事情,我一般采用Factory Method模式,帶著MM到服務(wù)員那兒,說“要一個漢堡”,具體要什么樣的漢堡呢,讓MM直接跟服務(wù)員說就行了。

          工廠方法模式:核心工廠類不再負責所有產(chǎn)品的創(chuàng)建,而是將具體創(chuàng)建的工作交給子類去做,成為一個抽象工廠角色,僅負責給出具體工廠類必須實現(xiàn)的接口,而不接觸哪一個產(chǎn)品類應(yīng)當被實例化這種細節(jié)。

          4、PROTOTYPE —跟MM用QQ聊天,一定要說些深情的話語了,我搜集了好多肉麻的情話,需要時只要copy出來放到QQ里面就行了,這就是我的情話prototype了。(100塊錢一份,你要不要)

          原始模型模式:通過給出一個原型對象來指明所要創(chuàng)建的對象的類型,然后用復制這個原型對象的方法創(chuàng)建出更多同類型的對象。原始模型模式允許動態(tài)的增加或減少產(chǎn)品類,產(chǎn)品類不需要非得有任何事先確定的等級結(jié)構(gòu),原始模型模式適用于任何的等級結(jié)構(gòu)。缺點是每一個類都必須配備一個克隆方法。

          5、SINGLETON —俺有6個漂亮的老婆,她們的老公都是我,我就是我們家里的老公Sigleton,她們只要說道“老公”,都是指的同一個人,那就是我(剛才做了個夢啦,哪有這么好的事)

          單例模式:單例模式確保某一個類只有一個實例,而且自行實例化并向整個系統(tǒng)提供這個實例單例模式。單例模式只應(yīng)在有真正的“單一實例”的需求時才可使用。

          結(jié)構(gòu)型模式

          6、ADAPTER —在朋友聚會上碰到了一個美女Sarah,從香港來的,可我不會說粵語,她不會說普通話,只好求助于我的朋友kent了,他作為我和Sarah之間的Adapter,讓我和Sarah可以相互交談了(也不知道他會不會耍我)

          適配器模式:把一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口原因不匹配而無法一起工作的兩個類能夠一起工作。適配類可以根據(jù)參數(shù)返還一個合適的實例給客戶端。

          7、BRIDGE —早上碰到MM,要說早上好,晚上碰到MM,要說晚上好;碰到MM穿了件新衣服,要說你的衣服好漂亮哦,碰到MM新做的發(fā)型,要說你的頭發(fā)好漂亮哦。不要問我“早上碰到MM新做了個發(fā)型怎么說”這種問題,自己用BRIDGE組合一下不就行了

          橋梁模式:將抽象化與實現(xiàn)化脫耦,使得二者可以獨立的變化,也就是說將他們之間的強關(guān)聯(lián)變成弱關(guān)聯(lián),也就是指在一個軟件系統(tǒng)的抽象化和實現(xiàn)化之間使用組合/聚合關(guān)系而不是繼承關(guān)系,從而使兩者可以獨立的變化。

          8、COMPOSITE —Mary今天過生日。“我過生日,你要送我一件禮物。”“嗯,好吧,去商店,你自己挑。”“這件T恤挺漂亮,買,這條裙子好看,買,這個包也不錯,買。”“喂,買了三件了呀,我只答應(yīng)送一件禮物的哦。”“什么呀,T恤加裙子加包包,正好配成一套呀,小姐,麻煩你包起來。”“……”,MM都會用Composite模式了,你會了沒有?

          合成模式:合成模式將對象組織到樹結(jié)構(gòu)中,可以用來描述整體與部分的關(guān)系。合成模式就是一個處理對象的樹結(jié)構(gòu)的模式。合成模式把部分與整體的關(guān)系用樹結(jié)構(gòu)表示出來。合成模式使得客戶端把一個個單獨的成分對象和由他們復合而成的合成對象同等看待。

          9、DECORATOR —Mary過完輪到Sarly過生日,還是不要叫她自己挑了,不然這個月伙食費肯定玩完,拿出我去年在華山頂上照的照片,在背面寫上“最好的的禮物,就是愛你的Fita”,再到街上禮品店買了個像框(賣禮品的MM也很漂亮哦),再找隔壁搞美術(shù)設(shè)計的Mike設(shè)計了一個漂亮的盒子裝起來……,我們都是Decorator,最終都在修飾我這個人呀,怎么樣,看懂了嗎?

          裝飾模式:裝飾模式以對客戶端透明的方式擴展對象的功能,是繼承關(guān)系的一個替代方案,提供比繼承更多的靈活性。動態(tài)給一個對象增加功能,這些功能可以再動態(tài)的撤消。增加由一些基本功能的排列組合而產(chǎn)生的非常大量的功能。

          10、FAÇADE —我有一個專業(yè)的Nikon相機,我就喜歡自己手動調(diào)光圈、快門,這樣照出來的照片才專業(yè),但MM可不懂這些,教了半天也不會。幸好相機有Facade設(shè)計模式,把相機調(diào)整到自動檔,只要對準目標按快門就行了,一切由相機自動調(diào)整,這樣MM也可以用這個相機給我拍張照片了。

          門面模式:外部與一個子系統(tǒng)的通信必須通過一個統(tǒng)一的門面對象進行。門面模式提供一個高層次的接口,使得子系統(tǒng)更易于使用。每一個子系統(tǒng)只有一個門面類,而且此門面類只有一個實例,也就是說它是一個單例模式。但整個系統(tǒng)可以有多個門面類。

          11、FLYWEIGHT —每天跟MM發(fā)短信,手指都累死了,最近買了個新手機,可以把一些常用的句子存在手機里,要用的時候,直接拿出來,在前面加上MM的名字就可以發(fā)送了,再不用一個字一個字敲了。共享的句子就是Flyweight,MM的名字就是提取出來的外部特征,根據(jù)上下文情況使用。

          享元模式:FLYWEIGHT在拳擊比賽中指最輕量級。享元模式以共享的方式高效的支持大量的細粒度對象。享元模式能做到共享的關(guān)鍵是區(qū)分內(nèi)蘊狀態(tài)和外蘊狀態(tài)。內(nèi)蘊狀態(tài)存儲在享元內(nèi)部,不會隨環(huán)境的改變而有所不同。外蘊狀態(tài)是隨環(huán)境的改變而改變的。外蘊狀態(tài)不能影響內(nèi)蘊狀態(tài),它們是相互獨立的。將可以共享的狀態(tài)和不可以共享的狀態(tài)從常規(guī)類中區(qū)分開來,將不可以共享的狀態(tài)從類里剔除出去。客戶端不可以直接創(chuàng)建被共享的對象,而應(yīng)當使用一個工廠對象負責創(chuàng)建被共享的對象。享元模式大幅度的降低內(nèi)存中對象的數(shù)量。

          12、PROXY —跟MM在網(wǎng)上聊天,一開頭總是“hi,你好”,“你從哪兒來呀?”“你多大了?”“身高多少呀?”這些話,真煩人,寫個程序做為我的Proxy吧,凡是接收到這些話都設(shè)置好了自動的回答,接收到其他的話時再通知我回答,怎么樣,酷吧。

          代理模式:代理模式給某一個對象提供一個代理對象,并由代理對象控制對源對象的引用。代理就是一個人或一個機構(gòu)代表另一個人或者一個機構(gòu)采取行動。某些情況下,客戶不想或者不能夠直接引用一個對象,代理對象可以在客戶和目標對象直接起到中介的作用。客戶端分辨不出代理主題對象與真實主題對象。代理模式可以并不知道真正的被代理對象,而僅僅持有一個被代理對象的接口,這時候代理對象不能夠創(chuàng)建被代理對象,被代理對象必須有系統(tǒng)的其他角色代為創(chuàng)建并傳入。

          行為模式

          13、CHAIN OF RESPONSIBLEITY —晚上去上英語課,為了好開溜坐到了最后一排,哇,前面坐了好幾個漂亮的MM哎,找張紙條,寫上“Hi,可以做我的女朋友嗎?如果不愿意請向前傳”,紙條就一個接一個的傳上去了,糟糕,傳到第一排的MM把紙條傳給老師了,聽說是個老處女呀,快跑!

          責任鏈模式:在責任鏈模式中,很多對象由每一個對象對其下家的引用而接起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。客戶并不知道鏈上的哪一個對象最終處理這個請求,系統(tǒng)可以在不影響客戶端的情況下動態(tài)的重新組織鏈和分配責任。處理者有兩個選擇:承擔責任或者把責任推給下家。一個請求可以最終不被任何接收端對象所接受。

          14、COMMAND —俺有一個MM家里管得特別嚴,沒法見面,只好借助于她弟弟在我們倆之間傳送信息,她對我有什么指示,就寫一張紙條讓她弟弟帶給我。這不,她弟弟又傳送過來一個COMMAND,為了感謝他,我請他吃了碗雜醬面,哪知道他說:“我同時給我姐姐三個男朋友送COMMAND,就數(shù)你最小氣,才請我吃面。”,

          命令模式:命令模式把一個請求或者操作封裝到一個對象中。命令模式把發(fā)出命令的責任和執(zhí)行命令的責任分割開,委派給不同的對象。命令模式允許請求的一方和發(fā)送的一方獨立開來,使得請求的一方不必知道接收請求的一方的接口,更不必知道請求是怎么被接收,以及操作是否執(zhí)行,何時被執(zhí)行以及是怎么被執(zhí)行的。系統(tǒng)支持命令的撤消。

          15、INTERPRETER —俺有一個《泡MM真經(jīng)》,上面有各種泡MM的攻略,比如說去吃西餐的步驟、去看電影的方法等等,跟MM約會時,只要做一個Interpreter,照著上面的腳本執(zhí)行就可以了。

          解釋器模式:給定一個語言后,解釋器模式可以定義出其文法的一種表示,并同時提供一個解釋器。客戶端可以使用這個解釋器來解釋這個語言中的句子。解釋器模式將描述怎樣在有了一個簡單的文法后,使用模式設(shè)計解釋這些語句。在解釋器模式里面提到的語言是指任何解釋器對象能夠解釋的任何組合。在解釋器模式中需要定義一個代表文法的命令類的等級結(jié)構(gòu),也就是一系列的組合規(guī)則。每一個命令對象都有一個解釋方法,代表對命令對象的解釋。命令對象的等級結(jié)構(gòu)中的對象的任何排列組合都是一個語言。

          16、ITERATOR —我愛上了Mary,不顧一切的向她求婚。
             Mary:“想要我跟你結(jié)婚,得答應(yīng)我的條件”
             我:“什么條件我都答應(yīng),你說吧”
             Mary:“我看上了那個一克拉的鉆石”
             我:“我買,我買,還有嗎?”
             Mary:“我看上了湖邊的那棟別墅”
             我:“我買,我買,還有嗎?”
             Mary:“你的小弟弟必須要有50cm長”
             我腦袋嗡的一聲,坐在椅子上,一咬牙:“我剪,我剪,還有嗎?”
             ……

          迭代子模式:迭代子模式可以順序訪問一個聚集中的元素而不必暴露聚集的內(nèi)部表象。多個對象聚在一起形成的總體稱之為聚集,聚集對象是能夠包容一組對象的容器對象。迭代子模式將迭代邏輯封裝到一個獨立的子對象中,從而與聚集本身隔開。迭代子模式簡化了聚集的界面。每一個聚集對象都可以有一個或一個以上的迭代子對象,每一個迭代子的迭代狀態(tài)可以是彼此獨立的。迭代算法可以獨立于聚集角色變化。

          17、MEDIATOR —四個MM打麻將,相互之間誰應(yīng)該給誰多少錢算不清楚了,幸虧當時我在旁邊,按照各自的籌碼數(shù)算錢,賺了錢的從我這里拿,賠了錢的也付給我,一切就OK啦,俺得到了四個MM的電話。

          調(diào)停者模式:調(diào)停者模式包裝了一系列對象相互作用的方式,使得這些對象不必相互明顯作用。從而使他們可以松散偶合。當某些對象之間的作用發(fā)生改變時,不會立即影響其他的一些對象之間的作用。保證這些作用可以彼此獨立的變化。調(diào)停者模式將多對多的相互作用轉(zhuǎn)化為一對多的相互作用。調(diào)停者模式將對象的行為和協(xié)作抽象化,把對象在小尺度的行為上與其他對象的相互作用分開處理。

          18、MEMENTO —同時跟幾個MM聊天時,一定要記清楚剛才跟MM說了些什么話,不然MM發(fā)現(xiàn)了會不高興的哦,幸虧我有個備忘錄,剛才與哪個MM說了什么話我都拷貝一份放到備忘錄里面保存,這樣可以隨時察看以前的記錄啦。

          備忘錄模式:備忘錄對象是一個用來存儲另外一個對象內(nèi)部狀態(tài)的快照的對象。備忘錄模式的用意是在不破壞封裝的條件下,將一個對象的狀態(tài)捉住,并外部化,存儲起來,從而可以在將來合適的時候把這個對象還原到存儲起來的狀態(tài)。

          19、OBSERVER  —想知道咱們公司最新MM情報嗎?加入公司的MM情報郵件組就行了,tom負責搜集情報,他發(fā)現(xiàn)的新情報不用一個一個通知我們,直接發(fā)布給郵件組,我們作為訂閱者(觀察者)就可以及時收到情報啦

          觀察者模式:觀察者模式定義了一種一隊多的依賴關(guān)系,讓多個觀察者對象同時監(jiān)聽某一個主題對象。這個主題對象在狀態(tài)上發(fā)生變化時,會通知所有觀察者對象,使他們能夠自動更新自己。

          20、STATE —跟MM交往時,一定要注意她的狀態(tài)哦,在不同的狀態(tài)時她的行為會有不同,比如你約她今天晚上去看電影,對你沒興趣的MM就會說“有事情啦”,對你不討厭但還沒喜歡上的MM就會說“好啊,不過可以帶上我同事么?”,已經(jīng)喜歡上你的MM就會說“幾點鐘?看完電影再去泡吧怎么樣?”,當然你看電影過程中表現(xiàn)良好的話,也可以把MM的狀態(tài)從不討厭不喜歡變成喜歡哦。

          狀態(tài)模式:狀態(tài)模式允許一個對象在其內(nèi)部狀態(tài)改變的時候改變行為。這個對象看上去象是改變了它的類一樣。狀態(tài)模式把所研究的對象的行為包裝在不同的狀態(tài)對象里,每一個狀態(tài)對象都屬于一個抽象狀態(tài)類的一個子類。狀態(tài)模式的意圖是讓一個對象在其內(nèi)部狀態(tài)改變的時候,其行為也隨之改變。狀態(tài)模式需要對每一個系統(tǒng)可能取得的狀態(tài)創(chuàng)立一個狀態(tài)類的子類。當系統(tǒng)的狀態(tài)變化時,系統(tǒng)便改變所選的子類。

          21、STRATEGY —跟不同類型的MM約會,要用不同的策略,有的請電影比較好,有的則去吃小吃效果不錯,有的去海邊浪漫最合適,單目的都是為了得到MM的芳心,我的追MM錦囊中有好多Strategy哦。

          策略模式:策略模式針對一組算法,將每一個算法封裝到具有共同接口的獨立的類中,從而使得它們可以相互替換。策略模式使得算法可以在不影響到客戶端的情況下發(fā)生變化。策略模式把行為和環(huán)境分開。環(huán)境類負責維持和查詢行為類,各種算法在具體的策略類中提供。由于算法和環(huán)境獨立開來,算法的增減,修改都不會影響到環(huán)境和客戶端。

          22、TEMPLATE METHOD ——看過《如何說服女生上床》這部經(jīng)典文章嗎?女生從認識到上床的不變的步驟分為巧遇、打破僵局、展開追求、接吻、前戲、動手、愛撫、進去八大步驟(Template method),但每個步驟針對不同的情況,都有不一樣的做法,這就要看你隨機應(yīng)變啦(具體實現(xiàn));

          模板方法模式:模板方法模式準備一個抽象類,將部分邏輯以具體方法以及具體構(gòu)造子的形式實現(xiàn),然后聲明一些抽象方法來迫使子類實現(xiàn)剩余的邏輯。不同的子類可以以不同的方式實現(xiàn)這些抽象方法,從而對剩余的邏輯有不同的實現(xiàn)。先制定一個頂級邏輯框架,而將邏輯的細節(jié)留給具體的子類去實現(xiàn)。

          23、VISITOR —情人節(jié)到了,要給每個MM送一束鮮花和一張卡片,可是每個MM送的花都要針對她個人的特點,每張卡片也要根據(jù)個人的特點來挑,我一個人哪搞得清楚,還是找花店老板和禮品店老板做一下Visitor,讓花店老板根據(jù)MM的特點選一束花,讓禮品店老板也根據(jù)每個人特點選一張卡,這樣就輕松多了;

          訪問者模式:訪問者模式的目的是封裝一些施加于某種數(shù)據(jù)結(jié)構(gòu)元素之上的操作。一旦這些操作需要修改的話,接受這個操作的數(shù)據(jù)結(jié)構(gòu)可以保持不變。訪問者模式適用于數(shù)據(jù)結(jié)構(gòu)相對未定的系統(tǒng),它把數(shù)據(jù)結(jié)構(gòu)和作用于結(jié)構(gòu)上的操作之間的耦合解脫開,使得操作集合可以相對自由的演化。訪問者模式使得增加新的操作變的很容易,就是增加一個新的訪問者類。訪問者模式將有關(guān)的行為集中到一個訪問者對象中,而不是分散到一個個的節(jié)點類中。當使用訪問者模式時,要將盡可能多的對象瀏覽邏輯放在訪問者類中,而不是放到它的子類中。訪問者模式可以跨過幾個類的等級結(jié)構(gòu)訪問屬于不同的等級結(jié)構(gòu)的成員類。
          轉(zhuǎn)載人員:Nicholas

          文章來源:http://www.cnblogs.com/obpm/archive/2010/07/12/1776045.html
          posted @ 2010-07-12 21:10 obpm 閱讀(129) | 評論 (0)編輯 收藏

          obpm一鍵生成視圖功能原理

          在obpm系統(tǒng)后臺表單右上角有一個“一鍵生成視圖”功能。實現(xiàn)它的真正目的是為了后臺管理人員方便從實現(xiàn)好的表單中快速生成所有帶值的列的視圖。這樣管理人員就不需要手工新建視圖,然后再添加視圖中的帶值的列。

          實現(xiàn)原理圖:

          在實現(xiàn)原理圖中,我們發(fā)現(xiàn)沒有視圖中并沒有不帶值Field4相應(yīng)的Column4在視圖中,這是因為在視圖中是要根據(jù)不同Column顯示不同的值的。如果Column是不帶值的話,那么視圖中就不應(yīng)該要這個Column,即使是要了,在視圖中沒有意義了。

          實現(xiàn)原理代碼:

          其中代碼路徑是:src-java-cn-myapps-core-dynaform-form-ejb-FormProcessBean.java

          /**

               * 根據(jù)表單編號來生成視圖

               * @param formid 表單編號

               * @throws Exception

               */

              public Form oneKeyCreateView(String formid) throws Exception {

                     FormProcess formPross = (FormProcess) ProcessFactory.createProcess(FormProcess.class);

                     ViewProcess viewPross = (ViewProcess) ProcessFactory.createProcess(ViewProcess.class);

                    

                     Form form = (Form) formPross.doView(formid);//獲得form

                     Collection formfield=form.getValueStoreFields();//獲得form存儲值的field

                    

                     //新建視圖

                     View view = new View();

                     if (view.getId() == null || view.getId().trim().length() <= 0) {

                        view.setId(Sequence.getSequence());//設(shè)置視圖的ID

                        view.setSortId(Sequence.getTimeSequence());//設(shè)置視圖的排序ID     }

                      view.setName(form.getName());//把表單的名字賦給視圖

                      view.setOpenType(view.OPEN_TYPE_NORMAL); //設(shè)置視圖打開類型-普通類型

                      view.setLastmodifytime(new Date());//最后修改日期

                      view.setApplicationid(form.getApplicationid());//把表單應(yīng)用程序Id賦給視圖的應(yīng)用程序Id

                      view.setModule(form.getModule());//把表單模塊Id賦給視圖的模塊ID

                      view.setPagelines("10");//設(shè)置視圖的分頁每頁顯示10條數(shù)據(jù)

                      view.setShowTotalRow(true); //是否顯示總共條數(shù)數(shù)據(jù)

                      view.setPagination(true); //是否分頁顯示

                      view.setRelatedForm(form.getId());//把表單ID賦給視圖的映射表單,從而映射了該表單

                    

                     

                      //將表單中對應(yīng)有值的列轉(zhuǎn)換為視圖的列

                      int i=0;

                     for(Iterator iterator=formfield.iterator();iterator.hasNext();){

                        FormField field=(FormField)iterator.next();

                       

                        Column column = new Column();

                        if (column.getId() == null || column.getId().trim().length() <= 0) {

                        column.setId(Sequence.getSequence());

                        column.setOrderno(i);

                        }

                        if(field.getDiscript()!=null && !field.getDiscript().equals("")){//如果該表單中帶值Field有描述的話,就作為視圖Column,否則的用Field名稱

                        column.setName(field.getDiscript());

                            }else{

                        column.setName(field.getName());

                            }

                        column.setFormid(form.getId());//把表單中的ID賦給Column的表單ID

                        column.setApplicationid(form.getApplicationid());//把表單中應(yīng)用程序的ID賦給Column的表單應(yīng)用程序ID

           

                        column.setFieldName(field.getName());  //把表單中的名稱賦給Column的表單名稱

           

                        column.setParentView(view.getId());//將視圖ID賦給Column的父視圖

           

                       

                        view.getColumns().add(column); //將視圖和Column關(guān)聯(lián)

                        i++;

                     }

                    

                    

                     //分別創(chuàng)建兩個按鈕  新建,刪除

                     Activity activityCreate = new Activity();

                     if (activityCreate.getId() == null || activityCreate.getId().trim().length() <= 0) {

                        activityCreate.setId(Sequence.getSequence());

                        activityCreate.setOrderno(0);

                     }

                     activityCreate.setApplicationid(form.getApplicationid());

                     activityCreate.setName("新建");

                     activityCreate.setParentView(view.getId());

                     activityCreate.setType(ActivityType.DOCUMENT_CREATE);

                     activityCreate.setOnActionForm(form.getId());

                    

                     view.getActivitys().add(activityCreate); //將視圖和新建按鈕關(guān)聯(lián)

                    

                    

                     Activity activityDelete = new Activity();

                     if (activityDelete.getId() == null || activityDelete.getId().trim().length() <= 0) {

                        activityDelete.setId(Sequence.getSequence());

                        activityDelete.setOrderno(1);

                     }

                     activityDelete.setApplicationid(form.getApplicationid());

                     activityDelete.setName("刪除");

                     activityDelete.setParentView(view.getId());

                     activityDelete.setType(ActivityType.DOCUMENT_DELETE);

                    

                     view.getActivitys().add(activityDelete); //將視圖和刪除按鈕關(guān)聯(lián)

                    

                    

                     viewPross.doCreate(view); //創(chuàng)建視圖

                      return form;

              }

           

          后臺效果圖:

          表單:

          視圖:

          視圖列:

          視圖按鈕:

          前臺效果:

          視圖:

           

          表單:

           

           

          原創(chuàng)人員:Denny


          文章來源:http://www.cnblogs.com/obpm/archive/2010/07/12/1775453.html
          posted @ 2010-07-12 02:08 obpm 閱讀(418) | 評論 (0)編輯 收藏

          鎖( locking )
          業(yè)務(wù)邏輯的實現(xiàn)過程中,往往需要保證數(shù)據(jù)訪問的排他性。如在金融系統(tǒng)的日終結(jié)算處理中,我們希望針對某個 cut-off 時間點的數(shù)據(jù)進行處理,而不希望在結(jié)算進行過程中(可能是幾秒種,也可能是幾個小時),數(shù)據(jù)再發(fā)生變化。此時,我們就需要通過一些機制來保證這些數(shù)據(jù)在某個操作過程中不會被外界修改,這樣的機制,在這里,也就是所謂的 “鎖” ,即給我們選定的目標數(shù)據(jù)上鎖,使其無法被其他程序修改。Hibernate 支持兩種鎖機制:即通常所說的 “悲觀鎖( Pessimistic Locking )”和 “樂觀鎖( Optimistic Locking )” 。

          悲觀鎖( Pessimistic Locking )
          悲觀鎖,正如其名,它指的是對數(shù)據(jù)被外界(包括本系統(tǒng)當前的其他事務(wù),以及來自外部系統(tǒng)的事務(wù)處理)修改持保守態(tài)度,因此,在整個數(shù)據(jù)處理過程中,將數(shù)據(jù)處于鎖定狀態(tài)。悲觀鎖的實現(xiàn),往往依靠數(shù)據(jù)庫提供的鎖機制(也只有數(shù)據(jù)庫層提供的鎖機制才能真正保證數(shù)據(jù)訪問的排他性,否則,即使在本系統(tǒng)中實現(xiàn)了加鎖機制,也無法保證外部系統(tǒng)不會修改數(shù)據(jù))。
          一個典型的倚賴數(shù)據(jù)庫的悲觀鎖調(diào)用:
          select * from account where name=”Erica” for update
          這條 sql 語句鎖定了 account 表中所有符合檢索條件(name=”Erica”)的記錄。本次事務(wù)提交之前(事務(wù)提交時會釋放事務(wù)過程中的鎖),外界無法修改這些記錄。Hibernate 的悲觀鎖,也是基于數(shù)據(jù)庫的鎖機制實現(xiàn)。
          下面的代碼實現(xiàn)了對查詢記錄的加鎖:
          String hqlStr ="from TUser as user where user.name='Erica'";
          Query query = session.createQuery(hqlStr);
          query.setLockMode("user",LockMode.UPGRADE); // 加鎖
          List userList = query.list();// 執(zhí)行查詢,獲取數(shù)據(jù)

          query.setLockMode 對查詢語句中,特定別名所對應(yīng)的記錄進行加鎖(我們?yōu)門User 類指定了一個別名 “user” ),這里也就是對返回的所有 user 記錄進行加鎖。
          觀察運行期 Hibernate 生成的 SQL 語句:
          select tuser0_.id as id, tuser0_.name as name, tuser0_.group_id
          as group_id, tuser0_.user_type as user_type, tuser0_.sex as sex
          from t_user tuser0_ where (tuser0_.name='Erica' ) for update

          這里 Hibernate 通過使用數(shù)據(jù)庫的 for update 子句實現(xiàn)了悲觀鎖機制。
          Hibernate 的加鎖模式有:
          LockMode.NONE : 無鎖機制。
          LockMode.WRITE : Hibernate 在 Insert 和 Update 記錄的時候會自動獲取。
          LockMode.READ : Hibernate 在讀取記錄的時候會自動獲取。
          以上這三種鎖機制一般由 Hibernate 內(nèi)部使用,如 Hibernate 為了保證 Update過程中對象不會被外界修改,會在 save 方法實現(xiàn)中自動為目標對象加上 WRITE 鎖。
          LockMode.UPGRADE :利用數(shù)據(jù)庫的 for update 子句加鎖。
          LockMode. UPGRADE_NOWAIT : Oracle 的特定實現(xiàn),利用 Oracle 的 for update nowait 子句實現(xiàn)加鎖。
          上面這兩種鎖機制是我們在應(yīng)用層較為常用的,加鎖一般通過以下方法實現(xiàn):
          Criteria.setLockMode
          Query.setLockMode
          Session.lock

          注意,只有在查詢開始之前(也就是 Hiberate 生成 SQL 之前)設(shè)定加鎖,才會真正通過數(shù)據(jù)庫的鎖機制進行加鎖處理,否則,數(shù)據(jù)已經(jīng)通過不包含 for update 子句的 Select SQL 加載進來,所謂數(shù)據(jù)庫加鎖也就無從談起。

          樂觀鎖( Optimistic Locking )
          相對悲觀鎖而言,樂觀鎖機制采取了更加寬松的加鎖機制。悲觀鎖大多數(shù)情況下依靠數(shù)據(jù)庫的鎖機制實現(xiàn),以保證操作最大程度的獨占性。但隨之而來的就是數(shù)據(jù)庫性能的大量開銷,特別是對長事務(wù)而言,這樣的開銷往往無法承受。
          如一個金融系統(tǒng),當某個操作員讀取用戶的數(shù)據(jù),并在讀出的用戶數(shù)據(jù)的基礎(chǔ)上進行修改時如更改用戶帳戶余額),如果采用悲觀鎖機制,也就意味著整個操作過程中(從操作員讀出數(shù)、開始修改直至提交修改結(jié)果的全過程,甚至還包括操作員中途去煮咖啡的時間),數(shù)據(jù)庫記錄始終處于加鎖狀態(tài),可以想見,如果面對幾百上千個并發(fā),這樣的情況將導致怎樣的后果。樂觀鎖機制在一定程度上解決了這個問題。樂觀鎖,大多是基于數(shù)據(jù)版本( Version )記錄機制實現(xiàn)。何謂數(shù)據(jù)版本?即為數(shù)據(jù)增加一個版本標識,在基于數(shù)據(jù)庫表的版本解決方案中,一般是通過為數(shù)據(jù)庫表增加一個 “version” 字段來實現(xiàn)。
          讀取出數(shù)據(jù)時,將此版本號一同讀出,之后更新時,對此版本號加一。此時,將提交數(shù)據(jù)的版本數(shù)據(jù)與數(shù)據(jù)庫表對應(yīng)記錄的當前版本信息進行比對,如果提交的數(shù)據(jù)版本號大于數(shù)據(jù)庫表當前版本號,則予以更新,否則認為是過期數(shù)據(jù)。
          對于上面修改用戶帳戶信息的例子而言,假設(shè)數(shù)據(jù)庫中帳戶信息表中有一個version 字段,當前值為 1 ;而當前帳戶余額字段(balance)為 $100 。
          1 操作員 A 此時將其讀出(version=1),并從其帳戶余額中扣除 $50($100-$50)。
          2 在操作員 A 操作的過程中,操作員 B 也讀入此用戶信息(version=1),并從其帳戶余額中扣除 $20 ($100-$20)。
          3 操作員 A 完成了修改工作,將數(shù)據(jù)版本號加一(version=2),連同帳戶扣除后余額(balance=$50),提交至數(shù)據(jù)庫更新,此時由于提交數(shù)據(jù)版本大于數(shù)據(jù)庫記錄當前版本,數(shù)據(jù)被更新,數(shù)據(jù)庫記錄 version 更新為 2 。
          4 操作員 B 完成了操作,也將版本號加一(version=2)試圖向數(shù)據(jù)庫提交數(shù)據(jù)(balance=$80),但此時比對數(shù)據(jù)庫記錄版本時發(fā)現(xiàn),操作員 B 提交的數(shù)據(jù)版本號為 2 ,數(shù)據(jù)庫記錄當前版本也為 2 ,不滿足“ 提交版本必須大于記錄當前版本才能執(zhí)行更新“ 的樂觀鎖策略,因此,操作員 B 的提交被駁回。這樣,就避免了操作員 B 用基于 version=1 的舊數(shù)據(jù)修改的結(jié)果覆蓋操作員 A 的操作結(jié)果的可能。
          從上面的例子可以看出,樂觀鎖機制避免了長事務(wù)中的數(shù)據(jù)庫加鎖開銷(操作員 A 和操作員 B 操作過程中,都沒有對數(shù)據(jù)庫數(shù)據(jù)加鎖),大大提升了大并發(fā)量下的系統(tǒng)整體性能表現(xiàn)。需要注意的是,樂觀鎖機制往往基于系統(tǒng)中的數(shù)據(jù)存儲邏輯,因此也具備一定的局限性,如在上例中,由于樂觀鎖機制是在我們的系統(tǒng)中實現(xiàn),來自外部系統(tǒng)的用戶余額更新操作不受我們系統(tǒng)的控制,因此可能會造成臟數(shù)據(jù)被更新到數(shù)據(jù)庫中。在系統(tǒng)設(shè)計階段,我們應(yīng)該充分考慮到這些情況出現(xiàn)的可能性,并進行相應(yīng)調(diào)整(如將樂觀鎖策略在數(shù)據(jù)庫存儲過程中實現(xiàn),對外只開放基于此存儲過程的數(shù)據(jù)更新途徑,而不是將數(shù)據(jù)庫表直接對外公開)。
          Hibernate 在其數(shù)據(jù)訪問引擎中內(nèi)置了樂觀鎖實現(xiàn)。如果不用考慮外部系統(tǒng)對數(shù)據(jù)庫的更新操作,利用 Hibernate 提供的透明化樂觀鎖實現(xiàn),將大大提升我們的生產(chǎn)力。
          Hibernate 中可以通過 class 描述符的 optimistic-lock 屬性結(jié)合 version描述符指定。

          現(xiàn)在,我們?yōu)橹笆纠械?TUser 加上樂觀鎖機制。
          1 . 首先為 TUser 的 class 描述符添加 optimistic-lock 屬性:
          <hibernate-mapping>
          <class name="org.hibernate.sample.TUser" table="t_user" dynamic-update="true"
          dynamic-insert="true" optimistic-lock="version">
          ……
          </class>
          </hibernate-mapping>

          optimistic-lock 屬性有如下可選取值: 
          none:無樂觀鎖 
          version:通過版本機制實現(xiàn)樂觀鎖
          dirty:通過檢查發(fā)生變動過的屬性實現(xiàn)樂觀鎖
          all:通過檢查所有屬性實現(xiàn)樂觀鎖
          其中通過 version 實現(xiàn)的樂觀鎖機制是 Hibernate 官方推薦的樂觀鎖實現(xiàn),同時也是 Hibernate 中,目前唯一在數(shù)據(jù)對象脫離 Session 發(fā)生修改的情況下依然有效的鎖機制。因此,一般情況下,我們都選擇 version 方式作為 Hibernate 樂觀鎖實現(xiàn)機制。
          2 . 添加一個 Version 屬性描述符
          <hibernate-mapping>
          <class name="org.hibernate.sample.TUser" table="t_user" dynamic-update="true" dynamic-insert="true"
          optimistic-lock="version">
          <id name="id" column="id" type="java.lang.Integer">
          <generator class="native">
          </generator>
          </id>
          <version column="version" name="version" type="java.lang.Integer"/>
          ……
          </class>
          </hibernate-mapping>

          注意 version 節(jié)點必須出現(xiàn)在 ID 節(jié)點之后。這里我們聲明了一個 version 屬性,用于存放用戶的版本信息,保存在 TUser 表的version 字段中。
          此時如果我們嘗試編寫一段代碼,更新 TUser 表中記錄數(shù)據(jù),如:
          Criteria criteria = session.createCriteria(TUser.class);
          criteria.add(Expression.eq("name","Erica"));
          List userList = criteria.list();
          TUser user =(TUser)userList.get(0);
          Transaction tx = session.beginTransaction();
          user.setUserType(1); // 更新 UserType 字段
          tx.commit();

          每次對 TUser 進行更新的時候,我們可以發(fā)現(xiàn),數(shù)據(jù)庫中的 version 都在遞增。而如果我們嘗試在 tx.commit 之前,啟動另外一個 Session ,對名為 Erica 的用戶進行操作,以模擬并發(fā)更新時的情形:
          Session session= getSession();
          Criteria criteria = session.createCriteria(TUser.class);
          criteria.add(Expression.eq("name","Erica"));
          Session session2 = getSession();
          Criteria criteria2 = session2.createCriteria(TUser.class);
          criteria2.add(Expression.eq("name","Erica"));
          List userList = criteria.list();
          List userList2 = criteria2.list();TUser user =(TUser)userList.get(0);
          TUser user2 =(TUser)userList2.get(0);
          Transaction tx = session.beginTransaction();
          Transaction tx2 = session2.beginTransaction();
          user2.setUserType(99);
          tx2.commit();
          user.setUserType(1);
          tx.commit();
          執(zhí)行以上代碼,代碼將在 tx.commit() 處拋出 StaleObjectStateException 異常,并指出版本檢查失敗,當前事務(wù)正在試圖提交一個過期數(shù)據(jù)。通過捕捉這個異常,我們就可以在樂觀鎖校驗失敗時進行相應(yīng)處理。

           

          轉(zhuǎn)載人員:Nicholas


          文章來源:http://www.cnblogs.com/obpm/archive/2010/07/11/1775120.html
          posted @ 2010-07-11 09:58 obpm 閱讀(248) | 評論 (0)編輯 收藏
          主站蜘蛛池模板: 兖州市| 湖南省| 涡阳县| 象州县| 论坛| 宜丰县| 三穗县| 炎陵县| 花垣县| 海丰县| 沙坪坝区| 肥乡县| 安国市| 聂拉木县| 古蔺县| 阳东县| 白城市| 哈尔滨市| 汽车| 蒲城县| 兴和县| 安化县| 康乐县| 星子县| 泸西县| 买车| 金山区| 广饶县| 张掖市| 清徐县| 南城县| 即墨市| 台江县| 屏东县| 房山区| 正蓝旗| 外汇| 万州区| 洛阳市| 武清区| 屯昌县|