利用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.mzph.cn/news/883968.shtml

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

相关文章

Mac OS 搭建MySQL开发环境

Mac OS 搭建MySQL开发环境 文章目录 Mac OS 搭建MySQL开发环境一、安装Mysql&#xff1a;二、配置环境变量三、安装Navicat 本地环境&#xff1a; Mac OS Sequoia15.0.1&#xff08;M3 Max) 目标状态&#xff1a; 下载安装Mysql&#xff0c;配置相关环境。 一、安装Mysql&…

关于springboot跨域与拦截器的问题

今天写代码的时候遇到的一个问题&#xff0c;在添加自己设置的token拦截器之后&#xff0c;报错&#xff1a; “ERROR Network Error AxiosError: Network Error at XMLHttpRequest.handleError (webpack-internal:///./node_modules/axios/lib/adapters/xhr.js:112:14) at Axi…

Java 面向对象编程(OOP)(4/30)

目录 Java 面向对象编程&#xff08;OOP&#xff09; 1. 类与对象 1.1 类的定义 1.2 对象的创建与使用 2. 封装 2.1 访问修饰符 2.2 使用 Getter 和 Setter 方法 3. 继承 3.1 继承的基本用法 3.2 方法重写 4. 多态 4.1 编译时多态&#xff08;方法重载&#xff09;…

NVR设备ONVIF接入平台EasyCVR视频分析设备平台视频质量诊断技术与能力

视频诊断技术是一种智能化的视频故障分析与预警系统&#xff0c;NVR设备ONVIF接入平台EasyCVR通过对前端设备传回的码流进行解码以及图像质量评估&#xff0c;对视频图像中存在的质量问题进行智能分析、判断和预警。这项技术在安防监控领域尤为重要&#xff0c;因为它能够确保监…

记录一个跳跃的小游戏

记录一个跳跃的小游戏 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevi…

ansible详细介绍和具体步骤

Ansible简介 1.1 Ansible的基本概念 Ansible是一款开源的自动化工具&#xff0c;旨在简化IT操作的复杂性。它由Michael DeHaan创建&#xff0c;并于2012年发布&#xff0c;随后在2015年被Red Hat收购。Ansible的核心理念是“简单即美”&#xff0c;它通过使用YAML&#xff08…

Python Pycharm下载

pycharm-professional-2023.3.3 python-3.9.0-amd64.exe 链接&#xff1a;https://pan.baidu.com/s/1YYf835hlleeDksPMmX9y2g?pwd9x16 提取码&#xff1a;9x16 更多资料获取学习书籍下面搜一搜这里不迷路&#xff0c;回复关键字获取&#xff1a;python

探秘 Feign 核心注解:@FeignClient 和 @EnableFeignClients 是如何打通微服务通信的 “任督二脉” 的?

前两篇文章揭秘 Feign 调用机制&#xff1a;微服务通信的无缝集成和微服务通信背后的秘密&#xff1a;Ribbon 如何选择最佳服务实例&#xff1f;&#xff0c;我们已经了解到 Feign 调用机制的一大优势 —— 在不需要指定域名的情况下&#xff0c;能够借助 Ribbon 精准地找到并调…

比较24个结构的迭代次数

(A,B)---6*30*2---(0,1)(1,0) 让A是结构1&#xff0c;让B全是0。收敛误差为7e-4&#xff0c;收敛199次取迭代次数平均值&#xff0c;得到28080.98 做一个同样的网络(A,B)---6*30*2---(0,1)(1,0)&#xff0c;让A是结构1-24&#xff0c;B全是0&#xff0c;用结构1的收敛权重做初…

Python unstructured库详解:partition_pdf函数完整参数深度解析

Python unstructured库详解&#xff1a;partition_pdf函数完整参数深度解析 1. 简介2. 基础文件处理参数2.1 文件输入参数2.2 页面处理参数 3. 文档解析策略3.1 strategy参数详解3.2 策略选择建议 4. 表格处理参数4.1 表格结构推断 5. 语言处理参数5.1 语言设置 6. 图像处理参数…

CentOS9 Stream上安装Edge浏览器

CentOS9 Stream上安装Edge浏览器 1. 下载 Microsoft Edge RPM 包2. 安装 Edge 浏览器3. 启动 Microsoft Edge4. 更新 Microsoft Edge&#xff08;可选&#xff09; 如果运行的时候出现错误&#xff1a;[5809:5809:1030/234136.530802:ERROR:zygote_host_impl_linux.cc(101)] Ru…

深度了解flink(七) JobManager(1) 组件启动流程分析

前言 JobManager是Flink的核心进程&#xff0c;主要负责Flink集群的启动和初始化&#xff0c;包含多个重要的组件(JboMaster&#xff0c;Dispatcher&#xff0c;WebEndpoint等)&#xff0c;本篇文章会基于源码分析JobManagr的启动流程&#xff0c;对其各个组件进行介绍&#x…

.NET内网实战:通过白名单文件反序列化漏洞绕过UAC

01阅读须知 此文所节选自小报童《.NET 内网实战攻防》专栏&#xff0c;主要内容有.NET在各个内网渗透阶段与Windows系统交互的方式和技巧&#xff0c;对内网和后渗透感兴趣的朋友们可以订阅该电子报刊&#xff0c;解锁更多的报刊内容。 02基本介绍 03原理分析 在渗透测试和红…

ELK之路第三步——日志收集筛选logstash和filebeat

logstash和filebeat&#xff08;偷懒版&#xff09; 前言logstash1.下载2.修改配置文件3.测试启动4.文件启动 filebeat1.下载2.配置3.启动 前言 上一篇&#xff0c;我们说到了可视化界面Kibana的安装&#xff0c;这一篇&#xff0c;会简单介绍logstash和filebeat的安装和配置。…

20 Docker容器集群网络架构:三、Docker集群部署

文章目录 Docker容器集群网络架构:三、Docker集群离线部署3.1 环境准备3.1.1 配置主机名3.1.2 关闭firewall防火墙3.1.3 关闭iptables防火墙3.1.3.1 安装iptables3.1.3.2 禁用iptables3.1.3.3 清空防火墙规则3.1.4 关闭selinux3.1.4.1 临时关闭3.1.4.2 永久关闭3.1.4.3 查询关…

分别用webpack和vite注册全局组件

基础组件的自动化全局注册 1. 组件全部导入后&#xff0c;批量注册 import dgDialog from "/components/dgDialog/index.vue"; import svgIcon from "/components/svgIcon/index.vue"; const allComponent { dgDialog, svgIcon }; export default {inst…

二十六、Python基础语法(函数进阶-下)

一、多值参数 多值参数&#xff08;可变参数、不定长参数&#xff09;&#xff1a;有的函数不确定参数有几个&#xff0c;在一个普通的参数前面加上一个*&#xff0c;这个参数就变为不定参数。可以接收任意多个位置传参的数据&#xff0c;类型为元组。 def test(name, *args,…

植物源UDP-糖基转移酶及其分子改造-文献精读75

植物源UDP-糖基转移酶及其分子改造 摘要 糖基化能够增加化合物的结构多样性,有效改善水溶性、药理活性和生物利用度,对植物天然产物的药物开发至关重要。UDP-糖基转移酶(UGTs)能够催化糖基从活化的核苷酸糖供体转移到受体形成糖苷键,植物中天然产物的糖基化修饰主要通过UGTs实…

计算机网络-常用网络命令和工具

目录 Ping命令 正常的执行结果 常见的失败反馈信息 语法格式 常用参数 Ipconfig命令简介 语法格式 命令参数 tracert 命令简介 工作原理 语法格式 常用参数 nbtstat命令简介 语法格式 常用参数 netstat 命令简介 语法格式 常用参数 Ping命令 ping( Packet Internet Grope…

[MySQL#7] CRUD(2) | 更新 | 删除 | 聚合函数 | group by

目录 3. 更新 4. 删除 截断表 日志的作用 5. (实验) 插入查询结果 6. 聚合函数 7. 分组查询 接着上篇文章[MySQL#6] 表的CRUD (1) | Create | Retrieve(查) | where继续讲解~ 3. 更新 语法&#xff1a; UPDATE table_name SET column expr [, column expr ...][WHE…