SpringBoot 整合poi 将JavaBean对象导出excel

说明:本人第一篇文章,希望各位多指教批评,同时希望该文章能够给各位读者带来帮助

运行环境

SpringBoot + maven + jdk1.8

1、配置maven依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.17</version>
        </dependency>

2、自定义注解用于自动标识需要导出的列

/**
 * @author goujj
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelResources {
    /**
     * 标题
     *
     * @return
     */
    String title();

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

3、poi 导出的格式xls、xlsx后缀,本文主要介绍使用HSSFWorkbook导出xls格式excel

import com.scty.pps.pps.aop.ExcelResources;
import com.scty.pps.pps.dto.ExportDataDTO;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static java.util.stream.Collectors.toList;
/**
 * @author goujj
 * 导出excel文件
 */
public class ExportExcelUtil {
    /**
     * 导出数据处理
     *
     * @param exportDataDTO
     * @param out
     */
    public static void exportDeal(ExportDataDTO exportDataDTO, OutputStream out, Class<?> cls) throws IOException {
        HSSFWorkbook hssfWorkbook = new HSSFWorkbook();
        try {
            if (exportDataDTO.getSheetName() == null) {
                exportDataDTO.setSheetName("sheet1");
            }
            HSSFSheet hssfSheet = hssfWorkbook.createSheet(exportDataDTO.getSheetName());
            writeWorkBook(hssfWorkbook, hssfSheet, exportDataDTO, cls);
            hssfWorkbook.write(out);
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            hssfWorkbook.close();
        }
    }

    /**
     * 数据写入到workbook
     */
    private static void writeWorkBook(HSSFWorkbook hssfWorkbook, HSSFSheet hssfSheet, ExportDataDTO exportDataDTO, Class<?> cls) {
        int rowIndex = 0;
        //------统计有多少列需要导出
        int count = 0;
        Field[] field = cls.getDeclaredFields();
        Map<Integer, Object[]> res = new ConcurrentHashMap<>();
        List<Map<Integer, Object[]>> collection = new ArrayList<>();
        for (Field fie : field) {
            if (fie.isAnnotationPresent(ExcelResources.class)) {
                ExcelResources resources = fie.getAnnotation(ExcelResources.class);
                if (!res.containsKey(resources.order())) {
                    res.put(resources.order(), new Object[]{resources, fie});
                    count++;
                }
            }
        }
        if (res.size() > 0) {
            //设置数据第一行标题并且居中
            createTitle(hssfWorkbook, hssfSheet, count, exportDataDTO);
            rowIndex++;
            //设置导出的每列标题
            collection.add(res);
            Map<Integer, Object[]> dealSort = new ConcurrentHashMap<>();
            //对res根据key的大小排序,dataList为Filed排序之后的结果
            res.entrySet().stream().sorted(Map.Entry.<Integer, Object[]>comparingByKey().reversed()).forEach(e -> dealSort.put(e.getKey(), e.getValue()));
            List<Object[]> dataList = dealSort.entrySet().stream().map(e -> e.getValue()).collect(toList());
            //导出属性列名对应的字段
            List<String> heads = new ArrayList<>();
            //------获取每列的列名
            HSSFRow row = hssfSheet.createRow(rowIndex);
            rowIndex++;
            int colIndex = 0;
            for (Object[] obj : dataList) {
                ExcelResources resources = (ExcelResources) obj[0];
                HSSFCell cell = row.createCell(colIndex);
                cell.setCellValue(resources.title());
                HSSFCellStyle hssfCellStyle = hssfWorkbook.createCellStyle();
                cell.setCellStyle(hssfCellStyle);
                Field file = (Field) obj[1];
                heads.add(file.getName());
                colIndex++;
            }
            //-----设置每行的值并根据注解排序
            Map<String, Map<Integer, String>> result = new ConcurrentHashMap<>(heads.size());
            orderBy(heads, exportDataDTO, result);
            for (int i = 0; i < exportDataDTO.getDataList().size(); i++) {
                int zdCell = 0;
                HSSFRow ro = hssfSheet.createRow(rowIndex);
                rowIndex++;
                for (String head : heads) {
                    //写进excel对象
                    ro.createCell((short) zdCell).setCellValue(result.get(head).get(i));
                    zdCell++;
                }
            }
        }
    }

    /**
     * 创建第一行数据标题
     *
     * @param hssfWorkbook
     * @param hssfSheet
     * @param mergeCount    统计合并列的结束位置
     * @param exportDataDTO 获取第一行数据的标题
     */
    public static void createTitle(HSSFWorkbook hssfWorkbook, HSSFSheet hssfSheet, int mergeCount, ExportDataDTO exportDataDTO) {
        Font font = hssfWorkbook.createFont();
        font.setFontName("Arial");
        font.setColor(IndexedColors.BLACK.index);
        font.setBold(true);
        HSSFCellStyle titleStyle = hssfWorkbook.createCellStyle();
        titleStyle.setAlignment(HorizontalAlignment.CENTER);
        setStyle(titleStyle, font);
        HSSFRow row = hssfSheet.createRow(0);
        HSSFCell cell = row.createCell(0);
        cell.setCellValue(exportDataDTO.getTitle());
        CellRangeAddress rangeAddress = new CellRangeAddress(0, 0, 0, mergeCount - 1);
        hssfSheet.addMergedRegion(rangeAddress);
        cell.setCellStyle(titleStyle);
        cell.setCellValue(exportDataDTO.getTitle());
    }


    /**
     * 排序
     *
     * @param
     * @param heads         列属性
     * @param exportDataDTO
     * @param result        排序结果
     */
    private static void orderBy(List<String> heads, ExportDataDTO exportDataDTO, Map<String, Map<Integer, String>> result) {
        for (String str : heads) {
            result.put(str, new HashMap<>());
        }
        Integer num = 0;
        for (Object t : exportDataDTO.getDataList()) {
            Field[] fields = t.getClass().getDeclaredFields();
            for (Field field : fields) {
                String propertyName = field.getName();
                if (heads.contains(propertyName)) {
                    //获取value值
                    String methodName = "get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
                    Class cl = t.getClass();
                    try {
                        Method getMethod = cl.getMethod(methodName,
                                new Class[]{});
                        //操控该对象属性的get方法,从而拿到属性值
                        Object val = getMethod.invoke(t, new Object[]{});
                        if (val != null) {
                            //转化成String
                            result.get(propertyName).put(num, String.valueOf(val));
                        } else {
                            result.get(propertyName).put(num, null);
                        }
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }
            num++;
        }
    }

    /**
     * 指定单元格的样式
     */
    private static void setStyle(HSSFCellStyle titleStyle, Font font) {
        titleStyle.setAlignment(HorizontalAlignment.CENTER);
        titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        titleStyle.setBorderLeft(BorderStyle.DOTTED);
        titleStyle.setBorderTop(BorderStyle.DOTTED);
        titleStyle.setBorderRight(BorderStyle.DOTTED);
        titleStyle.setBorderBottom(BorderStyle.DOTTED);
        titleStyle.setWrapText(true);
        titleStyle.setFont(font);
    }
}

4、测试方法

public static void main(String[] args) {
        try {
            ExportDataDTO exportDataDTO = new ExportDataDTO();
            exportDataDTO.setSheetName("测试1");
            exportDataDTO.setFileName("导出1");
            exportDataDTO.setTitle("测试");
            List<JiaofeiDTO> jiaofeiDTOS = new ArrayList<>();
            for (int i = 0; i < 100; i++) {
                JiaofeiDTO jiaofeiDTO = new JiaofeiDTO();
                jiaofeiDTO.setStudentId(i + 1L);
                jiaofeiDTO.setCostAll(i + 0.1);
                jiaofeiDTO.setCostType(0);
                jiaofeiDTOS.add(jiaofeiDTO);
            }
            exportDataDTO.setDataList(jiaofeiDTOS);
            FileOutputStream exportXls = new FileOutputStream(new StringBuffer("D://" + exportDataDTO.getFileName() + ".xls").toString());
            exportDeal(exportDataDTO, exportXls, JiaofeiDTO.class);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

poi 相关知识请参考官方文档

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,888评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,677评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,386评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,726评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,729评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,337评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,902评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,807评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,349评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,439评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,567评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,242评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,933评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,420评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,531评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,995评论 3 377
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,585评论 2 359

推荐阅读更多精彩内容