场景;在业务逻辑中,导出的时候需要给客户提供下载的模版,上传的文件有些字段值需要验证,如果不按照验证的规则,后端解析的时候就会失败,所以在导出模版需要给客户一个提示,一种方法是下载的模版中加入示例数据,另外一种就是在表头添加上备注。

以下是表头代码实现;

easyexcel 依赖以及对应的poi

  <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.1</version><exclusions><exclusion><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId></exclusion><exclusion><groupId>org.apache.poi</groupId><artifactId>poi</artifactId></exclusion><exclusion><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId></exclusion><exclusion><groupId>org.apache.poi</groupId><artifactId>poi-ooxml-schemas</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version></dependency>

easyexcel实体类

@Data
public class CtmsSubSaeExcel implements Serializable {/*** 受试者筛选号*/@ExcelProperty(value = "受试者筛选号",index = 0)@ColumnWidth(12)@ExcelValid(message = "受试者筛选号不能为空")@ExcelNotation(value = "受试者筛选号不能为空",remarkColumnWide =(short) 1)private String subjectCode;/*** SAE编号*/@ExcelProperty(value = "SAE编号唯一标识",index = 1)@ExcelValid(message = "SAE编号不能为空")@ColumnWidth(12)private String saeNum;@ExcelProperty(value = "SAE的医学术语",index = 2)@ColumnWidth(12)private String saeMedicalTerm;}

@ExcelValid ;校验必填字段

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelValid {String message() default "导入有未填入的字段";}

@ExcelNotation ;自定义备注注解 。注意 @ExcelProperty必须加上index 不然获取的时候会有问题

@Target(FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelNotation {/*** 文本内容*/String value() default "";/*** 批注行高, 一般不用设置* 这个参数可以设置不同字段 批注显示框的高度* @return*/int remarkRowHigh() default 0;/*** 批注列宽, 根据导出情况调整* 这个参数可以设置不同字段 批注显示框的宽度* @return*/int remarkColumnWide() default 0;

校验是否为空 工具

public class ExcelImportValid {/*** Excel导入字段校验* @param object 校验的JavaBean 其属性须有自定义注解*/public static void valid(Object object) {Field[] fields = object.getClass().getDeclaredFields();for (Field field : fields) {//设置可访问field.setAccessible(true);//属性的值Object fieldValue = null;try {fieldValue = field.get(object);} catch (IllegalAccessException e) {throw ServiceExceptionUtil.exception(new ErrorCode(9999,field.getAnnotation(ExcelValid.class).message()));}//是否包含必填校验注解boolean isExcelValid = field.isAnnotationPresent(ExcelValid.class);if (isExcelValid && Objects.isNull(fieldValue)) {// 返回自定义的异常 提示throw ServiceExceptionUtil.exception(new ErrorCode(9999,field.getAnnotation(ExcelValid.class).message()));}}}}

导入数据的监听器

public class SubSAEListener extends AnalysisEventListener<CtmsSubSaeExcel> {@Overridepublic void invoke(CtmsSubSaeExcel data, AnalysisContext context) {// 获取行号Integer rowIndex = context.readRowHolder().getRowIndex();// 校验必填ExcelImportValid.valid(data);// 操作数据值}@Overridepublic void onException(Exception exception, AnalysisContext context) throws Exception {batchAddList.clear();batchUpdateList.clear();super.onException(exception, context);}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 操作数据库}
}

备注使用的实体

@Data
public class ExcelComment {/** 列号 */private Integer column;/** 批注值 */private String remarkValue;/** 批注行高 */int remarkRowHigh;/** 批注列宽 */int remarkColumnWide;/*** 批注所在行** @return int*/int row;}

备注注册器

public class CommentCellWriteHandler implements CellWriteHandler {/*** 批注*/private final Map<Integer, ExcelComment> notationMap;public CommentCellWriteHandler(Map<Integer, ExcelComment> notationMap) {this.notationMap = notationMap;}@Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {// 这里使用isHead判断 是否是表头的时候为true ,填入数据的时候是false , 之前使用head判断,调整表头备注只能有一个,切记if(isHead){ Sheet sheet = writeSheetHolder.getSheet();Drawing<?> drawingPatriarch = sheet.createDrawingPatriarch();if (CollUtil.isNotEmpty(notationMap) && notationMap.containsKey(cell.getColumnIndex())) {// 批注内容ExcelComment excelComment = notationMap.get(cell.getColumnIndex());if(Objects.nonNull(excelComment)){// 创建绘图对象Comment comment = drawingPatriarch.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), 0,(short)excelComment.getRemarkColumnWide(), 1));comment.setString(new XSSFRichTextString(excelComment.getRemarkValue()));cell.setCellComment(comment);}}}}}

红线部分。是用来这是批注的宽度和高度,默认是0 ,我这里是从对应的实体中设置获取的。

备注解析

    /*** 获取批注Map** @param clazz 类class* @return java.util.Map<java.lang.Integer, java.lang.String>* @author SunLingDa* @date 2022/11/3 13:24*/public static Map<Integer, ExcelComment> getNotationMap(Class<?> clazz) {Map<Integer, ExcelComment> notationMap = new HashMap<>();Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {if (!field.isAnnotationPresent(ExcelNotation.class) ) {continue;}ExcelComment excelComment = new ExcelComment();ExcelNotation excelNotation = field.getAnnotation(ExcelNotation.class);ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);excelComment.setRemarkValue(excelNotation.value());excelComment.setRemarkColumnWide(excelNotation.remarkColumnWide());notationMap.put(excelProperty.index(), excelComment);}return notationMap;}

业务实现

 @PostMapping("/test")public void exportSubSAEExcel(HttpServletResponse response){try {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");// 防止中文乱码String fileName = URLEncoder.encode("SAE", "UTF-8").replaceAll("\\+","%20");response.setHeader("Content-disposition", "attachment;filename*=UTF-8''" + fileName + ExcelTypeEnum.XLSX.getValue());//响应的输入流ServletOutputStream outputStream = response.getOutputStream();// workbookExcelWriterBuilder writeWorkBook = EasyExcel.write(outputStream, CtmsSubSaeExcel.class).inMemory(Boolean.TRUE).inMemory(Boolean.TRUE).head(CtmsSubSaeExcel.class).useDefaultStyle(false).registerWriteHandler(new CommentCellWriteHandler(getNotationMap(CtmsSubSaeExcel.class))));// 添加备注的监听器// sheetwriteWorkBook.sheet().sheetName("SAE").sheetNo(0).doWrite(ctmsSubSaeExcels);outputStream.flush();outputStream.close();}catch (IOException e){throw ServiceExceptionUtil.exception(new ErrorCode(9999,"导出失败"));}catch (IllegalArgumentException e){throw ServiceExceptionUtil.exception(new ErrorCode(9999,e.getMessage()));}}

效果;

easyexcel 实现表头批注相关推荐

  1. EasyExcel 动态表头 + 数据单元格合并

    前言 本文想要达到以及最终实现的效果: 要实现这种效果,包含两个部分的操作: 1. 动态表头 EasyExcel 生成 Excel 时要使表头有合并效果,可以采用**注解和非注解(动态表头)**的方法 ...

  2. EasyExcel标题加批注和标题字体填充红色

    七. EasyExcel标题加批注和标题字体填充红色 一, 概述 在日常开发中, 经常会碰到导入导出的场景, 有导入就肯定有导入模板, 本文将介绍利用EasyExcel给标题添加批注和挑剔字体填充颜色 ...

  3. easyexcel 复杂表头、动态表头、复杂数据导出(非注解方式)

    easyexcel 复杂表头.动态表头.复杂数据导出 easyexcel 生成动态复杂表头(非注解)+数据填充(非注解) 实现代码 生成效果图 easyexcel 生成动态复杂表头(非注解)+数据填充 ...

  4. EasyExcel自定义表头导出模板并封装数据下拉选择

    EasyExcel自定义表头导出模板 首先查询可变数据 动态数据Controller 表头封装 定义导出模板时的下拉数据 最终结果 首先查询可变数据 动态数据Controller @ApiOperat ...

  5. EasyExcel复杂表头导入(一对多)

    一.前言 当前我使用过的导入导出框架有EasyPoi 和 EasyExcel,我用EasyPoi比较多. EasyPoi 框架的导入导出功能,乃至复杂表头的导入导出,网上都有很多示例,我也写过几篇博客 ...

  6. EasyExcel 批量添加批注

    目录 1 Maven配置 2 CommentModel 3 CommentWriteHandler 3 调试代码 4 调试结果 注: 1 Maven配置 <!--hutool工具包-->& ...

  7. easyExcel 复杂表头 动态表头

    需求: 要根据数据来导出这个excel 左侧菜单有一百多个固定菜单,这些肯定不能放到数据库里建字段,所以就根据上面的抽检总点数,合格总点数,合格率三个字段建立数据库字段. 技术实现: 我们选择的是ea ...

  8. EasyExcel自定义表头

    表头可以根据业务进行设置,然后后续赋值对应的值. @Testpublic void easyExcelTest() {List<List<String>> heads = Li ...

  9. easyexcel 检查表头是否匹配_利用easyexcel生成excel文件-自定义表头与数据栏对应的处理方式...

    前面几篇文章测试过用easyexcel生成动态表头,动态样式.特别是动态表头以及下面数据列表与表头字段的对应是采用注解方式实现的.但在实际工作中,有些到处是灵活生成的,也就是说对于同一个类,在不同的场 ...

最新文章

  1. SpringCloud + Consul服务注册中心 + gateway网关
  2. 鼠标滚动倾斜分割切换
  3. Android 开发(一)项目概况
  4. (十五)nodejs循序渐进-高性能游戏服务器框架pomelo之Protobuf模块
  5. Linux学习8-CentOS部署自己本地的django项目
  6. python数据分析-《Python数据分析与数据化运营》电子版
  7. JDBC — JDBC之Insert方法
  8. Disruptor学习笔记
  9. SpringMVC框架学习上篇
  10. Звезда 星星
  11. 计算机类中英附录,欧盟gmp附录11-计算机系统(中英文对照)-20210410004737.docx-原创力文档...
  12. idea、Pycharm提高效率常用配置
  13. icp光谱仪的工作原理_ICP的工作原理
  14. Linux 服务器后台运行.jar程序
  15. 计算机共享输入命令是什么意思,笔记本电脑共享WiFi命令怎么使用
  16. ICLR 2020 图神经学习论文汇总
  17. android 扫码枪 字符数少掉,BarTender条码字符数莫名变少是怎么回事?
  18. 想要刚毕业就月入过万必须要懂这些面试题(Vue 篇)
  19. 动态规划算法04-最长递增子序列问题
  20. 爬虫框架Scrapy(西瓜皮)

热门文章

  1. 商品交易和风险管理软件市场现状研究分析-
  2. java多租户架构_Java 多租户:配置选项、租户生命周期和所使用的隔离性
  3. python封装C++接口
  4. 微信公众号代运营公司有哪些_广州微信代运营公司有哪些
  5. SAP ECC6.0 R3 IDES FOR ORACLE 安装笔记 (一)
  6. 你不知道的JS(十):强制类型转换
  7. java获取当前日期和前一周、前一月、前一年的日期
  8. View的onAttachedToWindow, onDetachedFromWindow的调用时机,使用场景是什么?
  9. 微信分享接口,配置参数后无效分析
  10. 电子器件系列八:肖特基二极管