利用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.xdnf.cn/news/203.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Java项目实战II基于Spring Boot的文理医院预约挂号系统的设计与实现(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 一、前言 在医疗资源日益紧张的背景下&#xff0…

Mac下载 安装MIMIC-IV 3.0数据集

参考blog MIMIC IV 3.0数据库安装方法_mimic数据下载-CSDN博客 MIMIC IV数据库安装&#xff08;二&#xff09;_mimic数据库安装-CSDN博客 MIMIC-IV3.0安装_mimic iv 3.0-CSDN博客 MIMIC-IV-v2.0安装教程_mimic iv 安装教程-CSDN博客 MIMIC IV 3.0数据库安装方法或者思路&…

[ 应急响应靶场实战 ] VMware 搭建win server 2012应急响应靶机 攻击者获取服务器权限上传恶意病毒 防守方人员应急响应并溯源

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

UI 组件的二次封装

UI 组件的二次封装是指&#xff0c;在基础 UI 库的组件上进行自定义封装&#xff0c;以实现更贴合业务需求的功能和样式。通过二次封装&#xff0c;可以增强组件的复用性、便捷性和一致性&#xff0c;简化业务代码&#xff0c;同时降低后续维护成本。 1. 二次封装的原理 二次…

Redis高级篇之缓存一致性详细教程

文章目录 0 前言1.缓存双写一致性的理解1.1 缓存按照操作来分 2. 数据库和缓存一致性的几种更新策略2.1 可以停机的情况2.2 我们讨论4种更新策略2.3 解决方案 总结 0 前言 缓存一致性问题在工作中绝对没办法回避的问题&#xff0c;比如&#xff1a;在实际开发过程中&#xff0c…

python爬虫实现自动获取论文GB 7714引用

在写中文论文、本硕博毕业设计的时候要求非常严格的引用格式——GB 7714引用。对于普通学生来说都是在google scholar上获取&#xff0c;一个一个输入点击很麻烦&#xff0c;就想使用python完成这个自动化流程&#xff0c;实现批量的倒入论文标题&#xff0c;导出引用。 正常引…

redis v6.0.16 安装 基于Ubuntu 22.04

redis安装 基于Ubuntu 22.04 本文演示如何在ubuntu22.04下&#xff0c;安装redis v6.0.16&#xff0c;并配置测试远程访问。 Step1 更新环境 sudo apt updateStep2 安装redis sudo apt install redis-server -yStep3 启动 sudo systemctl restart redissudo systemctl sta…

✨基于python实现的文档管理系统✨

本项目是使用Django和layui实现的一个文档转换系统&#xff0c;支持各种文档的相互转换 &#x1f4c4; PPT转Word &#x1f4d1; PDF转Word &#x1f4da; 合并PDF &#x1f4dc; Word转PDF 系统支持用户注册、登录&#xff0c;还能管理你的转换任务&#xff1a; &#x1f504;…

ES索引:索引管理

索引管理 再讲索引&#xff08;Index&#xff09;前&#xff0c;我们先对照下 ElasticSearch Vs 关系型数据库&#xff1a; PUT /customer/_doc/1 {"name": "DLBOY" }系统默认是自动创建索引的 如果我们需要对这个建立索引的过程做更多的控制&#xff1a…

Linux安装Dcoker

目录 1、卸载&#xff08;可选&#xff09; 2、安装docker 3、启动docker 4、配置镜像加速 1、卸载&#xff08;可选&#xff09; 如果之前安装过旧版本的Docker&#xff0c;可以使用下面命令卸载&#xff1a; yum remove docker \docker-client \docker-client-latest \…

智能无损网络技术详解

什么是智能无损网络&#xff1f; 智能无损网络是一种集流量控制与拥塞控制于一体的先进技术&#xff0c;旨在提升网络性能&#xff0c;降低时延。同时&#xff0c;它通过智能无损存储网络等技术实现网络和应用系统的优化融合。该技术为AI人工智能、集中式/分布式存储以及HPC等应…

基于SSM+小程序的购物管理系统1

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 基于SSM小程序的购物管理系统1&#xff0c;可以实现首页、个人中心、商品分类管理、商品信息管理、特价商品管理、用户管理、留言板管理、系统管理、订单管理等功能。方便用户对首页、商品…

楼梯区域分割系统:Web效果惊艳

楼梯区域分割系统源码&#xff06;数据集分享 [yolov8-seg-FocalModulation&#xff06;yolov8-seg-GFPN等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAAI Global Al l…

ROS2入门学习——ROS在机器人中的运行

一、入门级基础平台TurtleBot TurtleBot 是 ROS 中重要且资源丰富的机器人之一&#xff0c;特别适合入门级机器人爱好者提供基础平台。用户可以直接利用其自带的软硬件&#xff0c;专注于应用程序的开发。TurtleBot 随着 ROS 的发展&#xff0c;一直处于开发前沿。 TurtleBot…

智谱发布AI助理,帮人类敲响AGI的大门

人工智能之父John McCarthy曾说&#xff1a;“只要AI可以开始正常工作&#xff0c;就不会有人再把它当AI了。”如今&#xff0c;这一预言正在逐渐变为现实。 10月25日&#xff0c;智谱AI推出了自主智能体AutoGLM&#xff0c;能够模拟人类操作手机&#xff0c;执行各种任务。 …

Profinet、Ethernet/IP 工业以太网无线通信解决方案

在工业现场&#xff0c;我们常常会面临这样的困扰&#xff1a;两个PLC之间、PLC 跟远程IO之间或者PLC 跟伺服之间由于种种原因不方便布线&#xff0c;严重影响了通讯效率和生产进程。为了解决这一难题&#xff0c;三格电子设计了一款工业以太网无线网桥&#xff0c;这款无线网桥…

重塑未来,开源AI数字人系统引领个性化语音新纪元!AigcPanel v0.03开启公测

你是否曾梦想拥有一个能够与你对话、与你共鸣的AI数字人伙伴&#xff1f;现在&#xff0c;这一切都不再是幻想&#xff01;我们自豪地推出——全新的开源AI数字人系统&#xff0c;一个集视频合成、声音合成、声音克隆与模型管理于一体的创新平台&#xff0c;让你轻松打造专属的…

js逆向-模拟加密

实战七麦数据&#xff1a; 1.寻找加密入口 尝试搜索的方法&#xff1a; 那只能使用跟栈的方法&#xff0c;进入send发包位置&#xff1a; 打上断点&#xff0c;寻找加密入口&#xff0c;前面是发包分包&#xff0c;promise注意到是一个异步操作&#xff0c;看是否在此加密&…

Kafka社区KIP-500中文译文(去除ZooKeeper)

原文链接&#xff1a;KIP-500: Replace ZooKeeper with a Self-Managed Metadata Quorum - Apache Kafka - Apache Software Foundation 译者&#xff1a;关于Kafka3.x版本最大的一个变化即是解除了对ZooKeeper的依赖&#xff0c;而本文的作者是大神Colin&#xff0c;他高屋建瓴…

【计算机网络教程】课程 章节测试1 计算机网络概述

一. 单选题&#xff08;共16题&#xff09; 1 【单选题】以下关于TCP/IP参考模型缺点的描述中&#xff0c;错误的是&#xff08; &#xff09;。 A、在服务、接口与协议的区别上不很清楚 B、网络接口层本身并不是实际的一层 C、它不能区分数据链路和物理层 D、传输层对…