自定义导出Excel数据注解实践
目录
- 前言
- 结构组成
- 定义自定义注解
- 定义导出数据的实体
- 定义Excel导出逻辑
- 定义导出服务
- 注解验证
- 总结
前言
在企业级应用中,导入导出 Excel 文件是很常见的需求。通过使用自定义注解不仅可以实现灵活的 Excel 数据导入导出还可以减少手动配置的麻烦,提高代码的可读性和可维护性。本文记录了如何通过自定义注解来实现将实体类数据导出为 Excel 文件的过程,适合所有有相同需求的开发者学习和参考✍✍✍

结构组成
自定义导出Excel注解编写类时,博主建议以模块化的思路来构建结构,博主以如下结构来组织,仅供大家参考

annotation用于存放自定义的注解,所有自定义的注解可以放在这里,其中创建一个Excel.java文件专门用于定义导出Excel的元数据entity用于存放实体类, 用于描述业务模型或数据结构。每个实体类可以和数据库表或导出的Excel表格列对应,创建一个User.java文件来加上@Excel注解util用于存放工具类,通常用于处理具体的操作逻辑,比如生成 Excel 文件、处理文件流等。这种工具类可以重复使用并且与具体业务逻辑分离,这里创建一个ExcelExporter.java用来实现 Excel 导出逻辑service用于存放服务类,负责核心业务逻辑,如从数据库获取数据或者对外提供 API 的功能。这里我们创建一个UserService.java负责定义用户数据并提供导出功能
定义自定义注解
我们首先创建一个自定义的注解 @Excel,用于标注需要导出到 Excel 文件中的字段。这个注解可以为每个字段提供额外的元数据,例如列名、列顺序、日期格式等。
小贴士:将
@Excel注解直接作用在实体类的字段上,用于指定字段的导出行为和格式 🤔
package com.jianzhou.annotation;import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @BelongsProject: pmhub-learn* @BelongsPackage: com.jianzhou.annotation* @Author: ZJ* @CreateTime: 2024-10-19 22:16* @Description: 自定义导出Excel数据注解*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Excel {//Excel 列名String name() default "";//列的顺序int sort() default Integer.MAX_VALUE;//日期格式String dateFormat() default "";//列的宽度(单位是字符)double width() default 16;//是否需要合并单元格boolean needMerge() default false;// 单元格对齐方式HorizontalAlignment align() default HorizontalAlignment.CENTER;// 列头颜色IndexedColors headerColor() default IndexedColors.WHITE;// 单元格颜色IndexedColors cellColor() default IndexedColors.BLACK;
}
在这个注解中博主定义了几个关键属性
| 属性 | 含义 |
|---|---|
| name | 导出的 Excel 列名 |
| sort | 列的顺序 |
| dateFormat | 日期格式化,适用于 Date 类型字段 |
| width | 列的宽度 |
| needMerge | 是否需要合并单元格 |
| align | 单元格的对齐方式 |
| headerColor | 列头的颜色 |
| cellColor | 单元格的颜色 |
@Retention(RetentionPolicy.RUNTIME) 和 @Target(ElementType.FIELD) 是两个元注解,它们分别控制自定义注解的生命周期和适用位置。
@Retention用于指定注解的 保留策略,即在代码的哪一个阶段能够获取到注解。RetentionPolicy是一个枚举类型,它定义了注解的三种保留策略,这里的@Retention(RetentionPolicy.RUNTIME)表示@Excel注解会保留到运行时,并且可以通过反射机制获取注解信息。在导出 Excel 时,我们正是通过反射读取这些注解的。
| RetentionPolicy保留策略 | 含义 | 用途 |
|---|---|---|
RetentionPolicy.SOURCE | 注解只会保留在源代码中,编译时就会被丢弃 | 注解@Override只用于代码检查或提高可读性,不会进入字节码文件 |
RetentionPolicy.CLASS | 注解会保留到编译后的 .class 文件中,但在运行时无法通过反射获取到它 | 常见于框架内部处理,这种注解仅在编译期间使用,不在运行时被访问 |
RetentionPolicy.RUNTIME | 注解不仅会保留到 .class 文件中,还能在运行时通过反射获取到 | 这种注解常用于需要在运行时动态获取注解信息的场景,例如 Spring、Hibernate 等框架广泛使用的注解 |
@Target用于指定注解可以作用在程序的哪些位置。ElementType是一个枚举,定义了注解可以应用的不同代码元素。这里的@Target(ElementType.FIELD)表示@Excel注解只能应用于 类的字段(Field) 上。也就是说,这个注解只能用在属性(字段)上,不能用在类、方法或构造函数等其他地方。
| 注解的可应用代码元素 | 含义 |
|---|---|
ElementType.TYPE | 类、接口(包括注解类型)或枚举声明 |
ElementType.FIELD | 字段声明(包括枚举常量) |
ElementType.METHOD | 方法声明 |
ElementType.PARAMETER | 参数声明 |
ElementType.CONSTRUCTOR | 构造函数声明 |
ElementType.LOCAL_VARIABLE | 局部变量声明 |
ElementType.ANNOTATION_TYPE | 注解类型声明 |
ElementType.PACKAGE | 包声明 |
ElementType.TYPE_PARAMETER | 类型参数(如泛型) |
ElementType.TYPE_USE | 可以用于所有的类型声明(如泛型、类声明、异常声明等) |
@interface 是 Java 中用来定义自定义注解的关键字。注解是一种特殊的接口,它允许我们为程序中的元素(如类、方法、字段等)添加元数据(metadata)。通过 @interface,我们可以自定义自己的注解,并使用这些注解来描述代码中的某些行为或特性。其中这样是定义注解的属性,default表示带有默认值的注解值,若没有定义默认值则使用注解时必须提供。
String name() default "";//带有默认值的属性
定义导出数据的实体
然后我们定义一个测试的用户实体类,代表需要导出数据的对象。在这个例子中,我们定义了一个 User 实体类,并在每个字段上加上 @Excel 注解来指定导出的配置。
提示:大家可以根据业务需求在实体类上加上自定义的
@Excel注解,来控制导出的格式
package com.jianzhou.entity;import com.jianzhou.annotation.Excel;import java.util.Date;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @BelongsProject: pmhub-learn* @BelongsPackage: com.jianzhou.entity* @Author: ZJ* @CreateTime: 2024-10-19 22:16* @Description: 定义用户实体数据*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {@Excel(name = "用户ID", sort = 1)private Long userId;@Excel(name = "用户名", sort = 2)private String userName;@Excel(name = "创建时间", dateFormat = "yyyy-MM-dd HH:mm:ss", sort = 3)private Date createTime;
}
定义Excel导出逻辑
为了实现将实体类数据导出为 Excel 文件的功能,博主编写了 ExcelExporter 工具类。这个类使用反射机制获取实体类中 @Excel 注解的字段,并根据注解配置生成 Excel 文件🤔
package com.jianzhou.util;import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.util.List;import com.jianzhou.annotation.Excel;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;/*** @BelongsProject: pmhub-learn* @BelongsPackage: com.jianzhou.service* @Author: ZJ* @CreateTime: 2024-10-19 22:16* @Description: 定义Excel导出逻辑*/
public class ExcelExporter {public static void exportExcel(List<?> data, Class<?> clazz, String filePath) throws Exception{Workbook workbook = new XSSFWorkbook();Sheet sheet = workbook.createSheet("Sheet1");Row headerRow = sheet.createRow(0);// 通过反射机制获取实体类clazz的所有字段信息并存储在Field数组中Field[] fields = clazz.getDeclaredFields();int colIdx = 0;for (Field field : fields) {if (field.isAnnotationPresent(Excel.class)) {//检查字段是否有 @Excel 注解Excel excel = field.getAnnotation(Excel.class);//获取 @Excel 注解的实例以便访问注解的属性Cell cell = headerRow.createCell(colIdx);//在表头行中创建一个单元格,colIdx 表示列的索引cell.setCellValue(excel.name());//设置该列的名称为注解中的 name 属性值/**设置该列的宽度,宽度基于注解中的 width 属性。256 是单位转换系数,因为 Apache POI 中宽度单位是 1/256 个字符*/sheet.setColumnWidth(colIdx, (int) (excel.width() * 256));colIdx++;}}// 填充数据int rowIdx = 1;//从第二行开始填充数据,第一行是表头for (Object obj : data) {//通过遍历每个对象,将其数据填充到对应的 Excel 行中Row dataRow = sheet.createRow(rowIdx++);colIdx = 0;for (Field field : fields) {if (field.isAnnotationPresent(Excel.class)) {field.setAccessible(true); // 允许访问私有字段Object value = field.get(obj);//通过反射获取该对象的字段值Cell cell = dataRow.createCell(colIdx++);if (value != null) {cell.setCellValue(value.toString()); // 将字段值转换为字符串写入单元格}}}}// 输出 Excel 文件try (FileOutputStream fileOut = new FileOutputStream(filePath)) {workbook.write(fileOut);}workbook.close();}
}
定义导出服务
为了模拟数据,博主在 UserService 中定义了用户数据生成逻辑,并调用 ExcelExporter 工具类将用户数据导出为 Excel 文件🤔🤔🤔
package com.jianzhou.service;import com.jianzhou.entity.User;
import com.jianzhou.util.ExcelExporter;import java.util.ArrayList;
import java.util.Date;
import java.util.List;/*** @BelongsProject: pmhub-learn* @BelongsPackage: com.jianzhou.service* @Author: ZJ* @CreateTime: 2024-10-19 22:16* @Description: 定义导出服务*/
public class UserService {public List<User> getUsers() {List<User> users = new ArrayList<>();users.add(new User(1L, "Alice", new Date()));users.add(new User(2L, "Bob", new Date()));return users;}public void exportUsersToExcel(String filePath) throws Exception {List<User> users = getUsers();ExcelExporter.exportExcel(users, User.class, filePath);}
}
注解验证
最后我们可以通过 Main 类验证整个注解和导出逻辑是否工作正常🤔🤔🤔
package com.jianzhou;import com.jianzhou.service.UserService;/*** @BelongsProject: pmhub-learn* @BelongsPackage: com.jianzhou* @Author: ZJ* @CreateTime: 2024-10-19 23:08* @Description: 注解验证*/
public class Main {public static void main(String[] args) {try {UserService userService = new UserService();userService.exportUsersToExcel("users.xlsx");System.out.println("Excel 文件导出成功!");} catch (Exception e) {e.printStackTrace();}}
}


总结
博主通过这篇文章展示了如何通过自定义注解简化 Excel 导出的开发过程。自定义注解不仅能让代码更加简洁,还能使代码具备高度的灵活性。在日常开发中,这种注解机制可以大大减少重复代码,同时让 Excel 导出操作更加直观和可控。希望这篇文章对大家有所帮助✊✊✊
相关文章:
自定义导出Excel数据注解实践
目录 前言结构组成定义自定义注解定义导出数据的实体定义Excel导出逻辑定义导出服务注解验证总结 前言 在企业级应用中,导入导出 Excel 文件是很常见的需求。通过使用自定义注解不仅可以实现灵活的 Excel 数据导入导出还可以减少手动配置的麻烦,提高代码…...
CSS3 动画相关属性实例大全(一)(@keyframes ,background属性,border 属性)
CSS3 动画相关属性实例大全(一) (keyframes ,background属性,border 属性) 本文目录: 零、时光宝盒 一、CSS3 动画基本概念 (1)、CSS3的动画基本属性 (2)…...
拦截器或过滤器往本次请求体中添加信息
步骤一:定义新的Request package com.ict.lux.framework.interceptor;import java.util.Collections; import java.util.Enumeration; import java.util.Map; import java.util.TreeMap;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.…...
Docker 安装达梦 DM8 数据库实战指南
Docker 安装达梦 DM8 数据库实战指南 文章目录 Docker 安装达梦 DM8 数据库实战指南一 安装环境二 下载 DM8 安装包三 导入镜像四 启动容器1)docker run 启动2)docker compose 启动3)名词解释 五 连接数据库 本文详细介绍了如何在 CentOS 7.9…...
QtCreator14调试Qt5.15出现 Launching Debugger 错误
1、问题描述 使用QtCreator14调试程序,Launching Debugger 显示红色,无法进入调试模式。 故障现象如下: 使能Debugger Log窗口,显示: 325^error,msg"Error while executing Python code." 不过ÿ…...
day1:基础了解
虚拟机网络设置 桥接模式:客户机使用宿主机的网段 使虚拟机像物理机一样直接连接到外部网络,拥有独立的IP地址,可与其他网络设备通信。 nat模式:客户机使用单独的局域网 通过宿主机的NAT功能,让虚拟机能够访问外部…...
【从零开始的LeetCode-算法】3099. 哈沙德数
如果一个整数能够被其各个数位上的数字之和整除,则称之为 哈沙德数(Harshad number)。给你一个整数 x 。如果 x 是 哈沙德数 ,则返回 x 各个数位上的数字之和,否则,返回 -1 。 示例 1: 输入&am…...
【Next.js 项目实战系列】02-创建 Issue
原文链接 CSDN 的排版/样式可能有问题,去我的博客查看原文系列吧,觉得有用的话,给我的库点个star,关注一下吧 上一篇【Next.js 项目实战系列】01-创建项目 创建 Issue 配置 MySQL 与 Prisma 在数据库中可以找到相关内容&…...
浅谈C++的future
std::future 是 C 标准库中的一个模板类,提供了一种机制来管理和获取异步任务的结果。它常与异步操作相关,允许你在不同线程中执行任务,并在将来(即“未来”)某个时刻获取这些任务的结果。std::future 通常和 std::asy…...
期货外盘行情源7个市场CTP推送式服务说明
在期货交易领域,及时、准确的市场行情信息是投资者做出决策的重要依据。为了满足广大期货投资者对国际期货市场信息的迫切需求,我们特别推出了“期货外盘行情源2千每月7个市场CTP推送式”服务。本服务旨在通过高效、稳定的技术手段,为投资者提…...
计算机毕业设计 | SSM 校园线上订餐系统(附源码)
1, 概述 1.1 项目背景 传统的外卖方式就是打电话预定,然而,在这种方式中,顾客往往通过餐厅散发的传单来获取餐厅的相关信息,通过电话来传达自己的订单信息,餐厅方面通过电话接受订单后,一般通…...
【iOS】使用一个单例通过AFNetworking来实现网络请求
【iOS】使用一个单例通过AFNetworking来实现网络请求 文章目录 【iOS】使用一个单例通过AFNetworking来实现网络请求前言OC网络请求的流程 使用单例的原因创建一个单例采用AFNetworking的网络申请 小结 前言 笔者这周主要学习了第三方库AFNetworking的使用,这里笔者…...
如何从模块内部运行 Pytest
在 Python 中,pytest 是一个强大的测试框架,用于编写和运行测试用例。通常我们会在命令行中运行 pytest,但是有时你可能希望从模块或脚本的内部运行 pytest,比如为了自动化测试或集成到某个工作流程中。 1、问题背景 当你从模块…...
oracle数据库---基本查询(单表查询、多表查询、子查询、分页查询、oracle内置函数、行列转换、集合运算)
思维导图 单表查询 数据准备 -- 练习的表如果存在 请先删除 -- 如果不存在直接创建 drop table t_owners;--业主表 create table t_owners (id number primary key,name varchar2(30),addressid number,housenumber varchar2(30),watermeter varchar2(30),adddate date,owner…...
web API基础
作用和分类 作用: 就是使用 JS 去操作 html 和浏览器 分类: DOM (文档对象模型)、 BOM (浏览器对象模型) 什么是DOM DOM (Document Object Model) 译为文档对象模型,是 HTML 和 XML 文档的编程接口。 HTML DOM 定义了访问和操作 …...
【C++】创建TCP服务端
实现了一个基本的 TCP 服务器,可以接受多个客户端连接,然后持续接收客户端发送的信息, 最后将接收到的信息再发送回客户端 。 源码 头文件(TCPServerTest.h) #include <iostream> #include <winsock2.h&g…...
每天练打字6:今日状况——常用字后五百击键3第2遍已完成,赛文速度93.56
今日跟打:763字 (截至当前) 总跟打:120408字 记录天数:2467天 (实际没有这么多天,这个是注册账号的天数) 平均每天:48字 本周目标完成进度: 练习常用单字后5…...
rk3568创建基于Ubuntu18.04交叉编译遇到的坑
尽管配置过rk3288,觉得rk3568也不会有啥问题,但还是掉坑了。 一、安装依赖库 安装完ubuntu后,先进行升级 sudo apt update sudo apt upgrade然后安装依赖库 $ sudo apt-get install repo git-core gitk git-gui gcc-arm-linux-gnueabihf u-…...
对“一个中心,三重防护”中安全管理中心的理解
安全管理中心 本控制项为网络安全等级保护标准的技术部分。本项主要包括系统管理、审计管理、安全管理和集中管控四个控制点,其中的集中管控可以说是重中之重,主要都是围绕它来展开的。 28448基本要求中安全管理中心 8.1.5 安全管理中心 8.1.5.1 系统…...
jmeter用csv data set config做参数化1
在jmeter中,csv data set config的作用非常强大,用它来做批量测试和参数化非常好用。 csv data set config的常用配置项如下: Variable Names处,写上源文件中的参数名,用于后续接口发送请求时引用 Ignore first line…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
