java-poi实现自定义注解excel生成合并单元格数据导出

在之前的一篇中,简述了如何导出简单的exce表格。但是,有些时候我们需要导出一些带有合并单元格的数据。如以下所示:

依赖导入

<dependency>

<groupId>org.apache.poi</groupId>

<artifactId>poi-ooxml</artifactId>

<version>4.0.1</version>

</dependency>

<dependency>

<groupId>org.apache.poi</groupId>

<artifactId>poi</artifactId>

<version>4.0.1</version>

</dependency>

实体定义

标题栏注解

java 复制代码
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelTitle {

    /**
     * 标题名称
     * @return 默认空
     */
    String titleName() ;

    /**
     * 标题背景
     * @return 默认空
     */
    IndexedColors titleBack() default IndexedColors.WHITE;

    /**
     * 标题文字大小
     * @return 默认空
     */
    short titleSize() default 14;

    /**
     * 标题文字颜色
     * @return 黑色
     */
    HSSFColor.HSSFColorPredefined titleColor() default HSSFColor.HSSFColorPredefined.BLACK;

    /**
     * 边框格式
     * @return 细
     */
    BorderStyle borderStyle() default BorderStyle.THIN;

    /**
     * 边框颜色
     * @return 默认
     */
    IndexedColors borderColor() default IndexedColors.AUTOMATIC;

    /**
     * 标题文字加粗
     * @return 黑色
     */
    boolean boldFont() default true;

    /**
     * 是否忽略
     * @return 黑色
     */
    boolean ignore() default false;

    /**
     * 排序
     * @return 0
     */
    int order() default 0;
}

数据栏注解

java 复制代码
/**
 * @author ZSC
 * @date 2024/7/19 - 9:33
 * @description: excel导出结果配置
 */
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelProperty {

    /**
     * 背景
     * @return 默认空
     */
    IndexedColors textBack() default IndexedColors.WHITE;

    /**
     * 内容类型,查看
     * @link org.apache.poi.ss.usermodel.BuiltinFormats
     * @return 默认TEXT
     */
    String textType() default "TEXT";

    /**
     * 文字大小
     * @return 默认18
     */
    short textSize() default 12;

    /**
     * 数据属于key:value时,可以自定义转换,配置格式为:key1=value;key2=value2;.....
     * @return 默认空
     */
    String textKv() default "";

    /**
     * 文字颜色
     * @return 黑色
     */
    HSSFColor.HSSFColorPredefined textColor() default HSSFColor.HSSFColorPredefined.BLACK;

    /**
     * 水平位置
     * @return 水平居中
     */
    HorizontalAlignment horizontal() default HorizontalAlignment.CENTER;

    /**
     * 垂直位置
     * @return 垂直居中
     */
    VerticalAlignment vertical() default VerticalAlignment.CENTER;

    /**
     * 文字加粗
     * @return 不加粗
     */
    boolean boldFont() default false;
}

合并单元格实体定义

java 复制代码
/**
 * @date 2024/7/23 - 16:24
 * @description: excel单元格合并数据定义实体
 */
@Data
public class ExcelMergeVo {

    /**
     * 默认的单元配置
     */
    private ExcelCellStyleDto excelCellStyleDto;


    /**
     * 水平占据的单元各数量,默认1
     */
    private int cellHorizontalSize = 1;

    /**
     * 占据的单元格数量,默认1
     */
    private int cellVerticalSize = 1;

    @ExcelProperty()
    private String value;
}

合并单元格样式实体

java 复制代码
@Data
public class ExcelCellStyleDto {
    /**
     * 背景 默认空
     */
    private IndexedColors textBack = IndexedColors.WHITE;

    /**
     * 内容类型,查看 默认TEXT
     * @link org.apache.poi.ss.usermodel.BuiltinFormats
     */
    private String textType =  "TEXT";

    /**
     * 文字大小  默认18
     */
    private short textSize = 12;

    /**
     * 文字颜色 默认 黑色
     */
    private HSSFColor.HSSFColorPredefined textColor = HSSFColor.HSSFColorPredefined.BLACK;

    /**
     * 水平位置 默认 水平居中
     */
    private HorizontalAlignment horizontal = HorizontalAlignment.CENTER;

    /**
     * 垂直位置 垂直居中
     */
    private VerticalAlignment vertical = VerticalAlignment.CENTER;

    /**
     * 文字加粗 默认 不加粗
     */
    private boolean boldFont = true;

    /**
     * 边框
     */
    private BorderStyle borderStyle;
}

每个sheet的数据定义

java 复制代码
@Data
public class ExcelSheetComplexVo {

    /**
     * 每一个sheet页得名称
     */
    private String sheetName;

    /**
     * 每个sheet里面得数据
     * 其中Object中得注解必须时包含 @ExcelTitle 和 @ExcelProperties
     */
    private List<ExcelComplexVo> sheetData;

    /**
     * 数据对象得类型
     */
    private Class dataClass;
}


@Data
public class ExcelComplexVo<T> {

    /**
     * 需要合并的单元格信息处理信息,需要排序好
     */
    private List<ExcelMergeVo> orderExcelMergeVos;

    /**
     * 每个正常的数据
     * 其中Object中得注解必须时包含 @ExcelTitle 和 @ExcelProperties
     */
    private List<T> subData;
}

数据生成实现

合并行主要代码

java 复制代码
/**
     * 生成每一个sheet数据
     * @param wb 问价实体
     * @param sxssfSheet 每个sheet
     * @param excelSheetComplexVo 每个sheet的数据定义
     * @param dataStartLine 起始行数据
     */
    private void initSheetData(SXSSFWorkbook wb, SXSSFSheet sxssfSheet, ExcelSheetComplexVo excelSheetComplexVo, int dataStartLine) {
        if (CollectionUtils.isEmpty(excelSheetComplexVo.getSheetData())) {
            return;
        }
        try {
            for (ExcelComplexVo excelComplexVo : excelSheetComplexVo.getSheetData()) {

                if (CollectionUtils.isNotEmpty(excelComplexVo.getOrderExcelMergeVos())) {
                    //是否有合并的行数据
                    dataStartLine = createMergeRow(wb, sxssfSheet, excelComplexVo.getOrderExcelMergeVos(), dataStartLine);
                }

                for (Object dataObject : excelComplexVo.getSubData()) {
                    SXSSFRow row = sxssfSheet.createRow(dataStartLine);
                    //获取所有有效字段,并排序
                    Field[] fields = dataObject.getClass().getDeclaredFields();
                    List<Field> fieldList = Arrays.stream(fields)
                            .filter(item -> item.getAnnotation(ExcelTitle.class) != null && !item.getAnnotation(ExcelTitle.class).ignore())
                            .sorted(Comparator.comparingInt(item -> {
                                ExcelTitle excelTitle = item.getAnnotation(ExcelTitle.class);
                                return excelTitle.order();
                            })).collect(Collectors.toList());

                    for (int i = 0; i < fieldList.size(); i++) {
                        Field field = fieldList.get(i);
                        //根据title的值对应的值
                        SXSSFCell cell = row.createCell(i);
                        cell.setCellStyle(initCellStyle(wb, field));
                        field.setAccessible(true);
                        cell.setCellValue(dealValue(field, dataObject));
                    }
                    dataStartLine++;
                }
            }
        } catch (Exception e) {
            LOGGER.error("生成数据异常", e);
        }
    }
 
/**
     * 解析并设置合并的单元格
     * @param wb 问价实体
     * @param sxssfSheet sheet实体
     * @param orderExcelMergeVos 需要设置的合并单元格定义
     * @param dataStartLine 合并单元格的开始设置的起始行
     * @return 后面数据的起始设置行
     */ 
private int createMergeRow(SXSSFWorkbook wb, SXSSFSheet sxssfSheet, List<ExcelMergeVo> orderExcelMergeVos, int dataStartLine) {
        if (CollectionUtils.isEmpty(orderExcelMergeVos)) {
            return dataStartLine;
        }

        int maxCellRowSize = 0;
        int index = 0;

        //创建合并行数据
        SXSSFRow row = sxssfSheet.createRow(dataStartLine);

        for (ExcelMergeVo excelMergeVo : orderExcelMergeVos) {

            if (maxCellRowSize < excelMergeVo.getCellHorizontalSize()) {
                maxCellRowSize = excelMergeVo.getCellHorizontalSize();
            }

            //计算需要合并的单元格信息
            int endRowIndex = dataStartLine + excelMergeVo.getCellVerticalSize();
            int cellIndex = index + excelMergeVo.getCellHorizontalSize();

            CellRangeAddress cellRangeAddress = new CellRangeAddress(dataStartLine, endRowIndex - 1, index, cellIndex - 1);
            sxssfSheet.addMergedRegion(cellRangeAddress);

            CellStyle cellStyle = initCellStyle(wb, excelMergeVo.getExcelCellStyleDto());
            SXSSFCell cell1 = row.createCell(index);
            cell1.setCellStyle(cellStyle);
            cell1.setCellValue(excelMergeVo.getValue());

            index = cellIndex;
        }
        return dataStartLine + maxCellRowSize;
    }

private CellStyle initCellStyle(SXSSFWorkbook wb, ExcelCellStyleDto excelCellStyleDto) {
        // 单元格样式(垂直居中)
        XSSFCellStyle cellStyle = (XSSFCellStyle) wb.createCellStyle();


        //水平居中
        if (excelCellStyleDto.getHorizontal() != null) {
            cellStyle.setAlignment(excelCellStyleDto.getHorizontal());
        }
        //垂直居中
        if (excelCellStyleDto.getVertical() != null) {
            cellStyle.setVerticalAlignment(excelCellStyleDto.getVertical());
        }
        //背景颜色
        if (excelCellStyleDto.getTextBack() != null) {
            cellStyle.setFillForegroundColor(excelCellStyleDto.getTextBack().getIndex());
        }

        //文字的设置字体颜色
        Font font = wb.createFont();
        if (excelCellStyleDto.getTextColor() != null) {
            font.setColor(excelCellStyleDto.getTextColor().getIndex());
        }

        font.setBold(excelCellStyleDto.isBoldFont());
        font.setFontHeightInPoints(excelCellStyleDto.getTextSize() != 0 ? excelCellStyleDto.getTextSize() : 12);
        cellStyle.setFont(font);

        if (excelCellStyleDto.getBorderStyle() != null) {
            cellStyle.setBorderTop(excelCellStyleDto.getBorderStyle());
            cellStyle.setBorderBottom(excelCellStyleDto.getBorderStyle());
            cellStyle.setBorderLeft(excelCellStyleDto.getBorderStyle());
            cellStyle.setBorderRight(excelCellStyleDto.getBorderStyle());
        }

        //设置为文本格式
        cellStyle.setDataFormat(BuiltinFormats.getBuiltinFormat(excelCellStyleDto.getTextType() != null ? excelCellStyleDto.getTextType() : "TEXT"));

        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        return cellStyle;
    }

完整的代码如下:

java 复制代码
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

public class ExcelComplexCreateUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(ExcelComplexCreateUtil.class);

    /**
     * 导出excel数据
     *
     * @param response 亲求返回
     * @param list     每个sheet页的数据,一个elist表示一个sheet页
     * @param fileName 导出的名称
     * @return 结果
     */
    public boolean creatExcel(HttpServletResponse response, List<ExcelSheetComplexVo> list, String fileName) {
        SXSSFWorkbook wb = creatBook(list);
        //导出数据
        try {
            //设置Http响应头告诉浏览器下载这个附件
            response.reset();
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/vnd.ms-excel");
            //名称要从新进行 ISO8859-1 编码否则会文件名称会乱码
            response.setHeader("Content-Disposition", "attachment;Filename=" + encodeFileName(fileName) + ".xlsx");
            OutputStream outputStream = response.getOutputStream();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            wb.write(baos);
            outputStream.write(baos.toByteArray());
            baos.flush();
            baos.close();
            outputStream.close();
        } catch (Exception ex) {
            LOGGER.error("导出excel失败", ex);
        }
        return true;
    }

    private SXSSFWorkbook creatBook(List<ExcelSheetComplexVo> list) {
        //创建工作簿
        SXSSFWorkbook wb = new SXSSFWorkbook();
        for (ExcelSheetComplexVo excelSheetComplexVo : list) {
            createSXSSFSheet(excelSheetComplexVo, wb);
        }
        return wb;
    }

    private SXSSFSheet createSXSSFSheet(ExcelSheetComplexVo excelSheetComplexVo, SXSSFWorkbook wb) {
        //创建工作簿
        SXSSFSheet sxssfSheet = wb.createSheet(excelSheetComplexVo.getSheetName());
        //设置默认的行宽
        sxssfSheet.setDefaultColumnWidth(20);
        //设置morning的行高(不能设置太小,可以不设置)
        sxssfSheet.setDefaultRowHeight((short) 300);
        //初始化标题栏
        initTitle(wb, sxssfSheet, excelSheetComplexVo.getDataClass());
        initSheetData(wb, sxssfSheet, excelSheetComplexVo, 1);

        return sxssfSheet;
    }

    /**
     * 生成每一个sheet数据
     * @param wb 问价实体
     * @param sxssfSheet 每个sheet
     * @param excelSheetComplexVo 每个sheet的数据定义
     * @param dataStartLine 起始行数据
     */
    private void initSheetData(SXSSFWorkbook wb, SXSSFSheet sxssfSheet, ExcelSheetComplexVo excelSheetComplexVo, int dataStartLine) {
        if (CollectionUtils.isEmpty(excelSheetComplexVo.getSheetData())) {
            return;
        }
        try {
            for (ExcelComplexVo excelComplexVo : excelSheetComplexVo.getSheetData()) {

                if (CollectionUtils.isNotEmpty(excelComplexVo.getOrderExcelMergeVos())) {
                    //是否有合并的行数据
                    dataStartLine = createMergeRow(wb, sxssfSheet, excelComplexVo.getOrderExcelMergeVos(), dataStartLine);
                }

                for (Object dataObject : excelComplexVo.getSubData()) {
                    SXSSFRow row = sxssfSheet.createRow(dataStartLine);
                    //获取所有有效字段,并排序
                    Field[] fields = dataObject.getClass().getDeclaredFields();
                    List<Field> fieldList = Arrays.stream(fields)
                            .filter(item -> item.getAnnotation(ExcelTitle.class) != null && !item.getAnnotation(ExcelTitle.class).ignore())
                            .sorted(Comparator.comparingInt(item -> {
                                ExcelTitle excelTitle = item.getAnnotation(ExcelTitle.class);
                                return excelTitle.order();
                            })).collect(Collectors.toList());

                    for (int i = 0; i < fieldList.size(); i++) {
                        Field field = fieldList.get(i);
                        //根据title的值对应的值
                        SXSSFCell cell = row.createCell(i);
                        cell.setCellStyle(initCellStyle(wb, field));
                        field.setAccessible(true);
                        cell.setCellValue(dealValue(field, dataObject));
                    }
                    dataStartLine++;
                }
            }
        } catch (Exception e) {
            LOGGER.error("生成数据异常", e);
        }
    }

    /**
     * 解析并设置合并的单元格
     * @param wb 问价实体
     * @param sxssfSheet sheet实体
     * @param orderExcelMergeVos 需要设置的合并单元格定义
     * @param dataStartLine 合并单元格的开始设置的起始行
     * @return 后面数据的起始设置行
     */
    private int createMergeRow(SXSSFWorkbook wb, SXSSFSheet sxssfSheet, List<ExcelMergeVo> orderExcelMergeVos, int dataStartLine) {
        if (CollectionUtils.isEmpty(orderExcelMergeVos)) {
            return dataStartLine;
        }

        int maxCellRowSize = 0;
        int index = 0;

        //创建合并行数据
        SXSSFRow row = sxssfSheet.createRow(dataStartLine);

        for (ExcelMergeVo excelMergeVo : orderExcelMergeVos) {

            if (maxCellRowSize < excelMergeVo.getCellHorizontalSize()) {
                maxCellRowSize = excelMergeVo.getCellHorizontalSize();
            }

            //计算需要合并的单元格信息
            int endRowIndex = dataStartLine + excelMergeVo.getCellVerticalSize();
            int cellIndex = index + excelMergeVo.getCellHorizontalSize();

            CellRangeAddress cellRangeAddress = new CellRangeAddress(dataStartLine, endRowIndex - 1, index, cellIndex - 1);
            sxssfSheet.addMergedRegion(cellRangeAddress);

            CellStyle cellStyle = initCellStyle(wb, excelMergeVo.getExcelCellStyleDto());
            SXSSFCell cell1 = row.createCell(index);
            cell1.setCellStyle(cellStyle);
            cell1.setCellValue(excelMergeVo.getValue());

            index = cellIndex;
        }
        return dataStartLine + maxCellRowSize;
    }

    private void initTitle(SXSSFWorkbook wb, SXSSFSheet sxssfSheet, Class dataClass) {
        //在第0行 设置标题
        SXSSFRow sxssfRow = sxssfSheet.createRow(0);

        Field[] fields = dataClass.getDeclaredFields();

        List<Field> fieldList = Arrays.stream(fields)
                .filter(item -> item.getAnnotation(ExcelTitle.class) != null && !item.getAnnotation(ExcelTitle.class).ignore())
                .sorted(Comparator.comparingInt(item -> {
                    ExcelTitle excelTitle = item.getAnnotation(ExcelTitle.class);
                    return excelTitle.order();
                })).collect(Collectors.toList());

        //设置每列的标题数据
        int i = 0;
        for (Field item : fieldList) {
            //设置列的默认格式为 String
            sxssfSheet.setDefaultColumnStyle(i, initDefaultCellStyle(wb));
            //设置单元格 和单元格的内容格式 - string
            SXSSFCell sxssfCell = sxssfRow.createCell(i, CellType.STRING);

            ExcelTitle excelTitle = item.getAnnotation(ExcelTitle.class);
            sxssfCell.setCellValue(StringUtils.isEmpty(excelTitle.titleName()) ? item.getName() : excelTitle.titleName());
            //设置默认的行格式
            CellStyle titleStyle = initTitleCellStyle(wb, item);
            sxssfCell.setCellStyle(titleStyle);
            i++;
        }
    }

    private CellStyle initCellStyle(SXSSFWorkbook wb, Field titleField) {
        // 单元格样式(垂直居中)
        XSSFCellStyle cellStyle = (XSSFCellStyle) wb.createCellStyle();

        ExcelProperty excelProperty = titleField.getAnnotation(ExcelProperty.class);

        //水平居中
        if (excelProperty != null && excelProperty.horizontal() != null) {
            cellStyle.setAlignment(excelProperty.horizontal());
        }
        //垂直居中
        if (excelProperty != null && excelProperty.vertical() != null) {
            cellStyle.setVerticalAlignment(excelProperty.vertical());
        }
        //背景颜色
        if (excelProperty != null && excelProperty.textBack() != null) {
            cellStyle.setFillForegroundColor(excelProperty.textBack().getIndex());
        }

        //文字的设置字体颜色
        Font font = wb.createFont();
        if (excelProperty != null && excelProperty.textColor() != null) {
            font.setColor(excelProperty.textColor().getIndex());
        }

        font.setBold(excelProperty != null && excelProperty.boldFont());
        font.setFontHeightInPoints(excelProperty != null && excelProperty.textSize() != 0 ? excelProperty.textSize() : 12);
        cellStyle.setFont(font);

        cellStyle.setBorderTop(BorderStyle.THIN);
        cellStyle.setBorderBottom(BorderStyle.THIN);
        cellStyle.setBorderLeft(BorderStyle.THIN);
        cellStyle.setBorderRight(BorderStyle.THIN);

        //设置为文本格式
        cellStyle.setDataFormat(wb.createDataFormat().getFormat(excelProperty != null && excelProperty.textType() != null ? excelProperty.textType() : "TEXT"));

        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        return cellStyle;
    }

    /**
     * 设置合并行的单元格格式
     * @param wb 文件实体
     * @param excelCellStyleDto 样式定义
     * @return 单元格样式
     */
    private CellStyle initCellStyle(SXSSFWorkbook wb, ExcelCellStyleDto excelCellStyleDto) {
        // 单元格样式(垂直居中)
        XSSFCellStyle cellStyle = (XSSFCellStyle) wb.createCellStyle();


        //水平居中
        if (excelCellStyleDto.getHorizontal() != null) {
            cellStyle.setAlignment(excelCellStyleDto.getHorizontal());
        }
        //垂直居中
        if (excelCellStyleDto.getVertical() != null) {
            cellStyle.setVerticalAlignment(excelCellStyleDto.getVertical());
        }
        //背景颜色
        if (excelCellStyleDto.getTextBack() != null) {
            cellStyle.setFillForegroundColor(excelCellStyleDto.getTextBack().getIndex());
        }

        //文字的设置字体颜色
        Font font = wb.createFont();
        if (excelCellStyleDto.getTextColor() != null) {
            font.setColor(excelCellStyleDto.getTextColor().getIndex());
        }

        font.setBold(excelCellStyleDto.isBoldFont());
        font.setFontHeightInPoints(excelCellStyleDto.getTextSize() != 0 ? excelCellStyleDto.getTextSize() : 12);
        cellStyle.setFont(font);

        if (excelCellStyleDto.getBorderStyle() != null) {
            cellStyle.setBorderTop(excelCellStyleDto.getBorderStyle());
            cellStyle.setBorderBottom(excelCellStyleDto.getBorderStyle());
            cellStyle.setBorderLeft(excelCellStyleDto.getBorderStyle());
            cellStyle.setBorderRight(excelCellStyleDto.getBorderStyle());
        }

        //设置为文本格式
        cellStyle.setDataFormat(BuiltinFormats.getBuiltinFormat(excelCellStyleDto.getTextType() != null ? excelCellStyleDto.getTextType() : "TEXT"));

        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        return cellStyle;
    }

    private CellStyle initTitleCellStyle(SXSSFWorkbook wb, Field titleField) {
        // 单元格样式
        XSSFCellStyle cellStyle = (XSSFCellStyle) wb.createCellStyle();
        //水平居中
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        //垂直居中
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);

        ExcelTitle excelTitle = titleField.getAnnotation(ExcelTitle.class);

        //背景颜色
        if (excelTitle != null && excelTitle.titleBack() != null) {
            cellStyle.setFillForegroundColor(excelTitle.titleBack().getIndex());
        } else {
            cellStyle.setFillForegroundColor(IndexedColors.WHITE1.getIndex());
        }

        //文字的设置字体颜色
        Font font = wb.createFont();
        if (excelTitle != null && excelTitle.titleColor() != null) {
            font.setColor(excelTitle.titleColor().getIndex());
        } else {
            font.setColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());
        }
        font.setBold(excelTitle != null && excelTitle.boldFont());
        font.setFontHeightInPoints(excelTitle != null && excelTitle.titleSize() != 0 ? excelTitle.titleSize() : 12);
        cellStyle.setFont(font);

        //设置为文本格式
        cellStyle.setDataFormat(BuiltinFormats.getBuiltinFormat("TEXT"));

        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

        //边框
        if (excelTitle != null && excelTitle.borderStyle() != null) {
            cellStyle.setBorderTop(excelTitle.borderStyle());
            cellStyle.setBorderBottom(excelTitle.borderStyle());
            cellStyle.setBorderLeft(excelTitle.borderStyle());
            cellStyle.setBorderRight(excelTitle.borderStyle());
        } else {
            cellStyle.setBorderTop(BorderStyle.THIN);
            cellStyle.setBorderBottom(BorderStyle.THIN);
            cellStyle.setBorderLeft(BorderStyle.THIN);
            cellStyle.setBorderRight(BorderStyle.THIN);
        }

        //边框
        if (excelTitle != null && excelTitle.borderColor() != null) {
            cellStyle.setTopBorderColor(excelTitle.borderColor().getIndex());
            cellStyle.setBottomBorderColor(excelTitle.borderColor().getIndex());
            cellStyle.setLeftBorderColor(excelTitle.borderColor().getIndex());
            cellStyle.setRightBorderColor(excelTitle.borderColor().getIndex());
        } else {
            cellStyle.setTopBorderColor(IndexedColors.RED.getIndex());
            cellStyle.setBottomBorderColor(IndexedColors.RED.getIndex());
            cellStyle.setLeftBorderColor(IndexedColors.RED.getIndex());
            cellStyle.setRightBorderColor(IndexedColors.RED.getIndex());
        }

        return cellStyle;
    }

    private CellStyle initDefaultCellStyle(SXSSFWorkbook wb) {
        // 单元格样式(垂直居中)
        XSSFCellStyle cellStyle = (XSSFCellStyle) wb.createCellStyle();
        //水平居中
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        //垂直居中
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);

        cellStyle.setBorderTop(BorderStyle.THIN);
        cellStyle.setBorderBottom(BorderStyle.THIN);
        cellStyle.setBorderLeft(BorderStyle.THIN);
        cellStyle.setBorderRight(BorderStyle.THIN);

        //文字的设置
        Font font = wb.createFont();
        font.setColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());   //设置字体颜色
        cellStyle.setFont(font);
        return cellStyle;
    }

    /**
     * 处理数据
     *
     * @param field      字段属性
     * @param dataObject 数据对象
     * @return 具体的属性值
     */
    private String dealValue(Field field, Object dataObject) throws IllegalAccessException {
        ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);

        Object value = field.get(dataObject);
        if (value == null) {
            return null;
        }
        if (excelProperty != null && StringUtils.isNotEmpty(excelProperty.textKv())) {
            String[] kvs = excelProperty.textKv().split(";");

            Map<String, String> map = new HashMap<>();
            for (String str : kvs) {
                map.put(str.split("=")[0], str.split("=")[1]);
            }
            return map.get(value.toString());
        }
        return value.toString();
    }

    private String encodeFileName(String fileName) {
        try {
            //fileName = java.net.URLEncoder.encode(fileName, "UTF-8");
            fileName = URLDecoder.decode(fileName, "UTF-8");
            return new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
        } catch (UnsupportedEncodingException e) {
            return "未命名";
        }
    }
}

导出测试

java 复制代码
@RestController
@RequestMapping(value = "exceExport")
public class ExcelExportController {

    @GetMapping("testComplexExport")
    public void testComplexExport(HttpServletResponse response){

        String fileName = "测试sheet";
        List<ExcelSheetComplexVo> sheetVoList = new ArrayList<>();

        for(int i = 0; i < 3; i++){
            sheetVoList.add(createComplexSheetData(i));
        }

        new ExcelComplexCreateUtil().creatExcel(response, sheetVoList, fileName);
    }

    private List<TestExcelVo> createTestExcelVo(int size, String sheetName){

        List<TestExcelVo> testExcelVos = new ArrayList<>();
        for(int i = 0; i < size; i++){
            TestExcelVo testExcelVo = new TestExcelVo();
            testExcelVo.setName(sheetName + "-" + i);
            testExcelVo.setAge(i);
            testExcelVo.setSex(i % 2);
            testExcelVo.setDes("哈哈哈哈哈" + i);
            testExcelVos.add(testExcelVo);
        }
        return testExcelVos;
    }


    private ExcelSheetComplexVo createComplexSheetData(int index){
        ExcelSheetComplexVo excelSheetVo = new ExcelSheetComplexVo();
        excelSheetVo.setDataClass(TestExcelVo.class);
        excelSheetVo.setSheetName("sheet" + index);

        List<ExcelComplexVo> excelComplexVos = createTestComplexExcelVo(5, "sheet" + index);
        excelSheetVo.setSheetData(excelComplexVos);
        return excelSheetVo;
    }


    private List<ExcelComplexVo> createTestComplexExcelVo(int size, String sheetName){

        List<ExcelComplexVo> excelComplexVos = new ArrayList<>();
        for(int i = 0; i < size; i++){
            ExcelComplexVo<TestExcelVo> excelComplexVo = new ExcelComplexVo<>();

            ExcelMergeVo excelMergeVo = new ExcelMergeVo();
            excelMergeVo.setExcelCellStyleDto(new ExcelCellStyleDto());
            excelMergeVo.setCellHorizontalSize(2);
            excelMergeVo.setCellVerticalSize(2);
            excelMergeVo.setValue(sheetName + "-合并单元格" + i + "-1");

            ExcelMergeVo excelMergeVo2 = new ExcelMergeVo();
            excelMergeVo2.setExcelCellStyleDto(new ExcelCellStyleDto());
            excelMergeVo2.setCellHorizontalSize(2);
            excelMergeVo2.setCellVerticalSize(2);
            excelMergeVo2.setValue(sheetName + "-合并单元格-" + i + "-2");

            excelComplexVo.setOrderExcelMergeVos(Lists.newArrayList(excelMergeVo, excelMergeVo2));

            List<TestExcelVo> testExcelVos = createTestExcelVo(new Random().nextInt(5) + 5, "sheet" + i);
            excelComplexVo.setSubData(testExcelVos);

            excelComplexVos.add(excelComplexVo);

        }
        return excelComplexVos;
    }

}

测试得到的结果如下:

相关推荐
qq_327342734 分钟前
Java实现离线身份证号码OCR识别
java·开发语言
阿龟在奔跑1 小时前
引用类型的局部变量线程安全问题分析——以多线程对方法局部变量List类型对象实例的add、remove操作为例
java·jvm·安全·list
飞滕人生TYF1 小时前
m个数 生成n个数的所有组合 详解
java·递归
代码小鑫2 小时前
A043-基于Spring Boot的秒杀系统设计与实现
java·开发语言·数据库·spring boot·后端·spring·毕业设计
真心喜欢你吖2 小时前
SpringBoot与MongoDB深度整合及应用案例
java·spring boot·后端·mongodb·spring
激流丶2 小时前
【Kafka 实战】Kafka 如何保证消息的顺序性?
java·后端·kafka
开心点幸运点2 小时前
Excel——宏教程(1)
excel
周全全2 小时前
Spring Boot + Vue 基于 RSA 的用户身份认证加密机制实现
java·vue.js·spring boot·安全·php
uzong3 小时前
一个 IDEA 老鸟的 DEBUG 私货之多线程调试
java·后端
AiFlutter3 小时前
Java实现简单的搜索引擎
java·搜索引擎·mybatis