Springboot+easyPoi 动态/多级表头导出

需求

根据前端传递的动态表头, 导出多级Excel

easyPoi依赖

    <dependency>
        <groupId>cn.afterturn</groupId>
        <artifactId>easypoi-spring-boot-starter</artifactId>
        <version>4.1.2</version>
    </dependency>

定义样式工具类

import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.afterturn.easypoi.excel.entity.params.ExcelForEachParams;
import cn.afterturn.easypoi.excel.export.styler.IExcelExportStyler;
import org.apache.poi.ss.usermodel.*;

/**
 * @author zbc
 * @Description easypoi导出样式工具类
 */
public class ExcelStyleUtil implements IExcelExportStyler {
    private static final short STRING_FORMAT = (short) BuiltinFormats.getBuiltinFormat("TEXT");
    private static final short FONT_SIZE_TEN = 9;
    private static final short FONT_SIZE_ELEVEN = 10;
    private static final short FONT_SIZE_TWELVE = 10;
    /**
     * 大标题样式
     */
    private CellStyle headerStyle;
    /**
     * 每列标题样式
     */
    private CellStyle titleStyle;
    /**
     * 数据行样式
     */
    private CellStyle styles;

    public ExcelStyleUtil(Workbook workbook) {
        this.init(workbook);
    }

    /**
     * 初始化样式
     *
     * @param workbook
     */
    private void init(Workbook workbook) {
        this.headerStyle = initHeaderStyle(workbook);
        this.titleStyle = initTitleStyle(workbook);
        this.styles = initStyles(workbook);
    }

    /**
     * 大标题样式
     *
     * @param color
     * @return
     */
    @Override
    public CellStyle getHeaderStyle(short color) {
        return headerStyle;
    }

    /**
     * 每列标题样式
     *
     * @param color
     * @return
     */
    @Override
    public CellStyle getTitleStyle(short color) {
        return titleStyle;
    }

    /**
     * 数据行样式
     *
     * @param parity 可以用来表示奇偶行
     * @param entity 数据内容
     * @return 样式
     */
    @Override
    public CellStyle getStyles(boolean parity, ExcelExportEntity entity) {
        return styles;
    }

    /**
     * 获取样式方法
     *
     * @param dataRow 数据行
     * @param obj     对象
     * @param data    数据
     */
    @Override
    public CellStyle getStyles(Cell cell, int dataRow, ExcelExportEntity entity, Object obj, Object data) {
        return getStyles(true, entity);
    }

    /**
     * 模板使用的样式设置
     */
    @Override
    public CellStyle getTemplateStyles(boolean isSingle, ExcelForEachParams excelForEachParams) {
        return null;
    }

    /**
     * 初始化--大标题样式
     *
     * @param workbook
     * @return
     */
    private CellStyle initHeaderStyle(Workbook workbook) {
        CellStyle style = getBaseCellStyle(workbook);
        style.setFont(getFont(workbook, FONT_SIZE_TWELVE, true));
        return style;
    }

    /**
     * 初始化--每列标题样式
     *
     * @param workbook
     * @return
     */
    private CellStyle initTitleStyle(Workbook workbook) {
        CellStyle style = getBaseCellStyle(workbook);
        style.setFont(getFont(workbook, FONT_SIZE_ELEVEN, false));
        //背景色
        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        return style;
    }

    /**
     * 初始化--数据行样式
     *
     * @param workbook
     * @return
     */
    private CellStyle initStyles(Workbook workbook) {
        CellStyle style = getBaseCellStyle(workbook);
        style.setFont(getFont(workbook, FONT_SIZE_TEN, false));
        style.setDataFormat(STRING_FORMAT);
        return style;
    }

    /**
     * 基础样式
     *
     * @return
     */
    private CellStyle getBaseCellStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        //下边框
        style.setBorderBottom(BorderStyle.THIN);
        //左边框
        style.setBorderLeft(BorderStyle.THIN);
        //上边框
        style.setBorderTop(BorderStyle.THIN);
        //右边框
        style.setBorderRight(BorderStyle.THIN);
        //水平居中
        style.setAlignment(HorizontalAlignment.CENTER);
        //上下居中
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        //设置自动换行
        style.setWrapText(true);
        return style;
    }

    /**
     * 字体样式
     *
     * @param size   字体大小
     * @param isBold 是否加粗
     * @return
     */
    private Font getFont(Workbook workbook, short size, boolean isBold) {
        Font font = workbook.createFont();
        //字体样式
        font.setFontName("宋体");
        //是否加粗
        font.setBold(isBold);
        //字体大小
        font.setFontHeightInPoints(size);
        return font;
    }
}

核心代码

private void export(List<JSONObject> jsonObjectList, MonthlyRatingDTO monthlyRatingDTO, HttpServletResponse response) {
        // jsonObjectList为查询出的动态数据集, monthlyRatingDTO为入参
        // 定义一级表头key集合
        Map<String, Object> keyMap = new HashMap<>();
        // 处理表头
        List<ExcelExportEntity> headerList = new ArrayList<>();
        // 前端传递的动态表头
        String dynamicHeader = monthlyRatingDTO.getDynamicHeader();
        List<JSONObject> lists = JSONObject.parseArray(dynamicHeader, JSONObject.class);
        lists.forEach(LambdaUtils.consumerWithIndex((jsonObj, index) -> {
            String label = jsonObj.get("label").toString();
            if(null != jsonObj.get("prop")) {
                String prop = jsonObj.get("prop").toString();
                ExcelExportEntity excelExportEntity = new ExcelExportEntity(label, prop);
                headerList.add(excelExportEntity);
            } else {
                ExcelExportEntity excelExportEntity = new ExcelExportEntity(label, label); // 此处第二个label对应子集数据key
                List<ExcelExportEntity> excelExportEntityList = new ArrayList<>();
                String children = jsonObj.getString("children");
                JSONArray childrenList = JSONArray.parseArray(children);
                keyMap.put(label, childrenList);
                childrenList.forEach(o -> {
                    JSONObject c = (JSONObject)o;
                    String sonLabel = c.getString("label");
                    String sonProp = c.getString("prop");
                    ExcelExportEntity son = new ExcelExportEntity(sonLabel, sonProp);
                    excelExportEntityList.add(son);
                });
                excelExportEntity.setList(excelExportEntityList);
                headerList.add(excelExportEntity);
            }
        }));
        // 处理数据
        List<Map<String, Object>> dataList = new ArrayList<>();
        for(JSONObject o : jsonObjectList) {
            Map<String, Object> maps = new HashMap<>();

            maps.put("name", o.getString("name"));
            maps.put("customerServiceNo", o.getString("customerServiceNo"));
            maps.put("type", "0".equals(o.getString("type")) ? "语音" : "IM");
            maps.put("callNum", o.getString("callNum"));
            maps.put("autoNum", o.getString("autoNum"));
            maps.put("checkNum", o.getString("checkNum"));

            if(ObjectUtil.isNotEmpty(keyMap)) {
                // 储存表格中的每一行数据
                List<Map<String, Object>> childrenList = null;
                for(Map.Entry<String, Object> entry : keyMap.entrySet()) {
                    String children = entry.getValue().toString();
                    if(StringUtil.isNotBlank(children)) {
                        JSONArray childrens = JSONArray.parseArray(children);
                        childrenList = new ArrayList<>();
                        Map<String, Object> map = new HashMap<>();
                        childrens.forEach(x -> {
                            JSONObject c = (JSONObject)x;
                            String sonProp = c.get("prop").toString();
                            if(null != o.get(sonProp)) {
                                map.put(sonProp, o.get(sonProp).toString());
                            }
                        });
                        childrenList.add(map);
                        maps.put(entry.getKey(), childrenList);
                    }
                }
            }
            maps.put("autoTotalScore", o.getString("autoTotalScore"));
            maps.put("finalTotalScore", o.getString("finalTotalScore"));
            maps.put("deductPoints", o.getString("deductPoints"));
            maps.put("averageScore", o.getString("averageScore"));
            dataList.add(maps);
        }
        String fileName = "导出文件名称";
        try {
            String headerMeassge = "选择月份: " + monthlyRatingDTO.getYearAndMonth() + "   " + "质检方案: " + schemeName;
            ExportParams params = new ExportParams(headerMeassge, fileName);
            params.setStyle(ExcelStyleUtil.class);
            Workbook workbook = ExcelExportUtil.exportExcel(params, headerList, dataList);
            // 获取文件导出日期
            String yyyyMmDdHhMmSs = DateUtil.format(DateUtil.now(), DateUtil.PATTERN_DATETIME_MINI);
            fileName += yyyyMmDdHhMmSs;

            response.setHeader("content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xls");
            response.setCharacterEncoding("UTF-8");
            ServletOutputStream outputStream = response.getOutputStream();
            workbook.write(outputStream);
            outputStream.flush();
            outputStream.close();
        } catch (Exception e) {
            log.error("导出异常", e);
        }
    }

导出效果

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

推荐阅读更多精彩内容