內(nèi)容如下:
<?xml version="1.0" encoding="GBK"?>
<bookstore>
<global>
<appname>菜單導(dǎo)航demo</appname>
<version>ver 1.0</version>
<creator>菠蘿大象</creator>
</global>
<catalog id="catalog-program" name="編程開(kāi)發(fā)" url="index.jsp" description="編程開(kāi)發(fā)">
<item id="item-program-java" name="Java開(kāi)發(fā)" url="index.jsp" description="Java開(kāi)發(fā)">
<book id="695043" name="Struts2 深入詳解" url="index.jsp" description="Struts2 深入詳解"/>
<book id="691254" name="Ant整合開(kāi)發(fā)" url="book_ant.jsp" description="Ant整合開(kāi)發(fā)"/>
<book id="693668" name="Java編程思想" url="book_java.jsp" description="Java編程思想"/>
</item>
<item id="item-program-database" name="數(shù)據(jù)庫(kù)開(kāi)發(fā)" url="book_oracle9.jsp" description="數(shù)據(jù)庫(kù)開(kāi)發(fā)">
<book id="691245" name="Oracle 9i數(shù)據(jù)庫(kù)寶典" url="book_oracle9.jsp" description="Oracle 9i數(shù)據(jù)庫(kù)寶典"/>
<book id="693254" name="SQL Server 2005應(yīng)用開(kāi)發(fā)" url="book_sqlserver.jsp" description="SQL Server 2005應(yīng)用開(kāi)發(fā)"/>
<book id="690215" name="Oracle 10g高級(jí)開(kāi)發(fā)" url="book_oracle10.jsp" description="Oracle 10g高級(jí)開(kāi)發(fā)"/>
</item>
</catalog>
<catalog id="catalog-system" name="系統(tǒng)相關(guān)" url="book_vista.jsp" description="系統(tǒng)相關(guān)">
<item id="item-system-windows" name="Windows系統(tǒng)" url="book_vista.jsp" description="Windows系統(tǒng)">
<book id="691258" name="Windows Vista入門(mén)" url="book_vista.jsp" description="Windows Vista入門(mén)"/>
<book id="695489" name="Windows注冊(cè)表實(shí)戰(zhàn)" url="book_windows.jsp" description="Windows注冊(cè)表實(shí)戰(zhàn)"/>
</item>
<item id="item-system-linux" name="Linux系統(tǒng)" url="book_linux9.jsp" description="Linux系統(tǒng)">
<book id="696598" name="Linux 9.0詳解" url="book_linux9.jsp" description="Linux 9.0詳解"/>
<book id="694585" name="Linux寶典" url="book_linux.jsp" description="Linux寶典"/>
</item>
</catalog>
</bookstore>
上面XML里面的東西我是隨便寫(xiě)的,大家千萬(wàn)不要較真,我用圖書(shū)來(lái)做菜單一是方便大家理解,另一個(gè)是簡(jiǎn)化程序,其實(shí)Openfire的服務(wù)器端是一個(gè)后臺(tái)管理系統(tǒng),它是基于XMPP(可擴(kuò)展消息處理現(xiàn)場(chǎng)協(xié)議)開(kāi)發(fā)的,XMPP貫穿整個(gè)系統(tǒng)設(shè)計(jì),如果你想用它的控制臺(tái)框架,但又不想用XMPP,請(qǐng)先從網(wǎng)頁(yè)入口開(kāi)始,結(jié)合頁(yè)面仔細(xì)分析代碼,把需要的部分抽取出來(lái)就行了,其它的不用去管。大象沒(méi)有研究過(guò)XMPP,只是抽取了控制臺(tái)框架,對(duì)Openfire的源代碼也沒(méi)能深入的研究,最主要還是E文太爛了。^_^
Openfire沒(méi)有采用現(xiàn)在很流行的技術(shù)架構(gòu)(SSH),只使用JSP+JavaBean,但是它有自己的系統(tǒng)設(shè)計(jì),就連日志都是自己做的,沒(méi)有使用我們熟悉的log4j,真的是太佩服鳥(niǎo)~~~~
2、創(chuàng)建ResourceManage.java
在util包下創(chuàng)建ResourceManage類(lèi),這個(gè)類(lèi)主要是用來(lái)讀取tag-console.xml文件,并取得文件中的基本信息,以及查找元素等操作。
我們先在Constant接口中,增加一個(gè)字符串常量:String TAG_CONFIG = "tag-console.xml"
ResourceManage前面加載資源的部分和上一篇,后來(lái)修改過(guò)的DataBaseConnect類(lèi)一樣,只需把Constant.DB_CONFIG換成Constant.TAG_CONFIG就行了。接下來(lái),在類(lèi)中加入幾個(gè)讀取XML中基本信息的方法:
<global>
<appname>菜單導(dǎo)航demo</appname>
<version>ver 1.0</version>
<creator>菠蘿大象</creator>
</global>
這里只舉出取得appname元素值的方法,其它的幾個(gè)都很相似,請(qǐng)查看源代碼。
/**
* 得到應(yīng)用程序名稱(chēng)
*/
public static String getAppName(){
Element appName = (Element) coreModel.selectSingleNode("//bookstore/global/appname");
if(appName!=null){
return appName.getText();
}else{
return null;
}
}
根據(jù)id屬性值查找對(duì)應(yīng)的元素:
/**
* 在整個(gè)文檔節(jié)點(diǎn)中查找id屬性值為傳入id的元素對(duì)象
* @param id 待查找的id屬性值
* @return 返回找到的元素對(duì)象
*/
public static Element getSingleElementById(String id){
return (Element)coreModel.selectSingleNode("//*[@id='"+id+"']");
}
這里用到了XPATH語(yǔ)法,根據(jù)傳入的id值,在整個(gè)文檔中查找id屬性值與此一致的元素對(duì)象。用下面的代碼舉例說(shuō)明:
<book id="695043" name="Struts2 深入詳解" url="index.jsp" description="Struts2 深入詳解"/>
當(dāng)傳入的id屬性值為"695043"時(shí),那么我們就會(huì)得到對(duì)應(yīng)這個(gè)id值的book元素對(duì)象,id屬性值在整個(gè)配置文件中就是一個(gè)key關(guān)鍵字,起到定位的作用。
根據(jù)id屬性值查找上下文中對(duì)應(yīng)的catalog元素:
/**
* 根據(jù)傳入的id查找上下文中對(duì)應(yīng)的catalog元素
* @param id 待查找的id屬性值
* @return 返回id值所在的catalog元素對(duì)象
*/
public static Element getElementByID(String id) {
return (Element) coreModel.selectSingleNode("http://*[@id='" + id
+ "']/ancestor::catalog");
}
ancestor是XPATH語(yǔ)法中軸的概念,我引用網(wǎng)上官方文檔中的說(shuō)明:“ancestor軸(axis)包含上下節(jié)點(diǎn)的祖先節(jié)點(diǎn),該祖先節(jié)點(diǎn)由其上下文節(jié)點(diǎn)的父節(jié)點(diǎn)以及父節(jié)點(diǎn)的父節(jié)點(diǎn)等等諸如此類(lèi)的節(jié)點(diǎn)構(gòu)成,所ancestor軸總是包含有根節(jié)點(diǎn),除非上下文節(jié)點(diǎn)就是根節(jié)點(diǎn)本身。”這句話的意思其實(shí)就是向上查找節(jié)點(diǎn),直到找到根節(jié)點(diǎn)為止。對(duì)于ancestor::catalog來(lái)說(shuō),就是向上查找直到catalog節(jié)點(diǎn)為止。所以getElementByID這個(gè)方法是根據(jù)傳入的id屬性值在上下文中查找節(jié)點(diǎn),直到找到這個(gè)id值所在的上下文catalog節(jié)點(diǎn)為止。當(dāng)傳入的id屬性值為"695043"時(shí),我們會(huì)得到id="catalog-program"這個(gè)catalog節(jié)點(diǎn)元素,而不會(huì)得到id="catalog-system"這個(gè)catalog節(jié)點(diǎn)元素。這樣說(shuō)大家大概能明白是什么意思了吧?
可以去這個(gè)網(wǎng)站看下XPATH教程:http://www.zvon.org/xxl/XPathTutorial/General_chi/examples.html
3、自定義標(biāo)簽
采用自定義標(biāo)簽的方式來(lái)生成菜單,借助ResourceManage類(lèi)取出XML文件中的信息,將這些內(nèi)容裝載到標(biāo)簽體中,然后在JSP頁(yè)面中呈現(xiàn)出來(lái)。
1、主菜單標(biāo)簽
主菜單有兩個(gè),catalog元素這一層表示主菜單。標(biāo)簽的實(shí)現(xiàn)類(lèi)如下:
MainTag.java
建com.demo.tag包,在tag包下創(chuàng)建MainTag類(lèi),繼承javax.servlet.jsp.tagext.BodyTagSupport類(lèi),主要的部分代碼如下,完整代碼請(qǐng)下載源碼包查看。
這些屬性與demo.tld中的屬性對(duì)應(yīng),每個(gè)屬性都有setter和getter方法。
private String css; //菜單的CSS樣式
private String currentcss; //當(dāng)前選中菜單的CSS樣式
doStartTag()方法是遇到標(biāo)簽開(kāi)始時(shí)調(diào)用的方法,EVAL_BODY_BUFFERED表示創(chuàng)建一個(gè)緩沖流,將標(biāo)簽體的內(nèi)容保存到BodyContent對(duì)象中,可以對(duì)其內(nèi)容進(jìn)行修改。BodyContent繼承了javax.servlet.jsp.JspWriter類(lèi),BodyContent對(duì)象的內(nèi)容不自動(dòng)寫(xiě)入servlet的輸出流,而是放在一個(gè)字符流緩存中。當(dāng)標(biāo)簽體完成后其對(duì)象仍可在doEndTag()方法中應(yīng)用,由getString()或getReader()方法操作。并在必要時(shí)修改及寫(xiě)入恢復(fù)的JspWriter輸出流。EVAL_BODY_INCLUDE表示將顯示標(biāo)簽間的文字。另一個(gè)返回值是SKIP_BODY,它表示不顯示標(biāo)簽間的文字。
public int doStartTag() throws JspException {
return EVAL_BODY_BUFFERED; //創(chuàng)建保存到BodyContent對(duì)象中的緩沖流
}
doEndTag()方法是遇到標(biāo)簽結(jié)束時(shí)調(diào)用的方法,EVAL_PAGE表示處理完標(biāo)簽后繼續(xù)執(zhí)行標(biāo)簽之后的JSP頁(yè)面。另一個(gè)返回值SKIP_PAGE表示不處理標(biāo)簽之后的JSP網(wǎng)頁(yè)。
public int doEndTag() throws JspException {
//代碼主體省略,請(qǐng)查看源碼
return EVAL_PAGE; //處理完標(biāo)簽后繼續(xù)執(zhí)行標(biāo)簽之后的JSP頁(yè)面
}
doEndTag()方法中部分比較重要的代碼說(shuō)明:
使用pageContext對(duì)象在JSP頁(yè)面上下文取得請(qǐng)求,不過(guò)請(qǐng)注意pageContext,它定義在javax.servlet.jsp.tagext.TagSupport中,而不是在BodyTagSupport中,因?yàn)?span lang="EN-US">BodyTagSupport繼承了TagSupport
//使用pageContext對(duì)象在JSP頁(yè)面上下文取得請(qǐng)求
HttpServletRequest request = (HttpServletRequest)pageContext.getRequest();
取得請(qǐng)求中的pageID值,這個(gè)pageID值在每個(gè)jsp頁(yè)面中放在meta標(biāo)簽中,通過(guò)sitemesh裝飾器取出放到request中。
/*
* 從請(qǐng)求中得到pageID值,即每個(gè)JSP里meta的content值
* 與XML文件中book元素的id屬性值一致
*/
String pageID = (String)request.getAttribute("pageID");
將所有的catalog元素取出放到List集合中,這里是只取得catalog這一層級(jí)的元素,實(shí)質(zhì)就是catalogs中只有兩個(gè)對(duì)象,一個(gè)是id="catalog-program",另一個(gè)是id="catalog-system",使用dom4j我們會(huì)發(fā)現(xiàn)處理元素非常容易,API相當(dāng)?shù)呢S富,想寫(xiě)成什么樣完全憑你自己的想法。
//將所有的catalog元素取出放到List集合
List catalogs = ResourceManage.getCoreModel().selectNodes("//catalog");
看看前面介紹的getElementByID這個(gè)方法,這個(gè)currentCatalog所表示就是pageID所在的catalog元素。上面的代碼是為了和下面的代碼結(jié)合來(lái)判斷當(dāng)前的菜單是否為選中,加入CSS樣式顯示。
//pageID所在的catalog元素,主要用來(lái)判斷當(dāng)前菜單是否被選中
Element currentCatalog = (Element)ResourceManage.getElementByID(pageID);
從BodyContent中將標(biāo)簽體緩存流讀取出來(lái),標(biāo)簽在WebRoot/decorators/main.jsp中:<a href="[url]" title="[description]" onmouseover="self.status='[description]';return true;" onmouseout="self.status='';return true;">[name]</a>
String value = getBodyContent().getString(); //得到標(biāo)簽體
Catalogs里面是兩個(gè)catalog對(duì)象,循環(huán)遍歷取出,將標(biāo)簽體中的[id]、[url]、[name]、[description]替換為XML文件中的屬性值,這樣主菜單標(biāo)簽就生成了。
for (int i=0; i<catalogs.size(); i++) {
Element catalog = (Element)catalogs.get(i); //catalog元素對(duì)象
String value = getBodyContent().getString(); //得到標(biāo)簽體
/*
* 將標(biāo)簽體中的[id]、[url]、[name]、[description]
* 替換為XML文件中的屬性值
* attributeValue方法是取屬性值
*/
if (value != null) {
value = StringUtils.replace(value, "[url]", request
.getContextPath()
+ "/" + catalog.attributeValue("url"));
value = StringUtils.replace(value, "[name]",catalog.attributeValue("name"));
value = StringUtils.replace(value, "[description]",catalog.
attributeValue("description"));
}
String css = getCss();
//對(duì)當(dāng)前選中菜單添加CSS樣式
if (catalog.equals(currentCatalog)) {
css = getCurrentcss();
}
buf.append("<li class=\"").append(css).append("\">");
if (i > 0) {
buf.append(" | ");
}
buf.append(value).append("</li>");
}
2、導(dǎo)航菜單及側(cè)邊欄菜單標(biāo)簽
導(dǎo)航菜單每個(gè)catalog下都有兩個(gè),而側(cè)邊欄菜單則在item下定義,這兩個(gè)標(biāo)簽類(lèi)與主菜單的標(biāo)簽類(lèi)沒(méi)有太大的區(qū)別,主要就是生成標(biāo)簽體,匹配CSS樣式,因此,代碼中相同的部分我不再細(xì)述,只說(shuō)一下不同的地方。
在tag包下創(chuàng)建NavTag類(lèi)和SideTag類(lèi),標(biāo)簽屬性與MainTag一樣,只是SideTag多了一個(gè)headercss屬性,這是在頁(yè)面顯示時(shí),加在邊欄上當(dāng)前選中項(xiàng)左側(cè)小箭頭的CSS樣式,不清楚的話,請(qǐng)運(yùn)行程序后觀察。
NavTag.java
根據(jù)pageID找到此元素對(duì)象:
//根據(jù)pageID找到此元素對(duì)象,即book元素對(duì)象
Element current = ResourceManage.getSingleElementById(pageID);
如果current不為空,取得父節(jié)點(diǎn),其為item元素。根據(jù)pageID值,如果為695043,則subnav為id="item-program-java"的item元素,如果為691245,則subnav為id="item-program-database"的item元素。這個(gè)subnav的作用也是用來(lái)判斷當(dāng)前的菜單是否為選中,加入CSS樣式顯示。
Element subnav = null;
if (current != null) {
subnav = current.getParent(); //取得父節(jié)點(diǎn),即item元素
}
SideTag.java
在SideTag中也有上面的代碼,但是subnav不再與CSS有關(guān),而是取得它的所有子元素集合,即book元素集合,然后遍歷所有book節(jié)點(diǎn),取出屬性值放入標(biāo)簽體中再輸出到頁(yè)面。
我注釋寫(xiě)得很詳細(xì),請(qǐng)查看代碼了解細(xì)節(jié)。
4、創(chuàng)建StringUtils.java
在util包下創(chuàng)建StringUtils類(lèi),這個(gè)類(lèi)作為字符串處理類(lèi)。添加public static String replace(String string, String oldString, String newString)方法,它的作用就是將標(biāo)簽體中的[id]、[url]、[name]、[description]替換為XML文件中的屬性值。如果被替換的字符串在標(biāo)簽體中有多個(gè),也能將它全部替換。
/**
* 將string中的oldString全部替換為newString
* @param string 原始字符串
* @param oldString 被替換的字符串
* @param newString 要替換的字符串
* @return 返回替換完后的新string
*/
public static String replace(String string, String oldString, String newString) {
if (string == null) {
return null;
}
int i = 0;
//判斷string中是否有被替換的字符串,i其實(shí)是索引值
if ((i = string.indexOf(oldString, i)) >= 0) {
char[] string2 = string.toCharArray(); //字符串放入數(shù)組
char[] newString2 = newString.toCharArray(); //要替換的字符串
int oLength = oldString.length(); //被替換的字符串的長(zhǎng)度
StringBuilder buf = new StringBuilder(string2.length);
/*
* 從索引0開(kāi)始,按i值的長(zhǎng)度在string2數(shù)組中截取字符
* 將截取的字符放到buf中,接著再加入要替換的內(nèi)容
*/
buf.append(string2, 0, i).append(newString2);
i += oLength; //得到被替換字符結(jié)束位置的索引
int j = i;
/*
* 查找string中,是否仍然含有被替換字符串
* 使用循環(huán),將所有oldString換成newString
*/
while ((i = string.indexOf(oldString, i)) > 0) {
buf.append(string2, j, i - j).append(newString2);
i += oLength; //得到被替換字符結(jié)束位置的索引
j = i;
}
/*
* 截取string2數(shù)組中從索引j開(kāi)始
* string2.length-j的長(zhǎng)度加到buf中
* 其實(shí)就是在buf中補(bǔ)全標(biāo)簽體
*/
buf.append(string2, j, string2.length - j);
return buf.toString();
}
return string;
}
如果看注釋就能懂那最好不過(guò),如果不明白,在這上面打個(gè)斷點(diǎn)調(diào)試一下,就會(huì)十分清楚了。這個(gè)方法是Openfire中的源代碼,不過(guò)全是E文,大象先也看不明白,后來(lái)調(diào)試了一下,知道是怎么回事了,特加上注釋和大家一起分享這個(gè)好東東。
寫(xiě)完了自定義標(biāo)簽類(lèi),我們還需要自定義標(biāo)簽文件,在WEB-INF目錄下新建demo.tld,代碼不帖出來(lái)了,使用源碼中的就行。
5、裝飾器
后臺(tái)的Java類(lèi),我們?nèi)繉?xiě)完了,現(xiàn)在開(kāi)始完成前臺(tái)部分,在頁(yè)面顯示上,Openfire使用了sitemesh裝飾器框架,它能幫助我們?cè)谟纱罅宽?yè)面構(gòu)成的項(xiàng)目中創(chuàng)建一致的頁(yè)面布局和外觀,如一致的導(dǎo)航條,一致的banner,一致的版權(quán)等等。至于怎樣使用sitemesh這里不作介紹了,請(qǐng)自行去搜索相關(guān)資料,這部分內(nèi)容網(wǎng)上很多的,sitemesh比較簡(jiǎn)單,很容易上手。
使用裝飾器,需要導(dǎo)入JAR包,在本例中,大象使用的是sitemesh-2.2.1.jar包,將jar包加到WEB-INF/lib目錄中,然后修改web.xml,添加如下代碼:
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
</filter >
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
然后在WEB-INF下新建decorators.xml文件,內(nèi)容如下:
<decorators defaultdir="/decorators">
<decorator name="main" page="main.jsp">
<pattern>/index.jsp</pattern>
<pattern>/book_*.jsp</pattern>
</decorator>
</decorators>
請(qǐng)注意defaultdir后面的值,這是你放裝飾器頁(yè)面的目錄位置。本例中,在WebRoot目錄下新建decorators文件夾,再在里面新建main.jsp,這個(gè)就是裝飾器頁(yè)面了。<pattern></pattern>之間的內(nèi)容就是需要被裝飾的頁(yè)面,*號(hào)是通配符,可以代替任何字符。/book_*.jsp表示:使用main.jsp裝飾WebRoot目錄下所有以book_開(kāi)頭的頁(yè)面,這里定義的name="main",可以在裝飾器頁(yè)面中使用,因?yàn)椴灰欢ㄖ挥幸粋€(gè)裝飾器頁(yè)面,可能會(huì)有很多個(gè)。因此,在裝飾器頁(yè)面中為了布局效果會(huì)聯(lián)合使用多個(gè)裝飾器來(lái)修飾頁(yè)面,以達(dá)到簡(jiǎn)化布局、降低維護(hù)難度、提高工作效率的作用。另外在使用時(shí),請(qǐng)注意被裝飾頁(yè)面與裝飾器頁(yè)面之間的相對(duì)位置。
6、main.jsp
在頁(yè)面中引用被裝飾頁(yè)面的page對(duì)象:<decorator:usePage id="decoratedPage" />
使用decoratedPage取得被裝飾頁(yè)面中meta標(biāo)簽的content值,再將它放到request請(qǐng)求中,這樣在自定義標(biāo)簽類(lèi)中我們使用pageContext對(duì)象得到的請(qǐng)求就是這個(gè)。
<%
request.setAttribute("pageID", decoratedPage.getProperty("meta.pageID"));
%>
顯示被裝飾頁(yè)面<title></title>之間的標(biāo)題:<decorator:title />
顯示被裝飾頁(yè)面body中的內(nèi)容,被裝飾頁(yè)面的主體都將在這里顯示:<decorator:body/>
除此之外,在main.jsp中,我們還發(fā)現(xiàn)大量的使用div來(lái)放置元素,并且每個(gè)標(biāo)簽中都有id屬性,沒(méi)有看到任何的CSS樣式,其實(shí)是通過(guò)id屬性在demo.css文件進(jìn)行了定義,所有的布局和顯示效果都在這個(gè)文件中進(jìn)行了定義,這樣就達(dá)到了內(nèi)容呈現(xiàn)與樣式布局相分離的結(jié)果,方便以后的修改和維護(hù),這種做法用的人現(xiàn)在已經(jīng)越來(lái)越多,大家趕快行動(dòng)吧!
sitemesh中還有一個(gè)sitemesh.xml文件,如果程序中沒(méi)有特別需求,可以不用加入它,我們也能在sitemesh-2.2.1.jar中找到,com.opensymphony.module.sitemesh.factory目錄下有一個(gè)sitemesh-default.xml文件,這就是sitemesh默認(rèn)的配置文件。
7、顯示頁(yè)面
在tag-console.xml的url屬性里定義了顯示頁(yè)面,接下來(lái)我們把這些頁(yè)面都做好,內(nèi)容很簡(jiǎn)單,本文只是演示Openfire的菜單設(shè)計(jì)思想,用容易懂的例子來(lái)說(shuō)明,以便大家能夠快速了解。
index.jsp頁(yè)面的代碼:
<%@ page contentType="text/html; charset=utf-8" %>
<html>
<head>
<title>Struts2 深入詳解</title>
<meta name="pageID" content="695043"/>
</head>
<body>
<center><h1>Struts2 深入詳解</h1></center>
</body>
</html>
其余的幾個(gè)頁(yè)面內(nèi)容大致一樣,把content值、<title></title>標(biāo)題、以及<center><h1></h1></center>之間的內(nèi)容換成book元素中定義的屬性值即可。
demo.css
在WebRoot目錄下新建css文件夾,再在里面創(chuàng)建demo.css文件。我直接把Openfire的樣式表COPY過(guò)來(lái)。然后把里面沒(méi)用的部分刪除了,體積小了不少。
圖片
我從Openfire中只取了本例用到的圖片,如果是專(zhuān)業(yè)美工,完全可以設(shè)計(jì)出自己的菜單風(fēng)格。
8、發(fā)布項(xiàng)目
我們?cè)?span lang="EN-US">web.xml中可以加入下面一段代碼,將index.jsp作為我們的默認(rèn)顯示頁(yè)面:
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
把demo部署到%TOMCAT_HOME%\webapps目錄下,啟動(dòng)tomcat,在地址欄中輸入:http://localhost:8080/demo 看看效果是不是和下面的一樣:

大家覺(jué)得這個(gè)菜單的顯示方式怎么樣呢?偶覺(jué)得這用來(lái)做后臺(tái)管理到還是不錯(cuò)滴,如果是其它的信息管理系統(tǒng),那這個(gè)配置文件的內(nèi)容就會(huì)很恐怖了,其實(shí)還可以把XML中的中文信息保存到國(guó)際化資源文件中,這樣可以實(shí)現(xiàn)多語(yǔ)種版本以及簡(jiǎn)化維護(hù)。各位有什么好的意見(jiàn)或建議,可以和我留言或E-mail給我。大象也想把自己的一點(diǎn)心得拿出來(lái)和大家分享。
點(diǎn)擊下載:demo源碼
點(diǎn)擊下載:dom4j-1.6.1.jar jaxen-1.1-beta-7.jar sitemesh-2.2.1.jar
本文為菠蘿大象原創(chuàng),如要轉(zhuǎn)載請(qǐng)注明出處