首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> JSP 程式設計 >> 關於JSP

JSP 文件目錄樹遞歸實現:Java 後端生成 + JavaScript 前端渲染

     編輯:關於JSP

整體架構

採用 後端遞歸掃描目錄 → 生成 JavaScript 數組結構 → 前端遞歸渲染樹狀 UI 的經典模式,分離數據獲取與展示邏輯。

後端:Java 遞歸生成目錄數據


package com.example.util;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class FileTreeBuilder {

    private int index = 1; // 節點層級/序號
    private boolean hasNextBrother = false; // 是否有下一個兄弟節點

    /**
     * 生成目錄樹 JavaScript 數組字符串
     * @param rootPath 根目錄絕對路徑
     * @return 可直接嵌入 JSP 的 JS 數組定義片段
     */
    public String buildTreeJson(String rootPath) {
        StringBuilder sb = new StringBuilder();
        File root = new File(rootPath);
        if (root.exists() && root.isDirectory()) {
            buildNode(sb, root);
        }
        // 終結標記
        sb.append("new Array(1, \"\", false)");
        return sb.toString();
    }

    private void buildNode(StringBuilder sb, File dir) {
        // 處理路徑特殊字符:單引號、空格
        String absPath = dir.getAbsolutePath()
                .replace("'", "\\'")  // 轉義單引號
                .replace(" ", "@");   // 空格用 @ 佔位,前端還原

        // 節點格式: [層級, 'HTML標題', 有無下一兄弟]
        sb.append("new Array(")
          .append(index).append(",")
          .append("'<a href=fileList.jsp?path=").append(absPath)
          .append(" target=mainFrame>").append(dir.getName()).append("</a>',")
          .append(hasNextBrother).append("), ");

        hasNextBrother = false;
        index++;

        // 遞歸處理子目錄
        File[] children = dir.listFiles(File::isDirectory);
        if (children != null) {
            List dirList = new ArrayList<>();
            for (File f : children) dirList.add(f);

            for (int i = 0; i < dirList.size(); i++) {
                if (i != dirList.size() - 1) hasNextBrother = true;
                buildNode(sb, dirList.get(i));
            }
        }
        index--; // 回溯層級
    }
}

JSP 页面嵌入調用


<%@ page import="com.example.util.FileTreeBuilder" %>
<%
    FileTreeBuilder builder = new FileTreeBuilder();
    // 可從配置/參數獲取根路徑
    String treeArray = builder.buildTreeJson("E:/data"); 
%>

前端:JavaScript 遞歸渲染樹狀菜單

核心渲染函數


/**
 * 遞歸構建樹 HTML
 * @param n 期望層級 (初始調用傳 0 或 1)
 * @returns HTML 字符串
 */
function tree(n) {
    // 圖標資源
    var icons = {
        bar: "<img src='images/bar.gif'>",           // 無子節點
        pad: "<img src='images/pad.gif'>",           // 有子節點 (可展開)
        open: "<img src='images/open.gif'>",         // 展開狀態
        close: "<img src='images/close.gif'>",       // 折疊狀態
        line: "<img src='images/line.gif'>",         // 連接線
        lastLine: "<img src='images/lastline.gif'>"  // 最後一個節點連接線
    };

    // 初始化
    if (n == 0) { n = 1; i = 0; s = ""; }
    s += "<table border=0 cellspacing=0 cellpadding=0>";

    for (; i < tree_ar.length - 1; i++) {
        var node = tree_ar[i];
        var level = node[0];
        var title = node[1];
        var hasBrother = node[2];

        // 判斷當前節點類型
        var isLast = !hasBrother;
        var isParent = (level < tree_ar[i+1][0]); // 下一節點層級更深 => 有子節點

        // 構建圖標 HTML
        var iconHtml = "";
        if (isParent) {
            iconHtml = icons.pad + (isLast ? icons.close : icons.open); // 簡化
        } else {
            iconHtml = icons.bar + (isLast ? icons.lastLine : icons.line);
        }

        // 生成行
        s += "<tr id='" + (isParent ? "pad" : "bar") + "' value='" + i + "'>"
           + "<td>" + iconHtml + "</td>"
           + "<td>" + title + "</td></tr>";

        // 遞歸處理子節點
        if (isParent) {
            s += "<tr style='display:none'><td>";
            if (hasBrother) s += "background='images/line.gif'";
            s += "></td><td>";
            var retLevel = tree(tree_ar[++i][0]); // 遞歸,傳入子節點層級
            s += "</td></tr>";
            if (retLevel < n) { // 回溯到更上層
                s += "</table>";
                return retLevel;
            }
        }

        // 同層最後一個節點,結束當前表格
        if (level > tree_ar[i+1][0]) {
            s += "</table>";
            return tree_ar[i+1][0];
        }
    }
    s += "</table>";
    return s;
}

節點點擊事件處理


// 展開/折疊分支節點
document.addEventListener('click', function(e) {
    var pad = e.target.closest('tr[id="pad"]');
    if (!pad) return;

    var nextRow = pad.parentElement.rows[pad.rowIndex + 1];
    var isHidden = nextRow.style.display === 'none';

    // 切換顯示
    nextRow.style.display = isHidden ? '' : 'none';

    // 更新圖標
    var iconCell = pad.cells[0];
    iconCell.innerHTML = isHidden 
        ? "<img src='images/pad.gif'><img src='images/open.gif'>"
        : "<img src='images/pad.gif'><img src='images/close.gif'>";

    // 可選:單展開模式 (關閉其他分支)
    // closeOtherBranches(pad.value);
});

初始化渲染





<!-- 樹渲染容器 --> <!-- 右側內容區 -->

關鍵技術點總結

環節關鍵點
後端遞歸用 index 追蹤層級,hasNextBrother 標記兄弟關係,生成扁平數組
路徑編碼單引號轉義、空格替換為 @,前端解碼還原
數據結構扁平數組 [level, titleHtml, hasNextBrother],前端按層級重構樹
前端遞歸函數 tree(n) 返回渲染後層級,利用返回值控制表格閉合
狀態持久化可擴展:用 Cookie/LocalStorage 記錄展開節點 ID,刷新恢復

現代化改造建議

  1. 後端輸出 JSON:替換 JS 數組字符串,用 Jackson 序列化 TreeNode 對象,前端 fetch 獲取。
  2. 前端組件化:Vue/React 遞歸組件 <TreeNode :node="node" />,狀態管理更清晰。
  3. 懶加載**:大目錄只加載一級,展開時 AJAX 請求子節點。
  4. 虛擬滾動**:節點超過千級使用虛擬列表渲染。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved