Struts-Menu是一組從基于XML的配置文件中生成多種樣式的菜單的JSP Tags,并且可以結合API開發通過數據庫生成的動態菜單。Struts-Menu支持國際化和多種權限控制。
二、運行環境
Windows 2000 Professional
JDK 1.4.2_03
Eclipse 3.1
Tomcat 5.0.28
Tomcat Plugin 3.1Beta
Struts 1.2.7
Commons-Lang 2.1
Commons-Collections 3.1
Struts-Menu 2.3
MySQL 4.1.10a-nt
三、下載與安裝
1:從http://java.sun.com下載J2SDK,當前1.4.x系列的最新版本為1.4.2_08
2:從http://www.eclipse.org下載Eclipse,當前最新版本為3.1正式版
3:從http://jakarta.apache.org/tomcat下載Tomcat,當前5.x系列的最新版本為5.0.28
4:從http://www.sysdeo.com/eclipse/tomcatplugin下載Eclipse的Tomcat插件,對應Eclipse3.1x的最新版本為3.1Beta
5:從http://struts.apache.org下載Struts,當前最新版本為1.2.7
6:從http://jakarta.apache.org/commons/下載Commons-Lang,當前最新版本為2.1,下載Commons-Collections,當前最新版本為3.1
7:從http://struts-menu.sourceforge.net下載Struts Menu,當前最新版本為2.3
8:從http://www.mysql.com下載MySQL數據庫,4.x系列的最新版本是4.1.12a
9:MySQL、JDK、Eclipse、Tomcat和TomcatPlugin的安裝及配置請參考相關資料
四、運行示例程序
1:安裝好Tomcat后,解壓縮struts-menu-2.3.zip,將struts-menu.war釋放到Tomcat安裝目錄下的webapps下,運行Tomcat
2:在地址欄輸入http://localhost:8080/struts-menu
五、安裝與配置
1:在Eclipse中新建Tomcat項目,Context為/mymenu,Subdirectory為/web
2:在項目目錄下面新建lib目錄和web目錄及WEB-INF,在web/WEB-INF目錄下新建web.xml,內容如下:
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>My Example Application -- Vinton Lee</display-name>
<!-- ============= The Struts ActionServlet Configuration ============= -->
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- ================================================================== -->
<!-- ============= The Struts Action Servlet Mapping ================== -->
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!-- ================================================================== -->
<!-- The Welcome File List -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- =============== The Struts Taglib Definition ===================== -->
<taglib>
<taglib-uri>struts-bean</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>struts-html</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>struts-logic</taglib-uri>
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>struts-nested</taglib-uri>
<taglib-location>/WEB-INF/struts-nested.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>struts-tiles</taglib-uri>
<taglib-location>/WEB-INF/struts-tiles.tld</taglib-location>
</taglib>
<!-- ================================================================== -->
<!-- ============= The Struts-Menu Taglib Definition ================== -->
<taglib>
<taglib-uri>struts-menu</taglib-uri>
<taglib-location>/WEB-INF/struts-menu.tld</taglib-location>
</taglib>
<!-- ================================================================== -->
</web-app>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://struts.apache.org/dtds/struts-config_1_2.dtd">
<struts-config>
<!-- ========== Data Source Configuration =============================== -->
<data-sources />
<!-- ========== Form Bean Definitions =================================== -->
<form-beans />
<!-- ========== Global Exception Definitions ============================ -->
<global-exceptions />
<!-- ========== Global Forward Definitions ============================== -->
<global-forwards />
<!-- ========== Action Mapping Definitions ============================== -->
<action-mappings />
<!-- ========== Controller Configuration ================================ -->
<!-- ========== Message Resources Definitions =========================== -->
<message-resources parameter="application" />
<!-- ========== Plug Ins Configuration ================================== -->
<plug-in className="net.sf.navigator.menu.MenuPlugIn">
<set-property property="menuConfig" value="/WEB-INF/menu-config.xml"/>
</plug-in>
</struts-config>
<MenuConfig>
<Displayers>
<Displayer name="DropDown"
type="net.sf.navigator.displayer.DropDownMenuDisplayer"/>
<Displayer name="Simple"
type="net.sf.navigator.displayer.SimpleMenuDisplayer"/>
<Displayer name="CoolMenu"
type="net.sf.navigator.displayer.CoolMenuDisplayer"/>
<Displayer name="CoolMenu4"
type="net.sf.navigator.displayer.CoolMenuDisplayer4"/>
<Displayer name="MenuForm"
type="net.sf.navigator.example.PermissionsFormMenuDisplayer"/>
<Displayer name="ListMenu"
type="net.sf.navigator.displayer.ListMenuDisplayer"/>
<Displayer name="TabbedMenu"
type="net.sf.navigator.displayer.TabbedMenuDisplayer"/>
<Displayer name="Velocity"
type="net.sf.navigator.displayer.VelocityMenuDisplayer"/>
</Displayers>
<Menus>
<Menu name="DoorSite" title="DoorSite" description="Some famous doorsite" width="50">
<Item name="Yahoo" title="Yahoo">
<Item name="YahooIndex" title="Yahoo Index" location="http://www.yahoo.com.cn"/>
<Item name="YahooMail" title="Yahoo Mail" location="http://cn.mail.yahoo.com"/>
</Item>
<Item name="Sohu" title="Sohu" location="http://www.sohu.com"/>
<Item name="Sina" title="Sina" location="http://www.sina.com.cn"/>
</Menu>
</Menus>
</MenuConfig>
6:你的目錄結構應該類似如下:
%PROJECT_HOME%\lib
%PROJECT_HOME%\lib\antlr.jar
%PROJECT_HOME%\lib\commons-beanutils.jar
%PROJECT_HOME%\lib\commons-digester.jar
%PROJECT_HOME%\lib\commons-fileupload.jar
%PROJECT_HOME%\lib\commons-lang-2.1.jar
%PROJECT_HOME%\lib\commons-logging.jar
%PROJECT_HOME%\lib\commons-validator.jar
%PROJECT_HOME%\lib\jakarta-oro.jar
%PROJECT_HOME%\lib\jstl-1.0.6.jar
%PROJECT_HOME%\lib\standard-1.0.6.jar
%PROJECT_HOME%\lib\struts.jar
%PROJECT_HOME%\lib\struts-menu-2.3.jar
%PROJECT_HOME%\src
%PROJECT_HOME%\src\log4j.properties
%PROJECT_HOME%\src\application.properties
%PROJECT_HOME%\src\application_zh_CN.properties
%PROJECT_HOME%\web
%PROJECT_HOME%\web\images\

%PROJECT_HOME%\web\scripts\

%PROJECT_HOME%\web\styles\

%PROJECT_HOME%\web\WEB-INF
%PROJECT_HOME%\web\WEB-INF\menu-config.xml
%PROJECT_HOME%\web\WEB-INF\struts-bean.tld
%PROJECT_HOME%\web\WEB-INF\struts-config.xml
%PROJECT_HOME%\web\WEB-INF\struts-html.tld
%PROJECT_HOME%\web\WEB-INF\struts-logic.tld
%PROJECT_HOME%\web\WEB-INF\struts-menu.tld
%PROJECT_HOME%\web\WEB-INF\struts-menu-el.tld
%PROJECT_HOME%\web\WEB-INF\struts-nested.tld
%PROJECT_HOME%\web\WEB-INF\struts-tiles.tld
%PROJECT_HOME%\web\WEB-INF\web.xml
六、實戰Struts-Menu
1:使用配置文件實現靜態菜單
新建JSP文件web/static-menu.jsp,內容如下:
<%@ taglib uri="struts-menu" prefix="menu" %>
<menu:useMenuDisplayer name="ListMenu"
bundle="org.apache.struts.action.MESSAGE">
<menu:displayMenu name="DoorSite"/>
</menu:useMenuDisplayer>
2:實現中文化
> 在src\application_zh_CN.properties中增加下面的內容,Unicode可以通過JDK自帶的native2ascii工具得到:
menu.DoorSite=\u95e8\u6237\u7f51\u7ad9
#雅虎
menu.Yahoo=\u96c5\u864e
#雅虎首頁
menu.YahooIndex=\u96c5\u864e\u9996\u9875
#雅虎郵件
menu.YahooMail=\u96c5\u864e\u90ae\u4ef6
#搜狐
menu.Sohu=\u641c\u72d0
#新浪
menu.Sina=\u65b0\u6d6a
menu.DoorSite=DoorSite
#雅虎
menu.Yahoo=Yahoo
#雅虎首頁
menu.YahooIndex=Yahoo Index
#雅虎郵件
menu.YahooMail=Yahoo Mail
#搜狐
menu.Sohu=Sohu
#新浪
menu.Sina=Sina
<Menu name="DoorSite" title="menu.DoorSite" description="Some famous doorsite" width="50">
<Item name="Yahoo" title="menu.Yahoo">
<Item name="YahooIndex" title="menu.YahooIndex" location="http://www.yahoo.com.cn"/>
<Item name="YahooMail" title="menu.YahooMail" location="http://cn.mail.yahoo.com"/>
</Item>
<Item name="Sohu" title="menu.Sohu" location="http://www.sohu.com"/>
<Item name="Sina" title="menu.Sina" location="http://www.sina.com.cn"/>
</Menu>
</Menus>
3:結合數據庫實現動態菜單
> 新建數據myexamples:
CREATE DATABASE myexamples
> 新建數據庫表menu_item:
























> 插入測試數據:








> 新建一個Struts的Action,代碼如下:
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.ListResourceBundle;
import java.util.Map;
import com.mysql.jdbc.Driver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import net.sf.navigator.menu.MenuComponent;
import net.sf.navigator.menu.MenuRepository;
import net.sf.navigator.menu.PermissionsAdapter;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
public class MenuAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
buildMenuRepository(request);
buildMenuResourceBundle(request);
buildMenuPermissions(request);
return (mapping.findForward("success"));
}
/**
* 創建菜單數據結構
*
* @param request
*/
private void buildMenuRepository(HttpServletRequest request) {
MenuRepository repository = new MenuRepository();
// Get the repository from the application scope - and copy the
// DisplayerMappings from it.
MenuRepository defaultRepository = (MenuRepository) request
.getSession().getServletContext().getAttribute(
MenuRepository.MENU_REPOSITORY_KEY);
repository.setDisplayers(defaultRepository.getDisplayers());
Map[] menus = getMenuComponents();
for (int i=0; i < menus.length; i++) {
MenuComponent mc = new MenuComponent();
Map row = menus[i];
String name = (String) row.get("name");
mc.setName(name);
String parent = (String) row.get("parent_name");
System.out.println(name + ", parent is: " + parent);
if (parent != null) {
MenuComponent parentMenu = repository.getMenu(parent);
if (parentMenu == null) {
System.out.println("parentMenu '" + parent + "' doesn't exist!");
// create a temporary parentMenu
parentMenu = new MenuComponent();
parentMenu.setName(parent);
repository.addMenu(parentMenu);
}
mc.setParent(parentMenu);
}
String title = (String) row.get("title");
mc.setTitle(title);
String location = (String) row.get("location");
mc.setLocation(location);
String description = (String) row.get("description");
mc.setDescription(description);
repository.addMenu(mc);
}
request.setAttribute("examplesRepository", repository);
}
/**
* 從數據庫中讀取菜單配置信息
*
* @return
*/
private Map[] getMenuComponents() {
ArrayList list = new ArrayList();
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rest = null;
String sql = "select name,parent_name,title,location,description from menu_item order by id";
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
conn = DriverManager.getConnection("jdbc:mysql://localhost/myexamples?user=root&password=mywangya&useUnicode=true&characterEncoding=UTF-8");
pstmt = conn.prepareStatement(sql);
rest = pstmt.executeQuery();
while (rest.next()) {
int i = 1;
HashMap map = new HashMap();
map.put("name", rest.getString(i++));
map.put("parent_name", rest.getString(i++));
map.put("title", rest.getString(i++));
map.put("location", rest.getString(i++));
map.put("description", rest.getString(i++));
list.add(map);
}
} catch (SQLException ex) {
ex.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (null!=rest) rest.close();
if (null!=pstmt) pstmt.close();
if (null!=conn) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return (Map[]) list.toArray(new HashMap[0]);
}
/**
* 構造菜單權限
*
* @param request
*/
private void buildMenuPermissions(HttpServletRequest request) {
PermissionsAdapter permession = new PermissionsAdapter() {
public boolean isAllowed(MenuComponent menu) {
// 名稱等于StandaloneMenu的菜單不顯示
return !"StandaloneMenu".equalsIgnoreCase(menu.getName());
}
};
request.setAttribute("examplesPermession", permession);
}
/**
* 構造菜單顯示標題
*
* @param request
*/
private void buildMenuResourceBundle(HttpServletRequest request) {
MenuResourceBundle resourceBundle = new MenuResourceBundle();
request.setAttribute("examplesBundle", resourceBundle);
}
/**
* MenuResourceBundle樹狀菜單國際語言顯示
*
* @author wenbin.zhang
*
*/
class MenuResourceBundle extends ListResourceBundle {
private ArrayList list = new ArrayList();
public MenuResourceBundle() {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rest = null;
String sql = "select title,titleCN from menu_item order by id";
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
conn = DriverManager.getConnection("jdbc:mysql://localhost/myexamples?user=root&password=mywangya&useUnicode=true&characterEncoding=UTF-8");
pstmt = conn.prepareStatement(sql);
rest = pstmt.executeQuery();
while (rest.next()) {
int i = 1;
String[] message = new String[2];
message[0] = rest.getString(i++);
try {
message[1] = new String(rest.getString(i++).getBytes("latin1"), "gbk");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (message[0] != null && message[1] != null) {
list.add(message);
}
}
} catch (SQLException ex) {
ex.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (null!=rest) rest.close();
if (null!=pstmt) pstmt.close();
if (null!=conn) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public Object[][] getContents() {
return (String[][]) list.toArray(new String[0][0]);
}
}
}
<action path="/menuAction" type="cn.appex.menu.MenuAction" >
<forward name="success" path="/struts-menu/dynamic-menu.jsp" />
</action>
</action-mappings>


























七、關于Struts-Menu配置文件和API的使用方法,請參考附錄中的官方網站
附:
Struts-Menu官方網站:http://struts-menu.sourceforge.net
數據庫驅動的動態菜單:http://demo.raibledesigns.com/struts-menu/dynamicMenu.jsp