SpringBoot2:web开发常用功能实现及原理解析-整合EasyExcel实现Excel导入导出功能
1、工程包结构
主要是这5个Java类

2、导入EasyExcel包
这里同时贴出其他相关springboot的基础包
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></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>2.2.6</version></dependency>
3、Java代码
ExcelSysUser
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.ContentStyle;
import com.alibaba.excel.annotation.write.style.HeadFontStyle;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import lombok.Data;
import lombok.ToString;
import org.apache.poi.ss.usermodel.HorizontalAlignment;@ContentRowHeight(25)
@HeadRowHeight(15)
@ColumnWidth(25)
@HeadFontStyle(fontHeightInPoints=9)
@ContentStyle(horizontalAlignment= HorizontalAlignment.CENTER)
@Data
@ToString
public class ExcelSysUser {public ExcelSysUser(){}public ExcelSysUser(String loginName, String userName, String userPwd){this.loginName = loginName;this.userName = userName;this.userPwd = userPwd;}@ExcelProperty(value = "登录名",index = 0)private String loginName;@ExcelProperty(value = "用户名",index = 1)private String userName;@ExcelProperty(value = "密码",index = 2)private String userPwd;}
ExcelFillCellMergeHandler
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;import java.util.List;/*** 合并单元格处理类*/
public class ExcelFillCellMergeHandler implements CellWriteHandler {//需要合并的列private int[] mergeColumnIndex;//从哪一列开始合并private int mergeRowIndex;public ExcelFillCellMergeHandler() {}public ExcelFillCellMergeHandler(int mergeRowIndex, int[] mergeColumnIndex) {this.mergeRowIndex = mergeRowIndex;this.mergeColumnIndex = mergeColumnIndex;}@Overridepublic void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {}@Overridepublic void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {}@Overridepublic void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {}@Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {int curRowIndex = cell.getRowIndex();int curColIndex = cell.getColumnIndex();if (curRowIndex > mergeRowIndex) {for (int i = 0; i < mergeColumnIndex.length; i++) {if (curColIndex == mergeColumnIndex[i]) {mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);break;}}}}/*** 当前单元格向上合并** @param writeSheetHolder* @param cell 当前单元格* @param curRowIndex 当前行* @param curColIndex 当前列*/private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();// 将当前单元格数据与上一个单元格数据比较Boolean dataBool = preData.equals(curData);Boolean bool = cell.getRow().getCell(0).getStringCellValue().equals(cell.getSheet().getRow(curRowIndex - 1).getCell(0).getStringCellValue());if (dataBool && bool) {Sheet sheet = writeSheetHolder.getSheet();List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();boolean isMerged = false;for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {CellRangeAddress cellRangeAddr = mergeRegions.get(i);// 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {sheet.removeMergedRegion(i);cellRangeAddr.setLastRow(curRowIndex);sheet.addMergedRegion(cellRangeAddr);isMerged = true;}}// 若上一个单元格未被合并,则新增合并单元if (!isMerged) {CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);sheet.addMergedRegion(cellRangeAddress);}}}}
ExcelListener
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;import java.util.ArrayList;
import java.util.List;/*** 解析监听器,* 每解析一行会回调invoke()方法。* 整个excel解析结束会执行doAfterAllAnalysed()方法*/
public class ExcelListener extends AnalysisEventListener {private List<Object> datas = new ArrayList<>();public List<Object> getDatas() {return datas;}public void setDatas(List<Object> datas) {this.datas = datas;}/*** 逐行解析* object : 当前行的数据*/@Overridepublic void invoke(Object object, AnalysisContext context) {//当前行// context.getCurrentRowNum()if (object != null) {datas.add(object);}}/*** 解析完所有数据后会调用该方法*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {//解析结束销毁不用的资源}
}
EasyExcelUtil
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.atguigu.boot.handler.ExcelFillCellMergeHandler;
import com.atguigu.boot.listener.ExcelListener;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;/*** EasyExcel工具类*/
public class EasyExcelUtil {/*** 读取 Excel(多个 sheet)** @param excel 文件* @param rowModel 实体类映射* @return Excel 数据 list*/public static List<Object> readExcel(MultipartFile excel, Object rowModel) throws IOException {String filename = excel.getOriginalFilename();if (filename == null || (!filename.toLowerCase().endsWith(".xls") && !filename.toLowerCase().endsWith(".xlsx"))) {throw new RuntimeException("文件格式错误!");}ExcelListener excelListener = new ExcelListener();EasyExcel.read(excel.getInputStream(),rowModel.getClass(),excelListener).doReadAll();return excelListener.getDatas();}/*** 导出 Excel :一个 sheet,带表头** @param response HttpServletResponse* @param list 数据 list* @param fileName 导出的文件名* @param sheetName 导入文件的 sheet 名* @param object 映射实体类,Excel 模型*/public static void writeExcel(HttpServletResponse response, List<?> list, String fileName,String sheetName, Object object) {EasyExcel.write(getOutputStream(fileName, response),object.getClass()).excelType(ExcelTypeEnum.XLSX).autoCloseStream(Boolean.TRUE).sheet(sheetName).doWrite(list);}/*** 导出 Excel 自动合并单元格* @param response HttpServletResponse* @param list 数据 list* @param fileName 导出的文件名* @param sheetName 导入文件的 sheet 名* @param object 映射实体类,Excel 模型* @param mergeColumnIndex 需要合并的列* @param mergeRowIndex 从哪一列开始合并*/public static void writeMergeExcel(HttpServletResponse response, List<?> list, String fileName,String sheetName, Object object, int[] mergeColumnIndex, int mergeRowIndex) {EasyExcel.write(getOutputStream(fileName, response),object.getClass()).excelType(ExcelTypeEnum.XLSX).autoCloseStream(Boolean.TRUE).registerWriteHandler(new ExcelFillCellMergeHandler(mergeRowIndex,mergeColumnIndex)).sheet(sheetName).doWrite(list);}/*** 导出文件时为Writer生成OutputStream*/private static OutputStream getOutputStream(String fileName, HttpServletResponse response) {//创建本地文件fileName = fileName + ".xls";try {fileName = new String(fileName.getBytes(), "ISO-8859-1");response.addHeader("Content-Disposition", "attachment;filename=" + fileName);return response.getOutputStream();} catch (Exception e) {throw new RuntimeException("导出异常!");}}}
EasyExcelLoadsController
import com.atguigu.boot.bean.ExcelSysUser;
import com.atguigu.boot.utils.EasyExcelUtil;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;@RestController
@RequestMapping("/excel")
public class EasyExcelLoadsController {/*** 用户信息导出Excel*/@RequestMapping(value = "/exportSysUser",method = RequestMethod.GET)public void exportSysUser(HttpServletResponse response){List<ExcelSysUser> excelSysUsers = new ArrayList<>();ExcelSysUser excelSysUser1 = new ExcelSysUser("张三", "zhangsan002", "zsmm123");ExcelSysUser excelSysUser2 = new ExcelSysUser("张三", "zhangsan003", "zsmm456");ExcelSysUser excelSysUser3 = new ExcelSysUser("张三", "zhangsan001", "zsmm789");ExcelSysUser excelSysUser4 = new ExcelSysUser("李四", "zhangsan001", "zsmm123");ExcelSysUser excelSysUser5 = new ExcelSysUser("李四", "zhangsan001", "zsmm456");excelSysUsers.add(excelSysUser1);excelSysUsers.add(excelSysUser2);excelSysUsers.add(excelSysUser3);excelSysUsers.add(excelSysUser4);excelSysUsers.add(excelSysUser5);EasyExcelUtil.writeExcel(response, excelSysUsers,"用户信息","用户信息", new ExcelSysUser());}/*** 用户信息导出Excel(合并单元格)*/@RequestMapping(value = "/exportMergeSysUser",method = RequestMethod.GET)public void exportMergeSysUser(HttpServletResponse response){List<ExcelSysUser> excelSysUsers = new ArrayList<>();ExcelSysUser excelSysUser1 = new ExcelSysUser("张三", "zhangsan002", "zsmm123");ExcelSysUser excelSysUser2 = new ExcelSysUser("张三", "zhangsan003", "zsmm456");ExcelSysUser excelSysUser3 = new ExcelSysUser("张三", "zhangsan001", "zsmm789");ExcelSysUser excelSysUser4 = new ExcelSysUser("李四", "zhangsan001", "zsmm123");ExcelSysUser excelSysUser5 = new ExcelSysUser("李四", "zhangsan001", "zsmm456");excelSysUsers.add(excelSysUser1);excelSysUsers.add(excelSysUser2);excelSysUsers.add(excelSysUser3);excelSysUsers.add(excelSysUser4);excelSysUsers.add(excelSysUser5);int[] mergeColumnIndex = {0,1};int mergeRowIndex = 0;EasyExcelUtil.writeMergeExcel(response, excelSysUsers,"用户信息","用户信息", new ExcelSysUser(), mergeColumnIndex, mergeRowIndex);}@RequestMapping(value = "/importSysUser",method = RequestMethod.POST)public void importSysUser(MultipartFile excel){List<Object> dataList = null;try {dataList = EasyExcelUtil.readExcel(excel, new ExcelSysUser());} catch (IOException e) {e.printStackTrace();}dataList.forEach(o -> System.out.println(o.toString()));}}
4、测试Excel
导入需要准备下图中的数据,导出直接浏览器访问接口即可。

相关文章:
SpringBoot2:web开发常用功能实现及原理解析-整合EasyExcel实现Excel导入导出功能
1、工程包结构 主要是这5个Java类 2、导入EasyExcel包 这里同时贴出其他相关springboot的基础包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><depend…...
CTFShow-信息搜集
Web1: 题目描述:开发注释未及时删除 。 打开题目后提示web1:where is flag? ctrlu读取源码。 Web2: 题目描述:js前台拦截 无效操作 打开题目后显示:无法查看源代码 右键无法用,…...
Facebook的虚拟现实功能简介:社交网络的新前沿
在科技飞速发展的今天,虚拟现实(VR)已经从科幻小说中的梦想变成了触手可及的现实。作为全球领先的社交平台,Facebook(现已更名为Meta)正大力推动虚拟现实技术的发展,以重新定义用户的社交体验。…...
Redis embstr 编码
embstr 编码 是 Redis 中一种优化存储小型字符串的编码方式。它是 Redis 内部存储字符串的多种方式之一,特别适用于存储长度不超过 44 字节的小字符串。...
【Elasticsearch系列二】安装 Kibana
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
中国电子学会202403青少年软件编程(Python)等级考试试卷(三级)真题与解析
202403Python 三级真题 一、选择题 1.在 Python 中,hex(2023)的功能是?( ) A.将十进制数 2023 转化为十六进制数 B.将十进制数 2023 转化为八进制数 C.将十六进制数 2023 转化为十进制数 D.将八进制数 2023 转化为十进制数 2.下列表达式的值与其他三个选项不相…...
k8s 资源管理
文章目录 ResourceQuota什么是资源配额定义一个ResourceQuotaResourceQuota的使用 LimitRangeLimitRange的用途示例1:配置默认的requests和limits示例2:配置requests和limits的范围 QoS什么是服务质量保证示例1:实现QoS为Guaranteed的Pod示例…...
演示:基于WPF的自绘的中国地铁轨道控件
一、目的:演示一个基于WPF的自绘的中国地铁轨道控件 二、效果演示 北京地铁 成都地铁 上海地铁 深圳地铁 南京地铁 长春地铁 哈尔滨地铁 武汉地铁 厦门地铁 香港地铁 三、功能 支持平移、缩放等操作 鼠标悬停显示线路信息和站点信息 按表格显示,按纸张…...
设计模式(Design Patterns)
设计模式(Design Patterns)是软件开发人员在软件设计过程中面临的一般性问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。设计模式的目的是为了提高代码的可重用性、可维护性、可读性、可靠性以及灵活性。设…...
C++:opencv生成结构元素用于膨胀腐蚀等cv::getStructuringElement
cv::getStructuringElement 是 OpenCV 库中用于生成结构元素的函数。结构元素在形态学操作中(如膨胀、腐蚀、开运算、闭运算等)扮演着关键角色。这个函数可以创建不同形状和尺寸的结构元素,以适应不同的图像处理需求。 函数原型 cv::Mat cv…...
最大余额法,解决百分比计算相加不等于100%(扇形/饼图百分比使用的此算法)
在开发项目的过程中有时候需要进行计算百分比,例如计算饼状图百分比。有时候在计算的过程中常规四舍五入计算会发生所有计算的值相加不等于100%的情况 这是 get_percent_value 函数的 JavaScript 版本: /*** 最大余额法,解决百分比计算相加不…...
哈希表简单介绍
概念 在顺序结构以及平衡树中,元素关键字与他们存储的位置并没有直接的映射关系,从而会影响查找关键字的效率,顺序结构中查找关键字的时间复杂度为O(N),平衡树查找关键字的时间复杂度为O(log2^…...
kafka 之 本地部署单机版
安装JDK 查看你选择的版本需要安装哪一个版本的jdk 网址 下载 JDK下载 注:如果网页不允许下载,使用wget命令下载即可,下载之后安装。 建议使用rpm安装,之后使用 update-alternatives --config java 控制当前环境使用Java的版…...
开发一款通过蓝牙连接控制水电表的微信小程序
增强软硬件交互 为了更好的解决师生生活中的实际问题,开发蓝牙小程序加强了和校区硬件的交互。 比如通过蓝牙连接控制水电表,减少实体卡片的使用。添加人脸活体检测功能,提高本人认证效率,减少师生等待时间。 蓝牙水电控展示 蓝…...
力扣14.最长公共前缀
思路:将字符串数组中第一个字符串用作参考; 8.将他的长度作为范围,因为超范围了之后就不会再有公共前缀了 9.将字符串数组的长度也作为范围,意思是便利字符串数组中的字符串 11.开始第一层循环,依次遍历第一个字符串的…...
你也喜欢“钓鱼“吗?
免责声明:本文仅做分享! 目录 什么是网络钓鱼 流程 攻击手法 0-隐藏自己 1-office宏 创建xxx.dotm 创建xxx.docx 2-RLO 自解压 3-快捷方式lnk 4-邮件伪造 Swaks Gophish 5-网站克隆 setoolkit nginx反向代理 前端页面克隆 6-wifi钓鱼 7-其他 防御 溯源 反…...
druid jdbc 执行 sql 输出 开销耗时
druid 执行sql输出 参考链接配置_LogFilter alibaba/druid Wiki GitHub 看不太懂的往这里瞅瞅。 1. 别名映射 这个地方 给我们提供了 5 种 logfilter : log4j、log4j2、slf4j、commonlogging和commonLogging 每一种实际上都代表一个日志框架 或 日志门面。 -Ddruid.fil…...
C++如何处理内存碎片问题
目录 一.前言二.什么是内存碎片三.如何处理内存碎片 一.前言 这篇文章简单讨论一下C如何处理内存碎片问题。 二.什么是内存碎片 所谓内存碎片就是系统中存在的不能供进程使用的小块内存,主要包括外部碎片以及内部碎片。 外部碎片:内存分配和回收的过…...
FreeRTOS常用API接口函数
提示:FreeRTOS常用API接口函数:并对部分参数附上自己的解释,后面继续补充 FreeRTOS常用API接口函数 1.任务相关的API1.1 创建任务:xTaskCreate1.2 开启任务调度器函数:vTaskStartScheduler1.3 任务的删除:vTaskDelete1…...
DesignPattern设计模式
1 前言 1.1 内容概要 理解使用设计模式的目的掌握软件设计的SOLID原则理解单例的思想,并且能够设计一个单例理解工厂设计模式的思想,能够设计简单工厂,理解工厂方法了解建造者模式的思想,掌握其代码风格理解代理设计模式的思想&a…...
KiCanvas:浏览器中的KiCAD设计查看器,5分钟快速入门指南
KiCanvas:浏览器中的KiCAD设计查看器,5分钟快速入门指南 【免费下载链接】kicanvas The KiCAD web viewer 项目地址: https://gitcode.com/gh_mirrors/ki/kicanvas 想要在浏览器中直接查看KiCAD电路设计文件,无需安装任何软件…...
如何快速搭建专业级游戏串流系统:Sunshine完整教程
如何快速搭建专业级游戏串流系统:Sunshine完整教程 【免费下载链接】Sunshine Sunshine: Sunshine是一个自托管的游戏流媒体服务器,支持通过Moonlight在各种设备上进行低延迟的游戏串流。 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine …...
SparkFun ICM-20948 Arduino库:DMP硬件协处理器深度实践指南
1. 项目概述SparkFun ICM-20948 Arduino Library 是面向 TDK InvenSense ICM-20948 九轴惯性测量单元(9DoF IMU)的官方 Arduino 封装库,专为 SparkFun 9DoF IMU Breakout - ICM-20948(Qwiic 接口版本,型号 SEN-15335&a…...
OpCore-Simplify:终极OpenCore EFI配置自动化解决方案
OpCore-Simplify:终极OpenCore EFI配置自动化解决方案 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 还在为复杂的黑苹果配置而烦恼吗&am…...
云容笔谈开源镜像优势:免编译、免依赖、BF16原生支持,开箱即生成
云容笔谈开源镜像优势:免编译、免依赖、BF16原生支持,开箱即生成 最近在尝试各种AI图像生成工具时,我发现了一个很有意思的现象:很多工具要么安装配置复杂,要么生成效果不尽如人意,特别是想要生成具有东方…...
避坑指南:如何在torch 2.4.0 + CUDA 12.1环境下成功安装llamafactory及其依赖
深度避坑:PyTorch 2.4.0与CUDA 12.1环境下的Llamafactory全栈部署实战 当开发者尝试在PyTorch 2.4.0和CUDA 12.1环境下部署Llamafactory时,往往会陷入依赖地狱——从Torch版本误装到vllm模块缺失,每个环节都可能成为耗时数小时的深坑。本文将…...
计算机毕设 java 基于 Android 的医疗预约系统的设计与实现 SpringBoot 安卓智能医疗预约挂号平台 JavaAndroid 医患预约诊疗管理系统
计算机毕设 java 基于 Android 的医疗预约系统的设计与实现 53m069,末尾的数字和英文也要加上 (配套有源码 程序 mysql 数据库 论文)本套源码可以先看具体功能演示视频领取,文末有联 xi 可分享随着信息技术的飞速发展和医疗需求的…...
python-flask-djangol框架的食品仓库管理系统
目录需求分析与功能规划技术栈选择系统架构设计开发与测试流程安全与性能优化部署方案项目技术支持源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作需求分析与功能规划 明确食品仓库管理系统的核心需求,包括库存管理、食品分类、…...
海康MVS相机+Halcon标定实战:18张图搞定畸变矫正(附标定板选购指南)
海康MVS相机Halcon标定实战:18张图搞定畸变矫正与标定板选购指南 工业视觉系统的精度往往取决于相机标定的准确性。在实际项目中,我们常遇到这样的困境:明明按照教程步骤操作,标定结果却总是不尽如人意。本文将分享一套经过实战验…...
别再ping IP了!手把手教你给ZeroTier虚拟网络里的设备起个‘好记’的名字(DNS/mDNS实战)
告别IP记忆困扰:ZeroTier网络中的智能命名方案实战指南 每次在ZeroTier虚拟网络中访问设备时,你是否也厌倦了反复查看和输入那串冗长的IP地址?想象一下,当你想连接家庭NAS时,只需输入nas.home就能立即访问,…...
