1. 程式人生 > >Struts原理與實踐(8)

Struts原理與實踐(8)

在上一篇文章中介紹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就可以看到執行效果。效果圖為:

354685.gif


    注:dtree的下載地址為: http://www.destroydrop.com/javascripts/tree/

本文作者:張永美 羅會波 湖北省當陽市國稅局 可通過[email protected]與他們聯絡

相關文章

·Struts原理與實踐(1)·(2)·(3)·(4)·(5)·(6)·(7)

相關推薦

Struts原理實踐8

在上一篇文章中介紹JavaScript實現級聯下拉選單的例子,本篇繼續介紹一個利用現存的JavaScript程式碼配合struts構成一個樹型選單的例子。     大家知道,樹型選單在應用中有著十分廣泛的用途。實現樹型選單的途徑較多,本文介紹的一種覺得理解起來比較直觀,與上篇

Struts原理實踐

                一、JDBC的工作原理 Struts在本質上是java程式,要在Struts應用程式中訪問資料庫,首先,必須搞清楚Java Database Connectivity API(JDBC)的工作原理。正如其名字揭示的,JDBC庫提供了一個底層API,用來支援獨立於任何特定SQL實

struts原理實踐

本篇我們來討論一下struts的國際化程式設計問題,即所謂的i18n程式設計問題,這一篇我們討論其基礎部分。與這個問題緊密相關的是在各java論壇中被頻繁提及的中文亂碼問題,因為,英、美程式設計人員較少涉及到中文亂碼問題,因此,這方面的英文資料也是非常奇缺的,同時也很少找到這方面比較完整的中文資料,本文也嘗試

Struts原理實踐4

本篇我們來討論一下struts的國際化程式設計問題,即所謂的i18n程式設計問題,這一篇我們討論其基礎部分。與這個問題緊密相關的是在各java論壇中被頻繁提及的中文亂碼問題,因為,英、美程式設計人員較少涉及到中文亂碼問題,因此,這方面的英文資料也是非常奇缺的,同時也很少找到這

struts原理實踐

  (第2部分) 下面,我們就一步步按照上面所說的步驟來完成我們的應用程式: 第一步,我們的應用程式的Views部分包含兩個.jsp頁面:一個是登入頁面logon.jsp,另一個是使用者登入成功後的使用者功能頁main.jsp,暫時這個頁面只是個簡單的歡迎頁面。 其中,

Struts原理實踐6

本文我們來討論一下Struts中的輸入校驗問題。我們知道,資訊系統有垃圾進垃圾出的特點,為了避免垃圾資料的輸入,對輸入進行校驗是任何資訊系統都要面對的問題。在傳統的程式設計實踐中,我們往往在需要進行校驗的地方分別對它們進行校驗,而實際上需要校驗的東西大多都很類似,如必需的欄位

Webpack原理實踐:打包流程

寫在前面的話 在閱讀 webpack4.x 原始碼的過程中,參考了《深入淺出webpack》一書和眾多大神的文章,結合自己的一點體會,總結如下。 總述 webpack 就像一條生產線,要經過一系列處理流程後才能將原始檔轉換成輸出結果。 這條生產線上的每個處理流程的職責都是單一的,多個流程之間有存在依賴關

Docker容器的原理實踐

系統 rest 引擎 服務器 分類 file creat 產品 maintain 歡迎訪問網易雲社區,了解更多網易技術產品運營經驗。虛擬化是一種資源管理技術,將計算機的各種資源予以抽象、轉換後呈現出來, 打破實體結構間的不可切割的障礙,使用戶可以比原本更好的方式來應用這些資

機器學習演算法原理實踐、卡爾曼濾波器演算法淺析及matlab實戰

卡爾曼濾波器是一種利用線性系統狀態方程,通過系統輸入輸出觀測資料,對系統狀態進行最優估計的演算法。而且由於觀測包含系統的噪聲和干擾的影響,所以最優估計也可看做是濾波過程。 卡爾曼濾波器的核心

機器學習演算法原理實踐、感知機演算法

感知機 感知機是二分類的線性分類模型,輸入為例項的特徵向量,輸出為例項的類別(取+1和-1)。感知機對應於輸入空間中將例項劃分為兩類的分離超平面。感知機旨在求出該超平面,為求得超平面匯入了基於誤分類的損失函式,利用梯度下降法對損失函式進行最優化(最優

Spring Boot自動配置原理實踐

前言   Spring Boot眾所周知是為了簡化Spring的配置,省去XML的複雜化配置(雖然Spring官方推薦也使用Java配置)採用Java+Annotation方式配置。如下幾個問題是我剛開始接觸Spring Boot的時候經常遇到的一些疑問,現在總結出來希望能幫助到更多的人理解Spring B

深度優先搜尋原理實踐java

概論 深度優先搜尋屬於圖演算法的一種,是一個針對圖和樹的遍歷演算法,英文縮寫為 DFS 即 Depth First Search。深度優先搜尋是圖論中的經典演算法,利用深度優先搜尋演算法可以產生目標圖的相應拓撲排序表,利用拓撲排序表可以方便的解決很多相關的圖論問題,如最大路徑問題等等。一般用堆資料結構來輔

數字圖像處理原理實踐MATLAB版勘誤表

blog 核心 灰度變換 圖像復原 京東 .html href target 數字圖像處理 本文系《數字圖像處理原理與實踐(MATLAB版)》一書的勘誤表。【內容簡單介紹】本書全面系統地介紹了數字圖像處理技術的理論與方法,內容涉及幾何變換、灰度變換、圖像增強、圖像切割、

編碼原則實例------c++程序設計原理實踐進階篇

組類型 運算 奇怪 head 不能 gui 簡單的 版本 布局 編碼原則: 一般原則 預處理原則 命名和布局原則 類原則 函數和表達式原則 硬實時原則 關鍵系統原則 (硬實時原則、關鍵系統原則僅用於硬實時和關鍵系統程序設計) (嚴格原則都用一個大寫字母R及其編號標識,而

有符號數和無符號數------c++程序設計原理實踐進階篇

效果 進階 str 二進制位 bsp () 都是 有符號 重新 有符號數與無符號數的程序設計原則: 當需要表示數值時,使用有符號數(如 int)。 當需要表示位集合時,使用無符號數(如unsigned int)。 有符號數和無符號數混合運算有可能會帶來災難性的後果。例如

動態內存分配存在的問題內存空洞------c++程序設計原理實踐進階篇

我們 程序 動態 height ++ idt 很多 alt 空間 new的問題究竟在哪裏呢?實際上問題出在new和delete的結合使用上。考察下面程序中內存分配和釋放過程: while(1){ Big* p=new big;  //...... Smal

數值限制------c++程序設計原理實踐進階篇

c++程序 its positive size true 設置 malle 設計原理 硬件 每種c++的實現都在<limits>、<climits>、<limits.h>和<float.h>中指明了內置類型的屬性,因此程序

實現求解線性方程矩陣、高斯消去法------c++程序設計原理實踐進階篇

ipy 類型 cat sys sca solution gaussian 拷貝 img 步驟: 其中A是一個n*n的系數方陣 向量x和b分別是未知數和常量向量: 這個系統可能有0個、1個或者無窮多個解,這取決於系數矩陣A和向量b。求解線性系統的方法有很多,這裏使用一種經典

c++11隨機數------c++程序設計原理實踐進階篇

ber linear 而在 希望 double 元素 light eal 區間   隨機數既是一個實用工具,也是一個數學問題,它高度復雜,這與它在現實世界中的重要性是相匹配的。在此我們只討論隨機數哦最基本的內容,這些內容可用於簡單的測試和仿真。在<random>

Exp2 後門原理實踐未完待續

bin image alt job 模塊 加強 ont .sh 問題 Exp2 後門原理與實踐 實驗環境 攻擊機 kali 4.14(64位) (IP: 10.0.2.6/24) 靶機 ubuntu 16.04(32位) (IP: 10.0.2.4/24) windo