实战Struts-Menu

一、简介
 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,内容如下:
<?xml version="1.0" encoding="ISO-8859-1"?>

<!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>

 3:解压缩struts-1.2.7.zip,将压缩包中的lib目录下所有的8个jar释放到lib目录中,将5个tld文件释放到web\WEB-INF目录中,在web\WEB-INF目录中新建struts-config.xml,内容如下:
<?xml version="1.0" encoding="ISO-8859-1" ?>

<!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>
 4:解压缩struts-menu-2.3.zip,将压缩包中的jstl-1.0.6.jar、standard-1.0.6.jar、struts-menu-2.3.jar释放到lib目录中,将压缩包中的struts-menu.tld、struts-menu-el.tld释放到web\WEB-INF目录中,解压缩commons-lang-2.1.zip,将commons-lang-2.1.jar解压缩到lib目录中,注意,在Struts-Menu的文档中没有看到需要这个包,但是没有这个包却无法成功加载。在web\WEB-INF目录中新建menu-config.xml,内容如下:
<?xml version="1.0" encoding="UTF-8" ?>

<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>
 5:将第四步的示例程序中的struts-menu应用目录下的images、scripts、styles三个目录中的内容复制到web目录下

 6:你的目录结构应该类似如下:
  %PROJECT_HOME%\classes
  %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,内容如下:
<%@ page contentType="text/html; charset=GBK" %>
<%@ taglib uri="struts-menu" prefix="menu" %>

<menu:useMenuDisplayer name="ListMenu"
  bundle="org.apache.struts.action.MESSAGE">
  <menu:displayMenu name="DoorSite"/>
</menu:useMenuDisplayer>
 运行Tomcat,在IE地址栏输入 http://localhost:8080/mymenu/static-menu.jsp查看

 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
       > 在src\application.properties中增加下面的内容:
      #门户网站
      menu.DoorSite=DoorSite
      #雅虎
      menu.Yahoo=Yahoo
      #雅虎首页
      menu.YahooIndex=Yahoo Index
      #雅虎邮件
      menu.YahooMail=Yahoo Mail
      #搜狐
      menu.Sohu=Sohu
      #新浪
      menu.Sina=Sina

 > 修改menu-config.xml文件<Menus></Menus>部分:
 <Menus>
  <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>
 重起Tomcat,在IE地址栏输入 http://localhost:8080/mymenu/static-menu.jsp 查看

 3:结合数据库实现动态菜单
 > 新建数据myexamples:
CREATE DATABASE myexamples
 > 新建数据库表menu_item:
CREATE TABLE menu_item (
  id BIGINT not null,
  parent_name VARCHAR(30),
  name VARCHAR(30),
  title VARCHAR(30),
  titleCN VARCHAR(30),
  description VARCHAR(50),
  location VARCHAR(255),
  target VARCHAR(10),
  onclick VARCHAR(100),
  onmouseover VARCHAR(100),
  onmouseout VARCHAR(100),
  image VARCHAR(50),
  altImage VARCHAR(30),
  tooltip VARCHAR(100),
  roles VARCHAR(100),
  page VARCHAR(255),
  width VARCHAR(5),
  height VARCHAR(5),
  forward VARCHAR(50),
  action VARCHAR(50),
  primary key (id)
)
 > 插入测试数据:
INSERT INTO menu_item
  (id, parent_name, name, title, titleCN, location)
VALUES
  (1,null,'DatabaseMenu','Database Menu','数据库动态菜单',null),
  (2,'DatabaseMenu','Yahoo','Yahoo Mail','雅虎邮件','http://mail.yahoo.com'),
  (3,'DatabaseMenu','JavaBlogs','JavaBlogs','Java博客','http://javablogs.com'),
  (4,null,'StandaloneMenu','Standalone Menu','独立的菜单','http://www.sohu.com')
 > 将数据库驱动程序放到lib目录中,并加入到Build Path,如MySQL的数据库驱动mysql-connector-java-3.1.8-bin.jar,解压缩commons-collections-3.1.zip,将commons-collections-3.1.jar释放到lib目录,并加入Build Path
 > 新建一个Struts的Action,代码如下:
package cn.appex.menu;

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]);
    }
  }
}
 > 将struts-config.xml文件的<action-mappings />部分修改为:
<action-mappings>
 <action path="/menuAction" type="cn.appex.menu.MenuAction" >
  <forward name="success" path="/struts-menu/dynamic-menu.jsp" />
 </action>
</action-mappings>
 > 新建JSP文件web/dynamic-menu.jsp,内容如下:
<%@ page contentType="text/html; charset=GBK" %>
<%@ taglib uri="struts-menu" prefix="menu" %>
没有使用Bundle和权限控制:
<menu:useMenuDisplayer name="ListMenu" repository="examplesRepository">
  <menu:displayMenu name="DatabaseMenu"/>
  <menu:displayMenu name="StandaloneMenu"/>
</menu:useMenuDisplayer>
使用Bundle, 没有使用权限控制:
<menu:useMenuDisplayer name="ListMenu" bundle="examplesBundle" repository="examplesRepository">
  <menu:displayMenu name="DatabaseMenu"/>
  <menu:displayMenu name="StandaloneMenu"/>
</menu:useMenuDisplayer>
使用Bundle和权限控制:
<menu:useMenuDisplayer name="ListMenu" permissions="examplesPermession" bundle="examplesBundle" repository="examplesRepository">
  <menu:displayMenu name="DatabaseMenu"/>
  <menu:displayMenu name="StandaloneMenu"/>
</menu:useMenuDisplayer>
 重起Tomcat,在地址栏输入 http://localhost:8080/mymenu/menuAction.do

七、关于Struts-Menu配置文件和API的使用方法,请参考附录中的官方网站  

你可能感兴趣的:(tomcat,Web,mysql,struts,REST)