esayExcel自定义注解导出表头批注

article/2025/7/18 14:50:16

注解

package com.baidu.activitidemo.annotation;import com.baidu.activitidemo.handler.ExcelRemarkHandler;import java.lang.annotation.*;/*** 设置表头的批注, 需要配合{@link ExcelRemarkHandler}使用** @author li* @date 2022/09/24*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExcelRemark {/*** 一般使用此属性的值进行批注的填充** @return {@link String[]}*/String value() default "";/*** 慎用此属性,建议使用value* 此处值应为一个SpEL,返回值需要是一个String* 此表达式若有值(无论是否调用是否成功),则会忽略value属性* 使用示例:#root.getBean('userService')?.getSelectedList('2')* 此处的使用示例中的 #root指的是applicationContext** @return {@link String}*/String dynamicAccess() default "";/*** 批注所在行,一般不用设置,代码自动判断* -1表示自动获取头的最后一个行** @return int*/int remarkRow() default -1;/*** 批注行高, 一般不用设置** @return*/int remarkRowHigh() default 0;/*** 批注列宽, 根据导出情况调整** @return*/int remarkColumnWide() default 0;}

Handler

package com.baidu.activitidemo.handler;import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.write.handler.RowWriteHandler;
import com.alibaba.excel.write.handler.context.RowWriteHandlerContext;
import com.baidu.activitidemo.annotation.ExcelRemark;
import com.baidu.activitidemo.config.SpringContextUtil;
import lombok.Data;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.CollectionUtils;import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;/*** 设置表头的批注, 需要配合注解{@link ExcelRemark}使用* eg:EasyExcel.write(fileName, Person.class).registerWriteHandler(new ExcelRemarkHandler(Person.class))** @author lxh* @date 2022/9/24 17:30*/
public class ExcelRemarkHandler<T> implements RowWriteHandler {/** 解析后的下拉数据 */private Map<Integer, ExcelRemarkResolve> excelRemarkResolveMap;/** spring表达式解析器 */private SpelExpressionParser spelExpressionParser;/** 标准上下文 */private StandardEvaluationContext standardEvaluationContext;/** 需要解析的类 */private Class<T> clazz;public ExcelRemarkHandler(Class<T> clazz) {this.clazz = clazz;//解析注解this.analysisAnnotation();}@Overridepublic void afterRowCreate(RowWriteHandlerContext context) {if (CollectionUtils.isEmpty(excelRemarkResolveMap)) {return;}if (context.getHead()) {Sheet sheet = context.getWriteSheetHolder().getSheet();Drawing<?> drawingPatriarch = sheet.createDrawingPatriarch();excelRemarkResolveMap.forEach((column, v) -> {//若当前行与解析数据后的批注行不一样,则跳过if (v.row != context.getRow().getRowNum()) {return;}//v.column, v.row决定批注放在哪个单元格, v.remarkColumnWide, v.remarkRowHigh决定单元个的长宽Comment comment =drawingPatriarch.createCellComment(new XSSFClientAnchor(0, 0, 0, 0,v.column, v.row, v.remarkColumnWide, v.remarkRowHigh));// 输入批注信息comment.setString(new XSSFRichTextString(v.getRemarkValue()));// 将批注添加到单元格对象中,这后面的的代码不知何用,删除的话,批注也能添加上Row row = sheet.getRow(v.row);if (row == null) {row = sheet.createRow(v.row);}Cell cell = row.getCell(v.column);if (cell == null) {cell = row.createCell(v.column);}cell.setCellComment(comment);});}}/*** 解析注释** @return {@link List}<{@link ExcelRemarkResolve}>*/private Map<Integer, ExcelRemarkResolve> analysisAnnotation() {Map<Integer, ExcelRemarkResolve> map = new TreeMap<>();//SpEL解析器//getDeclaredFields(): 返回全部声明的属性;getFields(): 返回public类型的属性Field[] fields = clazz.getDeclaredFields();for (int i = 0; i < fields.length; i++) {Field field = fields[i];//解析注解信息ExcelIgnore ignore = field.getAnnotation(ExcelIgnore.class);if (ignore != null) {continue;}//解析注解信息ExcelRemark remark = field.getAnnotation(ExcelRemark.class);if (remark != null) {ExcelRemarkResolve resolve = new ExcelRemarkResolve();String dynamicAccess = remark.dynamicAccess();if (dynamicAccess == null || dynamicAccess.isEmpty()) {//直接获取注解中的值resolve.setRemarkValue(remark.value());} else {//调用SpEL解析器resolve.setRemarkValue(this.getrRemarkValueFormApplicationContext(dynamicAccess));}if (resolve.getRemarkValue() == null || resolve.getRemarkValue().length() <= 0) {continue;}//解析注解信息ExcelProperty property = field.getAnnotation(ExcelProperty.class);if (property != null && property.index() >= 0) {resolve.setColumn(property.index());} else {resolve.setColumn(i);}resolve.setRemarkRowHigh(remark.remarkRowHigh());resolve.setRemarkColumnWide(remark.remarkColumnWide());//设置批注所在行,若都没执行,***则使用int初始化的默认值0***if (remark.remarkRow() != -1) {resolve.setRow(remark.remarkRow());} else if (property != null) {//length属性为元素个数,此处需转换算成indexresolve.setRow(property.value().length - 1);}//将参数放入集合map.put(resolve.getColumn(), resolve);}}this.excelRemarkResolveMap = map;return map;}/*** 调用上下文中的方法,动态获取下拉值** @param dynamicAccess 动态访问* @return {@link String}*/private String getrRemarkValueFormApplicationContext(String dynamicAccess) {if (spelExpressionParser == null) {this.spelExpressionParser = new SpelExpressionParser();}if (standardEvaluationContext == null) {standardEvaluationContext = new StandardEvaluationContext(SpringContextUtil.getApplicationContext());}Expression expression = spelExpressionParser.parseExpression(dynamicAccess);Object value = expression.getValue(standardEvaluationContext);return value.toString();}@Dataprivate class ExcelRemarkResolve {/** 列号 */private Integer column;/** 批注值 */private String remarkValue;/** 批注行高 */int remarkRowHigh;/** 批注列宽 */int remarkColumnWide;/*** 批注所在行** @return int*/int row;}
}

spring上下文工具

package com.baidu.activitidemo.config;import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;/*** spring上下文工具* @author lxh* @date 2022/9/24 13:17*/@Component
public class SpringContextUtil implements ApplicationContextAware {private static ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {SpringContextUtil.applicationContext = applicationContext;}/*** 获取ApplicationContext** @return {@link ApplicationContext}*/public static ApplicationContext getApplicationContext() {return applicationContext;}/*** 通过class获取Bean** @param clazz clazz* @return {@link T}*/public static <T> T getBean(Class<T> clazz) {return applicationContext.getBean(clazz);}/*** 通过name以及class获取Bean** @param name  名字* @param clazz clazz* @return {@link T}*/public static <T> T getBean(String name, Class<T> clazz) {return applicationContext.getBean(name, clazz);}}

使用示例

package com.baidu.activitidemo.entity;import com.alibaba.excel.annotation.ExcelProperty;
import com.baidu.activitidemo.annotation.ExcelRemark;
import com.baidu.activitidemo.annotation.ExcelSelected;
import lombok.Data;import java.time.LocalDateTime;/*** @author lxh* @date 2022/7/24 10:32*/
@Data
public class Person {@ExcelProperty("用户名")private String userName;@ExcelProperty(value = "年龄")private String userAge;@ExcelRemark(value = "编号只能从下拉框中选择\n否则无法通过校验")@ExcelSelected(value = {"code_001", "code_002"})@ExcelProperty(value = "编号")private String code;@ExcelProperty("创建时间")private LocalDateTime createTime;
}@Test
void contextLoads() {List<Person> list = new ArrayList<>();list.add(new Person());String fileName = "D:\\temp\\" + System.currentTimeMillis() + ".xlsx";EasyExcel.write(fileName, Person.class).registerWriteHandler(new ExcelRemarkHandler(Person.class)).sheet("模板").doWrite(list);}

大部分从网上搬的

主要来源:

Easyexcel生成excel并通过自定义注解实现下拉框以及动态下拉框(将数据库中的数据显示在excel下拉框中)EasyExcel在项目中的应用-在web中导出带下拉框和批注的excel文件


http://chatgpt.dhexx.cn/article/UYuBOsUK.shtml

相关文章

把Excel批注的“红三角”放在单元格左上角_Excel的批注功能,全部知道的不足10%,你会用的仅仅是冰山一角...

Excel【审阅】功能区中,显示了5个最基本的功能,如下图红色矩形框所示,这也是我们最常用的基础。其实,Excel中批注的相关操作远不止这些,一起来看看。 插入删除批注 【插入批注】 插入批注的方法常见的有这3种: ❶ 【审阅】→【新建批注】。 ❷ 单元格点击右键,插入批注。…

Excel批注教学:一键添加多个不同批注

今天要和大家分享的是Excel一键添加多个不同批注&#xff0c;看下面终端经销商反馈函件的统计表&#xff0c;想把最后一列的反馈情况&#xff0c;对应的添加为经销商的批注内容&#xff0c;如何操作呢 &#xff08;方方格子插件&#xff09; 1.选中需要添加批注的单元格 ​ 2.…

word保存html格式批注没有了,word批注不见了 怎么显示批注

为什么word批注里的字都没有了,怎么恢复? 文档处于修订状态,需要关闭它。 在退出修订模式前需要作以操作:1、接受或拒绝修改:审阅--更改--接受/拒绝,根据需要进行设置;2、显示最终状态:审阅--修订--显示最终状态(显示以供审阅),选择“最终状态”;退出修订模式:审阅--…

WPS表格Excel:提取批注到单元格(宏实现)

问题和目标&#xff1a;将带批注的数据 Public Function Pz(x As Range) Pz x.Cells.Comment.Text End Function 然后&#xff0c;在EXCEL中输入 Pz(A1) 就返回A1的批注内容了 打开VB编辑器&#xff08;wps收费&#xff0c;office可用AltF11打开VB编辑界面&#xff09; 插入模…

C# 如何在Excel表格中插入、编辑和删除批注(二)修改、隐藏Excel批注

修改、隐藏Excel批注 更多文章:http://www.iis7.com/ 步骤1&#xff1a;创建一个Workbook类对象&#xff0c;并加载Excel文档 Workbook workbook new Workbook(); workbook.LoadFromFile(“AddComment.xlsx”); 步骤2&#xff1a;获取第一个工作表 Worksheet sheet wor…

Excel答粉丝问:批量将单元格内容转为批注

点赞再看&#xff0c;养成习惯&#xff1b;烈士暮年&#xff0c;壮心不已。 微信搜索【亦心Excel】关注这个不一样的自媒体人。 本文 GitHub https://github.com/hugogoos/Excel 已收录&#xff0c;包含Excel系统学习指南系列文章&#xff0c;以及各种Excel资料。 前几天有粉丝…

更改Excel单元格中批注的显示位置

当在Excel中插入一个批注时&#xff0c;你可以把它调整到不同的位置(如 单元格的左边等等)。但是有一个问题&#xff0c;当把批注的显示方式更改为 只显示标示符 后。你移到鼠标到单元格上时批注还是恢复初始的位置-即显示单元格的右方。下面这个小程序就可以 解决这个问题。 O…

Excel中怎么添加批注

大家在做表格的时候&#xff0c;经常会遇到需要添加批注的情况&#xff0c;那么怎样添加、修改和删除批注呢&#xff1f;今天就用常用的speedoffice和大家分享一下。 1&#xff0c;首先运行office软件&#xff0c;新建一份表格&#xff0c;选中需要添加批注的单元格。 2&#…

把Excel批注的“红三角”放在单元格左上角_excel批注的玩法,看看你会几个

说道Excel批注,有许多用处和插入方法,今天带大家来看看! 1、插入批注 方法一:在【审阅】选项卡下【批注】组中点【新建批注】方法二:点鼠标右键,选择【插入批注】方法三:按键,快速插入批注2、删除批注 方法一:选中带批注单元格,在【审阅】选项卡下【批注】组中点【删…

C# 在Excel文档中显示或隐藏批注

在Excel文档中插入批注默认情况是不会显示的&#xff0c;如果插入的批注多了&#xff0c;想一次性快速查看所有批注就会比较麻烦。此时我们可以选中插入批注的单元格&#xff0c;然后单击菜单栏“审阅”选项卡“批注”功能区中的“显示或隐藏批注”选项来更改批注的显示状态。本…

Excel一键将批注内容显示,替换单元格内容

如下图所示&#xff0c;菜的价格为批注内容&#xff0c;想把菜价统一替换了当前单元格的内容&#xff0c;如何操作呢&#xff1f; &#xff08;方方格子插件&#xff09; 1.先看动图演示 2.选中数据区域 3.选择diy工具箱 4.选择批注中的导出批注 5.选择导出到批注所在单元格 …

excel批注不显示批注框_批注和批注处理器入门指南[解释]

excel批注不显示批注框 在Java中&#xff0c;大多数情况下&#xff0c;批注和批注处理器都被一团谜团包围。 他们看起来像是为“专家”保留的主题。 最重要的是&#xff0c;我相信他们周围也有一些FUD。 这篇文章旨在以最中立的方式深入探讨该主题。 这样&#xff0c;每个人都…

Error LNK2005 DllMain already defined in dllmain.obj

问题描述&#xff1a; 在创建Win32动态库时&#xff0c;使用了MFC库。 原因分析&#xff1a; MFC库中存在DllMain&#xff0c;与现有的DllMain重复 解决方案&#xff1a; 1.删除现有的DllMain函数 2.在工程设置里面&#xff0c;把WIN32,NDEBUG,_WINDOWS,_MBCS,_USRDLL,MS…

C++-导出类-导出宏-纯虚函数-DllMain函数-调用约定与参数命名

文章目录 1.普通类导出2.接口类导出3.调用约定与参数命名4.名字修饰约定5.MFC导出宏6.DLLMain函数7.一个DLL在内存中只有一个实例 在编写应用软件时&#xff0c;代码重用是非常关键的一步&#xff0c;C编程语言里&#xff0c;为了使编写的dll文件&#xff0c;能够实现重用&…

9.DLL的入口函数DllMain函数

1.dll的入口函数 类似程序的入口函数main或者WinMain一样&#xff0c;DLL也有一个入口函数&#xff0c;就是DllMain 2.DllMain函数原型 BOOL APIENTRY DllMain( HMODULE hModule, //指向自身的句柄DWORD ul_reason_for_call, //调用原因LPVOID lpReserved …

导致DllMain中死锁的关键隐藏因子

原文地址&#xff1a;https://blog.csdn.net/hczhiyue/article/details/18505087 有了前面两节的基础&#xff0c;我们现在切入正题&#xff1a;研究下DllMain为什么会因为不当操作导致死锁的问题。首先我们看一段比较经典的“DllMain中死锁”代码。 //主线程中 HMODULE h …

DllMain详解

DllMain详解 源码下载&#xff1a; DLL – 动态链接库 DllMainTest – 测试DLL的DllMain 1 DLL的进入/退出函数 1.1 DllMain简介 跟exe有个main或者WinMain入口函数一样&#xff0c;DLL也有一个入口函数&#xff0c;就是DllMain。以“DllMain”为关键字&#xff0c;来看看MSD…

Flash 加密和破解

关于Flash&#xff08;swf&#xff09;&#xff0c;我们需要明确一点&#xff1a; ***Flash字节码的意义都是公开的 所以如果cracker真的有足够的耐心他最终还是可以破解掉你的Flash。我们能做的只是尽量提高Flash被破解的门槛让cracker破解它需要消耗的时间大于自己更新版本的…

flashfxp是ftp软件吗,你知道flashfxp是ftp软件吗

flashfxp是ftp软件吗&#xff1f;当然。ftp是一种文件传输协议&#xff0c;用于互联网双向传输&#xff0c;控制文件下载空间在服务器复制文件从本地计算机或本地上传文件复制到服务器上。而FlashFXP是一款功能强大的FXP/FTP软件&#xff0c;集成了其它优秀的FTP软件的优点&…

pfx证书解析公钥私钥

从pfx中获取CA证书 openssl pkcs12 -in test.pfx -nodes -out server.pem 输入证书密码 提取公钥 X.509格式 openssl x509 -in server.pem -out public.cer RSA格式 openssl rsa -in server.pem -outform PEM -pubout -out public.pem 提取私钥 openssl rsa -in server…