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);}

(七)效果

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java 基于微信小程序的电子商城购物系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Java:字符集、IO流 --黑马笔记

一、字符集 1.1 字符集的来历 我们知道计算机是美国人发明的&#xff0c;由于计算机能够处理的数据只能是0和1组成的二进制数据&#xff0c;为了让计算机能够处理字符&#xff0c;于是美国人就把他们会用到的每一个字符进行了编码&#xff08;所谓编码&#xff0c;就是为一个…

测试开发基础 mvn test | 利用 Maven Surefire Plugin 做测试用例基础执行管理

【摘要】 在测试工作场景中&#xff0c;经常会遇到下面的问题&#xff1a;1、执行自动化测试用例的时候&#xff0c;只想指定某个测试类&#xff0c;或者某个方法&#xff0c;又或者某一类用例等&#xff0c;怎么办&#xff1f;2、想要和 Jenkins 一起进行持续集成&#xff0c;…

树莓派编程基础与硬件控制

1.编程语言 Python 是一种泛用型的编程语言&#xff0c;可以用于大量场景的程序开发中。根据基于谷歌搜 索指数的 PYPL&#xff08;程序语言流行指数&#xff09;统计&#xff0c;Python 是 2019 年 2 月全球范围内最为流行 的编程语言 相比传统的 C、Java 等编程语言&#x…

HarmonyOS 状态管理装饰器 Observed与ObjectLink 处理嵌套对象/对象数组 结构双向绑定

本文 我们还是来说 两个 harmonyos 状态管理的装饰器 Observed与ObjectLink 他们是用于 嵌套对象 或者 以对象类型为数组元素 的数据结构 做双向同步的 之前 我们说过的 state和link 都无法捕捉到 这两种数据内部结构的变化 这里 我们模拟一个类数据结构 class Person{name:…

【漏洞复现】狮子鱼CMS文件上传漏洞(image_upload.php)

Nx01 产品简介 狮子鱼CMS&#xff08;Content Management System&#xff09;是一种网站管理系统&#xff0c;它旨在帮助用户更轻松地创建和管理网站。该系统拥有用户友好的界面和丰富的功能&#xff0c;包括页面管理、博客、新闻、产品展示等。通过简单直观的管理界面&#xf…

uniapp设置不显示顶部返回按钮

一、pages文件中&#xff0c;在相应的页面中设置 "titleNView": {"autoBackButton": false} 二、对应的页面文件设置隐藏元素 document.querySelector(.uni-page-head-hd).style.display none

Python编程之旅:从入门到精通

在数字世界的无尽宇宙中&#xff0c;Python无疑是一颗璀璨的明星。其简洁易懂的语法、丰富的库和广泛的应用领域&#xff0c;使得Python成为了众多初学者的首选编程语言。那么&#xff0c;如何学习Python呢&#xff1f;本文将带你一步步踏上Python编程的旅程。 一、入门篇&…

使用R语言fifer包进行分层采样

使用R语言fifer包中的stratified()函数用来进行分层采样非常方便&#xff0c;但fifer包已经从CRAN存储库中删除&#xff0c;需要从存档中下载可用的历史版本&#xff0c;下载链接&#xff1a;Index of /src/contrib/Archive/fifer (r-project.org)https://cran.r-project.org/s…

EMC学习笔记(二十四)降低EMI的PCB设计指南(四)

降低EMI的PCB设计指南&#xff08;四&#xff09; 1.电路板分区2.信号走线2.1 电容和电感串扰2.2 天线2.3 端接和传输线2.4输入端的阻抗匹配 tips&#xff1a;资料主要来自网络&#xff0c;仅供学习使用。 1.电路板分区 电路板分区与电路板平面规划具有相同的基本含义&#x…

Vue3中Setup概述和使用(三)

一、引入Setup 1、Person.Vue 与Vue3编写简单的App组件(二) 中的区别是&#xff1a;取消data、methods等方法,而是将数据和方法定义全部放进setup中。 <template><div class"person"><h1>姓名:{{name}}</h1><h1>年龄:{{age}}</h…

UI自动刷新大法:DataBinding数据绑定

之前我们讲了DataBinding在Activity、Fragment、RecyclerView中的基础使用&#xff0c;而那些常规使用方法里&#xff0c;每当绑定的变量发生数据变化时&#xff0c;都需要ViewDataBinding重新设值才会刷新对应UI。而DataBinding通过内部实现的观察者模式来进行自动刷新UI&…