最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java實現(xiàn)解析Excel復雜表頭

 更新時間:2025年01月03日 10:46:16   作者:?遲暮  
這篇文章主要為大家詳細介紹了如何使用Java實現(xiàn)解析Excel復雜表頭功能,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下

在Java中如果想解析復雜的Excel表頭,可以使用Apache POI庫。

廢話不多說,直接上源碼。前后端都有哦

后端

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
 
/**
 * @Description:Excel工具類(復雜表頭解析)
 * @Author: sh
 * @Date: 2025/1/2 09:29
 */
public class ExcelComplexUtil {
    /**
     * 導入Excel文件,逐行讀取數(shù)據(jù),數(shù)據(jù)格式二維數(shù)組
     * @param filePath
     * @param sheetIndex
     * @return
     * @throws IOException
     */
    public String[][] importExcel(String filePath, int sheetIndex) throws IOException {
        List<String[]> dataList = new ArrayList<>();
 
        try (FileInputStream fis = new FileInputStream(new File(filePath));
             Workbook workbook = new XSSFWorkbook(fis)) {
 
            Sheet sheet = workbook.getSheetAt(sheetIndex); // 獲取第一個工作表
            // 獲取表頭行
            Row headerRow = checkHeaderRow(sheet);
 
            if (headerRow != null) {
                //封裝表頭數(shù)據(jù)
                warpHeaderData(headerRow, dataList);
            } else {
                throw new RuntimeException("Excel 文件中沒有找到表頭行,請修改表格");
            }
 
            // 讀取數(shù)據(jù)行
            for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
                Row row = sheet.getRow(rowIndex);
 
                if (row == null) {
                    continue; // 跳過空行
                }
                //封裝行數(shù)據(jù)
                warpRowData(headerRow, row, dataList);
            }
        }
 
        // 將 List<String[]> 轉換為 String[][] 數(shù)組
        String[][] result = new String[dataList.size()][];
        for (int i = 0; i < dataList.size(); i++) {
            result[i] = dataList.get(i);
        }
 
        return result; // 返回二維數(shù)組
    }
 
    /**
     * 檢查表頭行,表頭行必須在前10行中
     * @param sheet
     * @return
     */
    private Row checkHeaderRow(Sheet sheet) {
        int i = 0;
        Row headerRow = null;
 
        while (i < 10) {
            headerRow = sheet.getRow(i);
            if (headerRow != null) {
                break;
            }
 
            i++;
        }
 
        return headerRow;
    }
 
    /**
     * 數(shù)據(jù)遍歷
     * @param headerRow
     * @param dataList
     * @throws IOException
     */
    public void warpHeaderData(Row headerRow, List<String[]> dataList) {
        int columnCount = headerRow.getPhysicalNumberOfCells();
        short lastCellNum = headerRow.getLastCellNum();
 
        String[] data = new String[columnCount]; // 創(chuàng)建一維數(shù)組存儲表頭數(shù)據(jù)
        for (int colIndex = 0; colIndex < columnCount; colIndex++) {
            Cell cell = headerRow.getCell(lastCellNum - columnCount + colIndex);
            String cellValue = (cell != null) ? cell.toString() : ""; // 處理空單元格
            data[colIndex] = cellValue; // 將單元格值放入表頭數(shù)組中
        }
 
        dataList.add(data); // 將表頭數(shù)組添加到列表中
    }
 
    public void warpRowData(Row headerRow, Row row, List<String[]> dataList) {
        int columnCount = headerRow.getPhysicalNumberOfCells();
        short lastCellNum = headerRow.getLastCellNum();
 
        String[] data = new String[columnCount]; // 創(chuàng)建一維數(shù)組存儲表頭數(shù)據(jù)
        for (int colIndex = 0; colIndex < columnCount; colIndex++) {
            Cell cell = row.getCell(lastCellNum - columnCount + colIndex);
            String cellValue = (cell != null) ? cell.toString() : ""; // 處理空單元格
            data[colIndex] = cellValue; // 將單元格值放入表頭數(shù)組中
        }
 
        dataList.add(data); // 將表頭數(shù)組添加到列表中
    }
 
    /**
     * 獲取excel中所有合并單元格
     * @param filePath
     * @param sheetIndex
     * @throws IOException
     */
    public List<MergedCell> checkMergedCells(String filePath, int sheetIndex) throws IOException {
        try (FileInputStream fis = new FileInputStream(new File(filePath));
             Workbook workbook = new XSSFWorkbook(fis)) {
 
            Sheet sheet = workbook.getSheetAt(sheetIndex); // 獲取第一個工作表
            int numberOfMergedRegions = sheet.getNumMergedRegions(); // 獲取合并單元格的數(shù)量
 
            List<MergedCell> mergedCellArray = new ArrayList<>();
 
            for (int i = 0; i < numberOfMergedRegions; i++) {
                MergedCell mergedCell = new MergedCell();
 
                CellRangeAddress range = sheet.getMergedRegion(i); // 獲取合并單元格區(qū)域
                mergedCell.setRange(range.formatAsString());
                // 獲取合并單元格區(qū)域的起始單元格
                int firstRow = range.getFirstRow();
                int firstCol = range.getFirstColumn();
 
                // 獲取合并單元格的內(nèi)容
                Row row = sheet.getRow(firstRow);
                Cell cell = row.getCell(firstCol);
                String cellValue = (cell != null) ? cell.toString() : ""; // 處理空單元格
                mergedCell.setValue(cellValue);
 
                mergedCellArray.add(mergedCell);
            }
 
            return mergedCellArray;
        }
    }
 
    /**
     * 檢查特定單元格是否是合并單元格
     * @param sheet
     * @param row
     * @param col
     * @return
     */
    private boolean isMergedCell(Sheet sheet, int row, int col) {
        int numberOfMergedRegions = sheet.getNumMergedRegions();
        for (int i = 0; i < numberOfMergedRegions; i++) {
            CellRangeAddress range = sheet.getMergedRegion(i);
            if (range.isInRange(row, col)) {
                return true; // 如果該單元格在合并區(qū)內(nèi),返回 true
            }
        }
        return false; // 如果不在任何合并區(qū)內(nèi),返回 false
    }
 
    class MergedCell {
        private String range;
        private String value;
 
        public String getRange() {
            return range;
        }
 
        public void setRange(String range) {
            this.range = range;
        }
 
        public String getValue() {
            return value;
        }
 
        public void setValue(String value) {
            this.value = value;
        }
 
        @Override
        public String toString() {
            return "MergedCell{" +
                    "range='" + range + '\'' +
                    ", value='" + value + '\'' +
                    '}';
        }
    }
 
    //    public static void main(String[] args) {
//        String filePath = "/ceshi/ceshi.xlsx"; // Excel 文件路徑
//        try {
//            String[][] strings = importExcel(filePath, 0);
//            for (String[] row : strings) {
//                System.out.println(String.join(", ", row)); // 以逗號為分隔符打印每一行
//            }
//            List<MergedCell> mergedCells = checkMergedCells(filePath, 0);
//            for (MergedCell row : mergedCells) {
//                System.out.println(row); // 以逗號為分隔符打印每一行
//            }
//
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//    }
}

前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>合并單元格查看器</title>
    <style>
        table {
            border-collapse: collapse;
            width: 500px; /* 設置表格寬度 */
        }
        td {
            border: 1px solid black;
            padding: 0; /* 清除內(nèi)邊距 */
            text-align: center;
            vertical-align: middle; /* 垂直居中 */
            height: 50px; /* 設置每個單元格的高度 */
        }
        .merged {
            background-color: #f0f0f0; /* 合并單元格的背景顏色 */
            font-weight: bold; /* 合并單元格字體加粗 */
        }
    </style>
</head>
<body>
    <div id="app">
        <h1>合并單元格查看器</h1>
        <table>
            <tr v-for="(row, rowIndex) in tableData" :key="rowIndex">
                <td
                    v-for="(cell, colIndex) in row"
                    :key="colIndex"
                    v-if="!isCellOccupied(rowIndex, colIndex)"
                    :rowspan="getRowSpan(rowIndex, colIndex)"
                    :colspan="getColSpan(rowIndex, colIndex)"
                    :class="{ merged: isMergedCell(rowIndex, colIndex) }"
                >
                    {{ getCellValue(rowIndex, colIndex) }}
                </td>
            </tr>
        </table>
    </div>
 
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
    <script>
        new Vue({
            el: '#app',
            data() {
                return {
                    mergedCells: [
                        { range: "C1:D1", value: "合并單元格 1" },
                        { range: "B2:C2", value: "合并單元格 2" },
                        { range: "B3:C3", value: "合并單元格 " },
                        { range: "A2:A3", value: "合并單元格 " },
                        { range: "F2:F3", value: "合并單元格 " } 
                    ],
                    normalData: [
                        ["監(jiān)督員地區(qū)", "總數(shù)", "有效", "", "有效政治類", ""],
                        ["平谷區(qū)監(jiān)督員", "244", "", "197", "28", "169"],
                        ["", "244", "", "197", "28", ""],
                        ["數(shù)據(jù) 16", "數(shù)據(jù) 17", "數(shù)據(jù) 18", "數(shù)據(jù) 19", "數(shù)據(jù) 20"],
                        ["數(shù)據(jù) 21", "數(shù)據(jù) 22", "數(shù)據(jù) 23", "數(shù)據(jù) 24", "數(shù)據(jù) 25"],
                        ["", "", "", "", ""]
                    ],
                    occupiedCells: []
                };
            },
            computed: {
                // 生成完整表格數(shù)據(jù)
                tableData() {
                    const rows = this.normalData.length;
                    const cols = this.normalData[0].length;
                    const emptyTable = Array.from({ length: rows }, () => Array(cols).fill(null));
 
                    // 填充合并單元格
                    this.mergedCells.forEach(({ range, value }) => {
                        const [start, end] = range.split(':');
                        const startRow = parseInt(start.match(/\d+/)[0]) - 1;
                        const startCol = start.charCodeAt(0) - 65;
                        const endRow = parseInt(end.match(/\d+/)[0]) - 1;
                        const endCol = end.charCodeAt(0) - 65;
 
                        // 填充合并單元格的位置
                        for (let r = startRow; r <= endRow; r++) {
                            for (let c = startCol; c <= endCol; c++) {
                                if (r === startRow && c === startCol) {
                                    emptyTable[r][c] = value; // 合并單元格的值
                                } else {
                                    this.occupiedCells[r] = this.occupiedCells[r] || [];
                                    this.occupiedCells[r][c] = true; // 標記占用
                                }
                            }
                        }
                    });
 
                    // 填充普通單元格的數(shù)據(jù)
                    this.normalData.forEach((row, r) => {
                        row.forEach((cell, c) => {
                            if (!this.occupiedCells[r] || !this.occupiedCells[r][c]) {
                                emptyTable[r][c] = cell;
                            }
                        });
                    });
 
                    return emptyTable;
                }
            },
            methods: {
                isCellOccupied(rowIndex, colIndex) {
                    return this.occupiedCells[rowIndex] && this.occupiedCells[rowIndex][colIndex];
                },
                getCellValue(rowIndex, colIndex) {
                    return this.tableData[rowIndex][colIndex];
                },
                getRowSpan(rowIndex, colIndex) {
                    let rowspan = 1;
                    const firstValue = this.getCellValue(rowIndex, colIndex);
                    const mergedCell = this.mergedCells.find(({ range }) => {
                        const [start, end] = range.split(':');
                        const startRow = parseInt(start.match(/\d+/)[0]) - 1;
                        const startCol = start.charCodeAt(0) - 65;
                        const endRow = parseInt(end.match(/\d+/)[0]) - 1;
                        const endCol = end.charCodeAt(0) - 65;
                        return rowIndex === startRow && colIndex === startCol;
                    });
                    if (mergedCell) {
                        const [start, end] = mergedCell.range.split(':');
                        const startRow = parseInt(start.match(/\d+/)[0]) - 1;
                        const endRow = parseInt(end.match(/\d+/)[0]) - 1;
                        rowspan = endRow - startRow + 1;
                    }
                    return rowspan;
                },
                getColSpan(rowIndex, colIndex) {
                    let colspan = 1;
                    const firstValue = this.getCellValue(rowIndex, colIndex);
                    const mergedCell = this.mergedCells.find(({ range }) => {
                        const [start, end] = range.split(':');
                        const startRow = parseInt(start.match(/\d+/)[0]) - 1;
                        const startCol = start.charCodeAt(0) - 65;
                        const endRow = parseInt(end.match(/\d+/)[0]) - 1;
                        const endCol = end.charCodeAt(0) - 65;
                        return rowIndex === startRow && colIndex === startCol;
                    });
                    if (mergedCell) {
                        const [start, end] = mergedCell.range.split(':');
                        const startCol = start.charCodeAt(0) - 65;
                        const endCol = end.charCodeAt(0) - 65;
                        colspan = endCol - startCol + 1;
                    }
                    return colspan;
                },
                isMergedCell(rowIndex, colIndex) {
                    return this.mergedCells.some(({ range }) => {
                        const [start, end] = range.split(':');
                        const startRow = parseInt(start.match(/\d+/)[0]) - 1;
                        const startCol = start.charCodeAt(0) - 65;
                        return rowIndex === startRow && colIndex === startCol;
                    });
                }
            }
        });
    </script>
</body>
</html>

到此這篇關于Java實現(xiàn)解析Excel復雜表頭的文章就介紹到這了,更多相關Java解析Excel內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java程序的初始化順序,static{}靜態(tài)代碼塊和實例語句塊的使用方式

    Java程序的初始化順序,static{}靜態(tài)代碼塊和實例語句塊的使用方式

    這篇文章主要介紹了Java程序的初始化順序,static{}靜態(tài)代碼塊和實例語句塊的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Java中對象的創(chuàng)建和銷毀過程詳析

    Java中對象的創(chuàng)建和銷毀過程詳析

    這篇文章主要介紹了Java中對象的創(chuàng)建和銷毀過程,對象的創(chuàng)建過程包括類加載檢查、內(nèi)存分配、初始化零值內(nèi)存、設置對象頭和執(zhí)行init方法,對象的銷毀過程由垃圾回收機制負責,文中介紹的非常詳細,需要的朋友可以參考下
    2025-02-02
  • Spring基于xml實現(xiàn)自動裝配流程詳解

    Spring基于xml實現(xiàn)自動裝配流程詳解

    自動裝配是使用spring滿足bean依賴的一種方法,spring會在應用上下文中為某個bean尋找其依賴的bean,Spring中bean有三種裝配機制,分別是:在xml中顯式配置、在java中顯式配置、隱式的bean發(fā)現(xiàn)機制和自動裝配
    2023-01-01
  • springboot @WebFilter注解過濾器的實現(xiàn)

    springboot @WebFilter注解過濾器的實現(xiàn)

    這篇文章主要介紹了springboot @WebFilter注解過濾器的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-03-03
  • 深入淺出SpringBoot WebSocket構建實時應用全面指南

    深入淺出SpringBoot WebSocket構建實時應用全面指南

    WebSocket 是一種在單個 TCP 連接上進行全雙工通信的協(xié)議,這篇文章主要為大家詳細介紹了SpringBoot如何集成WebSocket構建實時應用,感興趣的小伙伴可以了解下
    2025-07-07
  • SpringBoot+Vue項目新手快速入門指南

    SpringBoot+Vue項目新手快速入門指南

    最近剛剛做了一個基于vue+springboot的系統(tǒng),于是基于這點,對遇到的一些問題進行一些配置的匯總,下面這篇文章主要給大家介紹了關于SpringBoot+Vue項目新手快速入門的相關資料,需要的朋友可以參考下
    2022-06-06
  • 一文詳解Java?Condition的await和signal等待通知機制

    一文詳解Java?Condition的await和signal等待通知機制

    這篇文章主要為大家詳細介紹了Java?Condition的await和signal等待通知機制的相關知識,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下
    2025-02-02
  • Spring Cloud Nacos配置修改不生效的解決方法詳解

    Spring Cloud Nacos配置修改不生效的解決方法詳解

    Nacos作為一個動態(tài)服務發(fā)現(xiàn)、配置管理和服務管理平臺,廣泛應用于Java Spring Cloud項目中,然而,有時在修改Nacos配置后,這些更改并不會立即生效,下面我們來看看這樣如何解決吧
    2025-01-01
  • vue+springboot讀取git的markdown文件并展示功能

    vue+springboot讀取git的markdown文件并展示功能

    Markdown-it 是一個用于解析和渲染 Markdown 標記語言的 JavaScript 庫,使用 Markdown-it,你可以將 Markdown 文本解析為 HTML 輸出,并且可以根據(jù)需要添加功能、擴展語法或修改解析行為,本文介紹vue+springboot讀取git的markdown文件并展示,感興趣的朋友一起看看吧
    2024-01-01
  • java實現(xiàn)簡單的客戶信息管理系統(tǒng)

    java實現(xiàn)簡單的客戶信息管理系統(tǒng)

    這篇文章主要為大家詳細介紹了java實現(xiàn)簡單的客戶信息管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06

最新評論

若尔盖县| 富蕴县| 武邑县| 昔阳县| 静宁县| 漯河市| 应城市| 济南市| 兖州市| 乐至县| 兖州市| 博罗县| 雷山县| 酒泉市| 那曲县| 湘乡市| 九江市| 青铜峡市| 和平区| 龙岩市| 广州市| 信宜市| 通榆县| 靖宇县| 容城县| 大兴区| 万安县| 太湖县| 合江县| 古丈县| 济宁市| 镇江市| 岐山县| 巫溪县| 永仁县| 汶川县| 平顶山市| 永年县| 壤塘县| 五大连池市| 名山县|