EasyExcel自定义下拉注解的三种实现方式

在这里插入图片描述

文章目录

  • 一、简介
  • 二、关键组件
    • 1、ExcelSelected注解
    • 2、ExcelDynamicSelect接口(仅用于方式二)
    • 3、ExcelSelectedResolve类
    • 4、SelectedSheetWriteHandler类
  • 三、实际应用
  • 总结

一、简介

  在使用EasyExcel设置下拉数据时,每次都要创建一个SheetWriteHandler组件确实比较繁琐。为了优化这个过程,我们可以通过自定义注解来简化操作,使得只需要在需要添加下拉数据的字段上添加注解即可。

注解实现三种方式可供选择

  • 方式一:固定值
  • 方式二:动态获取复杂数据
  • 方式三:通过码值获取码值表的数据列表

二、关键组件

1、ExcelSelected注解

  • 用于在数据模型类中标注需要添加下拉列表的字段及其属性
  • 三种方式都是通过此注解实现
/*** 定义Excel列下拉列表属性的注解。*/
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelSelected {/*** 方式一:固定的下拉选项*/String[] source() default {};/*** 方式二:提供动态下拉选项的类*/Class<? extends ExcelDynamicSelect>[] sourceClass() default {};/*** 方式三:基于码值从数据库查询数据*/String codeField() default "";/*** 下拉列表的起始行(默认从第二行开始)。*/int firstRow() default 1;/*** 下拉列表的结束行(默认到第65536行)。*/int lastRow() default 65536;
}

2、ExcelDynamicSelect接口(仅用于方式二)

  • 方式二定义动态获取下拉列表数据的规范
  • 实现该接口的类可以从数据库、外部服务或其他动态来源获取数据

/*** 动态下拉列表数据提供者接口。*/
public interface ExcelDynamicSelect {/*** 获取动态生成的下拉列表选项。* * @return 下拉选项数组。*/String[] getSource();
}

3、ExcelSelectedResolve类

  • 负责解析ExcelSelected注解,获取下拉列表的具体数据
/*** 根据 ExcelSelected 注解解析下拉列表数据源。*/
@Data
@Slf4j
public class ExcelSelectedResolve {/*** 下拉选项数组。*/private String[] source;/*** 下拉列表的起始行。*/private int firstRow;/*** 下拉列表的结束行。*/private int lastRow;/*** 解析下拉列表数据来源** @param excelSelected 下拉框注解对象* @return 下拉框选项数组*/public String[] resolveSelectedSource(ExcelSelected excelSelected) {if (excelSelected == null) {return null;}// 方式一:获取固定下拉框的内容String[] source = excelSelected.source();if (source.length > 0) {return source;}// 方式二:获取动态下拉框的内容Class<? extends ExcelDynamicSelect>[] classes = excelSelected.sourceClass();if (classes.length > 0) {try {ExcelDynamicSelect excelDynamicSelect = classes[0].newInstance();String[] dynamicSelectSource = excelDynamicSelect.getSource();if (dynamicSelectSource != null && dynamicSelectSource.length > 0) {return dynamicSelectSource;}} catch (InstantiationException | IllegalAccessException e) {log.error("解析动态下拉框数据异常", e);}}// 方式三:获取码值下拉数据(动态下拉)String codeField = excelSelected.codeField();if (ObjectUtils.isNotEmpty(codeField)) {try {// 这里就是通过码值查询码值表,写死了,每次传码值查询即可String[] codeFieldSource = SpringUtil.getBean(xxxService.class).selectByCode(codeField);if (ObjectUtils.isNotEmpty(codeFieldSource)) {return codeFieldSource;}} catch (Exception e) {log.error("解析动态下拉框(码值)数据异常", e);}}return null;}
}

4、SelectedSheetWriteHandler类

  • SheetWriteHandler实现类,在Sheet创建后设置下拉列表
  • 在隐藏的sheet中存储下拉选项,然后设置数据验证以实现下拉功能
  • 最后这里添加了阻止输入非下拉选项的值的校验
/*** 处理Excel下拉列表的SheetWriteHandler实现类。*/
@Slf4j
@Data
public class SelectedSheetWriteHandler implements SheetWriteHandler {// 存储列索引与对应下拉列表解析器的映射private Map<Integer, ExcelSelectedResolve> selectedMap = new HashMap<>();/*** 构造方法,解析表头类中的下拉列表注解信息。** @param head 表头类。*/public SelectedSheetWriteHandler(Class<?> head) {// 获取所有声明的字段Field[] fields = head.getDeclaredFields();for (int i = 0; i < fields.length; i++) {Field field = fields[i];// 获取 ExcelSelected 注解ExcelSelected selected = field.getAnnotation(ExcelSelected.class);ExcelProperty property = field.getAnnotation(ExcelProperty.class);if (selected != null) {ExcelSelectedResolve resolve = new ExcelSelectedResolve();// 解析下拉列表数据源String[] source = resolve.resolveSelectedSource(selected);if (source != null && source.length > 0) {resolve.setSource(source);resolve.setFirstRow(selected.firstRow());resolve.setLastRow(selected.lastRow());// 使用注解中的索引或字段顺序作为列索引if (property != null && property.index() >= 0) {selectedMap.put(property.index(), resolve);} else {selectedMap.put(i, resolve);}}}}}/*** 在创建Sheet之前调用的方法。*/@Overridepublic void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {// 此处无需操作,保持空实现}/*** 在Sheet创建后调用的方法,用于设置Excel下拉列表。** @param writeWorkbookHolder 写入的工作簿持有者。* @param writeSheetHolder    写入的Sheet持有者。*/@Overridepublic void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {Sheet sheet = writeSheetHolder.getSheet();Workbook workbook = sheet.getWorkbook();// SXSSFWorkbook 是 Apache POI 库中用于处理大文件的一种特殊工作簿类型SXSSFWorkbook sw = (SXSSFWorkbook) workbook;// 1.创建一个隐藏的sheet,名称为hidden,用于存储下拉列表选项String hiddenName = "hidden";XSSFSheet hiddenSheet = sw.getXSSFWorkbook().createSheet(hiddenName);// 将隐藏的sheet设置为不可见workbook.setSheetHidden(workbook.getSheetIndex(hiddenName), true);// 创建数据验证辅助器DataValidationHelper helper = sheet.getDataValidationHelper();// 为每个需要下拉列表的列创建数据验证selectedMap.forEach((index, selectedResolve) -> {// 设置下拉列表的范围:起始行,结束行,起始列,结束列CellRangeAddressList rangeList = new CellRangeAddressList(selectedResolve.getFirstRow(),selectedResolve.getLastRow(),index,index);// 在隐藏的sheet中生成下拉列表选项值String[] values = selectedResolve.getSource();generateSelectValue(hiddenSheet, index, values);// 获取Excel列标,例如A, B, AAString excelLine = getExcelLine(index);// 引用隐藏sheet中的单元格区域,例如hidden!$H$1:$H$50String refers = hiddenName + "!$" + excelLine + "$1:$" + excelLine + "$" + values.length;// 使用引用的内容作为下拉列表的值DataValidationConstraint constraint = helper.createFormulaListConstraint(refers);DataValidation validation = helper.createValidation(constraint, rangeList);// 设置验证属性,阻止输入非下拉选项的值validation.setErrorStyle(DataValidation.ErrorStyle.STOP);validation.setShowErrorBox(true);validation.setSuppressDropDownArrow(true);validation.createErrorBox("提示", "请输入下拉选项中的内容");// 将验证添加到当前的sheet中sheet.addValidationData(validation);});}/*** 获取Excel列标(例如:A-Z, AA-ZZ)。** @param num 列索引,从0开始。* @return Excel列标字符串。*/public static String getExcelLine(int num) {StringBuilder line = new StringBuilder();// 计算列标,使用字母表示,例如 A, B, ..., Z, AA, AB, ...int first = num / 26;int second = num % 26;if (first > 0) {line.append((char) ('A' + first - 1));}line.append((char) ('A' + second));return line.toString();}/*** 在隐藏的sheet中生成下拉列表选项值。** @param sheet  隐藏的sheet对象。* @param col    列索引。* @param values 下拉列表选项值数组。*/private void generateSelectValue(Sheet sheet, int col, String[] values) {// 将下拉列表选项值写入隐藏的sheet中,每个选项值占用一行for (int i = 0, length = values.length; i < length; i++) {Row row = sheet.getRow(i);if (row == null) {row = sheet.createRow(i);}// 在指定列中创建单元格并设置下拉列表选项值row.createCell(col).setCellValue(values[i]);}}
}

三、实际应用

  • 包含三种方式,固定值、动态获取、码值数据库获取
@Data
public class Employee {@ExcelProperty(value = "用户编号")private Integer id;@ExcelProperty(value = "姓名")private String name;@ExcelProperty(value = "性别")@ExcelSelected(source = {"男", "女"})private String gender;@ExcelProperty(value = "职位")@ExcelSelected(sourceClass = {PositionDynamicSelect.class})private String position;@ExcelProperty(value = "国家")@ExcelSelected(codeField = "country_code")private String country;
}
  • 方式二的动态获取数据
public class PositionDynamicSelect implements ExcelDynamicSelect {@Overridepublic String[] getSource() {// 动态生成职位列表return new String[]{"软件工程师", "项目经理", "人事专员", "财务分析师"};}
}
  • 测试类
public class EmployeeExcelTest {public static void main(String[] args) {String fileName = "/Users/xuchang/Documents/employee.xlsx";EasyExcel.write(fileName, Employee.class).registerWriteHandler(new SelectedSheetWriteHandler(Employee.class)).sheet().doWrite((Collection<?>) null);}
}
  • 下拉效果

在这里插入图片描述

  • 输入非下拉框数据效果

在这里插入图片描述

总结

  • 方式一只需要添加注解@ExcelSelected(source = {"x1", "x2"})即可
  • 方式二在查询复杂的情况下使用,每个下拉都需要创建一个ExcelDynamicSelect的实现类,并添加注解@ExcelSelected(sourceClass = {xxx.class})
  • 方式三只需要添加注解@ExcelSelected(codeField = "xxx_code"),所有系统应该都有码值表,在ExcelSelectedResolve类中已写好通过码值查询数据的方法
  • 同样也支持@ExcelSelected注解的扩展,添加属性,然后在ExcelSelectedResolve类中去添加获取下拉数据的方法。

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

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

相关文章

【vs2022】windows可用的依赖预编译库

ffmpeg 、x264 、x265 等。obs是基于qt6+vs2022+64bit obs的官网传统构建已经不用了obs的s2022构建OBS Deps Build 2024-09-12FFmpeg4.4 库,x64 可用。

每天五分钟深度学习pytoroch:基于pytorch搭建逻辑回归算法模型

本文重点 前面我们学习了线性回归模型的搭建,无论是基于pytorch还是不基于pytorch,以上的模型都是回归模型,本文我们将使用pytorch搭建逻辑回归模型,逻辑回归模型是一个经典的分类问题。 模型搭建 class LogisticRegression(nn.Module) : def __init__(self) :super (Lo…

嵌入式软件 Bug 排查与调试技巧

目录 1、准备工作 2、打印调试 实现步骤 注意事项 3、断点调试 4、观察点调试 5、远程调试 6、内存分析 内存泄漏检测 栈溢出检测 7、异常处理 8、性能分析 9、逻辑分析仪 10、示波器 11、常见bug类型 12、调试策略 1、准备工作 硬件工具准备 调试器:例如 J - …

玩转Docker | 使用Docker部署推箱子网页小游戏

玩转Docker | 使用Docker部署推箱子网页小游戏 一、项目介绍项目简介项目预览 二、系统要求环境要求环境检查Docker版本检查检查操作系统版本 三、部署推箱子网页小游戏下载镜像创建容器检查容器状态检查服务端口安全设置 四、访问推箱子网页小游戏五、总结 一、项目介绍 项目…

什么是服务器?服务器与客户端的关系?本地方访问不了网址与服务器访问不了是什么意思?有何区别

服务器是一种高性能的计算机&#xff0c;它通过网络为其他计算机&#xff08;称为客户端&#xff09;提供服务。这些服务可以包括文件存储、打印服务、数据库服务或运行应用程序等。服务器通常具有强大的处理器、大量的内存和大容量的存储空间&#xff0c;以便能够处理多个客户…

Iperius Backup(数据备份软件) v8.3.0 中文免费版

下载&#xff1a; 【1】https://pan.quark.cn/s/19ef716c02d5 【2】https://drive.uc.cn/s/197acba8d8d94?public1 Iperius Backup是一款专业的备份还原软件&#xff0c;功能强大&#xff0c;支持DAT备份、LTO备份、NAS备份、磁带备份、RDX驱动器、USB备份&#xff0c;满足用…

SOES(EtherCAT)从站API梳理

1. void ESC_config (esc_cfg_t * cfg); 功能&#xff1a;配置EtherCAT从站。参数&#xff1a;esc_cfg_t *cfg 指向配置结构体的指针&#xff0c;该结构体包含从站的配置参数。解释&#xff1a;该函数用于初始化或更新从站的配置&#xff0c;如通信参数、同步管理器设置等。 …

Java Lock Condition 总结

前言 相关系列 《Java & Lock & 目录》&#xff08;持续更新&#xff09;《Java & Lock & Condition & 源码》&#xff08;学习过程/多有漏误/仅作参考/不再更新&#xff09;《Java & Lock & Condition & 总结》&#xff08;学习总结/最新最准…

K8S测试pod内存和CPU资源不足

只设置requests参数 mysql主从pod启动后监控 读压测之后 同时设置limits和requests&#xff0c;只调低内存值 监控 压力测试 同时设置limits和requests&#xff0c;只调低CPU值 初始状态 开始压测 结论 对于CPU&#xff0c;如果pod中服务使用CPU超过设置的limits&…

谷歌云GCP基础概念讲解

概览 云的基础是虚拟化&#xff1a;服务器&#xff0c;存储&#xff0c;网络。服务器是远程计算机的逻辑分区。存储是物理硬盘的逻辑划分。网络则是虚拟私有云。 谷歌是唯一一个拥有全球私有基础设施的公司&#xff1b;他们的谷歌云基础设施没有任何一部分通过公共互联网。换句…

绿盟科技发布三季度报告,收入略增,亏损收窄,经营性净现金流同比翻倍

10月30日&#xff0c;绿盟科技发布2024年三季度报告。2024年公司前三季度实现营业收入12.74亿元&#xff0c;同比增长5.57%&#xff1b;毛利率59.50%&#xff0c;同比增长4.76个百分点&#xff1b;期间费用总额同比下降7.68%&#xff1b;公司实现归属于上市公司股东的净利润-3.…

【云原生】云原生后端详解:架构与实践

目录 引言一、云原生后端的核心概念1.1 微服务架构1.2 容器化1.3 可编排性1.4 弹性和可伸缩性 二、云原生后端的架构示意图三、云原生后端的最佳实践3.1 使用服务网格3.2 监控与日志管理3.3 CI/CD 流水线3.4 安全性 总结参考资料 引言 随着云计算的迅猛发展&#xff0c;云原生…

Python 爬虫的寻宝大冒险:如何捕获 API 数据的宝藏

在这个信息爆炸的数字时代&#xff0c;数据就像是隐藏在网络深处的宝藏&#xff0c;等待着勇敢的探险家去发现。今天&#xff0c;我们要讲述的是如何成为一名 Python 爬虫探险家&#xff0c;装备你的代码工具&#xff0c;深入 API 的迷宫&#xff0c;捕获那些珍贵的数据宝藏。 …

C++-类与对象总结

const函数声明 1. 修饰成员函数&#xff0c;不会改变成员变量&#xff1a; - a function b const (c){}: in member function means, all member properties in the function cannot be modified. 2.修饰形参&#xff0c;输入参数在函数中不会被更改&#xff0c;提高程序的…

《近似线性可分支持向量机的原理推导》 拉格朗日函数 公式解析

本文是将文章《近似线性可分支持向量机的原理推导》中的公式单独拿出来做一个详细的解析&#xff0c;便于初学者更好的理解。 公式 9-41 解释&#xff1a; L ( w , b , ξ , α , μ ) 1 2 ∥ w ∥ 2 C ∑ i 1 N ξ i − ∑ i 1 N α i ( y i ( w T x i b ) − ( 1 − ξ …

【云原生】云原生后端:安全性最佳实践

目录 引言一、身份管理1.1 身份验证1.2 身份授权 二、数据加密2.1 数据静态加密2.2 数据传输加密2.3 密钥管理 三、网络安全3.1 网络隔离3.2 防火墙与入侵检测3.3 安全组与网络访问控制列表 (NACL) 结论 引言 在云原生架构中&#xff0c;安全性是一个至关重要的考量。随着应用…

C++,STL 051(24.10.28)

内容 1.map容器的构造函数。 2.map容器的赋值操作。 运行代码 #include <iostream> #include <map>using namespace std;void printMap(map<int, int> &m) {for (map<int, int>::iterator it m.begin(); it ! m.end(); it){cout << &quo…

《链表篇》---环形链表II(返回节点)

题目传送门 方法一&#xff1a;哈希表&#xff08;与环形链表类似&#xff09; 很容易就可以找到链表的相交位置。 public class Solution {public ListNode detectCycle(ListNode head) {if(head null || head.next null){return null;}Set<ListNode> visited new Ha…

从0开始深度学习(17)——数值稳定性和模型初始化

在每次训练之前&#xff0c;都会对模型的参数进行初始化&#xff0c;初始化方案的选择在神经网络学习中起着举足轻重的作用&#xff0c; 它对保持数值稳定性至关重要。 我们选择哪个函数以及如何初始化参数可以决定优化算法收敛的速度有多快。 糟糕选择可能会导致我们在训练时遇…

重学SpringBoot3-怎样优雅停机

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-怎样优雅停机 1. 什么是优雅停机&#xff1f;2. Spring Boot 3 优雅停机的配置3. Tomcat 和 Reactor Netty 的优雅停机机制3.1 Tomcat 优雅停机3.2 Reac…