SpringBoot整合easyexcel实现Excel的导入与导出
导出
在一般不管大的或者小的系统中,各家的产品都一样,闲的无聊的时候都喜欢让我们这些程序员导出一些数据出来供他观赏,非说这是必须需求,非做不可,那么我们就只能苦逼的哼哧哼哧的写bug喽。
之前使用POI导出excel需要自己先去创建excel文件,还要创建sheet,写表头,操作起来确实很麻烦,针对产品这种随心而欲的需求我们能不能快速的做完这样一个产品看起来挺简单的功能。
基于这样一个快速开发的场景,我们来看看easyexcel应该如何使用。
首先我们创建一个springboot(版本是 2.1.4.RELEASE)项目,在此就不过多的啰嗦,创建好之后,首先需要引入easyexcel的maven坐标。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>1.1.2-beta5</version>
</dependency>
导入好了之后,我们接下来需要创建一个导出的模板类,首先要集成BaseRowModel,set、get省略,@ExcelProperty注解中的value就是表头的信息,index是在第几列,没有加注解的不会导出。
public class OrderExcelBO extends BaseRowModel {
@ExcelProperty(value = {"订单ID"}, index = 0)
private String id;
/**
* 订单描述
*/
@ExcelProperty(value = {"订单描述"}, index = 2)
private String description;
/**
* 订单对应产品id
*/
@ExcelProperty(value = {"产品ID"}, index = 2)
private Integer productId;
/**
* 支付方式描述,如:apple pay
*/
@ExcelProperty(value = {"支付方式"}, index = 3)
private String payMethod;
/**
* create_time
*/
@ExcelProperty(value = {"时间"}, index = 4)
private String createTime;
/**
* update_time
*/
private String updateTime;
/**
* 产生订单的用户
*/
@ExcelProperty(value = {"用户ID"}, index = 5)
private Integer userId;
/**
* 支付状态:0 未支付、1支付成功支付完成、-1支付失败
*/
@ExcelProperty(value = {"支付状态"}, index = 6)
private String status;
/**
* 订单来源描述,如:ios 安卓
*/
@ExcelProperty(value = {"手机型号"}, index = 7)
private String platform;
/**
* 订单流水
*/
@ExcelProperty(value = {"订单流水号"}, index = 8)
private String flowNum;
/**
* 订单金额
*/
@ExcelProperty(value = {"金额"}, index = 9)
private BigDecimal price;
// @ExcelProperty(value = {"收据字段"}, index = 10)
private String receipt;
@ExcelProperty(value = {"APP来源"}, index = 10)
private String sources;
}
导出的模板定义好之后,接下来就是一些封装好的工具类的调用
- 查出我们需要导出的数据;
- 生成Excel文件名和sheet名称;
- 直接调用封装好的工具类导出文件即可;
我们来看下导出的效果
如果你的表头比较复杂,那么根据需求,你也可自行定义,例如如下这种复杂的表头,应该如何设置
首先要修改模板类,如果合并的单元格最大为2,那么所有的表格都需要设置为2,不合并的单元格用空字符串填充,需要合并的单元格将合并部分写上相同的名称,并且排列的序号要连续,不能分开。
我们来看下导出的效果,这样就可以满足我们平时开发需要的excel导出功能。简单易上手。
工具类:
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener; import java.util.ArrayList;
import java.util.List; /**
* 监听类,可以自定义
*
* @author liuyi
* @Created 2019-7-18 18:01:53
**/
public class ExcelListener extends AnalysisEventListener { /**
* 自定义用于暂时存储data。
* 可以通过实例获取该值
*/
private List<Object> datas = new ArrayList<>(); /**
* 通过 AnalysisContext 对象还可以获取当前 sheet,当前行等数据
*/
@Override
public void invoke(Object object, AnalysisContext context) {
//数据存储到list,供批量处理,或后续自己业务逻辑处理。
datas.add(object);
//根据业务自行 do something
doSomething();
/*
如数据过大,可以进行定量分批处理
if(datas.size()<=100){
datas.add(object);
}else {
doSomething();
datas = new ArrayList<Object>();
}
*/
} /**
* 根据业务自行实现该方法
*/
private void doSomething() {
} @Override
public void doAfterAllAnalysed(AnalysisContext context) {
/*
datas.clear();
解析结束销毁不用的资源
*/
} public List<Object> getDatas() {
return datas;
} public void setDatas(List<Object> datas) {
this.datas = datas;
}
}
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Font;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.TableStyle;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.mochu.exception.ExcelException;
import org.apache.poi.poifs.filesystem.FileMagic;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List; /**
* Excel工具类
*
* @author liuyi
* @Created 2019-7-18 18:01:53
**/
public class ExcelUtil {
/**
* 读取 Excel(多个 sheet)
*
* @param excel 文件
* @param rowModel 实体类映射,继承 BaseRowModel 类
* @return Excel 数据 list
*/
public static List<Object> readExcel(MultipartFile excel, BaseRowModel rowModel) {
ExcelListener excelListener = new ExcelListener();
ExcelReader reader = getReader(excel, excelListener); if (reader == null) {
return null;
} for (Sheet sheet : reader.getSheets()) {
if (rowModel != null) {
sheet.setClazz(rowModel.getClass());
}
reader.read(sheet);
} return excelListener.getDatas();
} /**
* 读取某个 sheet 的 Excel
*
* @param excel 文件
* @param rowModel 实体类映射,继承 BaseRowModel 类
* @param sheetNo sheet 的序号 从1开始
* @return Excel 数据 list
*/
public static List<Object> readExcel(MultipartFile excel, BaseRowModel rowModel, int sheetNo) {
return readExcel(excel, rowModel, sheetNo, 1);
} /**
* 读取某个 sheet 的 Excel
*
* @param excel 文件
* @param rowModel 实体类映射,继承 BaseRowModel 类
* @param sheetNo sheet 的序号 从1开始
* @param headLineNum 表头行数,默认为1
* @return Excel 数据 list
*/
public static List<Object> readExcel(MultipartFile excel, BaseRowModel rowModel, int sheetNo, int headLineNum) {
ExcelListener excelListener = new ExcelListener();
ExcelReader reader = getReader(excel, excelListener); if (reader == null) {
return null;
} reader.read(new Sheet(sheetNo, headLineNum, rowModel.getClass())); return excelListener.getDatas();
} /**
* 导出 Excel :一个 sheet,带表头
*
* @param response HttpServletResponse
* @param list 数据 list,每个元素为一个 BaseRowModel
* @param fileName 导出的文件名
* @param sheetName 导入文件的 sheet 名
* @param object 映射实体类,Excel 模型
*/
public static void writeExcel(HttpServletResponse response, List<? extends BaseRowModel> list, String fileName,
String sheetName, BaseRowModel object) {
ExcelWriter writer = new ExcelWriter(getOutputStream(fileName, response), ExcelTypeEnum.XLSX);
Sheet sheet = new Sheet(1, 0, object.getClass());
sheet.setSheetName(sheetName); TableStyle tableStyle = new TableStyle();
tableStyle.setTableContentBackGroundColor(IndexedColors.WHITE);
Font font = new Font();
font.setFontHeightInPoints((short) 9);
tableStyle.setTableHeadFont(font);
tableStyle.setTableContentFont(font);
sheet.setTableStyle(tableStyle); writer.write(list, sheet);
writer.finish();
} /**
* 导出 Excel :多个 sheet,带表头
*
* @param response HttpServletResponse
* @param list 数据 list,每个元素为一个 BaseRowModel
* @param fileName 导出的文件名
* @param sheetName 导入文件的 sheet 名
* @param object 映射实体类,Excel 模型
*/
public static ExcelWriterFactory writeExcelWithSheets(HttpServletResponse response,
List<? extends BaseRowModel> list, String fileName,
String sheetName, BaseRowModel object) {
ExcelWriterFactory writer = new ExcelWriterFactory(getOutputStream(fileName, response), ExcelTypeEnum.XLSX);
Sheet sheet = new Sheet(1, 0, object.getClass());
sheet.setSheetName(sheetName);
sheet.setTableStyle(getTableStyle());
writer.write(list, sheet); return writer;
} /**
* 导出融资还款情况表
*
* @param response
* @param list
* @param fileName
* @param sheetName
* @param object
*/
public static void writeFinanceRepayment(HttpServletResponse response, List<? extends BaseRowModel> list,
String fileName, String sheetName, BaseRowModel object) {
ExcelWriter writer = new ExcelWriter(getOutputStream(fileName, response), ExcelTypeEnum.XLSX);
Sheet sheet = new Sheet(1, 0, object.getClass());
sheet.setSheetName(sheetName);
sheet.setTableStyle(getTableStyle());
writer.write(list, sheet); for (int i = 1; i <= list.size(); i += 4) {
writer.merge(i, i + 3, 0, 0);
writer.merge(i, i + 3, 1, 1);
} writer.finish();
} /**
* 导出文件时为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", "filename=" + fileName); return response.getOutputStream();
} catch (Exception e) { throw new ExcelException("导出异常!");
}
} /**
* 返回 ExcelReader
*
* @param excel 需要解析的 Excel 文件
* @param excelListener new ExcelListener()
*/
private static ExcelReader getReader(MultipartFile excel, ExcelListener excelListener) {
String filename = excel.getOriginalFilename(); if (filename == null || (!filename.toLowerCase().endsWith(".xls") && !filename.toLowerCase().endsWith(".xlsx"))) {
throw new ExcelException("文件格式错误!");
}
InputStream inputStream; try {
inputStream = new BufferedInputStream(excel.getInputStream()); return new ExcelReader(inputStream, null, excelListener, false);
} catch (IOException e) {
e.printStackTrace();
} return null;
} /**
* 资金收支导出 Excel :一个 sheet,带表头
*
* @param response HttpServletResponse
* @param list 数据 list,每个元素为一个 BaseRowModel
* @param fileName 导出的文件名
* @param sheetName 导入文件的 sheet 名
* @param object 映射实体类,Excel 模型
*/
public static void exportFundBudgetExcel(HttpServletResponse response, List<? extends BaseRowModel> list,
String fileName, String sheetName, BaseRowModel object) throws IOException {
ExcelWriter writer = new ExcelWriter(getOutputStream(fileName, response), ExcelTypeEnum.XLSX);
Sheet sheet = new Sheet(1, 0, object.getClass());
sheet.setSheetName(sheetName);
sheet.setTableStyle(getTableStyle()); writer.write(list, sheet);
writer.merge(2, 3, 0, 0);
writer.merge(4, 13, 0, 0);
writer.merge(14, 14, 0, 1);
writer.finish();
} /**
* 读取Excel表格数据,封装成实体
*
* @param inputStream
* @param clazz
* @param sheetNo
* @param headLineMun
* @return
*/
public static Object readExcel(InputStream inputStream, Class<? extends BaseRowModel> clazz, Integer sheetNo,
Integer headLineMun) {
if (null == inputStream) { throw new NullPointerException("the inputStream is null!");
} ExcelListener listener = new ExcelListener();
ExcelReader reader = new ExcelReader(inputStream, valueOf(inputStream), null, listener);
reader.read(new Sheet(sheetNo, headLineMun, clazz)); return listener.getDatas();
} /**
* 根据输入流,判断为xls还是xlsx,该方法原本存在于easyexcel 1.1.0 的ExcelTypeEnum中。
*/
public static ExcelTypeEnum valueOf(InputStream inputStream) {
try {
FileMagic fileMagic = FileMagic.valueOf(inputStream); if (FileMagic.OLE2.equals(fileMagic)) {
return ExcelTypeEnum.XLS;
} if (FileMagic.OOXML.equals(fileMagic)) {
return ExcelTypeEnum.XLSX;
} throw new ExcelException("excelTypeEnum can not null"); } catch (IOException e) {
throw new RuntimeException(e);
}
} /**
* 设置全局样式
*
* @return
*/
private static TableStyle getTableStyle() {
TableStyle tableStyle = new TableStyle(); tableStyle.setTableContentBackGroundColor(IndexedColors.WHITE);
Font font = new Font();
font.setBold(true);
font.setFontHeightInPoints((short) 9);
tableStyle.setTableHeadFont(font);
Font fontContent = new Font();
fontContent.setFontHeightInPoints((short) 9);
tableStyle.setTableContentFont(fontContent); return tableStyle;
}
}
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.support.ExcelTypeEnum; import java.io.IOException;
import java.io.OutputStream;
import java.util.List; /**
*ExcelWriterFactory 工具类
* @author liuyi
* @Created 2019-7-18 18:01:53
**/
public class ExcelWriterFactory extends ExcelWriter {
private OutputStream outputStream;
private int sheetNo = 1; public ExcelWriterFactory(OutputStream outputStream, ExcelTypeEnum typeEnum) {
super(outputStream, typeEnum);
this.outputStream = outputStream;
} public ExcelWriterFactory write(List<? extends BaseRowModel> list, String sheetName, BaseRowModel object) {
this.sheetNo++;
try {
Sheet sheet = new Sheet(sheetNo, 0, object.getClass());
sheet.setSheetName(sheetName);
this.write(list, sheet);
}
catch(Exception ex) {
ex.printStackTrace();
try {
outputStream.flush();
}
catch(IOException e) {
e.printStackTrace();
}
}
return this;
} @Override
public void finish() {
super.finish();
try {
outputStream.flush();
}
catch(IOException e) {
e.printStackTrace();
}
}
}
导入
其实在提供的那几个工具类中已经有了导入的方法,只需要直接调用即可。下面我们来简单演示一下,如何导入。我们先看下Controller是如何写的
@PostMapping("/import/order")
public ResultMsg import_order(MultipartFile excel) {
Object objList = ExcelUtil.readExcel(excel, new OrderExcelBO(), 1, 1);
if (objList == null) {
return ResultMsg.fail(500, "导入的数据不能为空");
}
List orderList = (List) objList;
if (orderList == null || orderList.size() <= 0) {
return ResultMsg.fail(500, "导入的数据不能为空");
}
orderList.forEach(System.out::println);
return ResultMsg.success();
}
我们主要再看下readExcel()方法是如何写的
/**
* 读取某个 sheet 的 Excel
*
* @param excel 文件
* @param rowModel 实体类映射,继承 BaseRowModel 类
* @param sheetNo sheet 的序号 从1开始
* @param headLineNum 表头行数,默认为1
* @return Excel 数据 list
*/
public static List<Object> readExcel(MultipartFile excel, BaseRowModel rowModel, int sheetNo, int headLineNum) {
ExcelListener excelListener = new ExcelListener();
ExcelReader reader = getReader(excel, excelListener); if (reader == null) {
return null;
} reader.read(new Sheet(sheetNo, headLineNum, rowModel.getClass())); return excelListener.getDatas();
}
在底层的方法我就不贴出来了,我大家可在()文章里面找到需要的工具类,我们就直接看下运行结果。
导出结果
那么数据都已经打印出来了,那么存入数据库就超级简单了。
SpringBoot整合easyexcel实现Excel的导入与导出的更多相关文章
- SpringBoot整合Easyexcel操作Excel,闲暇之余,让我们学习更多
关于封面:晚饭后回自习室的路上 Easyexcel 官方文档 Easyexcel | github 前言 最近也是在写的一个小练习中,需要用到这个.趁着这次就将写个整合的Demo给大家. 希望能够让大 ...
- springboot整合easyexcel实现Excel导入导出
easyexcel:快速.简单避免OOM的java处理Excel工具 Java解析.生成Excel比较有名的框架有Apache poi.jxl.但他们都存在一个严重的问题就是非常的耗内存,poi有一套 ...
- SpringBoot中关于Excel的导入和导出
前言 由于在最近的项目中使用Excel导入和导出较为频繁,以此篇博客作为记录,方便日后查阅.本文前台页面将使用layui,来演示对Excel文件导入和导出的效果.本文代码已上传至我的gitHub, ...
- excel的导入与导出---通用版
excel的导入与导出---通用版 web项目关于导入导出的业务场景很常见,最近我就又遇到了这个业务场景.这次将最近半个月做的导入导出总结一下 使用的pom如下,主要还是阿里巴巴的easyexcel依 ...
- .net数据库实现Excel的导入与导出
.net数据库实现Excel的导入与导出 参考路径:https://www.cnblogs.com/splendidme/archive/2012/01/05/2313314.html 1.defau ...
- SpringCloud微服务实战——搭建企业级开发框架(三十):整合EasyExcel实现数据表格导入导出功能
批量上传数据导入.数据统计分析导出,已经基本是系统必不可缺的一项功能,这里从性能和易用性方面考虑,集成EasyExcel.EasyExcel是一个基于Java的简单.省内存的读写Excel的开源项 ...
- C#中Excel的导入和导出的几种基本方式
在上一篇(http://www.cnblogs.com/fengchengjushi/p/3369386.html)介绍过,Excel也是数据持久化的一种实现方式.在C#中.我们常常会与Excel文件 ...
- Excel报表开发(主要讲Excel的导入和导出)
一.Excel数据导入 连接字符串Excel2003版: OleDbConnection conn = new OleDbConnection("provider=Microsoft.Jet ...
- java实现Excel的导入、导出
一.Excel的导入 导入可采用两种方式,一种是JXL,另一种是POI,但前者不能读取高版本的Excel(07以上),后者更具兼容性.由于对两种方式都进行了尝试,就都贴出来分享(若有错误,请给予指正) ...
随机推荐
- Codeforces Round #553 (Div. 2) E 贡献
https://codeforces.com/contest/1151/problem/E 题意 一条长n的链,每个点上有值\(a[i]\),定义\(f(l,r)\)为该区间的\(值\)所代表的点留下 ...
- 大话设计模式Python实现- 抽象工厂模式
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的类 下面是一个抽象工厂的demo: #!/usr/bin/env pyth ...
- LeetCode 200:岛屿数量 Number of Islands
题目: 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量.一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的.你可以假设网格的四个边均被水包围. Given ...
- MongoDB自学------(3)MongoDB文档操作
一.插入文档 二.查询文档 三.更新文档 可以看到标题(title)由原来的 "Mongodb" 更新为了 "MongoDBtest". 以上语句只会修改第一条 ...
- 使用 jQuery.TypeAhead 让文本框自动完成 (一)(最简单的用法)
项目地址:https://github.com/twitter/typeahead.js 直接贴代码了: @section headSection { <script type="te ...
- 一个简单的利用 WebClient 异步下载的示例(一)
继上一篇文章 一个简单的利用 HttpClient 异步下载的示例 ,我们知道不管是 HttpClient,还算 WebClient,都不建议每次调用都 new HttpClient,或 new We ...
- java函数式编程的形式
java中没有真正的函数变量: 一.所有的函数(拉姆达)表达式,都被解释为functional interface @FunctionalInterface interface GreetingSer ...
- [CrackMe]160个CrackMe之001
吾爱破解专题汇总:[反汇编练习]160个CrackME索引目录1~160建议收藏备用 一.Serial/Name 之 暴力破解 1. 熟悉界面:很常规的一个界面,输入完账号密码之后会进行验证. 2. ...
- dubbo入门学习
官方网址:http://dubbo.apache.org/zh-cn/index.html 学习可以参考官网中文文档:http://dubbo.apache.org/zh-cn/docs/user/q ...
- 三维网格补洞算法(Poisson Method)(转载)
转载:https://www.cnblogs.com/shushen/p/5864042.html 下面介绍一种基于Poisson方程的三角网格补洞方法.该算法首先需要根据孔洞边界生成一个初始化补洞网 ...