一切皆留「轨迹」

EasyExcel导出使用案例

Feb 09,2026
1
0

建议使用实例 1List 的方式,不需要建 Obj

样式规则主要代码:


    private class StyleStrategy extends AbstractCellStyleStrategy {
        private List<?> data;   // 把整份数据传进来
        private int type = 0; //不同的样式处理
        private Map<Integer, List<int[]>> mergeMap = new HashMap<>(); //存储合并信息
        private Set<Integer> mergeRows = new HashSet<>();   // 需要合并的行号 ,只 处理这些行进行相同单元格合并
        public StyleStrategy(List<?> data, int... mergeRows) {
            this.data = data;
            this.mergeRows =
                    Arrays.stream(mergeRows).boxed().collect(Collectors.toSet());
            calcMergedCol();
        }
        public StyleStrategy(int type, List<?> data, int... mergeRows) {
            this.type = type;
            this.data = data;
            this.mergeRows =
                    Arrays.stream(mergeRows).boxed().collect(Collectors.toSet());
            calcMergedCol();
        }
        /**
         * 设置单元格样式
         *
         * @param context
         */
        @Override
        protected void setContentCellStyle(CellWriteHandlerContext context) {
            Cell cell = context.getCell();
            Sheet sheet = context.getWriteSheetHolder().getSheet();
            int col = cell.getColumnIndex();
            int row = context.getRowIndex();
            //字符串若是数字的转为数字类型, 消除绿色角标
            String cellValue = cell.getStringCellValue();
            if (StringUtil.isNum(cellValue) != -1) {
                cell.setCellValue(Double.parseDouble(cellValue));
            }
            /* ——  指定行相同内容格合并 —— */
            List<int[]> rowMerge = mergeMap.get(row);
            if (rowMerge != null) {
                for (int[] range : rowMerge) {
                    int startCol = range[0];
                    int endCol = range[1];
                    if (col == startCol) {
                        // 如果已经合并过会抛异常,这里简单 try 住
                        try {
                            sheet.addMergedRegion(new CellRangeAddress(row, row,
                                    startCol, endCol));
                        } catch (IllegalStateException ignored) {
                            // 已合并则跳过
                        }
                    }
                }
            }
            // 全局设置列宽
//            sheet.setColumnWidth(col, 16 * 256);
            // 创建并设置单元格样式
            Workbook wb = sheet.getWorkbook();
            CellStyle style = wb.createCellStyle();
            // 居中 + 换行
            style.setAlignment(HorizontalAlignment.CENTER);
            style.setVerticalAlignment(VerticalAlignment.CENTER);
            style.setWrapText(true);
            //  刷背景色
//            if (row >= 2 ) {
            //
            style.setFillForegroundColor(IndexedColors.LIGHT_GREEN.getIndex());
            //                style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            //            }
            style.setBorderLeft(BorderStyle.THIN);
            style.setBorderRight(BorderStyle.THIN);
            style.setBorderTop(BorderStyle.THIN);
            style.setBorderBottom(BorderStyle.THIN);
            //设置空边框
//                style.setTopBorderColor(IndexedColors.WHITE.getIndex());
            //                style.setBottomBorderColor(IndexedColors.WHITE.getIndex());
            //          //设置边框
            style.setBorderTop(BorderStyle.THIN);
            style.setBorderBottom(BorderStyle.THIN);
            //设置行高、字号样式
            if (type == 0) {
                // 创建字体
                Font font = wb.createFont();
                font.setFontName("宋体");   // 字体名
                //各行样式:行高、字号、加粗等
                if (row == 0) {
                    sheet.getRow(row).setHeight((short) (46 * 20));
                    font.setFontHeightInPoints((short) 16); // 字号
                    font.setBold(true);                   // 加粗
                } else if (row == 1) {
                    sheet.getRow(row).setHeight((short) (30 * 20));
                    font.setFontHeightInPoints((short) 12); // 字号
                    font.setBold(true);                   // 加粗
                } else if (row == 2) {
                    sheet.getRow(row).setHeight((short) (30 * 20));
                    font.setFontHeightInPoints((short) 12); // 字号
                    font.setBold(true);                   // 加粗
                } else if (row == data.size() - 1) {
                    sheet.getRow(row).setHeight((short) (66 * 20));//行高
                    font.setFontHeightInPoints((short) 12); // 字号
                    font.setBold(false);                   // 加粗
                } else {
                    sheet.getRow(row).setHeight((short) (28 * 20));
                    font.setFontHeightInPoints((short) 12); // 字号
                    font.setBold(false);                   // 加粗
                }
                // font.setColor(IndexedColors.RED.getIndex()); // 需要颜色再打开
                style.setFont(font);  // 把字体挂到样式
                //各列样式:列宽,对其方式等
                if (col == 0) {
                    sheet.setColumnWidth(col, 12 * 256);
                } else if (col == 1) {
                    sheet.setColumnWidth(col, 24 * 256);
                } else if (col == 2) {
                    sheet.setColumnWidth(col, 18 * 256);
                } else if (col == 3) {
                    sheet.setColumnWidth(col, 12 * 256);
                } else if (col == 7) {
                    sheet.setColumnWidth(col, 32 * 256);
                } else {
                    sheet.setColumnWidth(col, 18 * 256);//其他的16
                }
                //指定单元格样式
                if (row == 1 && (col == 2 || col == 6)) {
                    style.setAlignment(HorizontalAlignment.LEFT); //水平对齐方式
                    style.setVerticalAlignment(VerticalAlignment.CENTER); //垂直 对齐方式
                }
            } else if (type == 1) {
                // 创建字体
                Font font = wb.createFont();
                font.setFontName("宋体");   // 字体名
                //各行样式:行高、字号、加粗等
                if (row == 0) {
                    sheet.getRow(row).setHeight((short) (42 * 20));
                    font.setFontHeightInPoints((short) 16); // 字号
                    font.setBold(true);                   // 加粗
                } else if (row == 1) {
                    sheet.getRow(row).setHeight((short) (32 * 20));
                    font.setFontHeightInPoints((short) 12); // 字号
                    font.setBold(true);                   // 加粗
                } else if (row == 2) {
                    sheet.getRow(row).setHeight((short) (32 * 20));
                    font.setFontHeightInPoints((short) 12); // 字号
                    font.setBold(true);                   // 加粗
                } else if (row == data.size() - 1) {
                    //                    style.setTopBorderColor(IndexedColors.WHITE.getIndex());// 空白上边框
//
                    style.setBottomBorderColor(IndexedColors.WHITE.getIndex());//空白下边框
//
                    style.setLeftBorderColor(IndexedColors.WHITE.getIndex());//空白左边框
//                    style.setRightBorderColor(IndexedColors.WHITE.getIndex());
//空白右边框
                    sheet.getRow(row).setHeight((short) (36 * 20));
                    font.setFontHeightInPoints((short) 12); // 字号
                    font.setBold(false);                   // 加粗
                } else {
                    sheet.getRow(row).setHeight((short) (28 * 20));
                    font.setFontHeightInPoints((short) 12); // 字号
                    font.setBold(false);                   // 加粗
                }
                // font.setColor(IndexedColors.RED.getIndex()); // 需要颜色再打开
                style.setFont(font);  // 把字体挂到样式
                //各列样式:列宽,对其方式等
                if (col == 0) {
                    sheet.setColumnWidth(col, 10 * 256);
                } else if (col == 1) {
                    sheet.setColumnWidth(col, 24 * 256);
                } else if (col == 2) {
                    sheet.setColumnWidth(col, 18 * 256);
                } else if (col == 3) {
                    sheet.setColumnWidth(col, 12 * 256);
                } else if (col == 4) {
                    sheet.setColumnWidth(col, 24 * 256);
                } else if (col == 5) {
                    sheet.setColumnWidth(col, 12 * 256);
                } else if (col == 6) {
                    sheet.setColumnWidth(col, 12 * 256);
                } else if (col == 7) {
                    sheet.setColumnWidth(col, 14 * 256);
                } else if (col == 8) {
                    sheet.setColumnWidth(col, 12 * 256);
                } else if (col == 9) {
                    sheet.setColumnWidth(col, 18 * 256);
                } else {
                    sheet.setColumnWidth(col, 36 * 256);//其他的
                }
                //指定单元格样式
                if (row == 1 && (col == 2 || col == 9)) {
                    style.setAlignment(HorizontalAlignment.LEFT); //水平对齐方式
                    style.setVerticalAlignment(VerticalAlignment.CENTER); //垂直 对齐方式
                }
            }
            cell.setCellStyle(style);
        }
        private void calcMergedCol() {
            if (data == null || data.isEmpty()) return;
            for (int r = 0; r < data.size(); r++) {
                if (!mergeRows.isEmpty() && !mergeRows.contains(r)) continue;
                Object row = data.get(r);          // 可能是 List<String> 也可能是 JavaBean
                Object[] cells;                    // 统一转成“列数组”
                /* ---------- ① List<List<String>> 情况 ---------- */
                if (row instanceof List) {
                    @SuppressWarnings("unchecked")
                    List<?> tmp = (List<?>) row;
                    // 如果第一个元素就是 String,就认为整行都是 String
                    if (!tmp.isEmpty() && tmp.get(0) instanceof String) {
                        cells = tmp.toArray();   // List<String> → String[]
                    } else {
                        /* ---------- ② List<YourBean> 情况 ---------- */
                        // EasyExcel 把每行包成 List<YourBean>,size=1
                        if (tmp.size() != 1) continue;
                        cells = objectToArray(tmp.get(0)); // 用你原来的反射
                    }
                } else {
                    /* ---------- ③ 直接是 JavaBean(理论上不会走到) ---------- */
                    cells = objectToArray(row);
                }
                /* ---------- 公共合并逻辑 ---------- */
                int colCount = cells.length;
                List<int[]> rowMerge = new ArrayList<>();
                int start = 0;
                while (start < colCount) {
                    Object val = cells[start];
                    int end = start;
                    while (end + 1 < colCount && Objects.equals(val, cells[end +
                            1])) {
                        end++;
                    }
                    if (end > start) rowMerge.add(new int[]{start, end});
                    start = end + 1;
                }
                if (!rowMerge.isEmpty()) mergeMap.put(r, rowMerge);
            }
        }
    }
    private static Object[] objectToArray(Object row) {
        try {
            Class<?> clz = row.getClass();
            Field[] fs = clz.getDeclaredFields();
            Object[] cells = new Object[fs.length];
            for (int i = 0; i < fs.length; i++) {
                fs[i].setAccessible(true);
                cells[i] = fs[i].get(row);
            }
            return cells;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

实例1: List excelData 无需创建对象导出,但需要自己组装 excelData 数据

 /**
     * 导出对账业务明细
     *
     * @param supplierStatement
     * @return
     */
    @PostMapping("/excelStatementDetail")
    public void excelStatementDetail(@RequestBody ProSupplierStatement 
supplierStatement) {
        Preconditions.checkNotNull(supplierStatement.getId(), "id参数不能为空");
        ProSupplierStatement old = 
supplierStatementApi.getById(supplierStatement.getId());
        Preconditions.checkNotNull(old, "数据不存在,请刷新后再试");
        //文件名,也是titleRow的内容
        String fileName = old.getTitle() + "业务明细";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
 //        DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd 
HH:mm:ss");
        //titleRow标题行数据
        List<List<String>> excelData = new ArrayList<>();
        List<String> head_1 = new ArrayList<>();
        head_1.add(fileName);
        head_1.add(fileName);
        head_1.add(fileName);
        head_1.add(fileName);
        head_1.add(fileName);
        head_1.add(fileName);
        head_1.add(fileName);
        head_1.add(fileName);
        head_1.add(fileName);
        head_1.add(fileName);
        head_1.add(fileName);
        excelData.add(head_1);
        //其他表头行数据
        List<String> head_2 = new ArrayList<>();
        head_2.add("供应商");
        head_2.add("供应商");
        head_2.add(old.getSupplierName());
        head_2.add(old.getSupplierName());
        head_2.add(old.getSupplierName());
        head_2.add(null);
        head_2.add(null);
        head_2.add("对账单号");
        head_2.add("对账单号");
        head_2.add(old.getCode());
        head_2.add(old.getCode());
        excelData.add(head_2);
        //表头行数据
        List<String> head_3 = new ArrayList<>();
        head_3.add("序号");
        head_3.add("业务单号");
        head_3.add("日期");
        head_3.add("类型");
        head_3.add("品名");
        head_3.add("单位");
        head_3.add("数量");
        head_3.add("总重量");
        head_3.add("单价");
        head_3.add("金额(元)");
        head_3.add("备注");
        excelData.add(head_3);
        //业务数据获取
        List<ProSupplierStatementDetail> details = 
supplierStatementApi.getStatementDetailData(supplierStatement.getId());
        //处理业务行数据,并统计合计列数据
        Integer index = 1;
        BigDecimal totalQuantity = BigDecimal.ZERO;
        BigDecimal totalWeight = BigDecimal.ZERO;
        BigDecimal totalPrice = BigDecimal.ZERO;
        for (ProSupplierStatementDetail detail : details) {
            totalQuantity = totalQuantity.add(detail.getQuantity());
            totalWeight = totalWeight.add(detail.getWeight());
            totalPrice = totalPrice.add(detail.getTotalPrice());
            List<String> row = new ArrayList<>();
            row.add(index.toString());
            row.add(detail.getSourceCode());
            row.add(formatter.format(detail.getSourceDate()));
            row.add(detail.getSourceType());
            row.add(detail.getMaterialsName());
            row.add(detail.getUnit());
            row.add(detail.getQuantity().stripTrailingZeros().toPlainString());
            row.add(detail.getWeight().stripTrailingZeros().toPlainString());
            row.add(detail.getUnitPrice().stripTrailingZeros().toPlainString());
           
 row.add(detail.getTotalPrice().stripTrailingZeros().toPlainString());
            row.add(detail.getSourceRemark());
            excelData.add(row); //将业务数据加到导出数据中
        }
        //合计行数据
        List<String> total_row = new ArrayList<>();
        total_row.add(null);
        total_row.add("合计");
        total_row.add(null);
        total_row.add(null);
        total_row.add(null);
        total_row.add(null);
        total_row.add(totalQuantity.stripTrailingZeros().toPlainString());
        total_row.add(totalWeight.stripTrailingZeros().toPlainString());
        total_row.add(null);
        total_row.add(totalPrice.stripTrailingZeros().toPlainString());
        total_row.add(null);
        excelData.add(total_row);
        //其他页脚行数据
 
实例2:
List<List> excelData 使用对象数据进行导出 
        List<String> audit_row = new ArrayList<>();
        audit_row.add("制表人");
        audit_row.add(null);
        audit_row.add(null);
        audit_row.add("审核人");
        audit_row.add(null);
        audit_row.add(null);
        audit_row.add(null);
        audit_row.add(null);
        audit_row.add(null);
        audit_row.add("核对无误");
        audit_row.add("核对无误");
        excelData.add(audit_row);
        //执行导出
        try (ExcelWriter writer = 
EasyExcel.write(response.getOutputStream()).build()) {
            writer.write(
                    excelData,
                    EasyExcel.writerSheet(0, "sheet1")
                            .registerWriteHandler(new StyleStrategy(1, 
excelData, 0, 1, excelData.size() - 1))//注册样式规则,type可以用来设置区分
                            .build());
        } catch (IOException e) {
            logError(e, "导出错误" + e.getMessage());
        }
    }