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

EasyExcel之动态表头导出不生效

今天接到一个优化需求,表格导出后的表头顺序和页面不一致,要优化成一致的。根据传入的字段,动态导出数据,并保证顺序。
我看到导出的实体类都有@ExcelProperty注解,同时也在官网查看了这注解的含义和使用。

@ExcelProperty有两个属性可以帮我们排序:index和order,所以我就想每次在去写excel的时候,对映射类字段的index去动态排序。
注意index的使用

  • index的值相同时会抛出异常
  • index的值不连续时会插入空白列

然后想直接用反射动态修改index

    /**** @param headList 前端上送的动态表头* @param clazz 导出实体类的class对象*/private static void handleExcelHead(List<String> headList, Class<?> clazz) {try {for (String excelHead : headList) {Field declaredField = clazz.getDeclaredField(excelHead);ExcelProperty annotation = declaredField.getAnnotation(ExcelProperty.class);InvocationHandler invocationHandler = Proxy.getInvocationHandler(annotation);Field field = invocationHandler.getClass().getDeclaredField("memberValues");field.setAccessible(true);Map<String, Object> memberValues = (Map<String, Object>) field.get(invocationHandler);memberValues.put("index", headList.indexOf(excelHead));}}catch (Exception e){e.printStackTrace();}}

完整代码如下:

public class Test {public static void main(String[] args) throws Exception {List<String> headList = new ArrayList<>();headList.add("name");headList.add("sex");headList.add("age");// 动态处理表头handleExcelHead(headList,User.class);EasyExcel.write("test.xlsx").head(User.class).sheet("test").includeColumnFiledNames(headList).doWrite(init());}/**** @param headList 前端上送的动态表头* @param clazz 导出实体类的class对象*/private static void handleExcelHead(List<String> headList, Class<?> clazz) {try {for (String excelHead : headList) {Field declaredField = clazz.getDeclaredField(excelHead);ExcelProperty annotation = declaredField.getAnnotation(ExcelProperty.class);InvocationHandler invocationHandler = Proxy.getInvocationHandler(annotation);Field field = invocationHandler.getClass().getDeclaredField("memberValues");field.setAccessible(true);Map<String, Object> memberValues = (Map<String, Object>) field.get(invocationHandler);memberValues.put("index", headList.indexOf(excelHead));}}catch (Exception e){e.printStackTrace();}}private static List<User> init() {List<User> userList = new ArrayList<>();for (int i = 0; i < 10; i++) {User user = new User();user.setName("test"+i);user.setSex("男");user.setAge(20 + i);userList.add(user);}return userList;}
}

代码运行后发现和预期结果一样。但是当我则调整表头顺序并增加表头后发现不生效了。后来debug发现由于使用的是class对象,只要这个jvm不重启或者这个对象不被回收修改的index就一直存在,所以我们每次应该把index恢复成默认值。但是发现还是不行。后来在想这框架应该是使用了缓存吧,毕竟导出实体是固定的。果然:

ClassUtils 这里使用了缓存

    public static final Map<Class<?>, FieldCache> FIELD_CACHE = new ConcurrentHashMap<>();private static FieldCache declaredFields(Class<?> clazz) {if (clazz == null) {return null;}return FIELD_CACHE.computeIfAbsent(clazz, key -> {List<Field> tempFieldList = new ArrayList<>();Class<?> tempClass = clazz;// When the parent class is null, it indicates that the parent class (Object class) has reached the top// level.while (tempClass != null) {Collections.addAll(tempFieldList, tempClass.getDeclaredFields());// Get the parent class and give it to yourselftempClass = tempClass.getSuperclass();}// Screening of fieldMap<Integer, List<Field>> orderFieldMap = new TreeMap<Integer, List<Field>>();Map<Integer, Field> indexFieldMap = new TreeMap<Integer, Field>();Map<String, Field> ignoreMap = new HashMap<String, Field>(16);ExcelIgnoreUnannotated excelIgnoreUnannotated = clazz.getAnnotation(ExcelIgnoreUnannotated.class);for (Field field : tempFieldList) {declaredOneField(field, orderFieldMap, indexFieldMap, ignoreMap, excelIgnoreUnannotated);}return new FieldCache(buildSortedAllFieldMap(orderFieldMap, indexFieldMap), indexFieldMap, ignoreMap);});}

这下难住我了,这个缓存也不刷新。后来想他把缓存放在map里,key是Class,我直接每次都给他remove不就可以了。加了一行代码放在处理表头前边,果然可行!

ClassUtils.FIELD_CACHE.remove(User.class);

相关文章:

  • 2024年06月在线IDE流行度最新排名
  • 数字化校园建设让学习更加广阔
  • spring的加载过程
  • 【机器学习】——驱动智能制造的青春力量,优化生产、预见故障、提升质量
  • 深入解析JVM堆内存管理:对象流转与优化策略全揭秘
  • d2-crud-plus 使用小技巧(六)—— 表单下拉选择 行样式 溢出时显示异常优化
  • 如何在Java中安全地在列表中插入元素
  • element-plus 自定义命名空间 el-config-provider namespace 不起作用,html 的class值改变了,但是样式不对
  • 【中年危机】程序猿自救指南
  • 【C#】多线程中,跨线程实现对UI控件更新
  • 【并发程序设计】15.信号灯(信号量)
  • 企业百度百科词条怎么修改
  • Python 将Word、Excel、PDF、PPT文档转为OFD文档
  • 使用老毛桃制作USB安装盘并安装WIN10系统完整过程
  • 基于SpringBoot+Vue租房网站设计和实现(源码+LW+部署文档+讲解等)
  • $translatePartialLoader加载失败及解决方式
  • CSS实用技巧
  • ES6 学习笔记(一)let,const和解构赋值
  • ES学习笔记(12)--Symbol
  • JavaScript学习总结——原型
  • java架构面试锦集:开源框架+并发+数据结构+大企必备面试题
  • Java面向对象及其三大特征
  • Meteor的表单提交:Form
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • oldjun 检测网站的经验
  • Python打包系统简单入门
  • Sublime Text 2/3 绑定Eclipse快捷键
  • 从输入URL到页面加载发生了什么
  • 关于 Cirru Editor 存储格式
  • 回顾2016
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 力扣(LeetCode)22
  • 浅谈web中前端模板引擎的使用
  • 区块链技术特点之去中心化特性
  • 微信支付JSAPI,实测!终极方案
  • 用 Swift 编写面向协议的视图
  • 你对linux中grep命令知道多少?
  • UI设计初学者应该如何入门?
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • ​1:1公有云能力整体输出,腾讯云“七剑”下云端
  • ​Java并发新构件之Exchanger
  • ​Z时代时尚SUV新宠:起亚赛图斯值不值得年轻人买?
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • ​香农与信息论三大定律
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • #{}和${}的区别是什么 -- java面试
  • #NOIP 2014#day.2 T1 无限网络发射器选址
  • #微信小程序(布局、渲染层基础知识)
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • (1)SpringCloud 整合Python
  • (2)空速传感器
  • (C++)栈的链式存储结构(出栈、入栈、判空、遍历、销毁)(数据结构与算法)
  • (附源码)ssm基于web技术的医务志愿者管理系统 毕业设计 100910
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (企业 / 公司项目)前端使用pingyin-pro将汉字转成拼音