EasyExcel 批量导出

news2024/11/22 22:14:58

文章目录

  • 前言
  • 一、EasyExcel 导出封装
  • 二、食用步骤
    • 1.自定义excel样式
    • 2.导出数据
  • 三、复杂excel导出
    • 3.1. 自定义复杂表头
    • 2. 多sheet


前言

上篇写了数据导入,本文补充一下EasyExcel 批量导出
包括常规excel和复杂excel

一、EasyExcel 导出封装

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.handler.WriteHandler;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.google.common.base.Charsets;
import com.gsafety.bg.gsdss.common.contants.CommonConstants;
import com.gsafety.bg.gsdss.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;

/**
 * AbstractExcelView
 */
@Slf4j
public abstract class AbstractExcelView<T> {

    private String excelName;

    private ExcelTypeEnum excelType;

    private HttpServletResponse response;

    public AbstractExcelView(HttpServletResponse response, String excelName, ExcelTypeEnum excelType) {
        this.excelName = excelName;
        this.excelType = excelType;
        this.response = response;
    }

    protected OutputStream prepareResponse(HttpServletResponse response) throws Exception {
        response.setContentType(CommonConstants.CONTENT_TYPE_EXCEL);
        response.setCharacterEncoding(Charsets.UTF_8.name());
        response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(excelName, Charsets.UTF_8.name()) + excelType.getValue());
        return response.getOutputStream();
    }

    public void exportExcel() {
        ExcelWriter excelWriter = null;
        try {
            List<Sheet<T>> sheets = this.sheets();
            if (CollectionUtils.isEmpty(sheets)) {
                return;
            }
            excelWriter = EasyExcel.write(this.prepareResponse(response)).excelType(excelType).build();
            for (Sheet s : sheets) {
                ExcelWriterSheetBuilder sb = EasyExcel.writerSheet(s.getIndex(), s.getName()).head(s.getClz());
                if (CollectionUtils.isNotEmpty(s.getHandlers())) {
                    List<WriteHandler> l = s.getHandlers();
                    l.forEach(h -> sb.registerWriteHandler(h));
                }
                if (CollectionUtils.isNotEmpty(this.sheetDynamicHead(s.getIndex()))){
                    sb.head(this.sheetDynamicHead(s.getIndex()));
                }
                excelWriter.write(this.sheetData(s.getIndex()), sb.build());
            }
        } catch (Exception e) {
            log.error(" 导出失败! ", e);
            throw new BusinessException(" 导出失败! ");
        } finally {
            if (Objects.nonNull(excelWriter)) {
                excelWriter.finish();
            }
        }
    }

    public String asyncExport(ThreadPoolTaskExecutor executor) {
        AtomicReference<String> result = new AtomicReference<>(StringUtils.EMPTY);
        ExcelWriter excelWriter = null;
        try {
            List<Sheet<T>> sheets = this.sheets();
            if (CollectionUtils.isEmpty(sheets)) {
                return result.get();
            }
            excelWriter = EasyExcel.write(this.prepareResponse(response)).excelType(excelType).build();
            WriteSheet[] writeSheets = sheets.stream().map(sheet -> {
                ExcelWriterSheetBuilder sb = EasyExcel.writerSheet(sheet.getIndex(), sheet.getName())
                        .head(sheet.getClz());
                if (CollectionUtils.isNotEmpty(sheet.getHandlers())) {
                    List<WriteHandler> l = sheet.getHandlers();
                    l.forEach(h -> sb.registerWriteHandler(h));
                }
                if (CollectionUtils.isNotEmpty(this.sheetDynamicHead(sheet.getIndex()))){
                    sb.head(this.sheetDynamicHead(sheet.getIndex()));
                }
                return sb.build();
            }).toArray(WriteSheet[]::new);
            ExcelWriter finalExcelWriter = excelWriter;
            CompletableFuture[] cfs = sheets.stream()
                    .map(sheet -> CompletableFuture.runAsync(
                            () -> {
                                log.info(" 当前sheet {} {} ", sheet.getIndex(), sheet.getName());

                                log.info(" 当前sheet {} ", writeSheets[sheet.getIndex()]);
                                finalExcelWriter.write(this.sheetData(sheet.getIndex()), writeSheets[sheet.getIndex()]);
                            }, executor)
                                    .exceptionally((e) -> {
                                                result.set(sheet.getName() + " 导出失败 ");
                                                log.error(sheet.getName() + " 导出失败 ", e);
                                                return null;
                                            }
                                    )
                    ).toArray(CompletableFuture[]::new);

            CompletableFuture.allOf(cfs).join();
        } catch (Exception e) {
            log.error(" 导出失败! ", e);
            throw new BusinessException(" 导出失败! ");
        } finally {
            if (Objects.nonNull(excelWriter)) {
                excelWriter.finish();
            }
        }
        return result.get();
    }

    protected abstract List<Sheet<T>> sheets();

    protected abstract List<T> sheetData(int sheetIndex);

    protected List<List<String>> sheetDynamicHead(int sheetIndex){
        return null;
    }

}

二、食用步骤

1.自定义excel样式

import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import org.apache.poi.ss.usermodel.*;

/**
 * @description excel样式策略类
 */

public class ExcelCustomStyleStrategy {

    public static HorizontalCellStyleStrategy getSimpleStyle(){
        // 头的策略
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        // 设置对齐
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        // 背景色
        headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE1.getIndex());
        // 字体策略
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setBold(false);
        headWriteFont.setFontName("微软雅黑");
        headWriteFont.setFontHeightInPoints((short) 12);
        headWriteCellStyle.setWriteFont(headWriteFont);

        // 内容的策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
        // 背景色
        // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色。头默认了 FillPatternType所以可以不指定。
        contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
        //背景设置白色
        contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE1.getIndex());
        // 字体策略
        WriteFont contentWriteFont = new WriteFont();
        //contentWriteFont.setFontHeightInPoints((short) 12);
        contentWriteCellStyle.setWriteFont(contentWriteFont);
        //设置 自动换行
        contentWriteCellStyle.setWrapped(false);
        //设置 垂直居中
        contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        //设置 水平居中
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        //设置边框样式
        contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
        contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
        contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
        contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
        return horizontalCellStyleStrategy;
    }

}

2.导出数据

import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.google.common.collect.Lists;
import com.gsafety.bg.gsdss.common.excel.out.AbstractExcelView;
import com.gsafety.bg.gsdss.common.excel.out.Sheet;
import com.gsafety.bg.sv.controller.excel.strategy.ExcelCustomStyleStrategy;
import com.gsafety.bg.sv.model.dto.resp.AccidentEduExcelResp;

import javax.servlet.http.HttpServletResponse;
import java.util.List;

public class AccidentEduExcelView extends AbstractExcelView<AccidentEduExcelResp> {
	//导出数据list对象 对象属性用@ExcelProperty("事故名称")即可生成表头
    private final List<AccidentEduExcelResp> data;

    public AccidentEduExcelView(HttpServletResponse response, List<AccidentEduExcelResp> data, String excelName) {
        super(response, excelName, ExcelTypeEnum.XLSX);
        this.data = data;
    }
	
	//定义excel样式、sheet名称等
    @Override
    protected List<Sheet<AccidentEduExcelResp>> sheets() {
        return Lists.newArrayList(Sheet.<AccidentEduExcelResp>builder().name("事故警示教育")
                .handlers(Lists.newArrayList(ExcelCustomStyleStrategy.getSimpleStyle(), new SimpleColumnWidthStyleStrategy(30))).clz(AccidentEduExcelResp.class).build());
    }
	
	//指定sheet页
    @Override
    protected List<AccidentEduExcelResp> sheetData(int sheetIndex) {
        return data;
    }

}

    @ApiOperation(value = "列表导出")
    @PostMapping("/v1/list/export")
    public void downLoadList(@RequestBody AccidentEduQO req, HttpServletResponse response) {
    	//查询导出数据list 对象
        List<AccidentEduExcelResp> data = service.list(req);
        new AccidentEduExcelView(response,data,"事故警示教育").exportExcel();
    }

三、复杂excel导出

3.1. 自定义复杂表头

通过重写sheetDynamicHead方法自定义复杂表头
@ExcelProperty(order = 0)注解指定excel列即可填充到指定单元格
在这里插入图片描述

import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.google.common.collect.Lists;
import com.gsafety.bg.gsdss.common.excel.out.AbstractExcelView;
import com.gsafety.bg.gsdss.common.excel.out.Sheet;
import com.gsafety.bg.sv.controller.excel.strategy.ExcelCustomStyleStrategy;
import com.gsafety.bg.sv.model.dto.resp.AccidentEduSLResp;
import com.gsafety.bg.sv.model.dto.resp.AccidentEduStatisticResp;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

public class AccidentEduSExcelView extends AbstractExcelView<AccidentEduSLResp> {

    private AccidentEduStatisticResp data;

    private Integer total;

    public AccidentEduSExcelView(HttpServletResponse response, AccidentEduStatisticResp data, String excelName) {
        super(response, excelName, ExcelTypeEnum.XLSX);
        this.data = data;
        this.total = data.getTotal();
    }

    @Override
    protected List<Sheet<AccidentEduSLResp>> sheets() {
        return Lists.newArrayList(Sheet.<AccidentEduSLResp>builder().name("警示教育信息")
                .handlers(Lists.newArrayList(ExcelCustomStyleStrategy.getSimpleStyle(),new SimpleColumnWidthStyleStrategy(30))).clz(AccidentEduSLResp.class).build());
    }

    @Override
    protected List<AccidentEduSLResp> sheetData(int sheetIndex) {
        return data.getList();
    }
	
	//这里是动态表头,需要读取数据库计算数据数量做表头,所以中间走了一层,如果不是动态数据可直接返回sheetDynamicHead(Integer total)方法的内容
    @Override
    protected List<List<String>> sheetDynamicHead(int sheetIndex) {
        return sheetDynamicHead(this.total);
    }

    private List<List<String>> sheetDynamicHead(Integer total){
        List<List<String>> head = Lists.newArrayList();
        head.add(new ArrayList() {{
            add(" ");
            add(" ");
            add(" ");
        }});
        head.add(new ArrayList() {{
            add("参与执法持证人员数");
            add("参与执法持证人员数");
            add("参与执法持证人员数");
        }});
        head.add(new ArrayList() {{
            add("执法检查次数(次)");
            add("合计");
            add("合计");
        }});
        head.add(new ArrayList() {{
            add("执法检查次数(次)");
            add("检查");
            add("检查");
        }});
        head.add(new ArrayList() {{
            add("执法检查次数(次)");
            add("复查");
            add("复查");
        }});
        return head;
    }

}

2. 多sheet

protected List sheets() 方法内返回多个sheet
protected List sheetData(int sheetIndex)方法内指定sheet填充的数据

import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.google.common.collect.Lists;
import com.gsafety.bg.emis.base.utils.ExcelCustomStyleStrategy;
import com.gsafety.bg.emis.euip.model.resp.EuipExcelListResp;
import com.gsafety.bg.emis.fpln.model.dto.resp.UavInfoResp;
import com.gsafety.bg.gsdss.common.excel.out.AbstractExcelView;
import com.gsafety.bg.gsdss.common.excel.out.Sheet;

import javax.servlet.http.HttpServletResponse;
import java.util.List;

public class EuipExcelView extends AbstractExcelView {
    private final List<EuipExcelListResp> euip;
    private final List<UavInfoResp> uva;
    
    public EuipExcelView(HttpServletResponse response, List<EuipExcelListResp> euip, List<UavInfoResp> uav, String excelName) {
        super(response, excelName, ExcelTypeEnum.XLSX);
        this.euip = euip;
        this.uva = uav;
    }
    
    @Override
    protected List<Sheet> sheets() {
        return Lists.newArrayList(Sheet.<EuipExcelListResp>builder().name("通讯装备信息")
                        .index(0)
                        .handlers(Lists.newArrayList(ExcelCustomStyleStrategy.getSimpleStyle(), new SimpleColumnWidthStyleStrategy(30))).clz(EuipExcelListResp.class).build(),
                Sheet.<UavInfoResp>builder().name("无人机信息").index(1)
                        .handlers(Lists.newArrayList(ExcelCustomStyleStrategy.getSimpleStyle(), new SimpleColumnWidthStyleStrategy(30))).clz(UavInfoResp.class).build());
        
    }
    
    @Override
    protected List sheetData(int sheetIndex) {
        if (0 == sheetIndex) {
            return euip;
        } else {
            return uva;
        }
    }
    
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/648983.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手把手教你如何解开安装UKUI的黑屏故障

手把手教你如何解开安装UKUI的黑屏故障 引子 作为一个不折腾不舒服斯基的Linuxer&#xff0c;我又开始安装配置开放欧拉操作系统了。这是国产自主安全可控的Linux发行版。欧拉发行版Linux的发起者就是干正经事的华为&#xff0c;比其它拉大旗扯虎皮的国产Linux低调务实多了。…

远程控制之原理和实战

按理来说&#xff0c;本人不该发表此类专业文章&#xff0c;鄙人零星碎片化的开发经历&#xff0c;让本人斗胆向诸位网友&#xff0c;在远控方面做一点演示说明&#xff0c;谈论一点自己的认识。 程序工程代码地址&#xff1a;点击此处下载。 程序分为两个部分&#xff0c;控…

(三)Kafka 生产者

文章目录 1. Kafka 发送消息的主要步骤2.创建 Kafka 生产者3.发送消息到 Kafka&#xff08;1&#xff09;发送并忘记&#xff08;2&#xff09;同步发送&#xff08;3&#xff09;异步发送 4.生产者配置&#xff08;1&#xff09;client.id&#xff08;2&#xff09;ack&#x…

查看P端日志操作步骤

1.登录PUTTY,这里以联调环境103.160.139.82为例。 2.登录&#xff0c;查看用户名&#xff1a;hxb或zzkpt,密码&#xff1a;用户名01动态口令。 例如hxb, sunmenglei01888888 3.进入P端日志存放目录&#xff0c; cd /home/zzkpt/logs/bcip 4.比如我要查看2023年5月5日&#xf…

索引常见问题

被问到SQL和索引优化问题&#xff0c;如何切入&#xff1f; 可以用 explain 进行分析 思考流程&#xff1a;找到哪些运行时间长浪费性能的sql&#xff0c;然后再用explain分析 慢查询日志 MySQL可以设置慢查询日志&#xff0c;当SQL执行的时间超过我们设定的时间&#xff0…

在UE中使用SVT(VirtualTexture)功能

前几年VT技术非常的火&#xff0c;这项技术主要运用在地形上&#xff0c;可以达到更高级别的精细度和更多次数的纹理混合&#xff0c;但实际非地形也可以用&#xff0c;特别是对于贴图尺寸比较大且多维度子材质比较多的模型&#xff0c;做了材质合并以及VT优化后&#xff0c;可…

二、线性神经网络

文章目录 前言一、线性回归1. 线性回归的基本元素1.1 线性模型1.2 损失函数1.3 解析解1.4 梯度下降1.5 用模型进行预测 2. 正态分布与平方损失3. 从线性回归到深度网络 二、线性回归的代码实现1. 生成数据集2. 读取数据集2.1 手动实现读取数据集2.2 简洁实现读取数据集 3. 初始…

便携补光LED化妆镜方案

近段时间&#xff0c;现代科技的衍生产品&#xff0c;智能化妆镜很受爱美女士的喜爱。为此&#xff0c;宇凡微推出无极调光的LED化妆镜方案。主控芯片采用宇凡微YF单片机&#xff0c;根据LED化妆镜方案的不同功能&#xff0c;支持定制开发。 一、LED化妆镜方案介绍 在日常过程中…

Html span标签的详细介绍

HTML &#xff1c;span&#xff1e;标签_span标签_allway2的博客-CSDN博客 一、span标签的定义及用法 在html中&#xff0c;span标签是使用来组合文档中的行内元素&#xff0c;以便使用样式来对它们进行格式化。 span标签本身并没有什么格式表现&#xff08;比如&#xff1a;换…

利用Matlab和cadence实现离散傅里叶分析(DFT)

例1&#xff1a; 采样定律&#xff0c;取100个点&#xff0c;信号频率是100HZ&#xff0c;采样频率是1000HZ&#xff0c;相当于采样十个周期&#xff0c;每个周期采样十个点。 cos&#xff08;2πT&#xff09;函数是以Ts1/fs为时间间隔对样本进行采样&#xff0c;取N个采样样…

Mini热风枪 制作过程

首先引个流吧 立创开源广场&#xff1a;https://oshwhub.com/abby_qi/mini-re-feng-qiang 哔哩哔哩&#xff1a; 实物图 然后说一下硬件的选型和图 风扇&#xff1a;3010无刷风扇 额定电压3.7V&#xff08;其实这个风扇还有其他额定电压的&#xff0c;比如9V12V&#xff0c;…

PyTorch 深度学习 || 专题九:PyTorch 全连接自编码网络的无监督学习

PyTorch 全连接自编码网络的无监督学习 文章目录 PyTorch 全连接自编码网络的无监督学习1. 数据去噪1.1 计算库和数据准备工作1.2 构建自编码网络1.3 调用主函数1.4 可视化 2. 数据的重建与降维2.1 计算模块和数据的准备2.2 自编码网络数据准备2.3 自编码网络的构建2.4 自编码网…

1.5 掌握Scala内建控制结构(一)

一、条件表达式 &#xff08;一&#xff09;语法格式 if (条件) 值1 else 值2 &#xff08;二&#xff09;执行情况 条件为真&#xff0c;结果是值1&#xff1b;条件为假&#xff0c;结果是值2。如果if和else的返回结果同为某种类型&#xff0c;那么条件表达式结果也是那种…

微信小程序开发20__第三方UI组件 ColorUI 的应用

ColorUI 有鲜艳的高饱和色彩&#xff0c; 是专注视觉的微信小程序组件库。 gitee 网址 &#xff1a;ColorUI: 鲜亮的高饱和色彩&#xff0c;专注视觉的小程序组件库 一 使用方法 在微信小程序中使用 ColorUI 需要两个步骤&#xff1a; 第一步&#xff1a; 下载源码解压…

【Linux】详解环境变量与命名行参数

目录 环境变量了解PATH什么是环境变量&#xff1f;使用环境变量系统自带环境变量示例 命名行参数argc与argvenvenviron 环境变量 了解PATH 提出问题&#xff1a; 我写的可执行程序&#xff0c;与系统的可执行程序都是可执行程序&#xff0c;那么为什么执行系统的可执行程序…

Dokcer安装---Mqtt

1、拉取镜像 docker pull registry.cn-hangzhou.aliyuncs.com/synbop/emqttd:2.3.6 老版本 2、运行 docker run -it --name emq -p 18083:18083 -p 1883:1883 -p 8084:8084 -p 8883:8883 -p 8083:8083 -d registry.cn-hangzhou.aliyuncs.com/synbop/emqttd:2.3.6 –name 容器…

佩戴舒适度极好的蓝牙耳机推荐,久戴不累的蓝牙耳机分享

​听歌、刷剧、游戏&#xff0c;运动、吃饭、睡觉等&#xff0c;要说现在年轻人除了离不开手机之外&#xff0c;还有就是蓝牙耳机了&#xff01;当然&#xff0c;随着蓝牙耳机的快速发展&#xff0c;各种各样的蓝牙耳机都有&#xff0c;导致很多人不知道耳机怎么选了&#xff0…

管理类联考——逻辑——知识篇——第五章 假言命题(必考)(最重要的基础)

第五章 假言命题&#xff08;必考&#xff09;&#xff08;最重要的基础&#xff09; 假言命题&#xff1a;陈述某一事物情况是另一件事物情况的条件的命题。假言命题中的充分条件假言命题和必要条件假言命题是联考逻辑最重要的必考考点。1 *本质为&#xff1a;充分必要&#…

Vue中如何进行分布式鉴权与认证

Vue中如何进行分布式鉴权与认证 随着前后端分离的趋势不断加强&#xff0c;前端应用的安全性问题也日益受到关注。在Vue应用中&#xff0c;我们通常需要实现分布式鉴权和认证&#xff0c;以确保用户的安全性和数据的保密性。本文将介绍在Vue中如何进行分布式鉴权与认证。 什么…

闲聊下最近哦

随便聊聊 聊聊最近工作或日常上一家公司一直比较忙,人也比较懒,一直没有写博客,最近换了下工作,争取坚持写博客吧 聊聊最近工作或日常 上一家公司一直比较忙,人也比较懒,一直没有写博客,最近换了下工作,争取坚持写博客吧 上家公司做了几年多了,上半年离职换了个工作,现阶段这…