整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          Web前端樹形級聯菜單怎么實現?

          eb前端開發中,樹形級聯菜單是一種常見的交互組件,通過層級結構展示信息并支持選擇操作。本文將以代碼為例,分步介紹如何實現一個樹形級聯菜單。無論你是否具備相關經驗,都能輕松掌握這一技能。

          1、理解樹形數據結構

          樹形結構是一種非線性數據結構,由節點和邊組成。每個節點可以有多個子節點,而根節點沒有父節點。在實現樹形級聯菜單之前,我們需要了解樹的基本概念。


          2、搭建基礎HTML結構

          我們從創建一個基礎的HTML文件開始,命名為index.html,并添加必要的樣式和腳本引用。在HTML的 <body> 標簽內,我們添加一個空白的 <ul> 元素,這將作為樹形菜單的容器。

          HTML

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>Tree Menu</title>
              <link rel="stylesheet" href="styles.css">
              <script src="main.js"></script>
          </head>
          <body>
              <ul id="tree-menu"></ul>
          </body>
          </html>


          3、數據準備與加載

          為了模擬樹形數據,我們可以定義一個包含層次結構的JSON對象。這里以一個網絡設備目錄作為示例,數據結構如下所示:

          JavaScript

          const data = [
              {
                  label: 'Device 1',
                  children: [
                      {
                          label: 'Subdevice 1-1',
                          children: []
                      },
                      {
                          label: 'Subdevice 1-2',
                          children: [
                              {
                                  label: 'Subdevice 1-2-1',
                                  children: []
                              }
                          ]
                      }
                  ]
              },
              {
                  label: 'Device 2',
                  children: []
              }
          ];


          4、遞歸生成樹形菜單

          我們通過document.getElementById("tree-menu")獲取樹形菜單的容器,然后遞歸遍歷數據對象,將每個節點生成為菜單項,并添加到容器中。`

          JavaScript

          function buildTree(menuContainer, data) {
              data.forEach(item => {
                  const li = document.createElement('li');
                  li.innerText = item.label;
                  
                  if (item.children.length > 0) {
                      const ul = document.createElement('ul');
                      buildTree(ul, item.children);
                      li.appendChild(ul);
                  }
                  
                  menuContainer.appendChild(li);
              });
          }
          
          const treeMenu = document.getElementById('tree-menu');
          buildTree(treeMenu, data);


          5、實現菜單展開與折疊

          通過添加自定義的CSS樣式和JavaScript事件處理,我們可以實現樹形菜單的展開與折疊功能。用戶點擊菜單項時,相應的子菜單將顯示或隱藏。

          CSS

          #tree-menu ul {
              display: none;
          }
          
          #tree-menu li.collapsed > ul {
              display: block;
          }

          以上代碼將初始狀態下的子菜單隱藏,當菜單項的父級li元素帶有collapsed類名時,顯示對應的子菜單。

          JavaScript

          document.querySelectorAll('#tree-menu li').forEach(li => {
              const subMenu = li.querySelector('ul');
              
              if (subMenu) {
                  li.addEventListener('click', () => {
                      li.classList.toggle('collapsed');
                  });
              }
          });

          通過以上代碼,當用戶點擊帶有子菜單項的菜單項時,通過添加或移除collapsed類名,實現子菜單的顯示或隱藏。


          6、菜單選擇與數據交互

          在樹形級聯菜單中,我們經常需要獲取用戶所選的值,并將其用于后續的數據交互。為了實現這一功能,我們可以為每個菜單項添加一個點擊事件處理函數,并將所選的值存儲在全局變量中。

          首先,在JavaScript代碼中,聲明一個全局變量selectedValue用于存儲用戶所選的值:

          JavaScript

          let selectedValue = '';
          document.querySelectorAll('#tree-menu li').forEach(li => {
              li.addEventListener('click', (e) => {
                selectedValue = li.innerText;
                // 阻止事件冒泡
                e.stopPropagation();
              });
          });

          然后,當用戶點擊任意菜單項時,相應的點擊事件將觸發,將該菜單項的文本內容賦值給selectedValue變量。


          在后續的數據交互過程中,我們可以使用selectedValue變量來獲取用戶所選的值,并進行相應的處理。


          希望本文能夠對您有所幫助,感謝您的閱讀!

          人人為我,我為人人,謝謝您的瀏覽,我們一起加油吧。

          Web前端開發中,樹形級聯菜單,是一種常見且實用的界面交互組件。它不僅可以提供清晰的導航和大量信息分類展示,還能讓用戶更方便地進行操作和查詢。然而,除了其直觀的功能外,樹形級聯菜單,還可以被用于學習和應用CSS選擇器以及CSS技巧。本文將通過代碼和實例,分步驟地講解如何通過樹形級聯菜單,來理解和運用CSS選擇器與CSS技巧。

          基本示例

          接下來,我們通過上一篇文章的例子,來了解本文的信息點。

          HTML

          <ul id="tree-menu">
              <li><label>Device 1</label>
                  <ul>
                      <li><label>Subdevice 1-1</label></li>
                      <li><label>Subdevice 1-2</label>
                          <ul>
                              <li><label>Subdevice 1-2-1</label></li>
                              <li><label>Subdevice 1-2-2</label></li>
                              <li><label>Subdevice 1-2-3</label></li>
                              <li><label>Subdevice 1-2-4</label></li>
                              <li><label>Subdevice 1-2-5</label></li>
                              <li><label>Subdevice 1-2-6</label></li>
                              <li><label>Subdevice 1-2-7</label></li>
                              <li><label>Subdevice 1-2-8</label></li>
                              <li><label>Subdevice 1-2-9</label></li>
                          </ul>
                      </li>
                  </ul>
              </li>
              <li><label>Device 2</label></li>
          </ul>

          基礎樣式

          CSS

          <style type="text/css">
          ul,
          li {
              margin: 0;
              padding: 0;
              list-style: none;
          }
          /* 默認隱藏子項 */
          #tree-menu ul {
              display: none;
          }
          /* 點擊節點展開子項 */
          #tree-menu li.collapsed>ul {
              display: block;
          }
          </style>

          層級樣式

          CSS

          <style type="text/css">
          #tree-menu li ul {
              padding: 0.5rem 1rem;
          } 
          </style>

          邊框及選中樣式

          CSS

          <style type="text/css">
          #tree-menu li ul {
              padding: 0.5rem 1rem;
          }
          
          #tree-menu li {
              border: 1px solid #ddd;
          }
          
          // 第一個子節點之后所有兄弟節點
          #tree-menu li+li {
              border-top: 0;
          }
          
          #tree-menu label {
              display: block;
              padding: 0.5rem 1rem;
          }
          
          #tree-menu label:hover {
              background-color: aliceblue;
          }
          </style>

          圓角樣式1

          CSS

          <style type="text/css">
          #tree-menu li ul {
              padding: 0.5rem 1rem;
          } 
          #tree-menu li {
              border: 1px solid #ddd;
              border-radius: 10px;
              margin-bottom:0.5rem;
          }
          /* #tree-menu li+li {
              border-top: 0;
          }  */
          #tree-menu label {
              display: block;
              padding: 0.5rem 1rem;
          }
          
          #tree-menu label:hover {
              background-color: aliceblue;
              border-radius: 10px;
          }
          </style>

          圓角樣式2

          li label{ }

          這個示例表示:li元素下面所有層級的label
          li>label{ }

          這個示例表示:li元素孩子級層級的label

          CSS

          #tree-menu li ul {
              padding: 0.5rem 1rem;
          } 
          #tree-menu li {
              border: 1px solid #ddd;
              /* border-radius: 10px;
              margin-bottom:0.5rem; */
          }
          /* 第一個子節點之后的所有兄弟節點 */
          #tree-menu li+li {
              border-top: 0;
          }
          /* 第一個子節點 設置頂部圓角 */
          #tree-menu li:first-child,
          #tree-menu li:first-child>label {
              border-radius: 10px 10px 0 0;
          }
          
          /* 最后一個子節點 設置底部圓角  */
          #tree-menu li:last-child,
          #tree-menu li:last-child>label {
              border-radius: 0 0 10px 10px ;
          }
          
          /* 只有唯一 一個子節點時,頂部底部都設置圓角 */
          #tree-menu li:only-child,
          #tree-menu li:only-child>label {
              border-radius: 10px ;
          }
          
          /* 
              展開時背景圓角修復 
              :first-child 第一個子節點
          
              :not(:only-child)非唯一子節點
              這里表示這個子節點有子項
          
          */
          #tree-menu li.collapsed:first-child:not(:only-child)>label {
              border-radius: 10px 10px 0 0;
          }
          #tree-menu li.collapsed:not(:only-child)>label {
              border-radius: 0;
          }
          
          #tree-menu label {
              display: block;
              padding: 0.5rem 1rem;
          }
          /* 
           :hover 鼠標在元素上面時
          */
          #tree-menu label:hover {
              background-color: aliceblue;
              /* border-radius: 10px; */
          }

          節點標記樣式

          CSS

          #tree-menu li label {
              position: relative;
              padding: 0.5rem 1rem 0.5rem 1.5rem;
          }
          
          /**
            如果有子項,添加展開或折疊的標記符號。
            默認折疊標記 
          */
          #tree-menu li label::before {
              position: absolute;
              content: '-';
              left: 0;
              width: 1.6rem;
              height: 1.2rem;
              text-align: center;
              line-height: 1.2rem;
              color: #333;
          }
          
          /** 
            :only-child表示沒有兄弟元素 
            不顯示標記
          */
          #tree-menu li label:only-child::before {
              content: ' ';
          }
          
          /* 顯示展開標記 */
          #tree-menu li.collapsed>label::before {
              content: '+';
          }

          到此,一個還比較美觀的樹形菜單,基本完成了。

          但是,有朋友說,我要實現以下需求呢?

          1、不要邊框;

          2、保留縮進;

          3、保留展開折疊標記;

          4、橫向拉通選擇;

          橫向拉通選擇樣式

          CSS

          #tree-menu label {
              position: relative;
              display: block;
              padding: 0.5rem 1rem;
          }
          
          #tree-menu label:hover {
              background-color: aliceblue;
          }
          
          /** 縮進拉通選擇*/
          #tree-menu li label {
              padding-left: 0;
          }
          #tree-menu li li label {
              padding-left: 0.5rem;
          }
          #tree-menu li li li label {
              padding-left: 1rem;
          }
          #tree-menu li li li li label {
              padding-left: 1.5rem;
          }
          #tree-menu li li li li li label {
              padding-left: 2rem;
          }
          #tree-menu li li li li li li label {
              padding-left: 2.5rem;
          }
          
          
          /**
            如果有子項,添加展開或折疊的標記符號。
            默認折疊標記 
          */
          #tree-menu li label::before {
              float: left;
              content: '-';
              width: 1.6rem;
              height: 1.2rem;
              text-align: center;
              line-height: 1.2rem;
              color: #333;
          }
          
          /** 
            :only-child表示沒有兄弟元素 
            不顯示標記
          */
          #tree-menu li label:only-child::before {
              content: ' ';
          }
          
          /* 顯示展開標記 */
          #tree-menu li.collapsed>label::before {
              content: '+';
          }

          如果層級很深,我不是得寫很多個li才能實現多級縮進?

          比如:tree-menu li li li li li li li li li li li label{}


          JavaScript方式

          查找所有 label 元素,然后看 label 元素上面有多少個 li 元素,以此判斷所屬層級。

          CSS

          <script>
            function parents(element, selector) {
            var parentsArray = [];
            var parent = element.parentNode;
            
            while (parent && parent !== document) {
              if (parent.matches(selector)) {
                parentsArray.push(parent);
              }
              parent = parent.parentNode;
            }
            return parentsArray;
          }
          
            const items = document.querySelectorAll('#tree-menu label');
            items.forEach((item) => {
              const level = parents(item.parentElement, 'li').length
              const padding = 10  * level;
              item.style.paddingLeft = `${padding}px`;
            });
          </script>

          1、我不想寫JavaScript;

          2、我不想寫多個li li li li li li li;

          3、我不想寫多個.level1{} .level2{} .level3{};

          4、我想寫少量CSS代碼,來解決這個問題,一勞永逸;

          5、我想它支持無限層級的縮進;

          有這樣CSS代碼嗎?我怎么不知道?

          你別說,還真有這樣得CSS代碼。

          當然,這也是本文得重點,算一個CSS得小技巧吧。


          counters() 簡介

          CSS 函數 counters() 是一個嵌套計數器,返回表示指定計數器當前值的連接字符串。counters() 函數有兩種形式: counters(name, string) counters(name, string, style) 。它通常和偽元素搭配使用,但是理論上可以在支持<string>值的任何地方使用。生成的文本是具有給定名稱的所有計數器的值,從最外層到最內層,之間由指定字符串分隔。計數器以指示的樣式呈現,如果未指定樣式,則默認為十進制。

          先看一個例子:

          HTML

          <ol>
            <li>
               <ol>
                  <li></li>
                  <li></li>
                  <li></li>
                </ol>
            </li>
            <li></li>
            <li></li>
            <li>
               <ol>
                  <li></li>
                  <li>
                     <ol>
                        <li></li>
                        <li></li>
                        <li></li>
                     </ol>
                  </li>
                </ol>
            </li>
          </ol>
          

          CSS

          ol {
            counter-reset: listCounter;
          }
          li {
            counter-increment: listCounter;
          }
          li::marker {
             content:  counters(listCounter, '.', upper-roman) ') ';
          }
          li::before {
            content:  counters(listCounter, ".") " == " counters(listCounter, ".", lower-roman) ;
          }
          

          counters() 示例

          通過上面的例子,我們看到了類似word的多級列表。此時很多朋友可能已經有思路了,那么我們將利用CSS這個特性,來實現上面的要求。

          修改了部分樣式

          #tree-menu label {
              position: relative;
              display: block;
              /* padding: 0.5rem 1rem; */
              padding: 0.5rem 1rem 0.5rem 0;
          }
          /* #tree-menu li label::before {} */
          #tree-menu li label::after {}
            
          /* #tree-menu li label:only-child::before {} */
          #tree-menu li label:only-child::after {}
            
          /* #tree-menu li.collapsed>label::before {} */
          #tree-menu li.collapsed>label::after {}

          counters屬性樣式

          
          /** 縮進拉通選擇 修改前*/
          /* #tree-menu li label {
              padding-left: 0;
          }
          #tree-menu li li label {
              padding-left: 0.5rem;
          }
          #tree-menu li li li label {
              padding-left: 1rem;
          }
          #tree-menu li li li li label {
              padding-left: 1.5rem;
          }
          #tree-menu li li li li li label {
              padding-left: 2rem;
          }
          #tree-menu li li li li li li label {
              padding-left: 2.5rem;
          } */
          
          /* 修改后 */
          #tree-menu,
          #tree-menu ul {
              counter-reset: listCounter;
          }
          
          #tree-menu label {
              counter-increment: listCounter;
          }
          
          #tree-menu label::before {
              float: left;
              /* 把標記設置成透明 */
              color:transparent;
              /* 默認數字*/
              content: counters(listCounter, "");
          }

          完整的CSS

          ul,
          li {
              margin: 0;
              padding: 0;
              list-style: none;
          }
          
          /** 
          折疊狀態與展開狀態樣的樣式
           */
          #tree-menu ul {
              display: none;
          }
          
          #tree-menu li.collapsed>ul {
              display: block;
          }
          
          #tree-menu label {
              position: relative;
              display: block;
              padding: 0.5rem 1rem 0.5rem 0;
          }
          
          #tree-menu label:hover {
              background-color: aliceblue;
          }
          
          /** 縮進拉通選擇*/
          /* 修改后 */
          #tree-menu,
          #tree-menu ul {
              counter-reset: listCounter;
          }
          
          #tree-menu label {
              counter-increment: listCounter;
          }
          
          #tree-menu label::before {
              float: left;
              /* 將序號設置為透明 */
              color:transparent;
              /***/
              content: counters(listCounter, "");
          }
          
          
          
          /**
            如果有子項,添加展開或折疊的標記符號。
            默認折疊標記 
          */
          #tree-menu li label::after {
              float: left;
              content: '-';
              width: 1.6rem;
              height: 1.2rem;
              text-align: center;
              line-height: 1.2rem;
              color: #333;
          }
          
          /** 
            :only-child表示沒有兄弟元素 
            不顯示標記
          */
          #tree-menu li label:only-child::after {
              content: ' ';
          }
          
          /* 顯示展開標記 */
          #tree-menu li.collapsed>label::after {
              content: '+';
          }

          通過樹形級聯菜單,學習CSS選擇器與CSS技巧,是一種非常有效的學習方法。我們不僅可以學會如何使用各種選擇器,來控制頁面元素,還能掌握一些實用的CSS技巧和概念。希望本文對您了解樹形級聯菜單、CSS選擇器和CSS技巧有所幫助,并能為您在Web前端開發中的工作提供一些啟發。

          希望本文能夠對您有所幫助,感謝您的閱讀!

          人人為我,我為人人,謝謝您的瀏覽,我們一起加油吧。

          件項目實訓及課程設計指導——Web表示層典型功能實現的應用實例

          1、Web頁面中的樹形菜單的功能實現

          利用樹形菜單可以實現層次化的命令集,方便導航用戶的操作。目前在 Web頁面中可以采用許多不同的技術實現樹形菜單的應用效果——如基于Ajax技術實現Web樹狀菜單、采用XML+JavaScript腳本創建樹形菜單或者利用CSS(Cascading Style Sheets,層疊樣式表)實現靜態效果的樹形菜單等。

          DHTMLXTree是Web開發中運用較多的一個開源的樹型菜單控件,允許開發人員快速開發Web界面中的樹形菜單,它基于Ajax的JavaScript腳本庫,允許在線編輯、拖拽、三種狀態(全選、不選、半選)、復選框等模式。在加載大數據量的時候,仍然可以保持非常高效的速度。

          DHTMLXTree本質上其實是一個在Web頁面上實現樹狀顯示效果的JavaScript控件,因此應用它不僅可以實現樹型菜單,也可以實現樹型目錄等"樹"狀結構的數據顯示效果。如下示圖為應用DHTMLXTree控件實現的一個樹形結構的數據顯示效果的應用示例局部截圖。

          而如下示圖為DHTMLXTree官方網站頁面提供的有關技術文檔局部截圖,讀者可以根據待開發的軟件應用系統項目的需要下載相關的系統庫文件和在線瀏覽技術參考文檔資料。

          在示例項目銀行賬戶信息管理系統的后臺頁面的設計和實現中,也采用了DHTMLXTree樹型控件實現應用系統中的后臺管理功能的樹形菜單,請見下圖所示頁面效果局部截圖。

          2、Web頁面數據的分頁顯示功能實現

          由于在軟件應用系統中某個功能的頁面需要顯示大量的數據,為了方便應用系統的操作者對數據的快速瀏覽,應該要對待顯示的目標數據進行分頁顯示。Web應用系統中數據分頁顯示技術也是Web表示層開發中比較通用的功能實現要求——所謂的數據分頁顯示功能要求,也就是將從軟件應用系統后臺數據庫表中獲得的各種結果數據人為地分成特定長度的數據塊、并在Web頁面中只顯示其中某一塊的數據,并為操作者提供繼續瀏覽其它塊數據的鏈接或者按鈕(包括前、后頁、第一和最后頁、快速定位某頁等方式)。

          下圖所示為示例項目銀行賬戶信息管理系統中對用戶賬戶信息進行數據分頁顯示的效果的局部截圖,該分頁實現技術是每次只向數據庫系統請求頁面大小的數據,大大地提高了每次前/后翻頁時的查詢速度。

          當然,在具體實現時一定要達到將軟件應用系統的表示層數據顯示與數據的業務邏輯處理相互分離的設計和開發實現的基本目標。

          3、解決Web表單重復提交的問題以保證數據的唯一性

          由于各個Web瀏覽器都提供有【刷新】功能菜單——請見下圖所示,為了防止操作者點擊【刷新】功能菜單而造成對軟件應用系統后臺的多次重復請求,在軟件應用系統的表示層開發中應該要避免產生表單重復提交的問題。

          對于解決表單重復提交的技術問題,許多基于MVC體系架構的應用框架都提供了對應的技術支持和具體的實現方法。早期的Struts框架是通過提供Token(令牌)機制很好地解決了表單重復提交的問題——其基本的實現原理是:

          Struts框架的服務器端程Action類程序在處理到達的請求之前,會將請求中包含的令牌值與保存在當前用戶會話中的令牌值進行比較,看是否匹配;而在處理完該次請求后,并且在將響應發送給客戶端瀏覽器之前,將會產生一個新的令牌(一個隨機的字符串),該令牌除傳給客戶端瀏覽器以外,也會將用戶Session會話中保存的舊的令牌進行替換。

          此時如果用戶回退到剛才的提交頁面并再次重復地提交請求時,客戶端Web瀏覽器再次傳遞過來的令牌字符串就和服務器端保存的令牌字符串內容也就不一致,從而有效地防止了Web表單重復提交的發生。

          而在Struts2應用框架中利用系統內帶的<s:token />標簽產生一個GUID(Globally Unique Identifier,全局唯一標識符)字符串值的隱藏輸入框,同時還將GUID字符串放到Session會話中;在執行某個Web請求之前,Struts2應用框架中的缺省的"token"攔截器將會話中的令牌字符串與此時的Web請求令牌字符串比較,如果兩者相同,則將會話中的令牌字符串刪除并繼續往下執行,否則向actionErrors程序類加入相關的錯誤信息。

          如此一來,如果用戶通過某種手段提交了兩次相同的請求,兩個令牌字符串就會不同。從而也有效地防止了Web表單重復提交的發生。

          在示例項目銀行賬戶信息管理系統中為了不依賴于Struts2等MVC框架系統,沒有簡單地采用這些MVC應用框架系統對Web表單重復提交的功能實現的技術支持。而是采用Web頁面表單中的圖形驗證碼進行限制,同樣也能夠達到相同的應用效果。

          由于圖形驗證碼在每次不同的Web請求時都會產生不同的值,從而控制重復提交的行為產生。在示例項目中的"開戶"功能成功后,用戶如果再次點擊Web瀏覽器中的"回退"按鈕后,將回到原來的Web表單請求頁面。但此時Web頁面表單中的驗證碼已經不一致,請見下圖所示的功能操作狀態圖示,此時提交后,軟件應用系統后臺的驗證碼驗證程序將報告錯誤而終止重復的Web請求。

          但如果用戶在Web表單中輸入正確的驗證碼后再發送本次請求,軟件應用系統后臺將通過業務數據中的邏輯性和數據的一致性加以限制,而避免在物理數據庫系統的數據庫表中出現完全一樣的兩條記錄數據。

          4、Web表單中的數據有效性驗證

          軟件應用系統的操作者可能由于操作的失誤或者惡意的攻擊或者無意識的錯誤數據輸入等行為,在Web頁面表單中將產生錯誤的輸入數據。為了保證在軟件應用系統后臺能夠正確地獲得所需要的目標數據,應該要對Web表單中的各種關鍵性的輸入數據進行數據驗證(數據有效性驗證)。

          對于Web表單中提交的數據不僅需要應用Web客戶端的數據驗證(一般是采用JavaScript腳本語言實現),更應該要應用Web服務器端數據驗證技術以真正達到軟件應用系統的數據安全性、正確性和有效性等應用的要求。

          這主要是由于目前有許多瀏覽器能夠禁止執行Web客戶端頁面中所內嵌的JavaScript腳本語言程序代碼而導致Web客戶端的數據驗證功能失效、或者惡意的攻擊者直接通過Web客戶端應用程序請求訪問軟件應用系統中的后臺Web服務器端相關程序。下圖所示為FireFox瀏覽器對Web頁面中的JavaScript腳本語言的控制項目的局部截圖。

          在示例項目銀行賬戶信息管理系統中應用Apache Validator驗證器框架實現Web服務器端的數據驗證,由于Apache Validator驗證器框架是Jakarta的公共項目的一部分,讀者可以從Apache Validator驗證器官方網站中下載Validator框架的系統包文件。如下示圖為Apache Validator驗證器官方網站中技術特性介紹、系統庫文件下載等信息頁面局部截圖。

          下圖所示為在示例項目銀行賬戶信息管理系統中的AccountInfoManageAction類的checkVerifyCodeOK方法中應用Validator框架的代碼片段局部截圖。

          5、統計軟件應用系統的在線人數

          Web應用系統的在線人數實時反映軟件應用系統的訪問狀態,如果能夠顯示當前軟件應用系統的在線人數,一方面能夠讓軟件應用系統的管理人員及時地了解軟件應用系統的當前負載情況,另一方面也讓訪問者了解到本軟件應用系統的熱門程度。

          但要想實時準確地統計Web應用系統的在線人數,其實也是一件不太現實的事情。這是因為HTTP協議本身是無狀態的協議,當Web客戶端程序(一般為Web瀏覽器程序)向Web服務器發出一個Web請求時,Web服務器會馬上建立一個新的TCP/IP連接(也就是會話Session);在該Web頁面完全載入后,這個會話連接也就關閉了;另外,正是由于HTTP協議是無狀態的,所以也就無法知道某個Web請求訪問是否已經離開或者Web請求者已經關閉了Web瀏覽器。

          因此,Web應用中所謂的在線人數其實應該是指在"一定時間段內"同時訪問Web站點的人數,而不是基于HTTP協議的并發連接數。但這個"一定時間段內"對于不同的Web服務器也是有差別的,如Tomcat服務器默認的Session會話超時為30分鐘(但一般的Web網站都采用15分種的時間標準)。

          在示例項目銀行賬戶信息管理系統中也提供了該功能的具體實現,是利用實現HttpSessionListener接口的Web監聽器統計在線Session個數、并將Tomcat服務器默認的Session會話超時時間改變為15分鐘,最后在Web頁面中顯示輸出本軟件應用系統的在線人數。本示例項目最后實現的效果局部截圖如圖所示。

          6、在軟件應用系統中實現文件上傳功能

          文件上傳或者下載也是Web應用系統中需要提供的功能,在示例項目銀行賬戶信息管理系統中利用Apache Commons-FileUpload組件實現文件的上傳功能,該FileUpload組件可以實現每次上傳一個或多個文件,并可限制文件大小——比如在用戶注冊表單中允許注冊者自行上傳自己的圖像文件,請見下圖所示的局部截圖。

          7、在軟件應用系統中實現文件下載功能

          在Web應用系統的開發實現中,大部分的文件下載都是直接通過建立下載文件的URL文件鏈接方式直接進行下載。但是考慮到在Web應用中的文件下載具體實現時的盜鏈、跨服務器下載訪問等方面的因素,直接文件流下載的方式也是必要的。因為,此時Web應用系統能夠對下載的文件以及下載的操作者進行更多方面的安全及身份驗證的檢查和控制。

          在Struts2應用框架中實現數據流下載時只需要改變Struts2應用框架中的result Type為Stream類型即可以實現本功能要求——請見下面的代碼示例所示的某個實現文件下載功能的DownLoadFileAction的配置定義示例內容中的黑體標識的內容。如下為某個實現文件下載功能的DownLoadFileAction的配置定義示例

          <action name="oneDownLoadGIFFile"
                  class="com.px1987.struts2.action.DownLoadFileAction">
                  <param name="inputPath">/downImages/logo.gif</param>
                  <result name="success" type="stream">
                        <param name="contentType">image/gif</param>
                        <param name="inputName">inputStream</param>
                        <param name="contentDisposition">filename="logo.gif"</param>
                        <param name="bufferSize">4096</param>
                  </result>
          </action>

          在示例項目銀行賬戶信息管理系統中采用在Servlet程序中直接控制文件輸出流的方式實現文件下載的控制。具體的功能實現代碼請見如下所附的代碼示例,該doDownLoadFile方法作為某個J2EE Servlet程序中一個功能方法被doGet方法所調用,并請注意其中的黑體部分的語句代碼——實現文件下載功能的代碼示例

          public void doDownLoadFile(HttpServletRequest request, String downFileName,
          HttpServletResponse response, String downFilePath)
          throws ServletException, IOException{
                  ServletOutputStream servletOutputStream = null;
                  FileInputStream fileInputStream = null;
                  BufferedInputStream bufferedInputStream =null;
                  File downLoadTargetFile = new File(downFilePath+"/"+downFileName);
                  if(!downLoadTargetFile.exists()){
                        response.sendError(404,"沒有找到要下載的目標文件!");
                        return;
                  }
                try {
                        response.setContentType("application/octet-stream");
                        response.setHeader("Content-Disposition",
                        "attachment; filename=\"" + downFileName + "\"");
                        servletOutputStream = response.getOutputStream(); fileInputStream = new java.io.FileInputStream(downFilePath +
                        "\\"+ downFileName);
                        bufferedInputStream = new BufferedInputStream(fileInputStream);
                        byte[] oneBuffer = new byte[10240];
                        int byteNumber;
                        while ((byteNumber=bufferedInputStream.read(oneBuffer)) != -1){
                        			servletOutputStream.write(oneBuffer,0,byteNumber);
                        }
                }
                catch (FileNotFoundException e) {
                }
                catch (IOException e) {
                }
                finally {
                      if(bufferedInputStream != null){
                     			 bufferedInputStream.close();
                      }
                      if(servletOutputStream != null){
                      			servletOutputStream.close();
                      }
                }
          }

          其中的response.setContentType("application/octet-stream");語句主要是設置Http響應頭和要下載保存的文件名,Web瀏覽器將根據開發人員在Http數據流的Head部分的MIME(Multipurpose Internet Mail Extensions,多用途互聯網郵件擴展類型)頭的設置內容"application/octet-stream"直接產生出文件下載的對話框提示、并且按照設置的內容采用二進制數據格式傳輸文件流數據。


          主站蜘蛛池模板: 视频一区在线免费观看| 日韩一区二区三区在线精品 | 国产精品久久亚洲一区二区| 精品亚洲一区二区三区在线观看| 一区二区三区杨幂在线观看 | 婷婷亚洲综合一区二区| 国产成人AV一区二区三区无码| 国产一区韩国女主播| 动漫精品第一区二区三区| 日本中文一区二区三区亚洲| 色系一区二区三区四区五区| 国产高清一区二区三区四区| 亚洲AV美女一区二区三区| 精品无码AV一区二区三区不卡| 国产香蕉一区二区三区在线视频 | 无码av免费毛片一区二区| 国产成人无码aa精品一区| 久久免费精品一区二区| 国精产品一区一区三区有限在线| 日韩成人无码一区二区三区| 国产女人乱人伦精品一区二区 | 精品女同一区二区三区免费播放| 精品视频一区在线观看| 日韩精品人妻一区二区中文八零| 亚洲一区二区三区精品视频| 日韩成人无码一区二区三区| 中日韩一区二区三区| 亚洲宅男精品一区在线观看| 精品一区二区三区免费视频| 99无码人妻一区二区三区免费 | 国产精品久久一区二区三区| 国产成人精品一区二区三在线观看| 一区二区三区无码高清| 精品视频一区二区三区四区| 无码少妇一区二区浪潮av| 亚洲精品无码一区二区| 亚洲国产成人精品无码一区二区| 久久国产精品免费一区二区三区| 国精品无码一区二区三区左线| 国产精品无码一区二区三区毛片| 久久精品一区二区|