EasyExcel动态列导出

2024-02-12 02:44
文章标签 动态 导出 easyexcel

本文主要是介绍EasyExcel动态列导出,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

测试代码地址:https://gitee.com/wangtianwen1996/cento-practice/tree/master/src/test/java/com/xiaobai/easyexcel/dynamiccolumn
官方文档:https://easyexcel.opensource.alibaba.com/docs/2.x/quickstart/write

一、实现方式

1、根据需要导出的列找到返回类对象属性的ExcelPropertyColumnWidth注解,最终生成需要显示的列名和每列的列宽;
2、根据需要导出的列获取Excel中的行数据;
3、添加自定义单元格拦截策略(实现com.alibaba.excel.write.handler.WriteHandler接口)和数据类型转换策略(实现com.alibaba.excel.converters.Converter接口);
4、创建Excel的Sheet页,设置第一步获取的列宽;

二、代码实现

(一)添加基础数据类型转换器(LocalDate、LocalDateTime、LocalTime、Integer)

package com.xiaobai.easyexcel.dynamiccolumn;import cn.hutool.core.date.DateTime;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;/*** @author wangtw* @ClassName DataConverter* @description: 类型转换器* @date 2024/2/919:23*/
public class DataConverter {public static class CoreConverter<T> implements Converter<T> {private final Class<T> tClass;public CoreConverter(Class<T> tClass) {this.tClass = tClass;}/*** 导出支持的类型* @return*/@Overridepublic Class supportJavaTypeKey() {return tClass;}/*** 导入支持的Excel类型* @return*/@Overridepublic CellDataTypeEnum supportExcelTypeKey() {return CellDataTypeEnum.STRING;}/*** 导入类型转换* @param cellData* @param excelContentProperty* @param globalConfiguration* @return* @throws Exception*/@Overridepublic T convertToJavaData(CellData cellData, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {if (cellData.getData() instanceof LocalDate) {return (T) LocalDate.parse(cellData.getStringValue(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));}if (cellData.getData() instanceof LocalTime) {return (T) LocalTime.parse(cellData.getStringValue(), DateTimeFormatter.ofPattern("HH:mm:ss"));}if (cellData.getData() instanceof LocalDateTime) {return (T) LocalDateTime.parse(cellData.getStringValue(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));}if (cellData.getData() instanceof Integer) {return (T) Integer.valueOf(cellData.getStringValue());}return null;}/*** 导出类型转换* @param obj* @param excelContentProperty* @param globalConfiguration* @return* @throws Exception*/@Overridepublic CellData convertToExcelData(T obj, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {if (obj instanceof LocalDate) {return new CellData(((LocalDate) obj).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));}if (obj instanceof LocalDateTime) {return new CellData(((LocalDateTime) obj).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));}if (obj instanceof LocalTime) {return new CellData(((LocalTime) obj).format(DateTimeFormatter.ofPattern("HH:mm:ss")));}if (obj instanceof Integer) {return new CellData(String.valueOf(obj));}return null;}}/*** localDate类型转换*/public static class LocalDateConverter extends CoreConverter<LocalDate> {public LocalDateConverter() {super(LocalDate.class);}}/*** localTime类型转换*/public static class LocalTimeConverter extends CoreConverter<LocalTime> {public LocalTimeConverter() {super(LocalTime.class);}}/*** LocalDateTime类型转换*/public static class LocalDateTimeConverter extends CoreConverter<LocalDateTime> {public LocalDateTimeConverter() {super(LocalDateTime.class);}}/*** Integer*/public static class IntegerConverter extends CoreConverter<Integer> {public IntegerConverter() {super(Integer.class);}}
}

(二)导出实现代码

package com.xiaobai.easyexcel.dynamiccolumn;import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.handler.WriteHandler;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sun.istack.internal.NotNull;
import jdk.nashorn.internal.runtime.regexp.joni.ast.StringNode;
import org.apache.poi.util.IOUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Stream;/*** @author wangtw* @ClassName DynamicColumnExport* @description: EasyExcel动态列导出* @date 2024/2/918:07*/
public class DynamicColumnExport {/**** @param d 查询数据方法参数* @param vClass 返回类型* @param getDataFun 查询数据函数式接口* @param outputStream 输出流* @param includeColumns 需要导出的列* @param writeHandlerList 自定义拦截器* @param converterList 自定义数据格式化转换器* @param <D>* @param <U>* @param <V>*/public static <D, U, V> void export(D d, Class<V> vClass,@NotNull Function<D, List<V>> getDataFun,@NotNull OutputStream outputStream,@NotNull List<String> includeColumns,@Nullable List<? extends WriteHandler> writeHandlerList,@Nullable List<? extends Converter> converterList) {/*** 1、根据需要导出的列获取每列的列名和单元格的列宽*/// 单元格宽度int columnIndex = 0;Map<Integer, Integer> columnWidthMap = new HashMap<>();//  获取表格头List<List<String>> headList = new ArrayList<>();List<Field> columnList = new ArrayList<>();Field[] declaredFields = vClass.getDeclaredFields();for (String includeColumn : includeColumns) {Optional<Field> includeColumnOptional = Arrays.stream(declaredFields).filter(f -> f.getName().equals(includeColumn)).findFirst();if (includeColumnOptional.isPresent()) {Field field = includeColumnOptional.get();field.setAccessible(true);ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);if (!ObjectUtils.isEmpty(excelProperty)) {// 列名String[] columNameArray = excelProperty.value();headList.add(Arrays.asList(columNameArray));// 可导出的列columnList.add(field);// 保存每列的宽度ColumnWidth columnWidth = field.getAnnotation(ColumnWidth.class);columnWidthMap.put(columnWidth == null ? -1 : columnWidth.value(), columnIndex++);}}}/*** 2、根据需要导出的列获取需要显示的数据*/List<List<Object>> exportDataList = new ArrayList<>();// 执行函数式接口获取需要导出的数据List<V> dataCollection = getDataFun.apply(d);for (V v : dataCollection) {// 拼装每行的数据List<Object> dataSubList = new ArrayList<>();for (Field field : columnList) {try {Object columnValue = field.get(v);dataSubList.add(Optional.ofNullable(columnValue).orElse(""));} catch (IllegalAccessException e) {e.printStackTrace();}}exportDataList.add(dataSubList);}// 表格处理策略ExcelWriterBuilder writerBuilder = EasyExcel.write(outputStream).head(headList);if (!ObjectUtils.isEmpty(writeHandlerList)) {writeHandlerList.forEach(writerBuilder::registerWriteHandler);}// 类型转换策略if (ObjectUtils.isEmpty(converterList)) {writerBuilder.registerConverter(new DataConverter.IntegerConverter());writerBuilder.registerConverter(new DataConverter.LocalDateConverter());writerBuilder.registerConverter(new DataConverter.LocalTimeConverter());writerBuilder.registerConverter(new DataConverter.LocalDateTimeConverter());} else {converterList.forEach(writerBuilder::registerConverter);}// 创建Sheet页String sheetName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();// 设置列宽writeSheet.setColumnWidthMap(columnWidthMap);// 把数据写入到Sheet页中ExcelWriter excelWriter = writerBuilder.build();excelWriter.write(exportDataList, writeSheet);// 关闭流excelWriter.finish();// 关闭输出流IOUtils.closeQuietly(outputStream);}
}

三、测试

(一)设置表头和内容策略

    /*** 设置颜色* @return*/private WriteHandler setColor() {// 头的策略WriteCellStyle headWriteCellStyle = new WriteCellStyle();// 背景设置为白色headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());WriteFont headWriteFont = new WriteFont();headWriteFont.setFontHeightInPoints((short)18);headWriteCellStyle.setWriteFont(headWriteFont);// 内容的策略WriteCellStyle contentWriteCellStyle = new WriteCellStyle();// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);WriteFont contentWriteFont = new WriteFont();// 字体大小contentWriteFont.setFontHeightInPoints((short)15);contentWriteCellStyle.setWriteFont(contentWriteFont);// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现HorizontalCellStyleStrategy horizontalCellStyleStrategy =new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);return horizontalCellStyleStrategy;}

(二)设置单元格样式策略

    public static class CellHandler implements CellWriteHandler {@Overridepublic void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {}@Overridepublic void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {}@Overridepublic void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {}@Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {CellStyle cellStyle = cell.getCellStyle();cellStyle.setBorderBottom(BorderStyle.THIN);cellStyle.setBorderTop(BorderStyle.THIN);cellStyle.setBorderLeft(BorderStyle.THIN);cellStyle.setBorderRight(BorderStyle.THIN);}}

(四)实体类

可选择某几种属性进行导出

package com.xiaobai.easyexcel.dynamiccolumn;import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;/*** @author wangtw* @ClassName DynamicData* @description: EasyExcel动态列导出* @date 2024/2/914:59*/
@AllArgsConstructor
@Builder
@Data
public class DynamicData {@ExcelProperty("id")private Integer id;@ColumnWidth(30)@ExcelProperty("姓名")private String realName;@ColumnWidth(30)@ExcelProperty("性别")private String sex;@ColumnWidth(30)@ExcelProperty("年龄")private int age;@ColumnWidth(50)@ExcelProperty("单位名称")private String orgName;@ColumnWidth(50)@ExcelProperty("部门名称")private String deptName;
}

(五)数据准备

    private List<DynamicData> getData(String condition) {List<DynamicData> dynamicDataList = new ArrayList<>();for (int i = 0; i < 100; i++) {DynamicData data = DynamicData.builder().id(i).age(random.nextInt(60)).sex("男").realName("王" + i).orgName("单位" + i).deptName("部门" + i).build();dynamicDataList.add(data);}return dynamicDataList;}

(六)测试代码(选择orgName、deptName、realName、sex进行导出)

    @Testpublic void exportTest() {File file = new File("测试.xlsx");OutputStream outputStream = null;try {outputStream = new FileOutputStream(file);} catch (FileNotFoundException e) {e.printStackTrace();}List<String> includeColumns = new ArrayList<>();includeColumns.add("orgName");includeColumns.add("deptName");includeColumns.add("realName");includeColumns.add("sex");List<WriteHandler> writeHandlers = new ArrayList<>();writeHandlers.add(setColor());writeHandlers.add(new CellHandler());DynamicColumnExport.export(null, DynamicData.class,this::getData, outputStream, includeColumns, writeHandlers, null);}

(七)效果

在这里插入图片描述

这篇关于EasyExcel动态列导出的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/701487

相关文章

Oracle Expdp按条件导出指定表数据的方法实例

《OracleExpdp按条件导出指定表数据的方法实例》:本文主要介绍Oracle的expdp数据泵方式导出特定机构和时间范围的数据,并通过parfile文件进行条件限制和配置,文中通过代码介绍... 目录1.场景描述 2.方案分析3.实验验证 3.1 parfile文件3.2 expdp命令导出4.总结

如何用Python绘制简易动态圣诞树

《如何用Python绘制简易动态圣诞树》这篇文章主要给大家介绍了关于如何用Python绘制简易动态圣诞树,文中讲解了如何通过编写代码来实现特定的效果,包括代码的编写技巧和效果的展示,需要的朋友可以参考... 目录代码:效果:总结 代码:import randomimport timefrom math

java poi实现Excel多级表头导出方式(多级表头,复杂表头)

《javapoi实现Excel多级表头导出方式(多级表头,复杂表头)》文章介绍了使用javapoi库实现Excel多级表头导出的方法,通过主代码、合并单元格、设置表头单元格宽度、填充数据、web下载... 目录Java poi实现Excel多级表头导出(多级表头,复杂表头)上代码1.主代码2.合并单元格3.

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字

.NET利用C#字节流动态操作Excel文件

《.NET利用C#字节流动态操作Excel文件》在.NET开发中,通过字节流动态操作Excel文件提供了一种高效且灵活的方式处理数据,本文将演示如何在.NET平台使用C#通过字节流创建,读取,编辑及保... 目录用C#创建并保存Excel工作簿为字节流用C#通过字节流直接读取Excel文件数据用C#通过字节

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d

LeetCode:64. 最大正方形 动态规划 时间复杂度O(nm)

64. 最大正方形 题目链接 题目描述 给定一个由 0 和 1 组成的二维矩阵,找出只包含 1 的最大正方形,并返回其面积。 示例1: 输入: 1 0 1 0 01 0 1 1 11 1 1 1 11 0 0 1 0输出: 4 示例2: 输入: 0 1 1 0 01 1 1 1 11 1 1 1 11 1 1 1 1输出: 9 解题思路 这道题的思路是使用动态规划

MySQL使用mysqldump导出数据

mysql mysqldump只导出表结构或只导出数据的实现方法 备份数据库: #mysqldump 数据库名 >数据库备份名 #mysqldump -A -u用户名 -p密码 数据库名>数据库备份名 #mysqldump -d -A --add-drop-table -uroot -p >xxx.sql 1.导出结构不导出数据 mysqldump --opt -d 数据库名 -u