海鷗航際

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

          Struts原理與實踐(8)

          Posted on 2005-03-23 18:00 海天一鷗 閱讀(341) 評論(0)  編輯  收藏 所屬分類: Struts專題
          在上一篇文章中介紹JavaScript實現級聯下拉菜單的例子,本篇繼續介紹一個利用現存的JavaScript代碼配合struts構成一個樹型菜單的例子。

              大家知道,樹型菜單在應用中有著十分廣泛的用途。實現樹型菜單的途徑較多,本文介紹的一種覺得理解起來比較直觀,與上篇文章的方法比較類似:就是將樹型菜單的節點保存在數據庫表中(當然,在實際項目中,節點的信息往往并不是放在一個單一的表中的。比如:在一個權限管理系統中,這些信息可能分別放在用戶表、角色表、功能表等表中,只要設法讓查詢出來的結果與下面給出的表格的內容相似就可以了。只要稍微有些數據庫方面的知識做到這點并不難,詳細的實現細節超出了本文的主題,不在此細說)。通過數據訪問對象將其從數據庫中查出后放在一個集合對象中,并將該集合對象傳遞給客戶端,再用一段現存的JavaScript代碼--dtree(一個免費的JavaScript程序)來操作集合中的數據。大方向確定之后,我們就來具體著手來實現它。

              根據dtree的要求,我們來建一個數據庫表來存儲樹的節點信息,表名為functions,其結構如下:

          id字段:varchar 10 主鍵--節點標識碼
          pid字段:varchar 10 not null--父節點標識碼
          name字段:varchar 20 not null
          url字段:varchar 50 not
          null--這個字段存儲的是點擊該節點時,要定位的資源(比如一個頁面的url),
          為了不使本文的篇幅過長,暫時不給出相應的頁面,
          您可以隨便輸入一個字母比如:a,以使本例能夠正常運行。
          title字段:varchar 20
          target字段:varchar 10
          icon字段:varchar 20
          iconopen字段:varchar 20
          opened字段:char 1


              在表中輸入如下一些記錄以供后面的實驗用:

          0、-1、我的權限、javascript: void(0);
          00、0、用戶管理、javascript: void(0);
          0001、00、創建新用戶;
          0002、00、刪除用戶;
          01、0、	文章管理、javascript: void(0);
          0101、01、添加新文章;
          0102、01、修改文章;
          0103、01、刪除文章;


              到此,數據庫方面的準備工作就告一段落。

              接下來的工作我們仍然在先前介紹的mystruts項目中進行。先編寫一個名為:FunctionsForm的ActionForm,其代碼如下:

          package entity;
          import org.apache.struts.action.*;
          import javax.servlet.http.*;
          
          public class FunctionsForm extends ActionForm {
            private String icon;
            private String iconOpen;
            private String id;
            private String name;
            private String opened;
            private String pid;
            private String target;
            private String title;
            private String url;
            public String getIcon() {
              return icon;
            }
            public void setIcon(String icon) {
              this.icon = icon;
            }
            public String getIconOpen() {
              return iconOpen;
            }
            public void setIconOpen(String iconOpen) {
              this.iconOpen = iconOpen;
            }
            public String getId() {
              return id;
            }
            public void setId(String id) {
              this.id = id;
            }
            public String getName() {
              return name;
            }
            public void setName(String name) {
              this.name = name;
            }
            public String getOpened() {
              return opened;
            }
            public void setOpened(String opened) {
              this.opened = opened;
            }
            public String getPid() {
              return pid;
            }
            public void setPid(String pid) {
              this.pid = pid;
            }
            public String getTarget() {
              return target;
            }
            public void setTarget(String target) {
              this.target = target;
            }
            public String getTitle() {
              return title;
            }
            public void setTitle(String title) {
              this.title = title;
            }
            public String getUrl() {
              return url;
            }
            public void setUrl(String url) {
              this.url = url;
            }
          }


              因為我們的樹型節點的數據都存儲在數據庫表中,接下來,要做一個數據訪問對象類,名稱為:FunctionsDao.java,其代碼如下:

          package db;
          import java.sql.*;
          import java.util.*;
          import entity.FunctionsForm;
          
          public class FunctionsDao {
            private static Connection con = null;
          
            public FunctionsDao(Connection con) {
              this.con=con;
            }
          
            public static Collection findTree() {
              PreparedStatement ps=null;
              ResultSet rs = null;
              ArrayList list=new ArrayList();
          
              String sql="select * from functions";
          
              try{
                if(con.isClosed()){
                  throw new IllegalStateException("error.unexpected");
          
                }
                ps=con.prepareStatement(sql);
          
                rs=ps.executeQuery();
                while(rs.next()){
                  FunctionsForm functionsForm=new FunctionsForm();
                  functionsForm.setId(rs.getString("id"));
                  functionsForm.setPid(rs.getString("pid"));
                  functionsForm.setName(rs.getString("name"));
                  functionsForm.setUrl(rs.getString("url"));
                  functionsForm.setTitle(rs.getString("title"));
                  functionsForm.setTarget(rs.getString("target"));
                  functionsForm.setIcon(rs.getString("icon"));
                  functionsForm.setIconOpen(rs.getString("iconOpen"));
                  functionsForm.setOpened(rs.getString("opened"));
                  list.add(functionsForm);
          
                }
                return list;
              }
              catch(SQLException e){
                  e.printStackTrace();
                  throw new RuntimeException("error.unexpected");
              }
              finally{
                try{
                  if(ps!=null)
                    ps.close();
                  if(rs!=null)
                    rs.close();
                }catch(SQLException e){
                  e.printStackTrace();
                  throw new RuntimeException("error.unexpected");
                }
              }
            }
          }


              這里值得注意的是:在以往我們見到的一些顯示樹型菜單的程序,如:一些asp程序中往往簡單地采用遞歸調用的方法來查找到樹的各個節點。這對那些樹的深度不確定的場合還是有些用處,但這種處理方法也有一個致命的弱點,那就是反復地進行數據庫查詢,對一些節點較多的應用,對應用程序性能的影響是非常大的,有時會慢得讓人難以接受;而在實際的應用中大多數情況下樹的深度往往是有限的,如:用于會計科目的樹一般最多也在六層以下。又如:用作網頁功能菜單的情況,網頁設計的原則就有一條是:達到最終目的地,鼠標點擊次數最好不要多于三次。因此,在實際設計存儲樹型結構的表時要考慮查詢的效率。對能確定樹的最大深度的情況下,要設法盡量優化查詢語句,減少查詢次數,以提高應用程序的性能同時減少數據庫的負荷。

              本例對應的Action的名稱為FunctionsAction,其代碼如下:

          package action;
          
          import entity.*;
          import org.apache.struts.action.*;
          import javax.servlet.http.*;
          import javax.sql.DataSource;
          import java.sql.Connection;
          import java.sql.SQLException;
          import java.util.Collection;
          import db.FunctionsDao;
          
          public class FunctionsAction extends Action {
            public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm,
            HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) 
            {
              DataSource dataSource;
              Connection cnn=null;
              ActionErrors errors=new ActionErrors();
              try{
                dataSource = getDataSource(httpServletRequest,"A");
                cnn = dataSource.getConnection();
                FunctionsDao functionsDao=new FunctionsDao(cnn);
                Collection col=functionsDao.findTree();
                httpServletRequest.setAttribute("treeList",col);
          
                return actionMapping.findForward("success");
              }
              catch(Throwable e){
                e.printStackTrace();
                //throw new RuntimeException("未能與數據庫連接");
                ActionError error=new ActionError(e.getMessage());
                errors.add(ActionErrors.GLOBAL_ERROR,error);
              }
              finally{
                try{
                  if(cnn!=null)
                    cnn.close();
                }
                catch(SQLException e){
                  throw new RuntimeException(e.getMessage());
                }
              }
              saveErrors(httpServletRequest,errors);
              return actionMapping.findForward("fail");
            }
          }


              在struts-config.xml文件中加入如下內容:

          <form-beans>    
              <form-bean name="functionsForm" type="entity.FunctionsForm" />
            </form-beans>
          <action-mappings>
              <action name="functionsForm" path="/functionsAction" scope="request"
          	type="action.FunctionsAction" validate="false" >
          <forward name="success" path="/testDTree.jsp" />
          <forward name="fail" path="/genericError.jsp" />
              </action>
            </action-mappings>


              為了對應配置中的,我們還要提供一個顯示錯誤信息的jsp頁面,其代碼如下:

          <%@ page contentType="text/html; charset=UTF-8" %>
          <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
          <html>
          <head>
          <title>
          genericError
          </title>
          <link href="css/mycss.css" rel="stylesheet" type="text/css">
          </head>
          <body bgcolor="#ffffff">
          <html:errors/>
          </body>
          </html>


              下面,我們來看一下我們顯示樹型菜單的頁面代碼,從配置中可以看出,頁面的名稱為testDTree.jsp,代碼如下:

          <%@ page contentType="text/html; charset=UTF-8" %>
          <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
          <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
          <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
          <html>
          <head>
          <title>
          testDTree
          </title>
          <link rel="StyleSheet" href="css/dtree.css" type="text/css" />
          </head>
          <body bgcolor="#eeeeee">
          <body leftmargin="0" topmargin="0"><table width="180">
          <tr><td height="300" valign="top" nowrap>
          <script type="text/javascript" src="js/dtree.js"></script>
          <script type='text/javascript'>
          tree = new dTree('tree');
          tree.config.folderLinks=false;
          tree.config.useCookies=false;
          <logic:iterate id="functionsForm" name="treeList" scope="request"
          type="entity.FunctionsForm">
              tree.add("<bean:write name="functionsForm" property="id"/>","<bean:write
          	name="functionsForm" property="pid"/>","<bean:write name="functionsForm"
          	property="name"/>","<bean:write name="functionsForm"
          	property="url"/>","<bean:write name="functionsForm"
          	property="title"/>","<bean:write name="functionsForm"
          	property="target"/>","<bean:write name="functionsForm" property="icon"/>");
          </logic:iterate>
                document.write(tree);
          </script>
              </td>
            </tr>
          </table>
          </body>
          </html>


              從 可以看出,我們要在mystruts目錄下,建一個名為js的目錄,并將下載的dtree文件dtree.js放在該目錄中。

              再在mystruts目錄下分別建一個名為img和名為css的目錄,將dtree中用到的圖標和層疊樣式表單文件分別放在相應的目錄中。

              有關dtree的使用方法,詳見其說明文檔,如:api.html。筆者在此要感謝dtree的作者為我們提供了一個結構如此清晰的javascript程序!

              現在,可以編譯執行這個例子程序了,編譯后在瀏覽器中輸入:http://127.0.0.1:8080/mystruts/functionsAction.do就可以看到運行效果。效果圖為:



              注:dtree的下載地址為: http://www.destroydrop.com/javascripts/tree/
          主站蜘蛛池模板: 图木舒克市| 府谷县| 兖州市| 岑溪市| 清丰县| 海宁市| 新龙县| 疏附县| 绥宁县| 麦盖提县| 甘南县| 台湾省| 随州市| 唐山市| 长治市| 章丘市| 灵寿县| 平武县| 广饶县| 康乐县| 郓城县| 河津市| 临邑县| 枞阳县| 曲靖市| 邯郸市| 泰安市| 大竹县| 贵德县| 翼城县| 兴隆县| 赤峰市| 虎林市| 绥芬河市| 永定县| 莱西市| 肇州县| 东光县| 元朗区| 紫金县| 义马市|