利用EasyExcel实现简易Excel导出

目标

通过注解形式完成对一个方法返回值的通用导出功能

工程搭建

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.13</version></parent><groupId>com.example</groupId><artifactId>export</artifactId><version>0.0.1-SNAPSHOT</version><name>export</name><description>export</description><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.7.6</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--    EasyExcel    --><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>4.0.3</version></dependency><!--    aspect    --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId></dependency><!--    util      --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.15.0</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-collections4</artifactId><version>4.4</version></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>com.example.export.ExportApplication</mainClass><skip>true</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>

核心代码

CusExport

package com.example.export.annotation;import java.lang.annotation.*;/*** @author PC* 基于EasyExcel实现动态列导出*/@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CusExport {/*** 导出数据对象*/Class<?> dataClass() default Void.class;/*** 是否是动态的** @return true 是 false 否*/boolean dynamicFlag() default false;/*** 文件名,未指定取实体类名,无实体类取 getDefaultFileName()** @return 文件名*/String fileName() default "";
}

CusExportAspect

package com.example.export.aspect;import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.example.export.annotation.CusExport;
import com.example.export.config.ExportProperties;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;/*** @author PC* 导出切面*/
@Aspect
@Component
public class CusExportAspect {private final static Logger logger = LoggerFactory.getLogger(CusExportAspect.class);private final ExportProperties exportProperties;@Autowiredpublic CusExportAspect(ExportProperties exportProperties) {this.exportProperties = exportProperties;}@AfterReturning(pointcut = "@annotation(com.example.export.annotation.CusExport)", returning = "result")public void afterReturningAdvice(JoinPoint joinPoint, Object result) throws IOException {MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();CusExport cusExport = methodSignature.getMethod().getAnnotation(CusExport.class);HttpServletResponse response = getHttpServletResponse();// 这里URLEncoder.encode可以防止中文乱码String generatorFileName = StringUtils.isEmpty(cusExport.fileName()) ? exportProperties.getDefaultFileName() : cusExport.fileName();String fileName = URLEncoder.encode(generatorFileName, "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");if (!cusExport.dynamicFlag()) {EasyExcel.write(response.getOutputStream(), cusExport.dataClass()).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet(exportProperties.getDefaultSheetName()).doWrite((Collection<?>) result);} else {this.dealSpecified(cusExport, result, fileName, response);}}private static HttpServletResponse getHttpServletResponse() {ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();assert attr != null;HttpServletResponse response = attr.getResponse();assert response != null;response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");return response;}@SuppressWarnings("unchecked")private void dealSpecified(CusExport cusExport, Object result, String fileName, HttpServletResponse response) throws IOException {if (Objects.isNull(cusExport) || Objects.isNull(result) || StringUtils.isEmpty(fileName)) {logger.error("the required field is missing");}logger.debug("the data type is not specified");List<Map<String, Object>> resultList = new ArrayList<>();if (result instanceof List) {resultList = (List<Map<String, Object>>) result;}if (CollectionUtils.isEmpty(resultList)) {logger.info("data is empty");}List<List<String>> headList = new ArrayList<>();boolean fillHeadFlag = false;for (Map<String, Object> resultItem : resultList) {if (!fillHeadFlag) {resultItem.keySet().forEach(keyCode -> headList.add(Collections.singletonList(keyCode)));fillHeadFlag = true;}}EasyExcel.write(response.getOutputStream()).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())// 放入动态头.head(headList).sheet(exportProperties.getDefaultSheetName()).doWrite(convertMapToList(resultList, headList));}private List<List<Object>> convertMapToList(List<Map<String, Object>> mapList, List<List<String>> headList) {List<List<Object>> list = new ArrayList<>();for (Map<String, Object> map : mapList) {List<Object> info = new ArrayList<>();for (List<String> itemHeadList : headList) {info.add(map.get(itemHeadList.get(0)));}list.add(info);}return list;}
}

测试

测试代码

在对应方法添加@CusExport注解即可,导出实体类需指定dataClass,导出动态数据需指定dynamicFlag = true,如需调整生成的文件名,还可以指定fileName

TestExportServiceImpl

package com.example.export.app.service.impl;import com.example.export.annotation.CusExport;
import com.example.export.app.service.TestExportService;
import com.example.export.domain.entity.ExcelTest;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @author PC*/
@Component
public class TestExportServiceImpl implements TestExportService {@Override@CusExport(dataClass = ExcelTest.class)public List<ExcelTest> generatorDataForClass() {List<ExcelTest> excelTestList = new ArrayList<>();for (int j = 0; j < 100; j++) {ExcelTest excelTest = new ExcelTest();excelTest.setCode("testCode" + j);excelTest.setName("testName" + j);excelTest.setEnabledFlag(j % 2);excelTestList.add(excelTest);}return excelTestList;}@Override@CusExport(dynamicFlag = true)public List<Map<String, Object>> generatorDataForMap() {List<Map<String, Object>> excelTestList = new ArrayList<>();for (int j = 0; j < 100; j++) {Map<String, Object> item = new HashMap<>(3);item.put("code", "testCodeMap" + j);item.put("name", "testNameMap" + j);item.put("enabledFlag", j % 2);excelTestList.add(item);}return excelTestList;}
//
}

ExportTestController

package com.example.export.api.controller;import com.example.export.app.service.TestExportService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author PC*/
@RestController("v1.exportTestController")
@RequestMapping("/export")
public class ExportTestController {private final TestExportService testExportService;@Autowiredpublic ExportTestController(TestExportService testExportService) {this.testExportService = testExportService;}@GetMapping("/by-class")public void exportTest(){testExportService.generatorDataForClass();}@GetMapping("/by-map")public void exportTestMap(){testExportService.generatorDataForMap();}
}

测试

访问127.0.0.1:18081/export/by-class

访问127.0.0.1:18081/export/by-map

参考资料

[1].EasyExcel官网文档

[2].demo

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

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

相关文章

练习LabVIEW第三十二题

学习目标&#xff1a; 刚学了LabVIEW&#xff0c;在网上找了些题&#xff0c;练习一下LabVIEW&#xff0c;有不对不好不足的地方欢迎指正&#xff01; 第三十二题&#xff1a; 利用labview elapsed time(已用时间)定时设计输出一个方波 开始编写&#xff1a; 前面板放置一…

桑基图在医学数据分析中的更复杂应用示例

桑基图&#xff08;Sankey Diagram&#xff09;能够有效地展示复杂的流动关系&#xff0c;特别适合用于医学数据分析中的多种转归和治疗路径的可视化。接下来&#xff0c;我们将构建一个稍微复杂的示例&#xff0c;展示不同疾病患者在治疗过程中的流动&#xff0c;以及他们的治…

Java毕业设计-基于微信小程序的校园二手物品交易系统的实现(V2.0)

博主介绍&#xff1a;✌stormjun、8年大厂程序员经历。全网粉丝15w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&…

聊一聊:ChatGPT搜索引擎会取代谷歌和百度吗?

当地时间 10 月 31 日&#xff0c;OpenAI 正式推出了 ChatGPT 搜索功能&#xff0c;能实时、快速获取附带相关网页来源链接的答案。这一重大升级标志着其正式向谷歌的搜索引擎霸主地位发起挑战。 本周五我们聊一聊&#xff1a; 欢迎在评论区畅所欲言&#xff0c;分享你的观点~ …

Hms?: 1渗透测试

靶机&#xff1a;Hms?: 1 Hms?: 1 ~ VulnHub 攻击机&#xff1a;kail linux 2024 主机扫描阶段发现不了靶机&#xff0c;所以需要按DriftingBlues2一样手动配置网卡 1,将两台虚拟机网络连接都改为NAT模式&#xff0c;并查看靶机的MAC地址 2&#xff0c;攻击机上做主机扫描发现…

<项目代码>YOLOv8 夜间车辆识别<目标检测>

YOLOv8是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题&#xff0c;能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法&#xff08;如Faster R-CNN&#xff09;&#xff0c;YOLOv8具有更高的…

MATLAB实现蝙蝠算法(BA)

MATLAB实现蝙蝠算法(BA) 1.算法介绍 蝙蝠算法&#xff08;简称BA&#xff09;是一种受微型蝙蝠回声定位机制启发的群体智能算法&#xff0c;由Xin-She Yang于2010年提出。这种算法模拟了微型蝙蝠通过向周围环境发出声音并监听回声来识别猎物、避开障碍物以及追踪巢穴的行为。…

【温酒笔记】UART

参考文档&#xff1a;野火STM32F103 1. 物理层 STM32见下图 1、TTL电平标准&#xff1a; 输出L&#xff1a;<0.8V&#xff1b;H:>2.4V。 输入L&#xff1a;<1.2V&#xff1b;H:>2.0V。 2、CMOS电平标准&#xff1a; 输出L&#xff1a;<0.1Vcc&#xff1b;…

Chromium127编译指南 Mac篇(一)- 环境准备详解

概述 在开源浏览器生态系统中&#xff0c;Chromium始终扮演着举足轻重的角色。作为Google Chrome的技术基石&#xff0c;它不仅支撑着全球最受欢迎的浏览器之一&#xff0c;更为众多定制化浏览器项目提供了坚实的基础。对于渴望探索浏览器技术深度&#xff0c;或计划开发自有浏…

【spark的集群模式搭建】spark集群之Yarn集群模式搭建(清晰明了的搭建流程)

文章目录 1、使用Anaconda部署Python2、上传、解压、重命名3、创建软连接&#xff08;如果在Standalone模式中创建有就删除&#xff09;4、配置spark环境变量5、修改spark-env.sh配置文件6、修改spark-defaults.conf 配置文件7、修改log4j.properties配置文件8、上传spark jar包…

h2 数据库命令行工具用法汇总

背景 h2 数据是个短小精悍的嵌入式数据库&#xff0c;纯 Java 实现&#xff0c;且非常小。 我们有一个比较底层的应用中就是用了 h2 数据库来存储应用的基础信息&#xff0c;这个数据库说起来比较容易。 本文总结实际项目中涉及到的 h2 的相关技术及问题。 控制台工具用法 …

再探“构造函数”(2)友元and内部类

文章目录 一. 友元‘全局函数’作友元‘成员函数’作友元‘类‘作友元 内部类 一. 友元 何时会用到友元呢&#xff1f; 当想让&#xff08;类外面的某个函数/其它的类&#xff09;访问 某个类里面的(私有或保护的)内容时&#xff0c;可以选择使用友元。 友元提供了一种突破&a…

告别枯燥数据!20种色彩缤纷的数据可视化图表任你选,轻松应对各种场景

我们每天都在和各种数据打交道&#xff0c;单纯的一串串数字&#xff0c;看着就头疼。如果数据不再是枯燥的表格&#xff0c;而是变成了色彩鲜艳的柱状图、线条流畅的折线图&#xff0c;或者是直观易懂的饼图&#xff0c;让用户一眼Get到重点&#xff0c;让老板为你的汇报方案鼓…

C++和OpenGL实现3D游戏编程【连载17】——着色器进阶(附源码)

🔥C++和OpenGL实现3D游戏编程【目录】 1、本节要实现的内容 在前面着色器初步一节我们了解了着色器的一些初步知识,通过顶点着色器和片段着色器显示出了一个彩色的立方体。我们这节课就来了解一些在着色器中显示纹理等一系列实用操作,同时了解一些进阶的图像渲染技术,比如…

散热器为什么要加风扇:【图文讲解】

前面我们聊到了TEC散热器中&#xff0c;TEC的工作原理&#xff0c;也大概聊了一下热的整个传递过程。TEC散热器在工作的时候&#xff0c;会产生冷热两个端面&#xff0c;核心工作原理是通电后TEC把冷端的热量搬移到热端。这样把TEC散热器的冷端放置在需要散热的器件表面&#x…

HO-XGBoost河马算法优化极限梯度提升树多变量回归预测(Matlab)

HO-XGBoost河马算法优化极限梯度提升树多变量回归预测&#xff08;Matlab&#xff09; 目录 HO-XGBoost河马算法优化极限梯度提升树多变量回归预测&#xff08;Matlab&#xff09;预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Matlab实现HO-XGBoost多变量回归预测&…

Zookeeper 简介 | 特点 | 数据存储

1、简介 zk就是一个分布式文件系统&#xff0c;不过存储数据的量极小。 1. zookeeper是一个为分布式应用程序提供的一个分布式开源协调服务框架。是Google的Chubby的一个开源实现&#xff0c;是Hadoop和Hbase的重要组件。主要用于解决分布式集群中应用系统的一致性问题。 2. 提…

[5] 一篇文章教会你如何实现端口敲门

文章目录 1. 描述2. 基本原理3. 优点4. 缺点5. 实现过程6. firewall-cmd命令介绍7. 写到最后 1. 描述 端口敲门技术(Prot Knocking)技术&#xff0c;用于通过一系列预定的端口来动态地打开防火墙或访问特定服务甚至执行一小段任务&#xff0c;用于增强系统地安全性&#xff0c;…

TensorRT-LLM的k8s弹性伸缩部署方案

Scaling LLMs with NVIDIA Triton and NVIDIA TensorRT-LLM Using Kubernetes | NVIDIA Technical Blog 一共涉及4个k8s组件&#xff1a; 1. Deployment&#xff1a;跑起来N个pod&#xff1b;指定NVIDIA官方的triton&trt-llm的docker image&#xff0c;指定好model放在哪个…

Chainlit集成LlamaIndex实现知识库高级检索(HyDE查询重写转换)

检索原理 HyDEQueryTransform 是一种用于信息检索系统中的查询转换技术&#xff0c;它基于假设文档嵌入&#xff08;Hypothetical Document Embeddings&#xff0c;简称HyDE&#xff09;的概念&#xff0c;旨在通过生成假设文档来改善查询与文档之间的语义对齐&#xff0c;进而…