easyexcel2.2.10对本地文件的指定行或指定列添加样式

图一是我动态表头生成的本地数据,使用下面的工具类处理成了图二

动态表头可参考这篇文章:动态表头

java 复制代码
package org.springblade.modules.api.controller;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 2.2.10版本:修改本地Excel文件的行样式 + 动态列宽度 + 文本自动换行
 * 列宽度动态规则:
 * - 第1列(日期列,索引0)= 16
 * - 从第2列开始,每6列为1个完整组(如揽月湾/翡丽蓝湾):
 *   → 每组内前3列 = 6
 *   → 每组内后3列 = 10
 * 支持无限新增组(自动适配)
 * 所有行统一使用细实线边框(BorderStyle.THIN)+ 黑色边框颜色
 */
public class LocalExcelRowStyleModifier {

    // 定义行样式配置类:封装单行的所有样式属性(包含边框+换行配置)
    public static class RowStyleConfig {
        private boolean bold;                // 是否加粗
        private String fontName;            // 字体名称
        private short fontSize;             // 字号
        private short fontColor;            // 字体颜色
        private short bgColor;              // 背景色
        private float rowHeight;            // 行高(磅)
        private HorizontalAlignment horizontalAlign; // 水平对齐
        private VerticalAlignment verticalAlign;     // 垂直对齐
        // 边框配置(所有行统一为细实线边框)
        private BorderStyle borderStyle;    // 边框样式(当前全量为细实线THIN)
        private short borderColor;          // 边框颜色(当前全量为黑色)
        // 新增:文本是否自动换行
        private boolean wrapText;           // true=自动换行,false=不换行

        // 全参构造器(新增 wrapText 参数)
        public RowStyleConfig(boolean bold, String fontName, short fontSize, short fontColor, short bgColor,
                              float rowHeight, HorizontalAlignment horizontalAlign, VerticalAlignment verticalAlign,
                              BorderStyle borderStyle, short borderColor, boolean wrapText) {
            this.bold = bold;
            this.fontName = fontName;
            this.fontSize = fontSize;
            this.fontColor = fontColor;
            this.bgColor = bgColor;
            this.rowHeight = rowHeight;
            this.horizontalAlign = horizontalAlign;
            this.verticalAlign = verticalAlign;
            this.borderStyle = borderStyle;
            this.borderColor = borderColor;
            this.wrapText = wrapText;
        }

        // Getter方法
        public boolean isBold() { return bold; }
        public String getFontName() { return fontName; }
        public short getFontSize() { return fontSize; }
        public short getFontColor() { return fontColor; }
        public short getBgColor() { return bgColor; }
        public float getRowHeight() { return rowHeight; }
        public HorizontalAlignment getHorizontalAlign() { return horizontalAlign; }
        public VerticalAlignment getVerticalAlign() { return verticalAlign; }
        public BorderStyle getBorderStyle() { return borderStyle; }
        public short getBorderColor() { return borderColor; }
        public boolean isWrapText() { return wrapText; }
    }

    /**
     * 动态列宽度设置(核心优化)
     * 规则:
     * 1. 首列(索引0)固定16
     * 2. 从索引1开始,每6列为1组:
     *    - 组内索引0-2(对应整体索引1-3/7-9/13-15...)→ 宽度6
     *    - 组内索引3-5(对应整体索引4-6/10-12/16-18...)→ 宽度10
     * 3. 自动适配任意数量的组(新增XX湾无需改代码)
     * @param sheet 工作表对象
     * @param maxColNum 需要设置的最大列数
     */
    private static void setColumnWidths(Sheet sheet, int maxColNum) {
        // 基础配置:Excel显示的目标宽度(不是POI字符数)
        final int FIRST_COL_DISPLAY_WIDTH = 16;
        final int GROUP_FIRST_3_DISPLAY_WIDTH = 6;
        final int GROUP_LAST_3_DISPLAY_WIDTH = 10;
        final int GROUP_TOTAL_COL = 6; // 每组固定6列

        // POI换算系数:显示宽度 = POI字符数 - 0.62 → POI字符数 = 显示宽度 + 0.62
        final double POI_CONVERT_RATIO = 0.62;

        // 遍历所有需要设置的列
        for (int colIndex = 0; colIndex < maxColNum; colIndex++) {
            double poiCharWidth; // POI需要的字符宽度
            if (colIndex == 0) {
                // 首列:目标显示16 → POI字符数=16+0.62
                poiCharWidth = FIRST_COL_DISPLAY_WIDTH + POI_CONVERT_RATIO;
            } else {
                int relativeIndex = colIndex - 1;
                int groupInnerIndex = relativeIndex % GROUP_TOTAL_COL;
                if (groupInnerIndex >= 0 && groupInnerIndex <= 2) {
                    // 组内前3列:目标显示6 → POI字符数=6+0.62
                    poiCharWidth = GROUP_FIRST_3_DISPLAY_WIDTH + POI_CONVERT_RATIO;
                } else {
                    // 组内后3列:目标显示10 → POI字符数=10+0.62
                    poiCharWidth = GROUP_LAST_3_DISPLAY_WIDTH + POI_CONVERT_RATIO;
                }
            }
            // 转换为POI的宽度单位(1单位=1/256字符)
            int poiWidth = (int) (poiCharWidth * 256);
            sheet.setColumnWidth(colIndex, poiWidth);
            // 打印日志:显示目标宽度 vs 实际设置的POI值
            System.out.printf("列索引%d → 目标显示宽度:%.0f → POI设置值:%d → Excel最终显示≈%.0f\n",
                    colIndex, poiCharWidth - POI_CONVERT_RATIO, poiWidth, poiCharWidth - POI_CONVERT_RATIO);
        }
        System.out.println("动态列宽度设置完成!Excel显示宽度:首列16,每组前3列6、后3列10");
    }

    /**
     * 核心方法:为多行设置不同样式(所有行统一应用细实线边框)+ 自定义列宽度 + 文本换行
     * @param sourceFilePath 原Excel路径
     * @param targetFilePath 保存路径
     * @param sheetIndex 工作表索引(0开始)
     * @param rowStyleMap 行号-样式配置的映射(key=行号,value=该行的样式)
     * @throws IOException 文件异常
     */
    public static void modifyMultiRowWithDifferentStyle(String sourceFilePath, String targetFilePath,
                                                       int sheetIndex, Map<Integer, RowStyleConfig> rowStyleMap) throws IOException {
        // 1. 读取Excel文件
        File sourceFile = new File(sourceFilePath);
        if (!sourceFile.exists()) {
            throw new IOException("原文件不存在:" + sourceFilePath);
        }
        FileInputStream fis = new FileInputStream(sourceFile);
        Workbook workbook = new XSSFWorkbook(fis); // 仅支持.xlsx,.xls替换为HSSFWorkbook
        Sheet sheet = workbook.getSheetAt(sheetIndex);

        // ========== 新增逻辑:获取Excel实际最大行号 ==========
        int maxRowNum = sheet.getLastRowNum();
        // ========== 新增逻辑:定义第四行及以后的统一样式 ==========
        RowStyleConfig defaultRowConfig = new RowStyleConfig(
                false,          // 不加粗
                "宋体",         // 宋体
                (short) 14,     // 14号字体
                IndexedColors.BLACK.getIndex(),
                IndexedColors.WHITE.getIndex(),
                34.8f,          // 行高34.8
                HorizontalAlignment.CENTER, // 水平居中
                VerticalAlignment.CENTER,   // 垂直居中
                BorderStyle.THIN,
                IndexedColors.BLACK.getIndex(),
                false           // 不换行
        );

        // 2. 遍历每一行,应用对应的样式(含细边框+换行)
        int maxColNum = 0; // 记录Excel中最大列数,用于后续设置列宽度
        // 遍历所有行(包括第四行及以后的行)
        for (int rowNum = 0; rowNum <= maxRowNum; rowNum++) {
            RowStyleConfig styleConfig;
            // 判断是否是已配置的行(0-3行),否则使用第四行及以后的统一样式
            if (rowStyleMap.containsKey(rowNum)) {
                styleConfig = rowStyleMap.get(rowNum);
            } else {
                styleConfig = defaultRowConfig;
            }

            // 定位目标行(不存在则创建)
            Row targetRow = sheet.getRow(rowNum);
            if (targetRow == null) {
                targetRow = sheet.createRow(rowNum);
            }

            // 3. 根据配置创建该行专属的字体和单元格样式
            Font font = workbook.createFont();
            font.setBold(styleConfig.isBold());
            font.setFontName(styleConfig.getFontName());
            font.setFontHeightInPoints(styleConfig.getFontSize());
            font.setColor(styleConfig.getFontColor());

            CellStyle cellStyle = workbook.createCellStyle();
            cellStyle.setFont(font);
            cellStyle.setFillForegroundColor(styleConfig.getBgColor());
            cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            cellStyle.setAlignment(styleConfig.getHorizontalAlign());
            cellStyle.setVerticalAlignment(styleConfig.getVerticalAlign());
            // 应用文本自动换行配置
            cellStyle.setWrapText(styleConfig.isWrapText());

            // 设置边框样式(上下左右统一为细实线边框)
            cellStyle.setBorderTop(styleConfig.getBorderStyle());
            cellStyle.setBorderBottom(styleConfig.getBorderStyle());
            cellStyle.setBorderLeft(styleConfig.getBorderStyle());
            cellStyle.setBorderRight(styleConfig.getBorderStyle());
            // 设置边框颜色(统一为黑色)
            cellStyle.setTopBorderColor(styleConfig.getBorderColor());
            cellStyle.setBottomBorderColor(styleConfig.getBorderColor());
            cellStyle.setLeftBorderColor(styleConfig.getBorderColor());
            cellStyle.setRightBorderColor(styleConfig.getBorderColor());

            // 4. 设置行高
            targetRow.setHeightInPoints(styleConfig.getRowHeight());

            // 5. 应用样式到该行所有单元格(含空单元格)
            int lastCellNum = targetRow.getLastCellNum();
            // 更新最大列数(确保列宽度覆盖所有单元格)
            if (lastCellNum > maxColNum) {
                maxColNum = lastCellNum;
            }
            // 处理已存在的单元格
            for (int i = 0; i < (lastCellNum == -1 ? 0 : lastCellNum); i++) {
                Cell cell = targetRow.getCell(i);
                if (cell == null) {
                    cell = targetRow.createCell(i);
                }
                cell.setCellStyle(cellStyle);
            }
        }

        // 6. 设置列宽度(核心新增逻辑)
        // 确保至少覆盖13列(2组:揽月湾+翡丽蓝湾),新增组自动扩展
        maxColNum = Math.max(maxColNum, 13);
        setColumnWidths(sheet, maxColNum);

        // 7. 保存并关闭资源
        FileOutputStream fos = new FileOutputStream(targetFilePath);
        workbook.write(fos);

        // 关闭流(按逆序关闭)
        fos.close();
        workbook.close();
        fis.close();

        System.out.println("多行多样式(全量细边框)+ 自定义列宽度 + 文本换行修改完成!修改后文件路径:" + targetFilePath);
    }

    // 保留原有单一行修改方法(兼容旧逻辑,默认细实线边框+不换行)
    public static void modifyRowStyle(String sourceFilePath, String targetFilePath, int sheetIndex, int targetRowNum) throws IOException {
        // 构建默认样式(含细实线边框:黑色细边框 + 不换行)
        RowStyleConfig defaultConfig = new RowStyleConfig(
                true, "黑体", (short)22, IndexedColors.BLACK.getIndex(),
                IndexedColors.WHITE.getIndex(), 47.6f,
                HorizontalAlignment.CENTER, VerticalAlignment.CENTER,
                BorderStyle.THIN, IndexedColors.BLACK.getIndex(), false // 默认不换行
        );
        Map<Integer, RowStyleConfig> rowStyleMap = new HashMap<>();
        rowStyleMap.put(targetRowNum, defaultConfig);
        modifyMultiRowWithDifferentStyle(sourceFilePath, targetFilePath, sheetIndex, rowStyleMap);
    }

    public static void main(String[] args) {
        try {
            String sourcePath = "F:\\machine\\noModelWrite1773206416743.xlsx";
            String targetPath = "F:\\machine\\test_modified_" + System.currentTimeMillis() + ".xlsx";

            Map<Integer, RowStyleConfig> rowStyleMap = new HashMap<>();

            // 第0行(表头):黑体、22号、加粗、白色背景、居中、行高47.6 + 黑色细边框 + 不换行
            rowStyleMap.put(0, new RowStyleConfig(
                    true,
                    "黑体",
                    (short) 22,
                    IndexedColors.BLACK.getIndex(),
                    IndexedColors.WHITE.getIndex(),
                    47.6f,
                    HorizontalAlignment.CENTER,
                    VerticalAlignment.CENTER,
                    BorderStyle.THIN, // 细实线边框
                    IndexedColors.BLACK.getIndex(), // 黑色边框
                    false // 不换行
            ));

            // 第1行:宋体、16号、加粗、白色背景、右对齐、行高47.6 + 黑色细边框 + 不换行
            rowStyleMap.put(1, new RowStyleConfig(
                    true,
                    "宋体",
                    (short) 16,
                    IndexedColors.BLACK.getIndex(),
                    IndexedColors.WHITE.getIndex(),
                    47.6f,
                    HorizontalAlignment.RIGHT,
                    VerticalAlignment.CENTER,
                    BorderStyle.THIN, // 细实线边框
                    IndexedColors.BLACK.getIndex(), // 黑色边框
                    false // 不换行(修正注释错误)
            ));

            // 第2行:楷体、16号、加粗、白色背景、居中、行高34.8 + 黑色细边框 + 不换行
            rowStyleMap.put(2, new RowStyleConfig(
                    true,
                    "楷体_GB2312",
                    (short) 16,
                    IndexedColors.BLACK.getIndex(),
                    IndexedColors.WHITE.getIndex(),
                    34.8f,
                    HorizontalAlignment.CENTER,
                    VerticalAlignment.CENTER,
                    BorderStyle.THIN, // 细实线边框
                    IndexedColors.BLACK.getIndex(), // 黑色边框
                    false // 不换行(修正注释错误)
            ));

            // 第3行:楷体、12号、加粗、白色背景、居中、行高34.8 + 黑色细边框 + 不换行
            rowStyleMap.put(3, new RowStyleConfig(
                    true,
                    "楷体_GB2312",
                    (short) 12,
                    IndexedColors.BLACK.getIndex(),
                    IndexedColors.WHITE.getIndex(),
                    34.8f,
                    HorizontalAlignment.CENTER,
                    VerticalAlignment.CENTER,
                    BorderStyle.THIN, // 细实线边框
                    IndexedColors.BLACK.getIndex(), // 黑色边框
                    true // 换行
            ));

            // 第4行:及以后统一样式(宋体14、不加粗、居中、行高34.8)
            rowStyleMap.put(4, new RowStyleConfig(
                    false, // 不加粗
                    "宋体", // 宋体
                    (short) 14, // 14号
                    IndexedColors.BLACK.getIndex(),
                    IndexedColors.WHITE.getIndex(),
                    34.8f, // 行高34.8
                    HorizontalAlignment.CENTER, // 居中
                    VerticalAlignment.CENTER,
                    BorderStyle.THIN, // 细实线边框
                    IndexedColors.BLACK.getIndex(), // 黑色边框
                    false // 不换行(修正注释错误)
            ));

            modifyMultiRowWithDifferentStyle(sourcePath, targetPath, 0, rowStyleMap);

        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("修改失败:" + e.getMessage());
        }
    }
}
相关推荐
城数派2 小时前
1901-2024年我国省市县三级逐年潜在蒸散发数据(Shp/Excel格式)
excel
门思科技2 小时前
ThinkLink批量操作功能详解:如何通过Excel高效管理物联网设备与配置
物联网·excel
scx_link4 小时前
使用 Excel 中的 “快速填充“
excel
蜜汁小强5 小时前
Vim简单配置: 加点颜色加点格式
编辑器·vim·excel
徒手千行代码无bug6 小时前
填充Excel
excel
认真学GIS6 小时前
日尺度地下水水位!全国11897个地下水动态监测站点2005-2021年日尺度地下水水位(地下水埋深)(EXCEL格式)数据
服务器·前端·excel
ekkcole9 小时前
easyexcel2.2.10版本对本地文件指定行或多行样式处理
java·easyexcel
fengyehongWorld9 小时前
Excel 超级表获取行列数据的方法
excel
WarPigs9 小时前
基于泛型+反射的Excel万能导表工具
unity·c#·excel·反射