SpringBoot操作Excel实现导入和导出功能(详细讲解+Gitee源码)

前言:在日常的开发中,避免不了操作Excel,比如从系统当中导出一个报表,或者通过解析客户上传的Excel文件进行批量解析数据入库等等,本篇博客主要汇总日常开发中如何使用开源的Apache提供的POI流操作Excel进行导入导出功能详解。

目录

一、导入pom.xml依赖

二、准备数据

三、导出功能 

1、新建文件

2、新建工作簿

3、自定义样式

4、创建行和列并填充数据

5、合并单元格 

6、创建批注 

7、遍历数据

8、设置响应下载

9、运行截图

四、导入功能

1、获取单元格值方法

2、获取文件流

3、获取Excel文件对象

4、获取工作簿

5、获取首尾行下标

6、读取数据 

7、测试运行

五、完整代码

六、Gitee源码  


一、导入pom.xml依赖

这边我使用的是Apache提供的POI流来操作Excel。 

    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- apache工具操作poi --><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

二、准备数据

1、学生实体类

@Data
public class Student {private int id;private String name;private String sex;private String address;private String phone;
}

2、初始化数据

    public List<Student> initData(){List<Student> list = new ArrayList<>();Student student = new Student();student.setId(1);student.setName("张三");student.setSex("男");student.setAddress("江苏");student.setPhone("19991198111");list.add(student);student = new Student();student.setId(2);student.setName("李四");student.setSex("女");student.setAddress("南京");student.setPhone("1887119121");list.add(student);return list;}public void export(HttpServletResponse response) throws IOException {//获取学生数据List<Student> students = initData();//获取标题String[] titles = {"编号","姓名","性别","地址","电话"};//导出Excel的代码...}

三、导出功能 

这边主要讲解关于遍历数据、设置单元格样式、合并单元格和插入批注一些常用的功能。

1、新建文件

这边提供了2种Excel格式的文件,选一个即可,为了更好的兼容性,这边我采用的是.xls格式。

//.xls格式
HSSFWorkbook workbook = new HSSFWorkbook();
//.xlsx格式
//XSSFWorkbook workbook = new XSSFWorkbook();

2、新建工作簿

这行代码就是新建一个名为学生表的工作簿

HSSFSheet sheet = workbook.createSheet("学生表");

3、自定义样式

实例化出来的cellStyle提供给了我们很多关于设置样式的方法,这边我就提供一些常用的设置单元格样式的代码,把它封装成了一个方法,每行代码上面都有注释。

HSSFCellStyle cellStyle = workbook.createCellStyle();

常用样式代码:

/*** 单元格样式* @param workbook* @param fontBold 是否加粗* @param isBorder 是否带边框* @param horizontalAlignment 水平对齐格式* @param verticalAlignment 垂直对齐格式* @return*/private HSSFCellStyle getColumnStyle(HSSFWorkbook workbook,boolean fontBold,boolean isBorder,HorizontalAlignment horizontalAlignment,VerticalAlignment verticalAlignment) {// 设置字体HSSFFont font = workbook.createFont();//设置字体大小font.setFontHeightInPoints((short) 12);//设置字体名字font.setFontName("宋体");font.setBold(fontBold);//设置样式;HSSFCellStyle style = workbook.createCellStyle();// 是设置前景色不是背景色style.setFillForegroundColor(IndexedColors.RED.getIndex());style.setFillPattern(FillPatternType.SOLID_FOREGROUND);if (isBorder) {//设置底边框;style.setBorderBottom(BorderStyle.THIN);//设置底边框颜色;style.setBottomBorderColor(IndexedColors.BLACK.index);//设置左边框;style.setBorderLeft(BorderStyle.THIN);//设置左边框颜色;style.setLeftBorderColor(IndexedColors.BLACK.index);//设置右边框;style.setBorderRight(BorderStyle.THIN);//设置右边框颜色;style.setRightBorderColor(IndexedColors.BLACK.index);//设置顶边框;style.setBorderTop(BorderStyle.THIN);//设置顶边框颜色;style.setTopBorderColor(IndexedColors.BLACK.index);}//在样式用应用设置的字体;style.setFont(font);//设置自动换行;style.setWrapText(false);//设置水平对齐的样式为居中对齐;style.setAlignment(horizontalAlignment);//设置垂直对齐的样式为居中对齐;style.setVerticalAlignment(verticalAlignment);return style;}

4、创建行和列并填充数据

首先我们需要先通过HSSFRow创建单元行,其次再通过HSSFRow实例化的对象去创建单元列,最后通过HSSFCell实例化的对象去填充数据,这边我创建了一个名为学生信息表的标题。

//创建单元行
HSSFRow header = sheet.createRow(0);
//创建单元列
HSSFCell headerCell = header.createCell(0);
//填充信息
headerCell.setCellValue("学生信息表");

再通过同样的代码遍历我们的字段标题

//创建第一行
HSSFRow titleRow = sheet.createRow(1);//写入标题
for(int i = 0 ; i < titles.length ; i++ ){
HSSFCell cell = titleRow.createCell(i);cell.setCellValue(titles[i]);cell.setCellStyle(cellStyle);
}

5、合并单元格 

首先创建 CellRangeAddress对象,表示要合并的单元格范围,然后使用 addMergedRegion()方法合并单元格,以下这是CellRangeAddress的参数详解。

startRow开始行0,表示第1行
endRow结束行1,表示第2行
startColumn开始列2,表示第3列
endColumn结束列3,表示第4列

代码如下:

CellRangeAddress region = new CellRangeAddress(0, 0 , 0, titles.length-1);
sheet.addMergedRegion(region);

6、创建批注 

首先如果要在工作表上添加批注/图片/图形等元素,需要先调用createDrawingPatriarch()来获取工作表的绘制对象Drawing。

其次在工作表中创建单元格批注的对象,HSSFClientAnchor用于创建一个新的端锚,并设置锚的左下和右下坐标,用于图片插入,画线等操作。

HSSFClientAnchor的参数顺序如下:

左边距、上边距、右边距、下边距 、 开始列、开始行 、结束列、 结束行。

Drawing drawing = sheet.createDrawingPatriarch();
Comment comment = drawing.createCellComment(new HSSFClientAnchor(0, 0, 0, 0,(short) headerCell.getColumnIndex(),headerCell.getRowIndex(),(short) (headerCell.getColumnIndex() + 5),headerCell.getRowIndex() + 6));comment.setString(new HSSFRichTextString("这是标题信息哦!"));
headerCell.setCellComment(comment);

所以这段代码的意思是:在工作表上,创建了一个单元格批注comment,这个批注的锚点设置在从单元格headerCell开始,延伸5列6行。

7、遍历数据

最后我们通过循环来遍历我们集合当中的数据,上面已经讲过,这边不再多做讲解。

         for(int i = 0 ; i < students.size() ; i++ ){Student student = students.get(i);HSSFRow row = sheet.createRow(i+2);for (int j = 0; j < titles.length; j++) {HSSFCell cell = null;switch (j) {case 0:cell = row.createCell(j);cell.setCellValue(i);break;case 1:cell = row.createCell(j);cell.setCellValue(student.getName());break;case 2:cell = row.createCell(j);cell.setCellValue(student.getSex());break;case 3:cell = row.createCell(j);cell.setCellValue(student.getAddress());break;case 4:cell = row.createCell(j);cell.setCellValue(student.getPhone());break;}}}

8、设置响应下载

1、定义Excel文件名

2、把文件名编码为 ISO-8859-1格式,从而支持中文下载文件名

3、设置 Response为附件应答

4、设置附件名称为codeFileName,告诉浏览器这是一个附件应答

5、从workbook中获取输出流,写入内容到response输出流

6、关闭workbook,释放资源

String fileName = "学生表统计";
String codeFileName = new String((fileName + ".xls").getBytes("UTF-8"), "ISO-8859-1");
response.reset();
response.setCharacterEncoding("UTF-8");
response.setContentType("application/vnd.ms-excel;charset=UTF-8");
response.setHeader("Content-Disposition", "attachment;filename=" + codeFileName);
OutputStream out = response.getOutputStream();
workbook.write(response.getOutputStream());
out.flush();
out.close();
workbook.close();

9、运行截图

浏览器访问:http://localhost:8080/student/export

四、导入功能

1、获取单元格值方法

如果当前单元格的格式是时间格式,则需要特殊处理为时间格式,否则会报错。

String dataFormatString = cell.getCellStyle().getDataFormatString();
if(dataFormatString.equals("m/d/yy")){cellValue = new SimpleDateFormat("yyyy-MM-dd").format(cell.getDateCellValue());return cellValue;
}

如果当前单元格是数字,比如1,那么读出来会默认是1.0,所以要把数字当成String来读。

if(cell.getCellType() == CellType.NUMERIC){cell.setCellType(CellType.STRING);
}

先判断读取的类型,来通过switch结构来获取单元格值。

//判断数据的类型
switch (cell.getCellType()){//数字case NUMERIC:cellValue = String.valbreak;//字符串case STRING:cellValue = String.valbreak;//Booleancase BOOLEAN:cellValue = String.valbreak;//公式case FORMULA:cellValue = String.valbreak;//空值case BLANK:cellValue = "";break;//故障case ERROR:cellValue = "非法字符";break;default:cellValue = "未知类型";break;
}

2、获取文件流

FileInputStream in = new FileInputStream("F:\\学生表统计.xls");

3、获取Excel文件对象

我这边我获取的是.xls后缀格式的文件

Workbook workbook = new HSSFWorkbook(in);

这个是获取.xlsx格式的对象 

Workbook workbook = new XSSFWorkbook(in);

4、获取工作簿

默认通过工作簿名称来获取工作簿对象

Sheet sheet = workbook.getSheet("学生表");

也可以通过下标来进行获取

Sheet sheet = workbook.getSheetAt(0);

5、获取首尾行下标

获取首行下标

int firstRowNum = sheet.getFirstRowNum();

获取尾行下标 

int lastRowNum = sheet.getLastRowNum();

6、读取数据 

使用for循环读取每行的第一列单元格的数据,获取数据的方法就是我上面封装好的方法。

for(int i = firstRowNum ; i <=lastRowNum ; i++){Row row = sheet.getRow(i);Cell cell = null;if(row != null){cell = row.getCell(0);}System.out.println(getCellValue(cell));}

7、测试运行

我准备了7种不同类型的数据进行读取

单元测试结果如下,读取一切正常。 

五、完整代码

导入和导出的完整代码:

package com.example.excel.service;import com.example.excel.domain.Student;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;/*** @author HTT*/
@Service
public class StudentService {public List<Student> initData(){List<Student> list = new ArrayList<>();Student student = new Student();student.setId(1);student.setName("张三");student.setSex("男");student.setAddress("江苏");student.setPhone("19991198111");list.add(student);student = new Student();student.setId(2);student.setName("李四");student.setSex("女");student.setAddress("南京");student.setPhone("1887119121");list.add(student);return list;}public void export(HttpServletResponse response) throws IOException {//获取学生数据List<Student> students = initData();//获取标题String[] titles = {"编号","姓名","性别","地址","电话"};//.xls格式HSSFWorkbook workbook = new HSSFWorkbook();//.xlsx格式//XSSFWorkbook workbook = new XSSFWorkbook();//新增工作表HSSFSheet sheet = workbook.createSheet("学生表");//单元格样式对象HSSFCellStyle cellStyle = this.getColumnStyle(workbook, true, true, HorizontalAlignment.CENTER,VerticalAlignment.CENTER);//创建第一行HSSFRow header = sheet.createRow(0);HSSFCell headerCell = header.createCell(0);headerCell.setCellValue("学生信息表");CellRangeAddress region = new CellRangeAddress(0, 0 , 0, titles.length-1);sheet.addMergedRegion(region);/*** - 左边距* - 上边距* - 右边距* - 下边距* - 开始列* - 开始行* - 结束列* - 结束行* 在工作表`drawing`上,* 创建了一个单元格批注 comment。* 这个批注的锚点设置在从单元格 headerCell 开始,延伸 5 列 6 行。*/Drawing drawing = sheet.createDrawingPatriarch();Comment comment = drawing.createCellComment(new HSSFClientAnchor(0, 0, 0, 0,(short) headerCell.getColumnIndex(),headerCell.getRowIndex(),(short) (headerCell.getColumnIndex() + 5),headerCell.getRowIndex() + 6));comment.setString(new HSSFRichTextString("这是标题信息哦!"));headerCell.setCellComment(comment);//创建第一行HSSFRow titleRow = sheet.createRow(1);//写入标题for(int i = 0 ; i < titles.length ; i++ ){HSSFCell cell = titleRow.createCell(i);cell.setCellValue(titles[i]);cell.setCellStyle(cellStyle);}for(int i = 0 ; i < students.size() ; i++ ){Student student = students.get(i);HSSFRow row = sheet.createRow(i+2);for (int j = 0; j < titles.length; j++) {HSSFCell cell = null;switch (j) {case 0:cell = row.createCell(j);cell.setCellValue(i);break;case 1:cell = row.createCell(j);cell.setCellValue(student.getName());break;case 2:cell = row.createCell(j);cell.setCellValue(student.getSex());break;case 3:cell = row.createCell(j);cell.setCellValue(student.getAddress());break;case 4:cell = row.createCell(j);cell.setCellValue(student.getPhone());break;}}}String fileName = "学生表统计";String codeFileName = new String((fileName + ".xls").getBytes("UTF-8"), "ISO-8859-1");response.reset();response.setCharacterEncoding("UTF-8");response.setContentType("application/vnd.ms-excel;charset=UTF-8");response.setHeader("Content-Disposition", "attachment;filename=" + codeFileName);OutputStream out = response.getOutputStream();workbook.write(response.getOutputStream());out.flush();out.close();workbook.close();}/*** 单元格样式* @param workbook* @param fontBold 是否加粗* @param isBorder 是否带边框* @param horizontalAlignment 水平对齐格式* @param verticalAlignment 垂直对齐格式* @return*/private HSSFCellStyle getColumnStyle(HSSFWorkbook workbook,boolean fontBold,boolean isBorder,HorizontalAlignment horizontalAlignment,VerticalAlignment verticalAlignment) {// 设置字体HSSFFont font = workbook.createFont();//设置字体大小font.setFontHeightInPoints((short) 12);//设置字体名字font.setFontName("宋体");font.setBold(fontBold);//设置样式;HSSFCellStyle style = workbook.createCellStyle();// 是设置前景色不是背景色style.setFillForegroundColor(IndexedColors.RED.getIndex());style.setFillPattern(FillPatternType.SOLID_FOREGROUND);if (isBorder) {//设置底边框;style.setBorderBottom(BorderStyle.THIN);//设置底边框颜色;style.setBottomBorderColor(IndexedColors.BLACK.index);//设置左边框;style.setBorderLeft(BorderStyle.THIN);//设置左边框颜色;style.setLeftBorderColor(IndexedColors.BLACK.index);//设置右边框;style.setBorderRight(BorderStyle.THIN);//设置右边框颜色;style.setRightBorderColor(IndexedColors.BLACK.index);//设置顶边框;style.setBorderTop(BorderStyle.THIN);//设置顶边框颜色;style.setTopBorderColor(IndexedColors.BLACK.index);}//在样式用应用设置的字体;style.setFont(font);//设置自动换行;style.setWrapText(false);//设置水平对齐的样式为居中对齐;style.setAlignment(horizontalAlignment);//设置垂直对齐的样式为居中对齐;style.setVerticalAlignment(verticalAlignment);return style;}/*** 获取单元格的值* @param cell* @return*/public static String getCellValue(Cell cell){String cellValue = "";if(cell == null){return cellValue;}//如果当前单元格内容为日期类型,需要特殊处理String dataFormatString = cell.getCellStyle().getDataFormatString();if(dataFormatString.equals("m/d/yy")){cellValue = new SimpleDateFormat("yyyy-MM-dd").format(cell.getDateCellValue());return cellValue;}//把数字当成String来读,避免出现1读成1.0的情况if(cell.getCellType() == CellType.NUMERIC){cell.setCellType(CellType.STRING);}//判断数据的类型switch (cell.getCellType()){//数字case NUMERIC:cellValue = String.valueOf(cell.getNumericCellValue());break;//字符串case STRING:cellValue = String.valueOf(cell.getStringCellValue());break;//Booleancase BOOLEAN:cellValue = String.valueOf(cell.getBooleanCellValue());break;//公式case FORMULA:cellValue = String.valueOf(cell.getCellFormula());break;//空值case BLANK:cellValue = "";break;//故障case ERROR:cellValue = "非法字符";break;default:cellValue = "未知类型";break;}return cellValue;}public void analysis() throws IOException {// 通过输入流,读取excel文件FileInputStream in = new FileInputStream("F:\\学生表统计.xls");// excel文件对象Workbook workbook = new HSSFWorkbook(in);// 通过工作簿的名字获取工作簿Sheet sheet = workbook.getSheet("学生表");// 通过工作簿的下标获取工作簿//Sheet sheet = workbook.getSheetAt(0);// 获取首行下标int firstRowNum = sheet.getFirstRowNum();// 获取尾行下标int lastRowNum = sheet.getLastRowNum();for(int i = firstRowNum ; i <=lastRowNum ; i++){Row row = sheet.getRow(i);Cell cell = null;if(row != null){cell = row.getCell(0);}System.out.println(getCellValue(cell));}}
}

请求层

package com.example.excel.controller;import com.example.excel.service.StudentService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@RestController
@RequestMapping("/student")
public class StudentController {@Resourceprivate StudentService service;@GetMapping("/export")public void export(HttpServletResponse response) throws IOException {service.export(response);}
}

六、Gitee源码  

SpringBoot使用Apache操作Excel导入与导出: 主要汇总日常开发中常用的关于一些关于Excel导入导出功能详解。

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

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

相关文章

【035】C++泛型编程(模板)实践:设计数组类模板模仿vector容器

C泛型编程&#xff08;模板&#xff09;实践 引言一、类模板的概述二、实现数组类模板三、类模板的继承3.1、类模板派生出普通类3.2、类模板派生出类模板 总结 引言 &#x1f4a1; 作者简介&#xff1a;专注于C/C高性能程序设计和开发&#xff0c;理论与代码实践结合&#xff0…

常州工学院单片机及应用系统设计2021-2022 学年第 二 学期 考试类型 开卷 课程编码 0302005

第一题 #include "SC95F861x_C.H" #include <INTRINS.H> unsigned char keydata0; void delay(unsigned int timer) //延时函数 { while(timer>0) timer--; } void IOinit() { P5CON0x00; P5PH0x03; P3CON0xFF; P3PH0xFF; } void readke…

回归预测 | MATLAB实现PSO-DNN粒子群算法优化深度神经网络的数据多输入单输出回归预测

回归预测 | MATLAB实现PSO-DNN粒子群算法优化深度神经网络的数据多输入单输出回归预测 目录 回归预测 | MATLAB实现PSO-DNN粒子群算法优化深度神经网络的数据多输入单输出回归预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 回归预测 | MATLAB实现PSO-DNN粒子…

【Java基础教程】(二)入门介绍篇 · 下:从JDK下载安装到第一个“Hello World!”程序,解析PATH和CLASSPATH环境变量的妙用~

Java基础教程之入门介绍 下 本节学习目标1️⃣ JDK安装与配置2️⃣ 第一个Java程序&#xff1a;“Hello World!”3️⃣ 环境变量 CLASSPATH&#x1f33e; 总结 本节学习目标 JDK 安装与配置&#xff1b;理解环境变量PATH和CLASSPATH的主要作用&#xff1b;运行第一个Java程序…

TypeScript 自定义装饰器

&#xff08;预测未来最好的方法就是把它创造出来——尼葛洛庞帝&#xff09; 装饰器 装饰器一种更现代的代码模式&#xff0c;通过使用的形式注入在属性&#xff0c;寄存器&#xff0c;方法&#xff0c;方法参数和类中&#xff0c;比如在Angular&#xff0c;Nestjs和midway等…

E类变换器仿真

1 参数计算&#xff08;待续&#xff09; &#xff08;1&#xff09;确定振荡频率&#xff1a; &#xff08;2&#xff09;计算各器件参数&#xff1b; 2 电路仿真 &#xff08;1&#xff09;电路图 &#xff08;2&#xff09;电路分析 3 结果 &#xff08;1&#xff09;…

微信小程序+SpringBoot接入后台服务,接口数据来自后端

前言 前两天开发了一个微信小程序项目&#xff0c;只不过接口数据是自己设置的假数据。然后我就想将这些假数据替换掉。这些数据来自接口&#xff0c;之前做过前后端分离的项目&#xff0c;我就想能不能直接调用那些后端数据接口。结果是可以的。以下是自己编写的部分方法 步骤…

【IDE 小程序】小程序控制台 不打印 console.log问题

小程序控制台 不打印 console.log问题 全局搜索compress.drop_console&#xff08;一般在config文件中&#xff09;&#xff0c;设置为false&#xff0c;再重新打开小程序即可

【JUC-7】ReentrantLock (可重入锁)基础

ReentrantLock (可重入锁) ReentrantLock实现了Lock接口, 内部通过继承AQS, 实现了一个同步器. 可以通过同步器来创建Condition条件变量, 可以用作容器, 存放不同条件的等待线程. 说明ReentrantLock与AQS的关系 类图: 相对于synchronized, 都支持可重入. 它还具备如下特点: …

对弈人工智能!myCobot 280开源六轴机械臂Connect 4 四子棋对弈

Connect 4 myCobot280 Introduction Hi,guys.今天我们来介绍一下人工智能下棋&#xff0c;我们将用机械臂来作为对手跟你进行下棋。 人工智能下棋的研究可以追溯到20世纪50年代。当时&#xff0c;计算机科学家开始探索如何编写程序&#xff0c;使计算机能够下象棋。其中最著…

Linux 解决root用户被限制连接服务器

Linux 解决root用户被限制连接服务器 1. 问题描述2. 解决问题2.1 方式一&#xff08;忘记root密码的情况&#xff09;2.2 方式二&#xff08;知道root密码的情况&#xff09; 3. 其他 1. 问题描述 使用 root 用户不能链接服务器&#xff0c;密码对&#xff0c;就是连接不上&am…

VBA之正则表达式(42)-- 快速提取名称

实例需求&#xff1a;A列为待处理数据&#xff0c;现需要从中提取商品名、通用名、胰岛素笔相关信息&#xff0c;保存到B列至D列&#xff0c;需要注意如下几点&#xff1a; 胰岛素笔&#xff08;E列&#xff09;数据只存在于每组产品的第一行记录中&#xff0c;例如第2行数据中…