Spring Boot集成EasyExcel

1. 初始化Spring Boot项目

首先,使用Spring Initializr(https://start.spring.io/)生成一个基本的Spring Boot项目。选择以下依赖项:

  • Spring Web
  • Lombok (用于减少样板代码)
  • SLF4J (用于日志记录)

2. 添加依赖

在你的pom.xml文件中添加EasyExcel的Maven依赖。确保版本号是最新的,你可以访问Maven仓库来获取最新版。

<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>最新的版本号</version>
</dependency>

3. 创建实体类

假设我们需要处理一个用户信息表,包含姓名和年龄两个字段。以下是实体类的设计,并使用Lombok简化代码:

package com.example.demo.model;import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;// 使用@Data注解自动生成getter、setter等方法
@Data
public class UserData {// 指定Excel列标题为“姓名”@ExcelProperty("姓名")private String name; // 用户姓名// 指定Excel列标题为“年龄”@ExcelProperty("年龄")private Integer age; // 用户年龄
}

4. 创建监听器类

创建一个监听器类来处理每一行的数据,并在服务类中调用它。我们使用@Slf4j注解简化日志记录:

package com.example.demo.listener;import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.example.demo.model.UserData;
import lombok.extern.slf4j.Slf4j;import java.util.ArrayList;
import java.util.List;@Slf4j // 使用@Slf4j注解简化日志记录
public class UserDataListener extends AnalysisEventListener<UserData> {private final List<UserData> dataList = new ArrayList<>(); // 存储读取的数据/*** 当解析一行数据时调用* @param userData 解析得到的用户数据* @param analysisContext 上下文对象*/@Overridepublic void invoke(UserData userData, AnalysisContext analysisContext) {dataList.add(userData); // 将每一行的数据添加到列表中log.info("读取到一条数据: {} {}", userData.getName(), userData.getAge()); // 日志记录}/*** 所有数据解析完成后调用* @param analysisContext 上下文对象*/@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {log.info("所有数据解析完成"); // 数据解析完成后记录日志}/*** 获取读取的数据列表* @return 读取的数据列表*/public List<UserData> getDataList() {return dataList; // 返回读取的数据列表}
}

5. 实现服务类

编写一个服务类来实现数据的读写操作,并增加异常处理和日志记录。我们将在此处添加分页功能,以确保当单个页面数据达到一定量时重新生成新的页面进行写入:

package com.example.demo.service;import com.alibaba.excel.EasyExcel;
import com.example.demo.listener.UserDataListener;
import com.example.demo.model.UserData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;@Slf4j // 使用@Slf4j注解简化日志记录
@Service
public class ExcelService {private static final int PAGE_SIZE = 100; // 每页最大数据条数/*** 写入Excel文件* @param filePath 文件路径* @param data 要写入的数据列表*/public void writeExcel(String filePath, List<UserData> data) {try {log.info("开始写入Excel文件: {}", filePath); // 记录日志int totalRows = data.size();int totalPages = (int) Math.ceil((double) totalRows / PAGE_SIZE);for (int page = 0; page < totalPages; page++) {int fromIndex = page * PAGE_SIZE;int toIndex = Math.min(fromIndex + PAGE_SIZE, totalRows);List<UserData> currentPageData = data.subList(fromIndex, toIndex);String sheetName = "用户信息" + (page + 1); // 设置工作表名称// 开始写入Excel文件EasyExcel.write(filePath, UserData.class).sheet(sheetName) // 设置工作表名称.doWrite(currentPageData); // 执行写入操作log.info("写入第 {} 页数据完成", page + 1); // 写入完成后记录日志}log.info("写入Excel文件完成"); // 写入完成后记录日志} catch (Exception e) {log.error("写入Excel失败", e); // 记录错误日志}}/*** 读取所有工作表的Excel文件* @param inputStream 输入流* @return 读取的数据列表*/public List<UserData> readAllSheets(InputStream inputStream) {List<UserData> allData = new ArrayList<>();try {log.info("开始读取所有工作表的Excel文件"); // 记录日志// 获取Excel文件中的所有Sheet信息List<String> sheetNames = EasyExcel.read(inputStream).excelExecutor().sheetList().get();for (String sheetName : sheetNames) {log.info("开始读取工作表: {}", sheetName);UserDataListener listener = new UserDataListener();// 执行读取操作EasyExcel.read(inputStream, UserData.class, listener).sheet(sheetName) // 指定工作表名称.doRead(); // 执行读取操作// 处理listener.getDataList()allData.addAll(listener.getDataList());log.info("读取工作表 {} 完成", sheetName);}log.info("读取所有工作表的Excel文件完成"); // 读取完成后记录日志} catch (Exception e) {log.error("读取所有工作表的Excel失败", e); // 记录错误日志}return allData;}/*** 读取特定工作表的Excel文件* @param filePath 文件路径* @param sheetIndex 工作表索引(从0开始)*/public void readSpecificSheet(String filePath, int sheetIndex) {try {log.info("开始读取特定工作表的Excel文件: {}, Sheet Index: {}", filePath, sheetIndex); // 记录日志UserDataListener listener = new UserDataListener();// 执行读取操作EasyExcel.read(filePath, UserData.class, listener).sheet(sheetIndex) // 指定工作表索引.doRead(); // 执行读取操作// 处理listener.getDataList()for (UserData userData : listener.getDataList()) {log.info("{} {}", userData.getName(), userData.getAge()); // 记录每条数据的日志}log.info("读取特定工作表的Excel文件完成"); // 读取完成后记录日志} catch (Exception e) {log.error("读取特定工作表的Excel失败", e); // 记录错误日志}}/*** 使用模板填充数据并生成新的Excel文件* @param templateFilePath 模板文件路径* @param outputFilePath 输出文件路径* @param data 要填充的数据列表*/public void fillTemplate(String templateFilePath, String outputFilePath, List<UserData> data) {try {log.info("开始使用模板填充数据: {}, 输出文件路径: {}", templateFilePath, outputFilePath); // 记录日志// 使用模板填充数据EasyExcel.write(outputFilePath).withTemplate(templateFilePath).sheet().doFill(data);log.info("模板填充数据完成"); // 填充完成后记录日志} catch (Exception e) {log.error("模板填充数据失败", e); // 记录错误日志}}/*** 下载文件并在失败时返回JSON* @param response HttpServletResponse 对象* @throws IOException 如果写入文件失败*/public void downloadFailedUsingJson(HttpServletResponse response) throws IOException {try {response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");// 这里URLEncoder.encode可以防止中文乱码String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");List<UserData> data = new ArrayList<>();for (int i = 1; i <= 100; i++) { // 假设我们有100条数据data.add(new UserData().setName("张三" + i).setAge(20 + i % 50));}EasyExcel.write(response.getOutputStream(), UserData.class).autoCloseStream(Boolean.FALSE).sheet("模板").doWrite(data);} catch (Exception e) {// 重置responseresponse.reset();response.setContentType("application/json");response.setCharacterEncoding("utf-8");Map<String, String> map = Map.of("status", "failure", "message", "下载文件失败: " + e.getMessage());response.getWriter().println(JSON.toJSONString(map));}}
}
}

6. 创建控制器类

为了方便测试,我们可以创建一个简单的控制器类来调用服务类中的方法:

package com.example.demo.controller;import com.example.demo.service.ExcelService;
import lombok.extern.slf4j.Slf4j;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;@Slf4j // 使用@Slf4j注解简化日志记录
@RestController
@RequestMapping("/excel")
public class ExcelController {@Autowiredprivate ExcelService excelService; // 自动注入ExcelService/*** 文件上传* @param file 上传的文件* @return 成功消息* @throws IOException 如果读取文件失败*/@PostMapping("upload")@ResponseBodypublic String upload(@RequestParam("file") MultipartFile file) throws IOException {InputStream inputStream = file.getInputStream();List<UserData> data = excelService.readAllSheets(inputStream);log.info("成功读取到 {} 条数据", data.size());return "success";}/*** 文件下载并且失败的时候返回json(默认失败了会返回一个有部分数据的Excel)** @param response HttpServletResponse 对象* @throws IOException 如果写入文件失败*/@GetMapping("downloadFailedUsingJson")public void downloadFailedUsingJson(HttpServletResponse response) throws IOException {excelService.downloadFailedUsingJson(response);}/*** 写入Excel文件* @param filePath 文件路径* @return 成功消息*/@GetMapping("/write")public String writeExcel(@RequestParam String filePath) {log.info("准备写入Excel文件: {}", filePath); // 记录日志List<UserData> data = new ArrayList<>();for (int i = 1; i <= 500; i++) { // 假设我们有500条数据data.add(new UserData().setName("张三" + i).setAge(20 + i % 50));}excelService.writeExcel(filePath, data); // 调用写入方法log.info("写入Excel文件完成"); // 返回成功消息return "写入Excel成功"; // 返回成功消息}/*** 读取所有工作表的Excel文件* @param filePath 文件路径* @return 成功消息*/@GetMapping("/read/allSheets")public String readAllSheets(@RequestParam String filePath) {log.info("准备读取所有工作表的Excel文件: {}", filePath); // 记录日志excelService.readAllSheets(filePath); // 调用读取方法log.info("读取所有工作表的Excel文件完成"); // 返回成功消息return "读取所有工作表的Excel成功"; // 返回成功消息}/*** 读取特定工作表的Excel文件* @param filePath 文件路径* @param sheetIndex 工作表索引(从0开始)* @return 成功消息*/@GetMapping("/read/specificSheet")public String readSpecificSheet(@RequestParam String filePath, @RequestParam int sheetIndex) {log.info("准备读取特定工作表的Excel文件: {}, Sheet Index: {}", filePath, sheetIndex); // 记录日志excelService.readSpecificSheet(filePath, sheetIndex); // 调用读取方法log.info("读取特定工作表的Excel文件完成"); // 返回成功消息return "读取特定工作表的Excel成功"; // 返回成功消息}/*** 使用模板填充数据并生成新的Excel文件* @param templateFilePath 模板文件路径* @param outputFilePath 输出文件路径* @return 成功消息*/@GetMapping("/fill/template")public String fillTemplate(@RequestParam String templateFilePath, @RequestParam String outputFilePath) {log.info("准备使用模板填充数据: {}, 输出文件路径: {}", templateFilePath, outputFilePath); // 记录日志List<UserData> data = new ArrayList<>();for (int i = 1; i <= 500; i++) { // 假设我们有500条数据data.add(new UserData().setName("张三" + i).setAge(20 + i % 50));}excelService.fillTemplate(templateFilePath, outputFilePath, data); // 调用模板填充方法log.info("模板填充数据完成"); // 返回成功消息return "模板填充数据成功"; // 返回成功消息}
}

7. 异常处理与日志记录

在实际应用中,建议增加更多的异常处理逻辑和日志记录,以便更好地调试和维护。我们已经在服务类中添加了基本的日志记录和异常处理机制。

全局异常处理

你可以在项目中添加全局异常处理器来捕获和处理未处理的异常:

package com.example.demo.exception;import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import lombok.extern.slf4j.Slf4j;@Slf4j // 使用@Slf4j注解简化日志记录
@ControllerAdvice
public class GlobalExceptionHandler {/*** 处理所有异常* @param e 异常对象* @return 错误响应*/@ExceptionHandler(Exception.class)public ResponseEntity<String> handleException(Exception e) {log.error("发生错误: ", e); // 记录错误日志return new ResponseEntity<>("发生错误: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); // 返回错误消息}
}

8. 启动应用程序

确保你的主应用程序类正确配置:

package com.example.demo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import lombok.extern.slf4j.Slf4j;@SpringBootApplication
@Slf4j // 使用@Slf4j注解简化日志记录
public class DemoApplication {/*** 主函数,启动Spring Boot应用* @param args 命令行参数*/public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args); // 启动Spring Boot应用log.info("Spring Boot应用已启动"); // 记录启动日志}
}

9. 测试

启动应用程序后,你可以通过浏览器或Postman等工具访问以下URL来测试Excel的读写功能:

  • 写入Excel:http://localhost:8080/excel/write?filePath=/path/to/your/output.xlsx
  • 读取Excel:http://localhost:8080/excel/read?filePath=/path/to/your/input.xlsx

总结

以上是完整的Spring Boot集成EasyExcel的详细步骤和代码示例,包括详细的注释以及实现了当单个页面数据达到一定量时重新生成新的页面进行写入的功能。

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

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

相关文章

第十次CCF-CSP认证(含C++源码)

第十次CCF-CSP认证 分蛋糕满分题解 学生排队满分题解 Markdown语法题目解读满分代码 结语 分蛋糕 题目链接 满分题解 基本思路&#xff1a;我们需要保证除了最后一个小朋友之外的所有人&#xff0c;分得的蛋糕都大于等于给定的K值&#xff0c;为什么是大于等于&#xff0c;是…

MyBatis框架操作数据库一>xml和动态Sql

目录 配置连接字符串和MyBatis:数据库的连接配置&#xff1a;XML的配置&#xff1a; XML编写Sql:model层&#xff1a;mapper层&#xff1a; 动态Sql:if 标签和trim标签&#xff1a;where标签:Set标签:Foreach标签: Mybatis的开发有两种方式&#xff1a;&#xff1a; 注解和XML&…

编写Dockerfile制作tomcat镜像,生成镜像名为tomcat:v1,并推送到私有仓库。

1.具体要求如下&#xff1a; 基于rockylinux:8基础镜像&#xff1b; 指定作者为openlab&#xff1b; 安装tomcat服务&#xff0c;暴露8080端口&#xff1b; 设置服务自启动。 总结步骤&#xff1a;基于rockylinux:8&#xff0c;安装Java环境&#xff0c;安装Tomcat&a…

医院手术麻醉信息系统是如何为医院提质增效的?

近年来&#xff0c;随着HIS系统、LIS系统、PACS系统、EMR系统等信息系统的出现&#xff0c;医疗信息化已成为医疗领域推广的重点&#xff0c;显著提高了医院业务的运营效率。手术麻醉系统作为医院信息系统的一部分&#xff0c;由两个子部分组成&#xff1a;监测设备数据采集系统…

ios打包需要的证书及步骤

官网&#xff1a;https://developer.apple.com/account 避免他人登录apple账号的方法&#xff1a;就是让他们发测试设备的udid&#xff0c;手动注册到账号下&#xff0c;然后再给他们导p12证书和描述文件 iOS App Development iOS 开发版本签名&#xff08;仅限 iOS App&#x…

C#特性和反射

1。特性概念理解&#xff1f; 特性&#xff08;Attribute&#xff09;是用于在【运行时】传递程序中各种元素&#xff08;比如类、属性、方法、结构、枚举、组件等&#xff09;行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所…

【毕业论文格式】word分页符后的标题段前间距消失

文章目录 【问题描述】 分页符之后的段落开头&#xff0c;明明设置了标题有段前段后间距&#xff0c;但是没有显示间距&#xff1a; 【解决办法】 选中标题&#xff0c;选择边框 3. 选择段前间距&#xff0c;1~31磅的一个数 结果

操作系统-八股

进程基础&#xff1a; 进程定义&#xff1a;运行中的程序&#xff0c;有独立的内存空间和地址&#xff0c;是系统进行资源调度和分配的基本单位。 并发&#xff0c;并行 并发就是单核上面轮询&#xff0c;并行就是同时执行&#xff08;多核&#xff09;&#xff1b; 进程上下…

骑士74CMS_v3.34.0SE版uniapp全开源小程序怎么编译admin和member流程一篇文章说清楚

有粉丝一直问我骑士系统怎么编译后台和小程序目前骑士人才系统74CMS分标准版&#xff0c;创业板&#xff0c;专业版&#xff0c;其除功能不同外其配置方法完全一致有喜欢系统的也可以私信我或者找我获取 一.安装打包环境[Nodejs]这个就不用我说了吧&#xff0c;用不小于V20的版…

c语言zixue

该文主要是记录我学习中遇到的一些重点、易出问题的内容 教材p16.17 先从一个简单的例子开始吧 #include <stdio.h> //编译预处理命令 int main() //程序的主函数 {printf("To C"); //输出语句return 0; //返回语句 } #include <stdio.h>是编译预…

ollama API 本地调用

ollama API 本地调用 前提条件&#xff0c;ollama 已经启动了模型&#xff0c;查看 ollama 中的 model 名称 ollama list使用 openai 调用 from openai import OpenAI import openaiopenai.api_key ollama openai.base_url http://localhost:11434/v1/def get_completion(pro…

es6 尚硅谷 学习

1、let 1.变量不能重复声明 2.块级作用域 &#xff0c;只在块内有效 3.不存在变量提升&#xff0c;变量未声明之前不可使用 4.不影响作用域链 2、const const SCHOOL “温医”&#xff1b; 1.一定要有初始值 2.一般常量使用大写 3.常量不能赋值 4.块级作用域 5.对数组和对象…

在微信小程序或前端开发中,picker 和 select 都是用户交互中用于选择的组件,但它们在功能、设计和使用场景上有一定的区别

在微信小程序或前端开发中&#xff0c;picker 和 select 都是用户交互中用于选择的组件&#xff0c;但它们在功能、设计和使用场景上有一定的区别。 1. picker 的特点 描述&#xff1a; picker 是微信小程序中的原生组件&#xff0c;通常用于选择单项或多项值&#xff0c;如时…

C#通过API接口返回流式响应内容---分块编码方式

1、背景 上一篇文章《C#通过API接口返回流式响应内容—SSE方式》阐述了通过SSE&#xff08;Server Send Event&#xff09;方式&#xff0c;由服务器端推送数据到浏览器。本篇是通过分块编码的方式实现 2、效果 3、具体代码 3.1 API端实现 [HttpGet] public async Task Chu…

【SpringMVC】入门版

1.基本概念 1.1三层架构 三层架构也就是我们常说的b/s架构中的表现层&#xff0c;业务层和持久层,每层都各司其职&#xff0c;下面来分别讲解这三层的作用。 表现层&#xff1a; 也就是我们常说的web层。它负责接收客户端的请求&#xff0c;向客户端响应结果&#xff0c;通…

各省水资源平台 水资源遥测终端机都用什么协议

各个省水资源平台 水资源遥测终端机 的建设大部分从2012年开始启动&#xff0c;经过多年建设&#xff0c;基本都已经形成了稳定的通讯要求&#xff1b;河北瑾航科技 遥测终端机&#xff0c;兼容了大部分省市的通讯协议&#xff0c;如果需要&#xff0c;可以咨询和互相学习&…

【Android】RuntimeShader 应用

1 简介 RuntimeShader 是 Android 13&#xff08;T&#xff09;中新增的特性&#xff0c;用于逐像素渲染界面&#xff0c;它使用 AGSL&#xff08;Android Graphics Shading Language&#xff09;编写着色器代码&#xff0c;底层基于 Skia 图形渲染引擎。官方介绍详见 → Runti…

ShenNiusModularity项目源码学习(16:ShenNius.Admin.Mvc项目分析-1)

ShenNius.Admin.Mvc项目是MVC模式的启动项目&#xff0c;包括了MVC模式下所需的所有的页面、控制器类、资源、js文件等数据&#xff0c;该项目仅依赖ShenNius.Admin.API项目&#xff0c;主要使用后者的ShenniusAdminApiModule模块类及一些依赖项目中定义的辅助类等。本文学习Sh…

maven wrapper的使用

写在前面 考虑这样的场景&#xff0c;张三创建了一个maven项目使用了3.9版本&#xff0c;当李四下载下来去开发配置的却是3.6版本&#xff0c;此时李四就不得不再去配置一个3.9版本的maven&#xff0c;为了解决这个问题&#xff0c;maven引入了maven wrapper的机制&#xff08…

1、操作系统引论

一、操作系统 会使用linux系统 建议大家先学会linux的基础指令&#xff0c;可以看菜鸟教程网站进行学习。 1、各种定义 操作系统定义 管理计算机的 硬件 和软件资源&#xff0c; 能对各类作业进行调度&#xff0c;方便用户使用计算机的程序集合。操作系统运行在内核态&#xf…