asklxf

          A java developer's notebook.

          常用鏈接

          統計

          積分與排名

          最新評論

          使用WebLogic Platform構建音樂站點

          Orienginal URL: http://dev2dev.bea.com.cn/bbs/yuanch/ArticleShow.jsp?Id=35

          摘要

          擁有自己的音樂站點是個不錯的想法,相比傳統的ASPPHP站點,我們將采用J2EE架構實現多層結構的,高度可擴展的站點。您將看到,采用J2EE技術,加上強大的WebLogic平臺,我們能更容易的實現一個音樂站點應用,而非傳統意義上的平面結構的網站。

          簡介

          隨著J2EE的快速普及,越來越多的開發人員都想編寫基于J2EE架構的分布式的企業級應用程序。為了降低開發難度,J2EE提供的基于組件的,分層的分布式應用模式,使具有可伸縮,可擴展和易維護等優點。利用J2EE,可以快速開發、部署和管理多層結構、面向Web的,以服務器為中心的企業級應用。

          在下面的這個示例中,我們將構建一個基于J2EE的音樂站點,暫定名為JetMusic,計劃給用戶提供瀏覽,下載等在線服務。事實上,Internet上已有很多這種類型的站點,但是它們大多是傳統的基于兩層結構的模型,使用了混合HTMLASPPHP腳本代碼的頁面。

          盡管我們的JetMusic站點可能現在規模不大,僅僅使用JSP/JavaBeans/數據庫就已經足夠了,但是作為示例,我們還是打算用J2EE來實現它。借助J2EE的強大功能,我們能夠輕易地快速創建這樣一個音樂站點,并且使我們的編碼量最小。更重要的是,它是完全的3層分布式結構,具有很強的擴展性。

          系統設計

          我們的站點需要對用戶提供瀏覽,下載等服務,還要允許系統管理員能隨時登陸并管理站點資源。對于我們的JetMusic站點,我們計劃使用樹型結構來組織分類、藝術家、專輯、歌曲,一個簡單的示例圖如下:

          對用戶而言,我們需要提供以下服務:

          用戶可以瀏覽分類、藝術家、專輯、歌曲、歌詞。

          用戶可以按關鍵字模糊搜索歌曲,專輯,藝術家和歌詞。

          用戶可以對某一首歌評分。

          如果歌曲文件存在,用戶可以下載歌曲。

          如果歌詞存在,用戶可以瀏覽歌詞。

          為了管理站點資源,我們把使用者分為用戶和管理員兩類:

          用戶可以注冊,更改自己的信息。

          管理員可以創建或刪除分類,藝術家,專輯,歌曲。

          以上可以簡單看作是我們分析的全部用例。我們將采用J2EE標準的三層結構模型,將系統分為表示層,邏輯層和持久層(EIS層就免了,因為我們并沒有所謂的“遺產系統”),下面將詳細討論設計方案。

          通常,設計總是從域模型開始的,我們通過對用例的分析,可以建立以下實體:

          分類對象(Category),藝術家對象(Artist),專輯對象(Album),歌曲對象(Song),這些對象是簡單的一對多關系。我們把這些對象都一一映射為實體Bean,由于這些對象最終映射為數據庫表,這些表的結構相對簡單,因此我們選擇CMP實現。相比BMPCMP不僅大大簡化了數據庫訪問的代碼,而且由容器管理的特性通常使CMPBMP具有更好的緩沖性能和可移植性。

          在邏輯層,毫無疑問,會話Bean將是最好的選擇。如果不使用Session Bean,您可能需要自行處理多線程同步,安全,事務處理等問題,這將是一項復雜而艱巨的工程。由于容器自動為我們處理了大量的如事務,安全,多線程等底層服務操作,我們就只需關注于我們的業務邏輯。此外,對于異步調用,消息驅動Bean是不錯的選擇。

          在表示層,我們用JSP頁面將界面呈現給用戶。有過網站開發經驗的開發人員一定有過這樣的深刻感受,HTML元素和JSP代碼混合在一起是多么巨大的災難,它將導致可維護性隨著頁面數量的增加呈指數增長。

          開源的Struts模型通過MVC架構大大簡化了JSP前端的開發。但是,使用Struts還要求開發人員對于Struts底層結構和配置文件有相當的了解。WebLogic提供的Java Page Flow技術完全基于Struts技術,并且隱藏了更多的底層細節,提供了圖形化的頁面導航功能,大大簡化了Web層的開發。此外,大量的NetUI標簽和數據綁定技術,使您的JSP頁面立刻具備了可視化開發的功能。我們將采用各種實現方式來編寫Web層。

          開發環境

          J2EE僅僅是一個標準,眾多的廠商提供了相應的實現平臺,其中,BEAWebLogic無疑是最優秀的J2EE平臺之一。我們將把JetMusic站點建立在WebLogic Platform 8.1平臺上,并采用WebLogic Workshop 8.1這個強大的IDE作為開發工具。你可以免費從BEA官方站點上下載非商業目的開發使用的5-IP限制版本的WebLogic Platform 8.1

          http://commerce.bea.com/showproduct.jsp?family=WLP&major=8.1&minor=2

          我們的站點資源除了歌曲文件外,將全部存放在關系數據庫中。選用MS SQL Server 2000的原因是這個數據庫對硬件資源的消耗要比Oracle少,適合于我們作開發使用。如果您計劃采用Oracle或其他數據庫,沒有關系,您只需修改實體Bean的相關部署配置,即可立刻移植到其他廠商的數據庫上。

          要流暢地運行WebLogic Server 8.1WebLogic Workshop 8.1,您至少需要512M內存,如果僅有256M內存,您可以修改WebLogic的啟動參數,指定較小的JVM內存(如128M)。

          配置數據庫:

          啟動MS SQL Server,打開企業管理器,新建數據庫music,請注意我們并不需要建立任何表,稍候部署我們的應用時WebLogic會自動創建相應的表。

          配置WebLogic

          新建一個名為“music”的配置,并選擇模板Basic Weblogic Workshop Domain,以便能使用Workshop進行開發和調試。

          啟動WebLogic,打開瀏覽器,輸入http://localhost:7001/console,登陸,在左邊找到musicServicesJDBCConnection Pools,新建一個連接池,選擇數據庫“MS SQL Server”,驅動程序“BEAs MS SQL Server Driver(Type 4) Versions:7.0, 2000”,填好數據庫名,用戶名,口令等,測試無誤后部署。然后選擇左邊的musicServicesJDBCData Sources,新建一個名為“jdbc/MusicDataSource”的數據源,使用剛才建好的連接池,部署。

          啟動Workshop,選擇NewApplication新建應用程序Music,然后選擇Browse,找到服務器配置文件“<BEA安裝目錄>user_projectsdomainsmusicconfig.xml”,確定后創建一個應用程序。

          為了有效組織和管理代碼,我們把所有的實體Bean均放在包music.ejb.db中,所有的會話Bean放在music.ejb中,另外建一個music.shared包用于存放會話Bean和表示層JSP/Servlets共享的Java類,包括各種自定義異常,傳遞的值對象等。

          我們將創建3個工程,分別為MusicEjb Project,實現持久層和邏輯層;MusicClient Project,用于在命令行測試和調試邏輯層和持久層;MusicWeb Project,用于實現表示層。創建好的結構在Workshop中顯示如下:

          設計持久層

          我們首先開始設計持久層,通過前面的分析,我們抽象出以下實體Bean

          Category實體Bean:代表一個分類;

          Artist實體Bean:代表一個藝術家;

          Album實體Bean:代表一個專輯;

          Song實體Bean:代表一首歌曲;

          Account實體Bean:代表一個用戶。

          對應的CMR關系為:

          Category-Artist:一對多

          Artist-Album:一對多

          Album-Song:一對多

          先建立一個簡單的名為CategoryEntity Bean:展開左側MusicEjbmusicejbdb,選擇菜單FileNewEntity Bean,在設計視圖中分別添加3CMP字段,一個Create方法,一個Finder方法,另外我們還添加了一個copy方法用于返回一個Value Object對象:

          然后在右邊的屬性面板中為Entity Bean設置屬性,在這里我們的主要設置如下:

          data-source-name: jdbc/MusicDataSource

          default-transaction: Required

          table-name: category

          Local EJB

            JNDI name: ejb/Category

            Bean class name: CategoryLocal

            Home class name: CategoryLocalHome

          為了實現自增主鍵的功能,需要指定一個Ejb-Gen屬性:點擊右鍵彈出菜單,選擇Insert EJB Gentagautomatic-key-generation,指定字段名id,數據庫類型SQLServer2000即可。

          為了提高CMP的性能,我們全部采用本地接口,如果某些CMP字段需要提供只讀接口(如id,username字段),只需右鍵點擊字段名,然后選擇“Read Only”。

          按相同方法建立Artist.ejbAlbum.ejbSong.ejbAccount.ejb,然后創建CMR關系:

          打開Category.ejb的設計視圖,點擊右鍵,在彈出菜單里選擇Add Relation,建立一對多的CMR關系:

          類似的,創建Artist-AlbumAlbum-Song的一對多關系。

          注意我們還設計了一個AccountUtil類,使用正則表達驗證用戶信息的有效性,比如用戶名,口令是否符合要求。

          設計邏輯層

          首先我們設計一個JndiHelper類,用于封裝查找實體BeanJNDI操作,同時還對實體BeanHome接口緩存。

          我們把所有的邏輯封裝到3Session Bean中:

          MusicView.ejb:用于封裝瀏覽,下載等頁面操作。

          AccountManage.ejb:用于封裝注冊,登陸等賬號操作。

          MusicManage.ejb:用于封裝管理員的各項操作。

          首先建立MusicView.ejb,我們一共設計了以下業務方法:

          所有的方法均為遠程方法,這樣Web層和EJB就可分開部署。當然你也可以將會話Bean接口全部改成本地接口以進一步提高性能。方法看上去雖多,但邏輯相當簡單,例如,getAlbums(int artistId)方法:

          基本邏輯大致為:

          查找相應的實體Bean,獲得實體Bean對應CMR關系的集合,在將其包裝成值對象返回給客戶端。你可以看到,由于沒有JDBC操作,代碼被大大的簡化了,并且由于容器處理了底層數據庫連接,使我們的代碼更加健壯。

          在這里我們采用了值對象(Value Object)模式,用于在Web層和邏輯層之間傳送對象。你可以很容易的寫出每個實體Bean對應的值對象,比如Album.ejb對應的值對象AlbumVO

          然后創建AccountManage.ejb,用于處理用戶帳號相關的操作:

          如果要提高系統的安全性,建議使用MD5碼存儲用戶口令,MD5算法是一個單向函數,即使獲得數據庫表也無法得知用戶口令。如果要進一步防止使用預先算好的MD5碼攻擊,還可以采用加鹽處理。為了簡單起見,我們直接將用戶口令存儲在數據庫表的字段中,因此login(String username, String password)看起來像這樣:

          如果找到了相應的實體Bean(即數據庫表中存在此記錄),再判斷password字段,如果相符,驗證通過,否則,拋出一個自定義的UnauthorizedException異常。這里也不涉及JDBC操作,因此代碼非常簡單。

          搜索功能是通過實體BeanFinder方法實現的,標準的EJB QL 2.0并不支持帶參數的like關鍵字(在SUN J2EE SDK中編譯就會失敗),幸好WebLogic對其進行了擴充。為了實現模糊搜索,這里我們定義了Song.ejb的一個Finder方法findByTitle(String title),對應的EJB QL為“SELECT OBJECT(o) FROM Song AS o WHERE lower(o.title) LIKE concat(%, concat(?1, %))”。如果使用其他廠商的服務器,你需要查看廠商的EJB QL文檔然后作相應的修改。

          最后一個是MusicManage.ejb,用于管理員創建、刪除信息:

          創建和刪除實體Bean的代碼都非常簡單,唯一需要的就是捕獲相應的異常,我們在deleteSong(int songId)中將RemoveException包裝成更一般的ApplicationException異常返回客戶端:

          需要特別注意的是,對存在一對多CMR關系的實體Bean,如果指定了級聯刪除,當刪除“一”時,對應的“多”會被自動刪除,因此執行刪除前要異常小心,至少應該提示用戶,或者,只允許刪除“多”為空的實體Bean,比如刪除Artist.ejb時:

          home = JndiHelper.getArtistLocalHome();

          artist = home.findByPrimaryKey(new Integer(artistId));

          Collection c = artist.getAlbums();

          if(c.size()>0) throw new Exception("Cannot delete unless it is empty.");

          為了安全起見,我們在刪除時不允許刪除“多”一方不為空的實體。

          編譯,部署。OK,小功告成!現在我們可以測試一下我們的邏輯層。一個好的辦法是使用JUnit測試,但是似乎Workshop尚未集成JUnit。沒關系,我們自己寫一個客戶端Java程序來測試邏輯層。

          MusicClientProject中建立Client.Java類,放在包music.client中。為了測試,我們首先在數據庫中創建一些測試數據:

          void initData () throws Exception { … }

          然后,我們寫一個testGetCategories()方法:

          void testGetCategoris(int parentCategoryId) throws Exception { … }

          類似的,我們對每個業務邏輯都寫一個相應的測試方法,直到每一個業務邏輯都正確無誤。在一個獨立的Java客戶端程序中測試EJB要比在JSP中方便得多,你可以方便地設置斷點,跟蹤以便查看變量,隨時使用System.out.println()在控制臺輸出任何調試信息。

          設計表示層

          表示層用于向用戶提供系統交互的接口。采用J2EE的系統表示層一般都是瘦客戶端,使用JSP/Servlets技術,使用戶能通過瀏覽器使用系統。在JetMusic站點中,我們將考慮以下幾種實現方式:

          1.在JSP中使用業務代表模式:

          通常,在JSP/Servlets中直接調用EJB并不是一個好主意,這需要大量的查找JNDI的代碼,業務代表(Business Delegate)是一個不錯的模式,它封裝了所有的EJB查找和調用,使得表示層和邏輯層的耦合度能降到最低,并且還可以進行一些緩存。

          由于業務代表類將WebEJB隔開了,因此,對于JSP/Servlets來說,它們根本就不知道EJB的存在。這將帶來另一個好處:只要在設計時仔細定義了業務代表的接口,Web層和EJB的開發人員立即可以同時開發各自的模塊,Web層的開發人員可以首先對業務代表類進行硬編碼,以便返回他們希望的結果。等到EJB開發完成后,再用實際的EJB調用替換即可。

          為了封裝對MusicView.ejb的所有調用,我們建立一個MusicViewBD的業務代表類:

          index.jsp中即可使用MusicViewBD以便輸出Categories

          2.使用NetUI標簽實現數據綁定

          WebLogic提供了大量的NetUI標簽,能夠方便地在JSP中綁定數據。我們下一步將創建一個viewCa.jsp頁面,此頁面向用戶展示分類。

          我們首先創建一個EJB ControlWebLogic向我們提供的EJB Control完全封裝了EJB調用。利用EJB Control,我們不用寫一行代碼,立刻就可以在JSP中調用EJB。這個EJB Control可以看作是一個用標簽封裝的業務代表模式的應用。

          MusicWeb工程下新建文件夾music.control,用于存放EJB Control。新建EJB Control,命名為CallMusicView

          選擇“Browse application EJBs…”,直接找到“MusicView (remote jndi)”,Workshop會自動填好相應的接口,點擊“create”即創建成功。

          當我們獲得了從EJB返回的Collection后,可以使用Repeater標簽顯示這個復雜的數據,在這里我們不打算進一步討論Repeater標簽的細節,關于如何使用Repeater標簽,可以參考下面的文章:

          http://dev2dev.bea.com/products/wlworkshop81/articles/repeater.jsp

          以下JSP頁面顯示了如何使用EJB Control調用EJBgetCategories遠程方法,并將返回的Collection結果集用Repeater標簽以超鏈接的形式顯示出來,這里還用到了一個netui:anchor標簽:

          第一個DeclareControl標簽申明了一個Control,名為ctrlMusicView,第二個CallControl標簽調用控件ctrlMusicView的一個方法getCategories并附帶參數MethodParameter,參數值由URLid確定,然后將結果放在變量categories中。Repeater標簽從categories取得數據源,然后循環顯示集合中的每個元素。

          對應的源代碼看起來是這樣:

          運行結果在IE中顯示如下:

          類似地,您可以自己“畫”出列藝術家,列專輯的頁面,然后將它們組合起來。這些JSP頁面僅僅是通過簡單的鼠標拖放和屬性設置完成的,真是太棒了!

          3.使用Java Page Flow

          Java Page Flow是完全基于開源的Struts模型,但提供了更強的易用性和自動化的狀態管理,支持數據綁定,擁有更強大的動作和異常處理。下一步,我們將創建一個名為FileUploadController的頁面流,完成一個文件上傳的功能。

          新建頁面流fileUploadWorkshop自動為我們創建了一個FileUploadController.jpf,這個jpf作為控制器,我們再添加一個uploadFileAction,包含一個名為“UploadForm”的ActionForm3JSP文件,然后設置導航如下:

          詳細代碼請下載源代碼包。

          使用Java Page Flow的最大的優點是完全的MVC架構,有清晰的導航模型,并且配合NetUI標簽,實現起來更為簡單。

          以上討論了基本的瀏覽頁面,下面我們要實現用戶登陸的功能和針對管理員的管理功能。

          實現用戶登陸

          為了跟蹤用戶,我們創建一個AccountManageBD的業務代理類,并將它放在Session中,封裝所有與用戶帳號相關的操作。幾個關鍵的方法如下:

          String getName() // 返回用戶登陸名

          boolean isAdmin() // 是否是管理員

          void login(String username, String password) // 登陸系統

          我們在MusicSessionListener中監聽Session事件,以便創建和銷毀與Session關聯的AccountManageBD對象。然后在/WEB-INF/web.xml中注冊MusicSessionListener

          這樣,任何時候均可在JSP中調用

          AccountManageBD account = (accountManageBD)

              session.getAttribute(AccountManageBD.ACCOUNT);

          來訪問用戶當前登陸信息。

          創建一個登陸頁面流LoginController.jpf實現登陸頁面:

          類似的,一個registerUser頁面流實現用戶注冊功能:

          實現管理功能

          為了能使管理員登陸后管理站點,我們把所有的管理頁面放在目錄{MusicWeb}/admin/下,為了防止未授權用戶訪問任何/admin/下的任何頁面,我們準備一個過濾器AdminFilter,將所有未授權的操作重定向到/login/LoginController.jpf中。核心代碼如下:

          修改/WEB-INF/web.xml,添加過濾器申明:

          最后,你只需要用Dreamwaver之類的網頁制作軟件強化界面,然后把這些JSP及頁面流組織起來,即可發布您的JetMusic站點。

          安全

          正如你所看到的,我們的安全是通過Web層的登陸驗證實現的,在邏輯層并未使用基于角色的驗證邏輯,對于我們現在的站點來說,可能已經足夠了。不過,如果您打算將來向用戶提供付費下載,付費收聽的業務,那么就需要切實保證系統的安全性。通常,不建議您自己開發安全邏輯,因為開發防攻擊的安全邏輯本身就不是一個簡單的任務,此外,自定義的安全邏輯可能會導致較低的可重用性。

          Java 1.4J2EE 1.3開始,Java驗證與授權服務JAASJava Authentication and Authorization Service)就被引入到核心包中。JAAS實現了驗證和授權兩類服務,驗證服務能夠可靠并安全地確定目前是誰在執行代碼,在我們的這個應用中,只需要用到JAAS的驗證服務。以下是JAAS驗證的一般步驟:

          1.創建一個LoginContext實例。

          2.指定LoginContext的配置文件。

          3.加載指定的LoginModule

          4.客戶端調用LoginContextlogin方法。

          5.如果登陸成功,就會將一個通過身份驗證的PrincipalSubject聯系起來。

          6LoginContext將通過身份驗證的Subject返回客戶機。

          WebLogic中,缺省的用戶,組和角色都是在XML配置文件中指定的,我們只需要提供一個登陸頁面,包含一個名為j_security_checkForm,一個名為j_usernameTextBox和一個名為j_passwordPasswordBox,然后在/WEB-INF/web.xml中配置即可使用WebLogic默認的JAAS身份驗證。但是,這些用戶是靜態的,無法滿足我們使用數據庫動態管理用戶的需求。好在JAAS本身就是一個“可插拔”的模塊,我們可以輕易地使用自定義的安全模塊實現驗證功能。

          要在WebLogic中實現自定義的安全驗證,需要提供一個Security Provider,包括自定義的Authentication ProviderLogin ModuleIdentity AssertionPrincipal Validation ProviderRole Mapping Provider,看上去有點復雜,不過,你可以從BEA站點下載一個示例代碼:

          http://dev2dev.bea.com/codelibrary/code/security_prov81.jsp

          然后修改相應的實現類,配置部署,即可實現自定義的JAAS驗證。

          使用JAAS驗證的好處是,驗證邏輯從頁面中分離,對頁面的限制訪問是通過/WEB-INF/web.xml中的配置指定的,無需自定義過濾器;在調用EJB時,Web容器能隱含的把Principal傳遞給EJB容器,從而和EJB的安全限制聯系起來。

          在我們的JetMusic站點中,目前僅僅使用Session+過濾器的機制,也許可以考慮在下一個版本中加入JAAS驗證,以便更清晰地劃分表示層邏輯和安全邏輯。

          部署

          可以直接在Workshop中啟動WebLogic Server,即可自動完成部署。如果部署成功,WebLogic不會輸出提示信息,如果部署失敗,會提示異常信息。

          常見的異常有:

          JDBC連接出錯:沒有啟動數據庫,或者沒有找到對應JNDI名稱的數據庫。你需要檢查JNDI設置和數據庫是否已經啟動。

          INSERT語句出錯:這是創建實體Bean時容器的INSERT語句出錯。如果指定了automatic-key-generation,第一次部署時WebLogic自動創建的主鍵為INT類型,但并不是AUTOINCREASE,需要打開數據庫,手動更改主鍵設置,或者,您可以直接下載示例數據庫,然后導入到SQL Server2000即可。

          總結

          我們已經利用J2EE技術在WebLogic Server上基本建立起了一個健壯的,可擴展的JetMusic音樂站點,其中涉及到EJBJSPServletsNetUIJava Page FlowJAAS以及幾個常用的EJB設計模式等。相信您能從這個小小的Web應用中看到J2EE體系強大的功能。由于時間倉促,水平有限,文中不免會有一些錯誤,懇請讀者指正。最后希望本文能夠給您帶來一點收獲。最后申明:如果您使用JetMusic系統在網上發布音樂,所引起的一切版權糾紛本文作者概不負責。

          源代碼下載

          JetMusic站點的全部源代碼(Workshop 8.1工程)和示例數據庫:

          http://javap2p.nease.net/src/jetmusic.zip

          參考

          Sun J2EE Tutorialhttp://java.sun.com/j2ee/tutorial/1_3-fcs/index.html

          EJB設計模式,[]Floyd Marinescu

          EJB 2.0企業級應用程序開發,[]Chuck CavanessBrian Keeton

          BEA WebLogic Server寶典,[]Joe Zuffoletto

          WebLogic Workshop Helphttp://e-docs.bea.com/workshop/docs81/doc/en/core/index.html

          關于作者

          廖雪峰(dev2dev論壇IDxuefengl

          北京郵電大學在校本科生,信息工程專業,對J2EE/J2ME開發有濃厚興趣。

          posted on 2005-12-02 10:38 Xuefeng's Weblog 閱讀(401) 評論(0)  編輯  收藏 所屬分類: J2EE

          主站蜘蛛池模板: 临沂市| 广元市| 怀远县| 武城县| 沈丘县| 呼伦贝尔市| 皮山县| 安陆市| 都匀市| 阿拉尔市| 桐庐县| 延津县| 鹿邑县| 贵定县| 松滋市| 南宁市| 钟祥市| 正阳县| 翁牛特旗| 都昌县| 临海市| 瑞金市| 镶黄旗| 龙里县| 平湖市| 曲松县| 明光市| 拉孜县| 五大连池市| 青冈县| 县级市| 辽源市| 五指山市| 肇州县| 华容县| 沾益县| 满城县| 黎城县| 上虞市| 威海市| 柘荣县|