自定义导出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…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...

【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...