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

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

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

    海鷗航際

    JAVA站
    posts - 11, comments - 53, trackbacks - 1, articles - 102

    Struts-menu源碼分析

    Posted on 2005-01-11 17:15 海天一鷗 閱讀(507) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): Struts專(zhuān)題

    Struts-menu源碼分析

            好的代碼讀起來(lái)讓人如飲醍醐,讀完以后神清氣爽。如果你想提高你的編程水平,如果你想提高你的設(shè)計(jì)能力,如果你也想成為大師,那么就去閱讀代碼吧。以本人十幾年來(lái)的編程經(jīng)驗(yàn),閱讀代碼能讓你得到的比閱讀文章(那怕是大師的文章)得到的更多。優(yōu)秀而且實(shí)用的代碼有很多,比如Junit,比如Jive,比如petStore,甚至是tomcat的Example、Log4j的Example。

            一段廣告完畢,下面就為大家分析一下struts-menu的源碼,作為送給大家的圣誕禮物吧。Struts-Menu也來(lái)自一位大師的作品, Matt Raible。有很多優(yōu)秀的作品,比如使用struts和hibernate的struts-resume。官方網(wǎng)站是http://raibledesigns.com/wiki/Wiki.jsp?page=Main。Struts-Menu的最新版本是2.1。功能是使用struts技術(shù),構(gòu)建樹(shù)形菜單。應(yīng)該說(shuō)是一個(gè)非常實(shí)用的技術(shù),極大的方便了廣大的開(kāi)發(fā)人員。與此同時(shí),個(gè)人認(rèn)為它的作用還不止于些。比如,同時(shí)它也是一個(gè)使用Mavenvelocity的一個(gè)很好的例子。

            首先,我們?nèi)タ匆幌滤男Ч?a target="_blank">http://www.raibledesigns.com/struts-menu/??梢钥吹剑绱素S富多彩的菜單效果,都是在演示一個(gè)配置文件里的內(nèi)容。這是一個(gè)非常好的數(shù)據(jù)與表示相分離的實(shí)現(xiàn)。我們打開(kāi)它的源碼來(lái)看。首先看一下它的包圖

    共有五個(gè)包,其中menu自然是完成數(shù)據(jù)組織功能,是核心之一,displayer是顯示方式包,完成數(shù)據(jù)顯示大部分功能。也是核心之一。taglib意義明顯。example自然是一些example。util是讀取資源文件的包。因些,我們重點(diǎn)研究的包只有三個(gè)menu,displayer和taglib。

    首先我們來(lái)看menu包的類(lèi)圖

    首先是MenuPlugIn這個(gè)類(lèi)。這個(gè)類(lèi)的功能很明顯,就是一個(gè)struts的plug-in??梢钥吹?,它只有一個(gè)參數(shù)menuConfig,就是menu的配置文件路徑。果然,在struts-conf文件中有這么一段

     <!-- ========== Plug Ins Configuration ================================== -->

    <plug-in className="net.sf.navigator.menu.MenuPlugIn">
    <set-property property="menuConfig" value="/WEB-INF/menu-config.xml"/>
    </plug-in>

     

    說(shuō)明配置文件來(lái)自于/WEB-INF/menu-config.xml,當(dāng)然,我們可以找到相應(yīng)路徑下找到這個(gè)文件。如果你以前沒(méi)有做過(guò)struts的plug-in,現(xiàn)在該知道怎么做了吧,就這么簡(jiǎn)單。通過(guò)閱讀初始化函數(shù),知道它的功能就是調(diào)用MenuRepository來(lái)建立菜單。因此。我們知道MenuRepository必然是一個(gè)組織管理管理菜單的組織類(lèi)。

    public void init(ActionServlet servlet, ModuleConfig config) throws ServletException { if (log.isDebugEnabled()) {  log.debug("Starting struts-menu initialization"); } this.servlet = servlet; repository = new MenuRepository(); repository.setLoadParam(menuConfig); repository.setServlet(servlet); try { repository.load(); servlet.getServletContext().setAttribute( MenuRepository.MENU_REPOSITORY_KEY, repository); if (log.isDebugEnabled()) { log.debug("struts-menu initialization successfull"); } } catch (LoadableResourceException lre) { throw new ServletException( "Failure initializing struts-menu: " + lre.getMessage()); } }

    打開(kāi)MenuRepository類(lèi),我們可以看到這個(gè)類(lèi)也很簡(jiǎn)單,不過(guò)已經(jīng)有少可以學(xué)習(xí)的了。首先是FastHashMap,可以看到,這個(gè)類(lèi)里有三個(gè)FastHashMap。顧名思議,是快速HashMap了,再看一下,它來(lái)自org.apache.commons.collections.FastHashMap;??吹給rg.apache.commons這個(gè)著名的包了?如果你以前從沒(méi)使用過(guò)它,那么建議你花上一段時(shí)間去研究使用它,我保證物有所值。

    protected FastHashMap menus = new FastHashMap();
    protected FastHashMap displayers = new FastHashMap();
    protected FastHashMap templates = new FastHashMap();

    接下來(lái)我們看到log的定義。對(duì)了,log,調(diào)試的核心之一。而下面這一句則是commons log的最常用的使用方法??炜熳屇愕某绦蚴褂蒙蟘ommons log吧,第一,它功能強(qiáng)大,第二,它使用簡(jiǎn)單,就是這么簡(jiǎn)單。

    private Log log = LogFactory.getLog(getClass().getName());

    下面看一個(gè)的函數(shù)

     protected Digester initDigester() { Digester digester = new Digester(); digester.setClassLoader(Thread.currentThread().getContextClassLoader()); digester.push(this); //digester.setDebug(getDebug()); // 1 digester.addObjectCreate("MenuConfig/Menus/Menu", "net.sf.navigator.menu.MenuComponent", "type"); digester.addSetProperties("MenuConfig/Menus/Menu"); digester.addSetNext("MenuConfig/Menus/Menu", "addMenu"); // 2 digester.addObjectCreate("MenuConfig/Menus/Menu/Item", "net.sf.navigator.menu.MenuComponent", "type"); digester.addSetProperties("MenuConfig/Menus/Menu/Item"); digester.addSetNext("MenuConfig/Menus/Menu/Item", "addMenuComponent", "net.sf.navigator.menu.MenuComponent"); // 3 digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item", "net.sf.navigator.menu.MenuComponent", "type"); digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item"); digester.addSetNext("MenuConfig/Menus/Menu/Item/Item", "addMenuComponent", "net.sf.navigator.menu.MenuComponent"); // 4 digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item/Item", "net.sf.navigator.menu.MenuComponent", "type"); digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item/Item"); digester.addSetNext("MenuConfig/Menus/Menu/Item/Item/Item", "addMenuComponent", "net.sf.navigator.menu.MenuComponent"); // 5 digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item/Item/Item", "net.sf.navigator.menu.MenuComponent", "type"); digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item/Item/Item"); digester.addSetNext("MenuConfig/Menus/Menu/Item/Item/Item/Item", "addMenuComponent", "net.sf.navigator.menu.MenuComponent"); // 6 digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item/Item/Item", "net.sf.navigator.menu.MenuComponent", "type"); digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item/Item/Item"); digester.addSetNext("MenuConfig/Menus/Menu/Item/Item/Item/Item", "addMenuComponent", "net.sf.navigator.menu.MenuComponent"); // 7 digester.addObjectCreate("MenuConfig/Menus/Menu/Item/Item/Item/Item", "net.sf.navigator.menu.MenuComponent", "type"); digester.addSetProperties("MenuConfig/Menus/Menu/Item/Item/Item/Item"); digester.addSetNext("MenuConfig/Menus/Menu/Item/Item/Item/Item", "addMenuComponent", "net.sf.navigator.menu.MenuComponent"); digester.addObjectCreate("MenuConfig/Displayers/Displayer", "net.sf.navigator.displayer.MenuDisplayerMapping", "mapping"); digester.addSetProperties("MenuConfig/Displayers/Displayer"); digester.addSetNext("MenuConfig/Displayers/Displayer", "addMenuDisplayerMapping", "net.sf.navigator.displayer.MenuDisplayerMapping"); digester.addSetProperty("MenuConfig/Displayers/Displayer/SetProperty", "property", "value"); return digester; }

    這里又是一個(gè)經(jīng)典,digester,Digester的使用,如果你需要讀一個(gè)XML配置文件,并且不想與DOM直接打交道的話(huà),Digester將是一個(gè)很好的選擇。實(shí)際上我們看到load函數(shù)調(diào)用一句 digester.parse(input);就已經(jīng)把menu-config.xml建立到內(nèi)存里了,就這么簡(jiǎn)單。如果你想要初始化你的系統(tǒng),這種方法是不是可以學(xué)習(xí)呢?"工欲善其事,必先利其器"。我們可以看到Raible是怎么樣利用現(xiàn)有的工具來(lái)減輕開(kāi)發(fā)量的。

    由于MenuRepository舉重若輕的初始化過(guò)程,甚至都沒(méi)有讓我們看到樹(shù)形結(jié)構(gòu)是怎么建立到內(nèi)存里去的。不過(guò)不要著急,類(lèi)圖給我們了明示。

    看到MenuBase類(lèi)了嗎?對(duì)了,看名字就知道是一個(gè)Menu的基類(lèi)??梢钥吹剑且粋€(gè)簡(jiǎn)單的JavaBean。而且相信它的每個(gè)屬性大家根據(jù)名字也能猜出來(lái)。所以重點(diǎn)講解是MenuComponent,一個(gè)簡(jiǎn)化的 "Composite"模式。

    如上圖所示。由于此處的Leaf沒(méi)有任何方法,只有屬性。因此Leaf和Composite收縮成了一個(gè)MenuComponent類(lèi)。大家都知道,Composite模式是實(shí)現(xiàn)樹(shù)形結(jié)構(gòu)最好的方法。如果你以前沒(méi)有機(jī)會(huì)實(shí)現(xiàn)或者沒(méi)有從Composite模式得到好處,那么,從這里看一下用Composite模式得到的好處。首先看它的簡(jiǎn)單,MenuComponet的實(shí)際代碼很少,加起來(lái)不到十行。

    public void addMenuComponent(MenuComponent menuComponent) { menuComponents.add(menuComponent); menuComponent.setParent(this); if ((menuComponent.getName() == null) || (menuComponent.getName().equals(""))) { menuComponent.setName(this.name + menuComponents.size()); } } public MenuComponent[] getMenuComponents() { MenuComponent[] menus = (MenuComponent[]) menuComponents.toArray(_menuComponent); return menus; }

    如果你用十行來(lái)實(shí)現(xiàn)一個(gè)樹(shù)型結(jié)構(gòu)(并且還是通用的),你愿不愿意?就是通過(guò)簡(jiǎn)單的這么一些代碼,實(shí)現(xiàn)的在內(nèi)存中建立樹(shù)型結(jié)構(gòu)的目標(biāo)。

    下面我們來(lái)看DispLay包,這個(gè)包的功能也是很清楚的,就是用來(lái)顯示啦。這個(gè)包的類(lèi)圖非常漂亮,遺憾的是也非常大。只能縮小了給大家看了。

    從類(lèi)圖中可以看到一個(gè)非常極漂亮的面象對(duì)象的設(shè)計(jì)思路。通過(guò)一個(gè)接口,利用模板方法。最后具體實(shí)現(xiàn)樹(shù)型結(jié)構(gòu)的顯示。其主要方法是displayComponents和display這兩方法,init方法則實(shí)現(xiàn)了初始化的工作,讀取javascript和圖片等文件。displayComponents是一個(gè)迭代函數(shù)。從而可以遍歷一個(gè)MenuCompont樹(shù)。并將其顯示出來(lái)。

    應(yīng)該說(shuō),Menu包是一個(gè)M層,而Dispplya包是一個(gè)view層,而加上TagLib包,就實(shí)現(xiàn)了MVC的完整結(jié)構(gòu)。

    兩個(gè)Tag類(lèi)很清楚,首先我們從怎么使用它來(lái)看它們實(shí)現(xiàn)的功能

    <menu:useMenuDisplayer name="ListMenu"
    bundle="org.apache.struts.action.MESSAGE">
            <menu:displayMenu name="ToDoListMenuFile"/>
            <menu:displayMenu name="ToDoListMenuEdit"/>
            <menu:displayMenu name="CaseDetailMenuCase"/>
            <menu:displayMenu name="Standalone"/>
    </menu:useMenuDisplayer>

    顯而易見(jiàn)。useMenuDisplayer這個(gè)類(lèi)是實(shí)現(xiàn)使用哪一種顯示方式。在menu-config里我們看到ListMenu的定義

    <Displayer name="ListMenu"
    type="net.sf.navigator.displayer.ListMenuDisplayer"/>

    displayMenu則是取得一菜單,并將其顯示出來(lái),同樣在menu-config也能找到。

    <Menu name="ToDoListMenuEdit" title="EDIT">
    <Item name="TDLselect" title="SELECT_ALL" image="images/select-all.png"
    location="index.jsp" width="100" />
    <Item name="TDLprefs" title="USER_PREFERENCES" image="images/prefs.png"
    location="index.jsp" width="150" />
    <Item title="Action Test" action="setPermissions?displayer=${displayer}"/>
    </Menu>

    查看 DisplayMenu的代碼,可以看到。它完成的功能只是從context里取得MenuComponent對(duì)象,然后通過(guò) displayer.display(menu);把它交給一個(gè)MenuDisplayer的實(shí)例來(lái)負(fù)責(zé)畫(huà)出來(lái)。

    因此,Control層很好的完成了控制的功能。

    綜上所述。通過(guò)這樣一個(gè)優(yōu)美的設(shè)計(jì),把各個(gè)功能都他離開(kāi)來(lái)了。如果我們需要增加一種顯示方式,只要繼承MenuDisplayer或它的一個(gè)子類(lèi),然后寫(xiě)出我們的方法,而不需要修改系統(tǒng)的其他部分。同樣的,如果我們的菜單不準(zhǔn)備存放在ServletContext而準(zhǔn)備存放在比如Session里了,那么我們也只需要修改control部分和生成部分(即MenuRepository)部分。而不影響Display部分。

    OK,對(duì)struts-menu的介紹結(jié)束了,下一篇文章將是如果使用struts-menu和數(shù)據(jù)庫(kù)技術(shù)動(dòng)態(tài)生成菜單了。請(qǐng)大家繼續(xù)關(guān)注我的網(wǎng)站。

     

     

    紫龍,于 12/22/2003 16:45:09

    藍(lán)色天空版權(quán)所有

    主站蜘蛛池模板: 极品美女一级毛片免费| www免费黄色网| 中国国产高清免费av片| 亚洲一区二区三区免费在线观看 | 老湿机一区午夜精品免费福利| 成人无码精品1区2区3区免费看 | 最近免费2019中文字幕大全| 免费特级黄毛片在线成人观看| 亚洲色爱图小说专区| 亚洲综合伊人制服丝袜美腿| 成av免费大片黄在线观看| 91网站免费观看| 国产亚洲精品精品国产亚洲综合| 亚洲天堂一区在线| 99精品视频免费| 日日操夜夜操免费视频| 91亚洲一区二区在线观看不卡| 羞羞网站免费观看| 国产国产人免费视频成69堂| 不卡一卡二卡三亚洲| 亚洲天然素人无码专区| 免费成人高清在线视频| 凹凸精品视频分类国产品免费 | 亚洲无线电影官网| 特级毛片全部免费播放a一级 | 国产成人精品亚洲精品| 亚洲短视频在线观看| a毛片成人免费全部播放| 在线免费视频一区二区| 久久夜色精品国产噜噜噜亚洲AV| 乱淫片免费影院观看| 成人毛片视频免费网站观看| 久久精品国产亚洲AV香蕉| www成人免费视频| 国产精品成人无码免费| 亚洲大尺码专区影院| 成人无码a级毛片免费| 亚洲高清无码专区视频| 亚洲人成未满十八禁网站| 在线a免费观看最新网站| 久久亚洲高清观看|