JAVA:记一次excel导出的需求

java 导出excel java 导出excel去除插件广告 阅读详情

公司业务大范围改造,包括一些代码重构,数据来源迁移等,其中很小的一个点就是对列表数据的导出。当时参考了一下公司前辈写的代码。代码不好贴出来,但是流程基本如下:
``` java
public void exportData(Object...params){
    // 参数校验,包括非法校验和时间跨度校验 
    // 封装Workbook(在方法里进行了导出数据的查询)
    // 设置名字
    // 设置response参数
    // 具体的数据写出
    // 关闭相关资源
}
```
这么看过来似乎流程有些混乱,但是没法去评判之前人写代码的好与坏,毕竟不知道当时是什么样的开发周期和情况。

文件名设置,文件内容写出,参数设置,关闭资源。等等这些,完全可以封装到一起,不然每次写导出,都和这个一样写一串,对于后来者而言就是灾难了。

我想要的是抽成公用的方法,参数是传入具体的需要导出的list数据,然后方法里把别的都干了。当然,就单单这个功能而言,easyexcel有更加完备的技术实现。我看了看代码里,并没有引入easyxcel的依赖,本着小心谨慎引入新依赖的想法,决定自己封一个比较类似的。

接下来就直接贴代码了,可以将如下几个类放在一个包下。

ExcelWriteDataBuilder用于构建导出时需要的文件名,sheet名等数据:
```java

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.OutputStream;

@Slf4j
@Data
public class ExcelWriteDataBuilder {

    private String fileName;
    private String sheetName;
    private Class clazz;
    private OutputStream outputStream;


    public static ExcelWriteDataBuilder outputStream(OutputStream outputStream) {
        ExcelWriteDataBuilder data = new ExcelWriteDataBuilder();
        data.outputStream = outputStream;
        return data;
    }

    public ExcelWriteDataBuilder clazz(Class clazz) {
        this.clazz = clazz;
        return this;
    }

    public ExcelWriteDataBuilder sheetName(String sheetName) {
        this.sheetName = sheetName;
        return this;
    }

    public ExcelExportHandler fileName(String fileName) {
        this.fileName = fileName;
        ExcelExportHandler excelExportHandler = new ExcelExportHandler();
        excelExportHandler.setWriteDataBuilder(this);
        return excelExportHandler;
    }
}
```


ExcelExportHandler作为方法调用入口
```java

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

@Data
@Slf4j
public class ExcelExportHandler {
    private ExcelWriteDataBuilder writeDataBuilder;

    public <T extends ExcelWriteTool,R> void write(List<R> list, Class<T> clazz) {
        try {
            log.info( "write excel start ==== ");
            T t = clazz.newInstance();
            t.setWriteDataBuilder(writeDataBuilder);
            t.doAction(list);
        } catch (Exception e) {
            log.error("write error e :", e);
        }
    }
}
```

ExcelWriteTool 具体的写excel逻辑,同时支持字类对它进行扩展,支持自定义的excel格式,比如前后增加特定提示语等。
```java
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@Data
public class ExcelWriteTool {
    private ExcelWriteDataBuilder writeDataBuilder;
    // 当前行数
    private Integer index;
    private XSSFWorkbook wb;
    private XSSFSheet sheet;
    // 需要写出的属性
    private List<Field> fields;

    @SneakyThrows
    public void pre() {
        // 前置操作
        HttpServletResponse resp = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        if (resp != null) {
            log.info("ExcelWriteTool.pre resp set ");
            resp.reset();
            resp.setContentType("application/vnd.ms-excel;charset=utf-8");
            resp.setHeader("Content-Disposition", "attachment;filename=" + new String((writeDataBuilder.getFileName() + ".xlsx").getBytes(), "iso-8859-1"));
        }
    }

    public <T> void action(List<T> data) {
        // 写表头
        writeHead();
        // 写数据
        writeData(data);
    }

    public <T> void writeData(List<T> data) {
        // 具体的写数据逻辑
        log.info("writeData start ");
        for (T item : data) {
            XSSFRow row = sheet.createRow(index++);
            for (int i = INT_ZERO; i < fields.size(); i++) {
                val field = fields.get(i);
                createCell(row, i, ReflectUtils.getValue(item, field, String.class));
            }
        }
        log.info("writeData end  ");
    }


    public void writeHead() {
        log.info("writeHead start ");
        // 可能在实现类中有些前置操作属性发生变化,所以判空
        index = Optional.ofNullable(index).orElse(INT_ZERO);
        wb = Optional.ofNullable(wb).orElseGet(XSSFWorkbook::new);
        sheet = Optional.ofNullable(sheet).orElseGet(() -> wb.createSheet(writeDataBuilder.getSheetName()));
        XSSFRow titleRow = sheet.createRow(index);
        // 获取实体的所有属性
        List<Field> fs = ReflectUtils.getFields(writeDataBuilder.getClazz());
        fields = Optional.ofNullable(fields).orElseGet(() -> fs.stream()
                // 过滤 不可见的
                .filter(item -> item.getAnnotation(ExcelExport.class).visible())
                // 排序
                .sorted(Comparator.comparingInt(item -> item.getAnnotation(ExcelExport.class).index()))
                .collect(Collectors.toList()));
        for (int i = INT_ZERO; i < fields.size(); i++) {
            String titleCell = fields.get(i).getAnnotation(ExcelExport.class).desc();
            String[] cellPair = titleCell.split(COLON);
            createCell(titleRow, i, cellPair[INT_ZERO]);
            String width = cellPair.length == INT_ONE ? DEFAULT_EXCEL_WIDTH : cellPair[INT_ONE];
            sheet.setColumnWidth(i, 256 * Integer.parseInt(width) + 184);
        }
        // index自增
        index++;
        log.info("ExcelWriteTool.writeHead write head success");
    }

    public <T> void doAction(List<T> data) {
        try {
            pre();
            action(data);
            after();
        } catch (Exception e) {
            log.error("ExcelWriteTool.doAction error e:", e);
        } finally {
            // 关闭资源
            closeResource();
        }
    }

    private void closeResource() {
        // 关闭资源
        try {
            if (writeDataBuilder.getOutputStream() != null) {
                writeDataBuilder.getOutputStream().close();
            }
        } catch (Exception e) {
            log.error("ExcelWriteTool.after close outStream error e:", e);
        }

        if (wb != null) {
            try {
                wb.close();
            } catch (IOException e) {
                log.error("ExcelWriteTool.after close wb error e:", e);
            }
        }
    }

    public void after() throws IOException {
        log.info("ExcelWriteTool.after start");
        wb.write(writeDataBuilder.getOutputStream());
    }
    
    private static Cell createCell(Row row, int cellNum, String value) {
        Cell cell = row.createCell(cellNum, Cell.CELL_TYPE_STRING);
        cell.setCellValue(getNotNullStr(value));
        return cell;
    }

}
```

ExcelExport定义注解,对实体需要写出的字段进行标识
```java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelExport {

    /**
     * 字段描述:单元格宽度
     */
    String desc();

    /**
     * index
     */
    int index();

    /**
     * 可见性
     */
    boolean visible() default true;
}
```
注解使用场景,需要导出的实体类上

![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4b43b82935b14be38074de92ee8e423b~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=954&h=492&s=110352&e=png&b=2b2b2b)


MerchantApplyWideWriter继承ExcelWriteTool,可以进行一些功能的扩展

```java

import java.util.List;

public class MerchantApplyWideWriter extends ExcelWriteTool{

    public <T> void action(List<T> data) {
        // 进行定制化的操作...
        super.action(data);
    }
}
```

使用姿势
``` java
// write Data
ExcelWriteDataBuilder.outputStream(resp.getOutputStream())
        .sheetName("商家入驻申请信息")
        .clazz(MerchantApplyWideExcelData.class)
        .fileName("商家入驻申请信息")
        .write(exportData, MerchantApplyWideWriter.class);
```
其中clazz里面是需要导出的实体类型,write里面放待导出数据和导出的处理器。

这样的话,每次新的导出需求,需要修改的地方,只有新增实体,实体上写注解,然后如果没有特定的格式问题,甚至都可以直接照搬上面的使用姿势,大大缩短了开发流程,也更加规范和统一。

当然了,代码肯定会存在一些瑕疵,比如一些魔法值的处理,类的冗余,或者其他可能出现优化的地方。

时间问题,这些目前没有处理,也欢迎大佬指证和补充。


 

ExportHandler:SAP UI5 表格导出背后的调度中枢 在 SAP UI5 的导出体系里,经常被直接使用的是。它把表格或列表的模型数据转成 Office Open XML 的xlsx文件;而在SmartTable或的产品化场景里,用户点击工具栏的导出按钮,会触发一套更完整的Export与Export As流程:组装导出配置、弹窗收集用户偏好、拉取 OData 或本地数据、在 Web Worker 中生成文件、下载并清理资源。承接这条端到端链路的中间大脑,就是本文要解析的。尽管它并非公开文档里主推的直接使用类,但从 Demo Kit 的说明、SmartTable。 阅读详情

相关推荐

fcexporthandler.jar

fcexporthandler.jar 这个东西很不好找的

Spring Boot下的一种导出Excel文件的代码框架

1、前言 ​ 在Spring Boot项目中,将数据导出成Excel格式文件是常见的功能。与Excel文件导入类似,此处也用代码框架式的方式实现Excel文件导出,使得代码具有可重用性,并保持导出数据转换的灵活性。 ​ 相对于导入Excel文件的处理,导出Excel文件要简单一些。这里的Excel文件支持xlsx格式。 2、基本框架 ​ 包括一个接口类ExcelExportable和一个Excel导出处理类ExcelExportHandler,以及支持ExcelExportable接口类的实体类。与基

alabo1999的博客 453

linux操作系统使用以太网连接ubuntu,设置固定ipv4

首先,您需要确定要配置的网络接口。可以使用ifconfig -a或ip addr命令来列出当前系统上的所有网络接口及其相关信息。找到您要配置的网络接口名称,例如eth0、ens33或enp0s3;保存并关闭文件后,您需要重启网络服务以使更改生效。在linux操作系统中,要使用交换机连接以太网可以直接使用交互界面;如果你的操作系统没有交互界面,你可以使用命令方式配置;点击ipv4,方式为手动,可以设置ip和子网了;开头,后接网络接口名称。第三步:点击有线最右边圆形控件;第二步:点击有线设置;

2301_79311842的博客 2404

超好用的excel异步导入导出组件

1、asyncexcel基于阿里的easyexcel包装,抽取异步骨架,不改变easyexcel的特性2、有个小坑就是@excelproperty注解的index无法使用了,所以编写excel model的时候需要注意编写顺序需要于excel中的表头顺序一致。......

a807719447的专栏 5356

Cursor+Playwright MCP实战:如何用自然语言一键生成UI自动化测试脚本

本文探讨了如何利用Cursor与Playwright MCP实现自然语言驱动的UI自动化测试脚本生成。通过智能IDE与浏览器自动化协议的结合,开发者可以高效创建稳定的测试脚本,显著提升测试效率与维护性。重点介绍了MCP架构的优势、项目结构最佳实践及团队协作规范,为自动化测试带来革命性改进。

k8l9m0n的博客 441

达梦DM8整合Seata AT模式实战:手把手教你搞定分布式事务(含源码修改避坑)

本文详细介绍了达梦DM8数据库与Seata AT模式的深度整合实战,包括环境准备、架构设计、源码适配及分布式事务落地。通过独创性源码改造,解决了Seata官方对达梦数据库AT模式支持的限制,为国产数据库在微服务架构中的应用提供了可靠的事务保障。

weixin_30764771的博客 332

Easypoi导出功能

Easypoi导出功能

weixin_43762113的博客 410

单细胞双胞过滤-scrublet安装

pip install scrublet ----use-pep517有如下报错,分析可知安装annoy时不会自动更新gcc的版本,centos默认是4.8.5。pip install scrublet ----use-pep517 仍然报错,但似乎不影响使用,提示Successfully installed。打开终端,进入Python环境,输入以下代码,查看Python安装位置。暂时还没尝试是否存在问题,如果存在问题,降级scrublet版本。包的开发依赖的是比较低版本的numpy,会用到。

hzau_t的博客 792

vue导出excel表格

今天讲一下vue项目中的导出excel。

weixin_51938823的博客 654

【QT】基于QSerialPort的跨平台串口通信实战指南

本文是一份基于Qt QSerialPort模块的跨平台串口通信实战指南。详细介绍了从硬件基础、QSerialPort核心类使用、参数配置、设备自动发现到数据异步读写和错误处理的完整流程,并通过构建一个功能齐全的串口调试助手实例,帮助开发者快速掌握在Windows、Linux和macOS系统下进行高效、稳定的串口应用开发。

a1b2c3d的博客 981

计算机视觉入门:从像素到理解的旅程

计算机视觉入门:从像素到理解的旅程,计算机视觉是人工智能领域的核心方向之一,旨在让计算机具备理解和解释视觉信息的能力。本文以系统化的知识框架,结合 Python 代码与经典案例,带您从像素级操作逐步掌握计算机视觉核心技术。涵盖图像处理、特征工程、传统机器学习到深度学习模型,助您构建从基础到进阶的完整能力体系。

不踩坑,不知道坑有多深;不总结,踩过的坑白踩。 18万+

记一次java实现excel导出

java导出excel表格,涉及poi,easypoi,easyexcel,多行表头,合并单元格等...

weixin_43818323的博客 1295

MATLAB 图像滤波:高通、低通、带通和方向滤波器

在 MATLAB 中,我们可以使用不同类型的滤波器对图像进行处理,包括高通滤波器、低通滤波器、带通滤波器和方向滤波器。通过以上代码示例,我们介绍了 MATLAB 中使用高通滤波器、低通滤波器、带通滤波器和方向滤波器对图像进行滤波的方法。高斯滤波器可以实现带通滤波效果,通过调整滤波器的方差参数可以控制带通滤波器的频率范围。这里的平均滤波器是一种常见的低通滤波器,通过对图像周围的像素进行平均来实现平滑效果。Sobel 滤波器是一种常用的方向滤波器,用于检测图像中的水平和垂直边缘。函数将高通滤波器应用于图像。

CyberSparkZ的博客 1394

java 文件导出Excel 文本形式转数字格式解决,字段是int导出需求是数字解决方案

问题:java字段是int类型等,然后导出时是文本,需要操作人员转换为数字格式. 应操作人员要求,导出的时候就是数字格式可以不用转换,方便操作等 java 后台处理过程: 这里我只处理表格的0,2,7,8列的格式转换 图: java 代码: // 总行数 private int totalRows = 0; // 总条数 private int totalCells = 0; // ...

zhanxiaochu的博客 1万+

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

【记一次Excel的批量导出】

【记一次Excel的批量导出】 概述 需求,某私有化客户需要对聊天搜索的结果,进行批量导出,最大量达到17W,而我们目前情况一次只能导出1W 解决思路 目前导出瓶颈1W在于,查询方式为ES集群,返回值最大结果集默认为1W。 index.max_result_window:10000 修改默认返回值配置 index.max_result_window:200000 (弊端:会影响整体ES性能,由于是私有化客户独立服务器,且非长期需求,所以,改!) 返回值超过缓存大小报错,利用反射修改es配置工厂

qq_35374297的博客 1783

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

记一次文件导出(excel)

最近做了一个文件数据导出(excel) 记录一下! 用的是apache的包 meven依赖如下: <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</...

H_g_y_的博客 7632

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

记一次动态插入数据到excel并且转pdf导出(JAVA)

所以难度是在动态填充里面,其次是PDF,至于用户名这种固定的,直接占位符替换即可。所以整体可以拆到两步。Apache POI 是一个开源的 Java 库,用于读取和写入 Microsoft Office 格式的文件,例如 Excel(.xls 和 .xlsx)、Word(.doc 和 .docx)以及 PowerPoint(.ppt 和 .pptx)文件。支持多种文件格式(.xls、.xlsx、.doc、.docx、.ppt、.pptx),几乎涵盖了所有常见的 Microsoft Office 文件类型。

huang_xiaoen的博客 1002

接了个变态需求:生成 Excel + PDF 导出,用 Java 怎么实现?

Excel、PDF的导出、导入是我们工作中经常遇到的一个问题,刚好今天公司业务遇到了这个问题,顺便记个笔记以防下次遇到相同的问题而束手无策。公司有这么两个需求:需求一、给了一个表单,让把查出来的数据组装到表单中并且提供以PDF格式的下载功能。需求二、将数据查出来以Excel表格的形式下载下来。

LoveSummer 1万+

java excel导出下载_Java导出excel并下载功能

我们使用的导出并下载功能是利用一个插件叫POI的插件提供的导出功能,很实用;首先先导入Jar包:Action代码:public void exportToExcel(List data) throws Exception{this.setEnableAccessRequest(true);this.setEnableAccessResponse(true);HttpServletRequest ...

weixin_28730131的博客 4950

记一次用java导入导出excel遇到的问题

解决excel导入导出的问题(导出excel不用ajax而用表单提交的方式来导出)

vcvictory的博客 2175

JAVA导出EXCEL表格

hi~ 好久不见 小伙伴们,最近比较忙,没什么时间写,今天给大家分享的是JAVA如何导出EXCEL表格,因为最近有做这样一个功能,所以分享出来,如有不对之处,敬请指正。 在许多企业办公系统中,经常会有用户要求,需要对数据进行统计并且可以直接下载Excel文件,这样子的话,既然客户提出了要求,我们就应该去满足吖,毕竟客户是上帝嘛,那么我们如何去实现呢?且看我为你一一道来。 POI简介:Jakarta POI 是一套用于访问微软格式文档的Java API。Jakarta POI有很多组件组成,其中有用于操作

m0_59595915的博客 1586

java从List<Map>导出excel

本来我以为已经完事了,找头头过来让他看看,他说一般hibernate多表查询之后返回的List里面的内容一般都是Map类型的,我前面写的那个是List,我以为可以的。。。但是我试了一下,传一个List进去,结果输出的结果我也看不懂了,没办法,只好再写个处理List的方法:代码如下 package com.zhangbinhui.ManageBean; import java.io.Output

装B龟的专栏 6325

记一次悲惨的 Excel 导出事件

作者:kid_2412blog.youkuaiyun.com/kid_2412/article/details/76633525背景分析过程看看XSSF和HSSF的区别解决方案总结背景话说这个背景挺...

Java笔记虾 738
上一篇: 关于优化接口或程序响应的总结
下一篇: idea技巧:临时文件 Scratch File 创建
桥边红药_
博客等级 码龄5年 40粉丝 11原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值