目录
一、EasyExcel介绍
1、简介
2、常用注解
二、SpringBoot整合EasyExcel
1、基本环境
(1)引入依赖
(2)创建实体类
2、EasyExcel内容读取
(1)创建监听器
(2)测试
3、EasyExcel内容校验
(1)场景描述
(2)EasyExcel监听器
(3)测试
4、EasyExcel内容批量插入数据库
(1)创建数据库
(2)编写Mapper
(3)编写Service
(4)Controller层
(5)自定义转换器
(6)EasyExcel监听器
(7)测试
5、EasyExcel写入文件(基础版)
(1)写入操作
(2)测试结果
6、EasyExcel写入文件(Web模式基础版)
(1)Web模式写入操作
(2)测试结果
7、EasyExcel写入文件(Web模式进阶版)
(1)Web模式写入操作进阶版
(2)测试结果
8、EasyExcel写入操作(批量写入)
(1)Mapper文件
(2)编写Service
(3)Controller层
(4)测试结果
EasyExcel是阿里巴巴开源poi插件之一,是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。尽管Java解析、生成Excel不止EasyExcel,还有一些其他的框架,例如:Apache poi、jxl,但这些都存在一个严重的问题就是非常的耗内存。而EasyExcel是在尽可能节约内存的情况下支持读写百M的Excel,能在不用考虑性能、内存的等因素的情况下,快速完成Excel的读、写等功能。因此,本文将通过一个书籍列表的导入,作为案例,来揭开EasyExcel的使用过程。
- @ExcelProperty:指定当前字段对应excel中的那一列。可以根据名字或者Index去匹配。当然也可以不写,默认第一个字段就是index=0,以此类推。千万注意,要么全部不写,要么全部用index,要么全部用名字去匹配。千万别三个混着用,除非你非常了解源代码中三个混着用怎么去排序的。
- @ExcelIgnore:默认所有字段都会和excel去匹配,加了这个注解会忽略该字段
- @DateTimeFormat:日期转换,用String去接收excel日期格式的数据会调用这个注解。里面的value参照java.text.SimpleDateFormat
- @NumberFormat:数字转换,用String去接收excel数字格式的数据会调用这个注解。里面的value参照java.text.DecimalFormat
- @ExcelIgnoreUnannotated:默认不加ExcelProperty 的注解的都会参与读写,加了不会参与
com.alibaba
easyexcel
3.1.2
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.math.BigDecimal;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Book {
@ExcelProperty(value = "发布日期")
@DateTimeFormat("yyyy-MM-dd")
private String publishDate;
@ExcelProperty("书名")
private String bookName;
@ExcelProperty("作者")
private String author;
@ExcelProperty("价格")
private BigDecimal price;
@ExcelProperty("售卖数量")
private Integer saleNum;
@ExcelProperty(value = "是否热卖")
private String status;
}
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.example.yht.entity.Book;
import java.util.*;
public class ExcelListener extends AnalysisEventListener {
@Override
public void invokeHeadMap(Map headMap, AnalysisContext context) {
System.out.println("解析表头信息");
System.out.println(headMap);
}
@Override
public void onException(Exception exception, AnalysisContext context) {
System.out.println("Error Message : " + exception);
}
@Override
public void invoke(Book book, AnalysisContext analysisContext) {
System.out.println(book);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
System.out.println("解析完毕");
}
@Override
public boolean hasNext(AnalysisContext context) {
return super.hasNext(context);
}
}
主方法:
public static void main(String[] args) {
String filename="D:\\其他\\书籍列表.xlsx";
System.out.println("Excel内容如下:");
ExcelListener excelListener = new ExcelListener();
EasyExcel.read(filename, Book.class, excelListener).sheet(0).doRead();
}
测试结果:
上面介绍的内容只是一个简单的Excel读取案例。接下来,我们可以在解析加一些校验规则,例如:书籍的发布日期格式必须为YYYY-MM-DD格式;价格的整数位不能超过10位,小数位不能超过三位。接下来就来改造ExcelListener,以实现我们的需求。
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.exception.ExcelAnalysisStopException;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.example.yht.entity.Book;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;
public class ExcelListener extends AnalysisEventListener {
private List list = new ArrayList<>();
private List errList= new ArrayList<>();
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public List getErrList() {
return errList;
}
public void setErrList(List errList) {
this.errList = errList;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getCol() {
return col;
}
public void setCol(int col) {
this.col = col;
}
public Map getErrorMessageMap() {
return errorMessageMap;
}
private int row = 1;
private int col = 1;
private final Map errorMessageMap = new HashMap<>();
@Override
public void invokeHeadMap(Map headMap, AnalysisContext context) {
System.out.println("解析表头信息");
System.out.println(headMap);
row++;
}
@Override
public void onException(Exception exception, AnalysisContext context) {
String errMsg = "第" + row + "行, 第" + col + "列解析失败";
errList.add(errMsg);
row++ ;
if(exception instanceof ExcelAnalysisException) {
throw new ExcelAnalysisStopException("解析失败!");
}else{
throw new ExcelAnalysisStopException("解析失败!");
}
}
@Override
public void invoke(Book book, AnalysisContext analysisContext) {
if(book == null){
return;
}
if(!preDealEntity(book)){
throw new ExcelAnalysisException("数据解析错误");
}
list.add(book);
row++;
}
public boolean preDealEntity(Book book){
if(null == book){
return false;
}
Field[] fields = book.getClass().getDeclaredFields();
col = 1;
for(int i=0; i < fields.length; i++){
Field field = fields[i];
field.setAccessible(true);
try {
Object val = field.get(book);
if(val != null){
if(field.getName().equals("publishDate") && !isValidDate((String)val, "yyyy-MM-dd")){
return false;
}
if(val instanceof BigDecimal && !isNumeric(val+"")){
return false;
}
}
col++;
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return true;
}
public static boolean isNumeric(String str) {
if (null == str || "".equals(str)) {
return false;
}
String regx = "[+-]*\\d+\\.?\\d*[Ee]*[+-]*\\d+";
Pattern pattern = Pattern.compile(regx);
boolean isNumber = pattern.matcher(str).matches();
if (!isNumber) {
return isNumber;
}
regx = "^[-\\+]?[.\\d]*$";
pattern = Pattern.compile(regx);
isNumber = pattern.matcher(str).matches();
if (!isNumber) {
return isNumber;
}
String[] arrs = str.split("\\.");
return arrs[0].length() <= 10 && arrs[1].length() <= 3;
}
public static boolean isValidDate(String dateStr, String format) {
SimpleDateFormat sdf = new SimpleDateFormat(format);
sdf.setLenient(false); // 设置解析日期时严格匹配,不容忍格式错误
try {
sdf.parse(dateStr);
return true;
} catch (ParseException e) {
return false;
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
System.out.println("解析完毕");
}
@Override
public boolean hasNext(AnalysisContext context) {
return super.hasNext(context);
}
}
主方法:
public static void main(String[] args) {
//SpringApplication.run(FtpDemoApplication.class);
String filename="D:\\其他\\书籍列表.xlsx";
System.out.println("Excel内容如下:");
ExcelListener excelListener = new ExcelListener();
EasyExcel.read(filename, Book.class, excelListener).sheet(0).doRead();
if(excelListener.getErrList().isEmpty()){
System.out.println("所有数据解析成功!");
System.out.println(excelListener.getList());
}else{
System.out.println("数据解析失败:");
System.out.println(excelListener.getErrList());
}
}
第一种情况:解析正常的情况
Excel内容如下:
21:05:22.869 [main] DEBUG com.alibaba.excel.metadata.property.ExcelHeadProperty - The initialization sheet/table 'ExcelHeadProperty' is complete , head kind is CLASS
21:05:22.891 [main] DEBUG com.alibaba.excel.context.AnalysisContextImpl - Initialization 'AnalysisContextImpl' complete
21:05:23.018 [main] DEBUG com.alibaba.excel.cache.selector.SimpleReadCacheSelector - Use map cache.size:590
21:05:23.227 [main] DEBUG com.alibaba.excel.metadata.property.ExcelHeadProperty - The initialization sheet/table 'ExcelHeadProperty' is complete , head kind is CLASS
21:05:23.227 [main] DEBUG com.alibaba.excel.context.AnalysisContextImpl - Began to read:com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder@6a021575
解析表头信息
{0=发布日期, 1=书名, 2=作者, 3=价格, 4=售卖数量, 5=是否热卖}
解析完毕
所有数据解析成功!
[Book(publishDate=2013-5-4, bookName=三国演义, author=罗贯中, price=24.15, saleNum=34, status=是), Book(publishDate=2016-2-14, bookName=水浒传, author=施耐庵, price=49.34, saleNum=23, status=否), Book(publishDate=2013-12-14, bookName=三国演义, author=罗贯中, price=24.15, saleNum=1, status=是)]
Process finished with exit code 0
在表格中添加一些错误数据,如下:
可以看到:上面的代码案例中,如果某一行解析失败,则剩余行不做解析,直接返回解析错误的信息。
还有另外一种错误情况:如果某一行解析失败,剩余行依旧需要解析,直到解析完毕返回所有的错误信息。那么可以将监听器代码改成下面这样:
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.exception.ExcelAnalysisStopException;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.example.yht.entity.Book;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;
public class ExcelListener extends AnalysisEventListener {
private List list = new ArrayList<>();
private List errList= new ArrayList<>();
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public List getErrList() {
return errList;
}
public void setErrList(List errList) {
this.errList = errList;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getCol() {
return col;
}
public void setCol(int col) {
this.col = col;
}
public Map getErrorMessageMap() {
return errorMessageMap;
}
private int row = 1;
private int col = 1;
private final Map errorMessageMap = new HashMap<>();
@Override
public void invokeHeadMap(Map headMap, AnalysisContext context) {
System.out.println("解析表头信息");
System.out.println(headMap);
row++;
}
@Override
public void onException(Exception exception, AnalysisContext context) {
String errMsg = "第" + row + "行, 第" + col + "列解析失败";
row++ ;
}
@Override
public void invoke(Book book, AnalysisContext analysisContext) {
if(book == null){
return;
}
preDealEntity(book);
list.add(book);
row++;
}
public void preDealEntity(Book book){
if(null == book){
return;
}
Field[] fields = book.getClass().getDeclaredFields();
col = 1;
for(int i=0; i < fields.length; i++){
Field field = fields[i];
field.setAccessible(true);
try {
Object val = field.get(book);
if(val != null){
if(field.getName().equals("publishDate") && !isValidDate((String)val, "yyyy-MM-dd")){
String errMsg = "第" + row + "行, 第" + col + "列解析失败";
errList.add(errMsg);
}
if(val instanceof BigDecimal && !isNumeric(val+"")){
String errMsg = "第" + row + "行, 第" + col + "列解析失败";
errList.add(errMsg);
}
}
col++;
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
public static boolean isNumeric(String str) {
if (null == str || "".equals(str)) {
return false;
}
String regx = "[+-]*\\d+\\.?\\d*[Ee]*[+-]*\\d+";
Pattern pattern = Pattern.compile(regx);
boolean isNumber = pattern.matcher(str).matches();
if (!isNumber) {
return isNumber;
}
regx = "^[-\\+]?[.\\d]*$";
pattern = Pattern.compile(regx);
isNumber = pattern.matcher(str).matches();
if (!isNumber) {
return isNumber;
}
String[] arrs = str.split("\\.");
return arrs[0].length() <= 10 && arrs[1].length() <= 3;
}
public static boolean isValidDate(String dateStr, String format) {
SimpleDateFormat sdf = new SimpleDateFormat(format);
sdf.setLenient(false); // 设置解析日期时严格匹配,不容忍格式错误
try {
sdf.parse(dateStr);
return true;
} catch (ParseException e) {
return false;
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
System.out.println("解析完毕");
}
@Override
public boolean hasNext(AnalysisContext context) {
return super.hasNext(context);
}
}
create table t_book(
publish_date date,
book_name varchar(50),
author varchar(20),
price decimal(10,3),
sale_num int,
status tinyint(1)
);
@Mapper
public interface BookMapper {
Integer saveBook(@Param("bookList") List bookList);
}
insert into t_book(publish_date, book_name, author, price, sale_num, status)
VALUES
(#{book.publishDate},
#{book.bookName},
#{book.author},
#{book.price},
#{book.saleNum},
#{book.status})
public interface IBookService {
Integer saveBook(List bookList);
}
@Service
public class BookServiceImpl implements IBookService {
@Autowired
private BookMapper bookMapper;
@Override
public Integer saveBook(List bookList) {
return bookMapper.saveBook(bookList);
}
}
import com.alibaba.excel.EasyExcel;
import com.example.yht.entity.Book;
import com.example.yht.entity.Student;
import com.example.yht.listener.ExcelListener;
import com.example.yht.service.IBookService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.text.SimpleDateFormat;
@RestController
public class TestController {
@Autowired
private IBookService bookService;
@GetMapping("/excelToDB")
public void excelToDB(){
String filename="D:\\其他\\书籍列表.xlsx";
System.out.println("Excel内容如下:");
ExcelListener excelListener = new ExcelListener(bookService);
EasyExcel.read(filename, Book.class, excelListener).sheet(0).doRead();
if(excelListener.getErrList().isEmpty()){
System.out.println("所有数据解析成功!");
}else{
System.out.println("数据解析失败:");
System.out.println(excelListener.getErrList());
}
}
}
从Excel中可以看到一个细节,是否热卖这一列在excel里面的值有两种:是/否。但是在数据库里面,status的类型却是tinyint。因此我们就需要将excel里面的是/否转换为1/0,从而存储在数据库中。这里我们介绍一个Excel的转换器,可以实现这项操作。
这里首先将Book的实体类中的status改为Integer类型:
@ExcelProperty(value = "是否热卖", converter = StatusConverter.class)
private Integer status;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ReadConverterContext;
import com.alibaba.excel.converters.WriteConverterContext;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
public class StatusConverter implements Converter {
@Override
public Class> supportJavaTypeKey() {
return Converter.super.supportJavaTypeKey();
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return Converter.super.supportExcelTypeKey();
}
@Override
public Integer convertToJavaData(ReadCellData> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
return Converter.super.convertToJavaData(cellData, contentProperty, globalConfiguration);
}
@Override
public Integer convertToJavaData(ReadConverterContext> context) throws Exception {
return context.getReadCellData().getStringValue().equals("是") ? 1 : 0;
}
@Override
public WriteCellData> convertToExcelData(Integer value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
return new WriteCellData(value.equals(1) ? "是" : "否");
}
}
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.exception.ExcelAnalysisStopException;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.util.ListUtils;
import com.example.yht.entity.Book;
import com.example.yht.service.IBookService;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;
public class ExcelListener extends AnalysisEventListener {
//假设每5条插入一次数据库
private static int BATCH_COUNT = 5;
private List bookList = new ArrayList<>();
private List errList= new ArrayList<>();
private IBookService bookService;
public ExcelListener(IBookService bookService) {
this.bookService = bookService;
}
public List getBookList() {
return bookList;
}
public void setBookList(List bookList) {
this.bookList = bookList;
}
public List getErrList() {
return errList;
}
public void setErrList(List errList) {
this.errList = errList;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getCol() {
return col;
}
public void setCol(int col) {
this.col = col;
}
public Map getErrorMessageMap() {
return errorMessageMap;
}
private int row = 1;
private int col = 1;
private final Map errorMessageMap = new HashMap<>();
@Override
public void invokeHeadMap(Map headMap, AnalysisContext context) {
System.out.println("解析表头信息");
System.out.println(headMap);
row++;
}
@Override
public void onException(Exception exception, AnalysisContext context) {
String errMsg = "第" + row + "行, 第" + col + "列解析失败";
errList.add(errMsg);
System.out.println(exception);
row++ ;
if(exception instanceof ExcelAnalysisException) {
throw new ExcelAnalysisStopException("解析失败!");
}else{
throw new ExcelAnalysisStopException("解析失败!");
}
}
@Override
public void invoke(Book book, AnalysisContext analysisContext) {
if(book == null){
return;
}
if(!preDealEntity(book)){
throw new ExcelAnalysisException("数据解析错误");
}
bookList.add(book);
if(bookList.size() >= BATCH_COUNT){
saveData(bookList);
}
row++;
}
/**
* 保存数据
* @param list
*/
private void saveData(List list) {
bookService.saveBook(list);
bookList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
}
public boolean preDealEntity(Book book){
if(null == book){
return false;
}
Field[] fields = book.getClass().getDeclaredFields();
col = 1;
for(int i=0; i < fields.length; i++){
Field field = fields[i];
field.setAccessible(true);
try {
Object val = field.get(book);
if(val != null){
if(field.getName().equals("publishDate") && !isValidDate((String)val, "yyyy-MM-dd")){
return false;
}
if(val instanceof BigDecimal && !isNumeric(val+"")){
return false;
}
}
col++;
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return true;
}
public static boolean isNumeric(String str) {
if (null == str || "".equals(str)) {
return false;
}
String regx = "[+-]*\\d+\\.?\\d*[Ee]*[+-]*\\d+";
Pattern pattern = Pattern.compile(regx);
boolean isNumber = pattern.matcher(str).matches();
if (!isNumber) {
return isNumber;
}
regx = "^[-\\+]?[.\\d]*$";
pattern = Pattern.compile(regx);
isNumber = pattern.matcher(str).matches();
if (!isNumber) {
return isNumber;
}
String[] arrs = str.split("\\.");
return arrs[0].length() <= 10 && arrs[1].length() <= 3;
}
public static boolean isValidDate(String dateStr, String format) {
SimpleDateFormat sdf = new SimpleDateFormat(format);
sdf.setLenient(false); // 设置解析日期时严格匹配,不容忍格式错误
try {
sdf.parse(dateStr);
return true;
} catch (ParseException e) {
return false;
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
System.out.println("解析完毕");
//解析完之后,将list中的数据保存在数据库中
saveData(bookList);
}
@Override
public boolean hasNext(AnalysisContext context) {
return super.hasNext(context);
}
}
页面请求:http://localhost:8800/excelToDB
终端输出:
数据库内容:
这里先看一个基本的案例,首先指定文件位置,并添加一些模拟数据,再通过write方法写入该文件中。
@GetMapping("/writeBasic")
public void writeBasic(){
String fileName = "D:\\Data\\easyexcel.xlsx";
List list = new ArrayList<>();
list.add(new Book("2022-12-1", "人物传记1", "迪丽热巴1", new BigDecimal("34.5"), 20, 1));
list.add(new Book("2022-12-2", "人物传记2", "迪丽热巴2", new BigDecimal("44.5"), 30, 0));
list.add(new Book("2022-12-3", "人物传记3", "迪丽热巴3", new BigDecimal("54.5"), 40, 1));
EasyExcel.write(fileName, Book.class).sheet("模板").doWrite(list);
}
浏览器请求:http://localhost:8800/writeBasic
Web模式的写入操作,可以在页面发起请求的时候,将数据内容写入到excel中,并下载到本地。代码如下:
@GetMapping("/doWrite")
public void download(HttpServletResponse response) throws IOException {
// 这里直接用浏览器或者用postman
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("书籍列表.xlsx", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName);
//模拟要写入excel的数据
List list = new ArrayList<>();
list.add(new Book("2023-1-1", "花朵1", "张清1", new BigDecimal("34.5"), 20, 1));
list.add(new Book("2023-1-2", "花朵2", "张清2", new BigDecimal("44.5"), 30, 0));
list.add(new Book("2023-1-3", "花朵3", "张清3", new BigDecimal("54.5"), 40, 1));
EasyExcel.write(response.getOutputStream(), Book.class).sheet("新增").doWrite(list);
}
浏览器发起请求:http://localhost:8800/doWrite
文件下载:
表格内容:
这里的进阶版是在基础班的上面,加入了文件流的关闭操作等。
@GetMapping("/doWrite2")
public void downloadAdvanced(HttpServletResponse response){
//模拟写入的数据
List list = new ArrayList<>();
list.add(new Book("2023-2-1", "碧螺春1", "肖战1", new BigDecimal("34.5"), 20, 1));
list.add(new Book("2023-2-2", "碧螺春2", "肖战2", new BigDecimal("44.5"), 30, 0));
list.add(new Book("2023-2-3", "碧螺春3", "肖战3", new BigDecimal("54.5"), 40, 1));
try {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
//防止中文乱码
String fileName = URLEncoder.encode("书籍列表-new.xlsx", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName);
ServletOutputStream outputStream = response.getOutputStream();
//工作簿对象
ExcelWriterBuilder writerWork = EasyExcel.write(outputStream, Book.class);
//工作表对象
ExcelWriterSheetBuilder sheet = writerWork.sheet(0);
sheet.doWrite(list);
outputStream.flush();
outputStream.close();
} catch (Exception e) {
// 重置response
response.reset();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
Map map = new HashMap<>();
map.put("status", "failure");
map.put("message", "下载文件失败" + e.getMessage());
e.printStackTrace();
}
}
浏览器发起请求:http://localhost:8800/doWrite2
既然我们在插入数据库的时候,有批量插入的功能,那么自然也可以实现批量写入excel的方式。这里我们就从数据库里将插入的数据再次读 取出来,放入一个新的excel表格中。
Integer selectCount();
List selectBatch(Map map);
Integer selectCount();
List selectBatch(Map map);
@Override
public Integer selectCount() {
return bookMapper.selectCount();
}
@Override
public List selectBatch(Map map) {
return bookMapper.selectBatch(map);
}
这里为了验证批量插入的效果,在每次读取之后,写入不同的sheet。
@GetMapping("/doWriteBatch")
public void downloadBatch(HttpServletResponse response){
// 数据的总量(要写入Excel文件中的数据)
int count = bookService.selectCount();
int batchCount = 5;
List dataList = new ArrayList<>(batchCount);
// 总Sheet数
int num = count / batchCount;
// 输出流
OutputStream outputStream = null;
try {
response.setCharacterEncoding("UTF-8");
String excelName = URLEncoder.encode("batch_book", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + excelName + ".xlsx");
// 以字节流的形式输出响应正文
outputStream = response.getOutputStream();
try (ExcelWriter excelWriter = EasyExcel.write(outputStream, Book.class).build()) {
// 调用写入
for (int i = 0; i <= num; i++) {
// 每次写入都要创建WriteSheet, 这里注意必须指定sheetNo, 并且sheetName必须不一样
Map queryMap = new HashMap<>();
queryMap.put("limitVal", batchCount);
queryMap.put("offsetVal", i * batchCount);
WriteSheet writeSheet = EasyExcel.writerSheet(i, "batch" + (i + 1)).build();
dataList = bookService.selectBatch(queryMap);
System.out.println(dataList);
excelWriter.write(dataList, writeSheet);
}
}
// 清空集合
dataList.clear();
} catch (IOException ex) {
throw new RuntimeException(ex);
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}
}
请求:http://localhost:8800/doWriteBatch