欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java實(shí)現(xiàn)解析Excel復(fù)雜表頭

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

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

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

后端

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工具類(復(fù)雜表頭解析)
 * @Author: sh
 * @Date: 2025/1/2 09:29
 */
public class ExcelComplexUtil {
    /**
     * 導(dǎo)入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); // 獲取第一個(gè)工作表
            // 獲取表頭行
            Row headerRow = checkHeaderRow(sheet);
 
            if (headerRow != null) {
                //封裝表頭數(shù)據(jù)
                warpHeaderData(headerRow, dataList);
            } else {
                throw new RuntimeException("Excel 文件中沒(méi)有找到表頭行,請(qǐng)修改表格");
            }
 
            // 讀取數(shù)據(jù)行
            for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
                Row row = sheet.getRow(rowIndex);
 
                if (row == null) {
                    continue; // 跳過(guò)空行
                }
                //封裝行數(shù)據(jù)
                warpRowData(headerRow, row, dataList);
            }
        }
 
        // 將 List<String[]> 轉(zhuǎn)換為 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ù)組存儲(chǔ)表頭數(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ù)組存儲(chǔ)表頭數(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); // 獲取第一個(gè)工作表
            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)); // 以逗號(hào)為分隔符打印每一行
//            }
//            List<MergedCell> mergedCells = checkMergedCells(filePath, 0);
//            for (MergedCell row : mergedCells) {
//                System.out.println(row); // 以逗號(hào)為分隔符打印每一行
//            }
//
//        } 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; /* 設(shè)置表格寬度 */
        }
        td {
            border: 1px solid black;
            padding: 0; /* 清除內(nèi)邊距 */
            text-align: center;
            vertical-align: middle; /* 垂直居中 */
            height: 50px; /* 設(shè)置每個(gè)單元格的高度 */
        }
        .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; // 標(biāo)記占用
                                }
                            }
                        }
                    });
 
                    // 填充普通單元格的數(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>

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

相關(guān)文章

  • SpringBoot處理form-data表單接收對(duì)象數(shù)組的方法

    SpringBoot處理form-data表單接收對(duì)象數(shù)組的方法

    form-data則是一種更加靈活的編碼方式,它可以處理二進(jìn)制數(shù)據(jù)(如圖片、文件等)以及文本數(shù)據(jù),這篇文章主要介紹了SpringBoot處理form-data表單接收對(duì)象數(shù)組,需要的朋友可以參考下
    2023-11-11
  • Java判斷是否為閏年的方法示例

    Java判斷是否為閏年的方法示例

    這篇文章主要介紹了Java判斷是否為閏年的方法示例,本文直接給出示例代碼,并講解了判斷原理,需要的朋友可以參考下
    2015-06-06
  • java反射機(jī)制示例

    java反射機(jī)制示例

    這篇文章主要介紹了java反射機(jī)制示例,需要的朋友可以參考下
    2014-04-04
  • Java?根據(jù)XPATH批量替換XML節(jié)點(diǎn)中的值

    Java?根據(jù)XPATH批量替換XML節(jié)點(diǎn)中的值

    這篇文章主要介紹了Java根據(jù)XPATH批量替換XML節(jié)點(diǎn)中的值,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-09-09
  • Eclipse常用快捷鍵大全

    Eclipse常用快捷鍵大全

    這篇文章主要介紹了Eclipse常用快捷鍵大全,較為詳細(xì)的針對(duì)eclipse中各種應(yīng)用中使用快捷鍵進(jìn)行了分類總結(jié),具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-11-11
  • 使用Jackson進(jìn)行JSON生成與解析的新手指南

    使用Jackson進(jìn)行JSON生成與解析的新手指南

    這篇文章主要為大家詳細(xì)介紹了如何使用Jackson進(jìn)行JSON生成與解析處理,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-04-04
  • 深入剖析Java ReentrantLock的源碼

    深入剖析Java ReentrantLock的源碼

    ReentrantLock和Synchronized都是Java開(kāi)發(fā)中最常用的鎖,與Synchronized這種JVM內(nèi)置鎖不同的是,ReentrantLock提供了更豐富的語(yǔ)義。本文就來(lái)深入剖析一下ReentrantLock源碼,需要的可以參考一下
    2022-11-11
  • JDK8并行流及串行流區(qū)別原理詳解

    JDK8并行流及串行流區(qū)別原理詳解

    這篇文章主要介紹了JDK8并行流及串行流區(qū)別原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • Java Spring的數(shù)據(jù)庫(kù)開(kāi)發(fā)詳解

    Java Spring的數(shù)據(jù)庫(kù)開(kāi)發(fā)詳解

    這篇文章主要介紹了Spring的數(shù)據(jù)庫(kù)開(kāi)發(fā),主要圍繞SpringJDBC和Spring Jdbc Template兩個(gè)技術(shù)來(lái)講解,文中有詳細(xì)的代碼示例,需要的小伙伴可以參考一下
    2023-04-04
  • java高并發(fā)的volatile與Java內(nèi)存模型詳解

    java高并發(fā)的volatile與Java內(nèi)存模型詳解

    這篇文章主要介紹了java高并發(fā)的volatile與Java內(nèi)存模型,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2021-10-10

最新評(píng)論