導航菜單每個catalog下都有兩個,而側邊欄菜單則在item下定義,這兩個標簽類與主菜單的標簽類沒有太大的區別,主要就是生成標簽體,匹配CSS樣式,因此,代碼中相同的部分我不再細述,只說一下不同的地方。
在tag包下創建NavTag類和SideTag類,標簽屬性與MainTag一樣,只是SideTag多了一個headercss屬性,這是在頁面顯示時,加在邊欄上當前選中項左側小箭頭的CSS樣式,不清楚的話,請運行程序后觀察。
NavTag.java
根據pageID找到此元素對象:
//根據pageID找到此元素對象,即book元素對象
Element current = ResourceManage.getSingleElementById(pageID);
如果current不為空,取得父節點,其為item元素。根據pageID值,如果為695043,則subnav為id="item-program-java"的item元素,如果為691245,則subnav為id="item-program-database"的item元素。這個subnav的作用也是用來判斷當前的菜單是否為選中,加入CSS樣式顯示。
Element subnav = null;
if (current != null) {
subnav = current.getParent(); //取得父節點,即item元素
}
SideTag.java
在SideTag中也有上面的代碼,但是subnav不再與CSS有關,而是取得它的所有子元素集合,即book元素集合,然后遍歷所有book節點,取出屬性值放入標簽體中再輸出到頁面。
我注釋寫得很詳細,請查看代碼了解細節。
4、創建StringUtils.java
在util包下創建StringUtils類,這個類作為字符串處理類。添加public static String replace(String string, String oldString, String newString)方法,它的作用就是將標簽體中的[id]、[url]、[name]、[description]替換為XML文件中的屬性值。如果被替換的字符串在標簽體中有多個,也能將它全部替換。
/**
* 將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其實是索引值
if ((i = string.indexOf(oldString, i)) >= 0) {
char[] string2 = string.toCharArray(); //字符串放入數組
char[] newString2 = newString.toCharArray(); //要替換的字符串
int oLength = oldString.length(); //被替換的字符串的長度
StringBuilder buf = new StringBuilder(string2.length);
/*
* 從索引0開始,按i值的長度在string2數組中截取字符
* 將截取的字符放到buf中,接著再加入要替換的內容
*/
buf.append(string2, 0, i).append(newString2);
i += oLength; //得到被替換字符結束位置的索引
int j = i;
/*
* 查找string中,是否仍然含有被替換字符串
* 使用循環,將所有oldString換成newString
*/
while ((i = string.indexOf(oldString, i)) > 0) {
buf.append(string2, j, i - j).append(newString2);
i += oLength; //得到被替換字符結束位置的索引
j = i;
}
/*
* 截取string2數組中從索引j開始
* string2.length-j的長度加到buf中
* 其實就是在buf中補全標簽體
*/
buf.append(string2, j, string2.length - j);
return buf.toString();
}
return string;
}
如果看注釋就能懂那最好不過,如果不明白,在這上面打個斷點調試一下,就會十分清楚了。這個方法是Openfire中的源代碼,不過全是E文,大象先也看不明白,后來調試了一下,知道是怎么回事了,特加上注釋和大家一起分享這個好東東。
寫完了自定義標簽類,我們還需要自定義標簽文件,在WEB-INF目錄下新建demo.tld,代碼不帖出來了,使用源碼中的就行。
5、裝飾器
后臺的Java類,我們全部寫完了,現在開始完成前臺部分,在頁面顯示上,Openfire使用了sitemesh裝飾器框架,它能幫助我們在由大量頁面構成的項目中創建一致的頁面布局和外觀,如一致的導航條,一致的banner,一致的版權等等。至于怎樣使用sitemesh這里不作介紹了,請自行去搜索相關資料,這部分內容網上很多的,sitemesh比較簡單,很容易上手。
使用裝飾器,需要導入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文件,內容如下:
<decorators defaultdir="/decorators">
<decorator name="main" page="main.jsp">
<pattern>/index.jsp</pattern>
<pattern>/book_*.jsp</pattern>
</decorator>
</decorators>
請注意defaultdir后面的值,這是你放裝飾器頁面的目錄位置。本例中,在WebRoot目錄下新建decorators文件夾,再在里面新建main.jsp,這個就是裝飾器頁面了。<pattern></pattern>之間的內容就是需要被裝飾的頁面,*號是通配符,可以代替任何字符。/book_*.jsp表示:使用main.jsp裝飾WebRoot目錄下所有以book_開頭的頁面,這里定義的name="main",可以在裝飾器頁面中使用,因為不一定只有一個裝飾器頁面,可能會有很多個。因此,在裝飾器頁面中為了布局效果會聯合使用多個裝飾器來修飾頁面,以達到簡化布局、降低維護難度、提高工作效率的作用。另外在使用時,請注意被裝飾頁面與裝飾器頁面之間的相對位置。
6、main.jsp
在頁面中引用被裝飾頁面的page對象:<decorator:usePage id="decoratedPage" />
使用decoratedPage取得被裝飾頁面中meta標簽的content值,再將它放到request請求中,這樣在自定義標簽類中我們使用pageContext對象得到的請求就是這個。
<%
request.setAttribute("pageID", decoratedPage.getProperty("meta.pageID"));
%>
顯示被裝飾頁面<title></title>之間的標題:<decorator:title />
顯示被裝飾頁面body中的內容,被裝飾頁面的主體都將在這里顯示:<decorator:body/>
除此之外,在main.jsp中,我們還發現大量的使用div來放置元素,并且每個標簽中都有id屬性,沒有看到任何的CSS樣式,其實是通過id屬性在demo.css文件進行了定義,所有的布局和顯示效果都在這個文件中進行了定義,這樣就達到了內容呈現與樣式布局相分離的結果,方便以后的修改和維護,這種做法用的人現在已經越來越多,大家趕快行動吧!
sitemesh中還有一個sitemesh.xml文件,如果程序中沒有特別需求,可以不用加入它,我們也能在sitemesh-2.2.1.jar中找到,com.opensymphony.module.sitemesh.factory目錄下有一個sitemesh-default.xml文件,這就是sitemesh默認的配置文件。
7、顯示頁面
在tag-console.xml的url屬性里定義了顯示頁面,接下來我們把這些頁面都做好,內容很簡單,本文只是演示Openfire的菜單設計思想,用容易懂的例子來說明,以便大家能夠快速了解。
index.jsp頁面的代碼:
<%@ 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>
其余的幾個頁面內容大致一樣,把content值、<title></title>標題、以及<center><h1></h1></center>之間的內容換成book元素中定義的屬性值即可。
demo.css
在WebRoot目錄下新建css文件夾,再在里面創建demo.css文件。我直接把Openfire的樣式表COPY過來。然后把里面沒用的部分刪除了,體積小了不少。
圖片
我從Openfire中只取了本例用到的圖片,如果是專業美工,完全可以設計出自己的菜單風格。
8、發布項目
我們在web.xml中可以加入下面一段代碼,將index.jsp作為我們的默認顯示頁面:
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
把demo部署到%TOMCAT_HOME%\webapps目錄下,啟動tomcat,在地址欄中輸入:http://localhost:8080/demo 看看效果是不是和下面的一樣:

大家覺得這個菜單的顯示方式怎么樣呢?偶覺得這用來做后臺管理到還是不錯滴,如果是其它的信息管理系統,那這個配置文件的內容就會很恐怖了,其實還可以把XML中的中文信息保存到國際化資源文件中,這樣可以實現多語種版本以及簡化維護。各位有什么好的意見或建議,可以和我留言或E-mail給我。大象也想把自己的一點心得拿出來和大家分享。
點擊下載:demo源碼
點擊下載:dom4j-1.6.1.jar jaxen-1.1-beta-7.jar sitemesh-2.2.1.jar
本文為菠蘿大象原創,如要轉載請注明出處