当前位置: 首页 > article >正文

使用注解动态映射:根据实体List列表动态生成Excel文件

我们一般通过POI来生成对应的Excel文件,绝大多数情况是需要手动编写单元格内容,然后顺序填充值,今天我们将动态根据实体来生成Excel表头,同时自动填充内容。

文章目录

  • 1. 定义注解
  • 2. 实体类应用注解
  • 3. 动态导出工具类

1. 定义注解

import java.lang.annotation.*;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelColumn {String name();          // Excel列名int order();            // 列顺序(从0开始)String format() default ""; // 格式(如日期、数字格式)
}

2. 实体类应用注解

public class Employee {@ExcelColumn(name = "员工ID", order = 0)private Integer id;@ExcelColumn(name = "姓名", order = 1)private String name;@ExcelColumn(name = "部门", order = 2)private String department;@ExcelColumn(name = "薪资", order = 3, format = "#,##0.00")private Double salary;@ExcelColumn(name = "入职日期", order = 4, format = "yyyy-MM-dd")private Date hireDate;// getter/setter省略...
}

3. 动态导出工具类

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.List;public class DynamicExcelExporter {public static <T> void export(List<T> dataList, OutputStream outputStream) throws IOException {if (dataList == null || dataList.isEmpty()) {throw new IllegalArgumentException("数据列表不能为空");}Class<?> clazz = dataList.get(0).getClass();Field[] fields = clazz.getDeclaredFields();// 获取带注解的字段并按order排序List<Field> annotatedFields = Arrays.stream(fields).filter(f -> f.isAnnotationPresent(ExcelColumn.class)).sorted(Comparator.comparingInt(f -> f.getAnnotation(ExcelColumn.class).order())).toList();try (Workbook workbook = new XSSFWorkbook()) {Sheet sheet = workbook.createSheet("Sheet1");// 1. 动态生成表头createDynamicHeader(workbook, sheet, annotatedFields);// 2. 动态填充数据fillDynamicData(workbook, sheet, dataList, annotatedFields);// 3. 自动调整列宽for (int i = 0; i < annotatedFields.size(); i++) {sheet.autoSizeColumn(i);}workbook.write(outputStream);}}private static void createDynamicHeader(Workbook workbook, Sheet sheet, List<Field> fields) {Row headerRow = sheet.createRow(0);CellStyle headerStyle = createHeaderStyle(workbook);for (int i = 0; i < fields.size(); i++) {ExcelColumn annotation = fields.get(i).getAnnotation(ExcelColumn.class);Cell cell = headerRow.createCell(i);cell.setCellValue(annotation.name());cell.setCellStyle(headerStyle);}}private static <T> void fillDynamicData(Workbook workbook, Sheet sheet, List<T> dataList, List<Field> fields) {for (int rowIdx = 0; rowIdx < dataList.size(); rowIdx++) {T item = dataList.get(rowIdx);Row row = sheet.createRow(rowIdx + 1);for (int colIdx = 0; colIdx < fields.size(); colIdx++) {Field field = fields.get(colIdx);field.setAccessible(true);try {Object value = field.get(item);ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);createCell(workbook, row, colIdx, value, annotation.format());} catch (IllegalAccessException e) {createCell(workbook, row, colIdx, "", null);}}}}private static void createCell(Workbook workbook, Row row, int column, Object value, String format) {Cell cell = row.createCell(column);if (value == null) {cell.setCellValue("");} else if (value instanceof Number) {cell.setCellValue(((Number) value).doubleValue());if (format != null && !format.isEmpty()) {CellStyle style = workbook.createCellStyle();style.setDataFormat(workbook.createDataFormat().getFormat(format));cell.setCellStyle(style);}} else if (value instanceof Boolean) {cell.setCellValue((Boolean) value);} else if (value instanceof Date) {cell.setCellValue((Date) value);CellStyle style = workbook.createCellStyle();String dateFormat = format != null ? format : "yyyy-MM-dd";style.setDataFormat(workbook.createDataFormat().getFormat(dateFormat));cell.setCellStyle(style);} else {cell.setCellValue(value.toString());}}private static CellStyle createHeaderStyle(Workbook workbook) {CellStyle style = workbook.createCellStyle();Font font = workbook.createFont();font.setBold(true);font.setColor(IndexedColors.WHITE.getIndex());style.setFont(font);style.setFillForegroundColor(IndexedColors.BLUE.getIndex());style.setFillPattern(FillPatternType.SOLID_FOREGROUND);style.setAlignment(HorizontalAlignment.CENTER);// 设置边框style.setBorderBottom(BorderStyle.THIN);style.setBorderTop(BorderStyle.THIN);style.setBorderLeft(BorderStyle.THIN);style.setBorderRight(BorderStyle.THIN);return style;}
}

在这里插入图片描述

http://www.lryc.cn/news/2385171.html

相关文章:

  • 基于cornerstone3D的dicom影像浏览器 第二十一章 显示DICOM TAGS
  • 【循环位运算——uint32,DP】
  • 贪心介绍 LeetCode 455.分发饼干 LeetCode 376. 摆动序列 LeetCode 53. 最大子序和
  • 算法学习笔记·数学·快速幂
  • Postgresql 数据库体系架构
  • [创业之路-377]:企业战略管理案例分析-战略制定/设计-市场洞察“五看”:看宏观之社会发展趋势:数字化、智能化、个性化的趋势对初创公司的战略机会
  • Vue框架1(vue搭建方式1,vue指令,vue实例生命周期)
  • 分布式系统核心技术全解析
  • skywalking 10.2 源码编译
  • C++ --- string
  • Android Studio 连接夜神模拟器 自动断开的问题
  • Python入门手册:Python中的数据结构类型
  • 《P3435 [POI 2006] OKR-Periods of Words》
  • C/C++---隐式显式转换
  • 巡礼中国西极·跨越昆仑天山 | 北斗卫星徽章护航昆仑科考
  • Vue常用自定义指令-积累的魅力【VUE】
  • LangChain4j第三篇: RAG的简单应用与实践
  • 机器学习第二十六讲:官方示例 → 跟着菜谱学做经典菜肴
  • 功能强大且易于使用的 JavaScript 音频库howler.js 和AI里如何同时文字跟音频构思想法
  • 品鉴JS的魅力之防抖与节流【JS】
  • 如何使用patch-package给npm包打补丁
  • maxkey单点登录系统
  • windows bat 在目录下(包括子目录)搜索批量指定文件名称复制到另一个文件夹内
  • Notepad++ 下载与安装教程(小白专属)
  • Spring Cloud Gateway 微服务网关实战指南
  • 微服务架构实战:Eureka服务注册发现与Ribbon负载均衡详解
  • 采用多维计算策略(分子动力学模拟+机器学习),显著提升 α-半乳糖苷酶热稳定性
  • 【java】小练习--零钱通
  • 旅游信息检索
  • 贝叶斯理论