1、导入EasyExcel依赖
————————————————
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.google.common.collect.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName ExcelController
* @Descripition EasyExcel导入/导出
* @Author admin
* @Date 2023/10/10 15:40
*/
@RestController
@RequestMapping("/excel/test")
public class ExcelController {
// Excel文件名称
private static final String FILE_NAME = "订单列表test";
//一个sheet装100w数据
private static final Integer PER_SHEET_ROW_COUNT = 30;
//每次查询20w数据,每次写入20w数据
private static final Integer PER_WRITE_ROW_COUNT = 10;
/**
* 一、EasyExcel简单导入
*
* @param file
* @throws IOException
*/
@PostMapping("/import")
public void importExcel(@RequestParam MultipartFile file) throws IOException {
InputStream inputStream = file.getInputStream();
List
.head(CustomerImportClass.class)
// 设置sheet,默认读取第一个
.sheet()
// 设置标题所在行数
.headRowNumber(1)
.doReadSync();
for (CustomerImportClass customerImportClass : list) {
System.out.println(customerImportClass);
}
System.out.println("【成功导入Excel数据】条数 : " + list.size());
}
/**
* 二、EasyExcel简单导入
* 1.1、单sheet导入(读)Excel
* 1.2、分页(批次)查询数据循环写入Excel表格
*
* @param file
* @throws IOException
*/
@PostMapping("/importPage")
public void importPage(@RequestParam MultipartFile file) throws IOException {
InputStream inputStream = file.getInputStream();
// 1.1、单sheet导入(读)Excel
// 1.2、分页(批次)查询数据循环写入Excel表格
EasyExcel.read(inputStream, new CustomListener())
// 设置sheet,默认读取第一个
.sheet()
// 设置标题所在行数
.headRowNumber(1)
.doRead();
}
/**
* 三、EasyExcel简单导入
* 1.1、多sheet导入(读)Excel
* 1.2、分页(批次)查询数据循环写入Excel表格
*
* @param file
* @throws IOException
*/
@PostMapping("/importSheetPage")
public void importSheetPage(@RequestParam MultipartFile file) throws IOException {
InputStream inputStream = file.getInputStream();
// 2.1、多sheet导入(写入)Excel
// 2.2、分页(批次)查询数据循环写入Excel表格
EasyExcel.read(inputStream, new CustomListener())
// 设置标题所在行数
.headRowNumber(1)
.doReadAll();
}
/**
* 一、EasyExcel简单导出
*
* @param response
*/
@GetMapping("/export")
public void exportExcel(HttpServletResponse response) {
try {
// 设置响应结果
this.setExcelResponseProp(response, FILE_NAME);
// 模拟业务代码,获取数据集
List
EasyExcel.write(response.getOutputStream())
.head(ExcelTemplate.class)
.excelType(ExcelTypeEnum.XLSX)
.sheet(FILE_NAME)
.doWrite(list);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 二、EasyExcel简单批量导出
* 1、单sheet导出(写入)Excel
* 2、分页(批次)查询数据循环写入Excel表格
*
* @param response
*/
@GetMapping("/exportPage")
public void exportPage(HttpServletResponse response) {
try {
// 设置响应结果
this.setExcelResponseProp(response, FILE_NAME);
// 单sheet导出(写入)Excel
exportSheet(response);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 三、EasyExcel简单批量导出
* 1、多sheet导出(写入)Excel
* 2、分页(批次)查询数据循环写入Excel表格
*
* @param response
*/
@GetMapping("/exportSheetPage")
public void exportSheetPage(HttpServletResponse response) {
try {
// 设置响应结果
this.setExcelResponseProp(response, FILE_NAME);
// 多sheet分页(批)查询数据循环写入Excel表格
exportMoreSheet(response);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 设置响应结果
*
* @param response 响应结果对象
* @param rawFileName 文件名
* @throws UnsupportedEncodingException 不支持编码异常
*/
private void setExcelResponseProp(HttpServletResponse response, String rawFileName) throws UnsupportedEncodingException {
// 下载EXCEL
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止浏览器端导出excel文件名中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode(rawFileName, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
}
/**
* easyExcel 导出Excel表格简单 : Demo
*/
public void excelWriteUtil() {
//1、创建一个文件对象
File excelFile = new File("D:\\test\\test001\\desktop\\excel_test1001.xlsx");
//2、判断文件是否存在,不存在则创建一个Excel文件
if (!excelFile.exists()) {
try {
excelFile.createNewFile();//创建一个新的文件
} catch (IOException e) {
e.printStackTrace();
}
}
//3、指定需要那个class去写。然后写到第一个sheet,名字为模版,然后文件流会自动关闭
EasyExcel.write(excelFile, ExcelTemplate.class).sheet("订单模版").doWrite(queryToExcel());
}
/**
* 1、查询数据库获取导出的数据集合
* 2、集合转换导出模版实体集合:ExcelTemplate
*
* @return
*/
public List
// 1、查询数据库获取导出的数据集合
// 模拟业务代码,获取数据集
List
for (int i = 0; i < 115; i++) {
ExcelTemplate template1 = new ExcelTemplate(1000L + i, "订单01" + i, "商品名称" + i, "sk1001" + i, 36L + i, 50L + i, "收件人" + i, "北京科技园" + i);
orders.add(template1);
}
// 2、集合转换导出模版实体集合:ExcelTemplate
List
//遍历数据集,导出Excel
for (int i = 0; i < orders.size(); i++) {
ExcelTemplate order = orders.get(i);
ExcelTemplate data = new ExcelTemplate();
data.setOrderNum(order.getOrderNum());
data.setOrderName(order.getOrderName());
data.setGoodsName(order.getGoodsName());
data.setGoodsNum(order.getGoodsNum());
data.setPrice(order.getPrice());
data.setNum(order.getNum());
data.setUserName(order.getUserName());
data.setAddress(order.getAddress());
excels.add(data);
}
return excels;
}
/**
* EasyExcel简单批量导出
* 1、单sheet导出(写入)Excel
* 2、分页(批次)查询数据循环写入Excel表格
*
* @param response
* @throws IOException
*/
public void exportSheet(HttpServletResponse response) throws IOException {
OutputStream outputStream = null;
try {
//记录总数:实际中需要根据查询条件进行统计即可
Integer totalCount = queryToExcel().size();
//每次写入的数据量20w,每页查询20W
Integer writeDataRows = PER_WRITE_ROW_COUNT;
//计算sheet需要写入的次数
Integer lastSheetWriteCount = totalCount % writeDataRows == 0 ? totalCount / writeDataRows : (totalCount / writeDataRows + 1);
// ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
// HttpServletResponse response = requestAttributes.getResponse();
outputStream = response.getOutputStream();
//必须放到循环外,否则会刷新流
ExcelWriter excelWriter = EasyExcel.write(outputStream).build();
//创建Sheet
// WriteSheet sheet = new WriteSheet();
// sheet.setSheetName("测试Sheet001");
// sheet.setSheetNo(0);
//循环写入次数: j的自增条件是当不是最后一个Sheet的时候写入次数为正常的每个Sheet写入的次数,如果是最后一个就需要使用计算的次数lastSheetWriteCount
for (int j = 0; j < lastSheetWriteCount; j++) {
//分页查询一次20w
List
// 集合截取起始下标计算
int startIndex = j * writeDataRows;
// 判断是否是最后一次写入Excel
if (j < (lastSheetWriteCount - 1)) {
list = queryToExcel().subList(startIndex, writeDataRows * (j + 1));
}
// 判断是否是最后一次写入Excel
if (j == (lastSheetWriteCount - 1)) {
// 计算是否是最后一次截取集合
int stepValue = queryToExcel().size() - (startIndex) >= writeDataRows ? writeDataRows : queryToExcel().size() - (startIndex);
list = queryToExcel().subList(startIndex, startIndex + stepValue);
}
// Page
// List
List
for (ExcelTemplate emp : list) {
ExcelTemplate empVo = new ExcelTemplate();
BeanUtils.copyProperties(emp, empVo);
empVoList.add(empVo);
}
WriteSheet writeSheet = EasyExcel.writerSheet(0, FILE_NAME).head(ExcelTemplate.class)
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();
//写数据
excelWriter.write(empVoList, writeSheet);
}
/*// 下载EXCEL
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止浏览器端导出excel文件名中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("员工信息", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");*/
excelWriter.finish();
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} catch (BeansException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
outputStream.close();
}
}
}
/**
* EasyExcel简单批量导出
* 1、多sheet导出(写入)Excel
* 2、分页(批次)查询数据循环写入Excel表格
*
* @param response
* @throws IOException
*/
public void exportMoreSheet(HttpServletResponse response) throws IOException {
OutputStream outputStream = null;
try {
//记录总数:实际中需要根据查询条件进行统计即可
Integer totalCount = queryToExcel().size();
//每一个Sheet存放100w条数据
Integer sheetDataRows = PER_SHEET_ROW_COUNT;
//每次写入的数据量20w,每页查询20W
Integer writeDataRows = PER_WRITE_ROW_COUNT;
//计算需要的Sheet数量
Integer sheetNum = totalCount % sheetDataRows == 0 ? (totalCount / sheetDataRows) : (totalCount / sheetDataRows + 1);
//计算一般情况下每一个Sheet需要写入的次数(一般情况不包含最后一个sheet,因为最后一个sheet不确定会写入多少条数据)
Integer oneSheetWriteCount = sheetDataRows / writeDataRows;
//计算最后一个sheet需要写入的次数
Integer lastSheetWriteCount = totalCount % sheetDataRows == 0 ? oneSheetWriteCount : (totalCount % sheetDataRows % writeDataRows == 0 ? (totalCount % sheetDataRows / writeDataRows) : (totalCount % sheetDataRows / writeDataRows + 1));
// 获取响应 response
// ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
// HttpServletResponse response = requestAttributes.getResponse();
// 获取输出流
outputStream = response.getOutputStream();
//必须放到循环外,否则会刷新流
ExcelWriter excelWriter = EasyExcel.write(outputStream).build();
//开始分批查询分次写入
for (int i = 0; i < sheetNum; i++) {
//创建Sheet
WriteSheet sheet = new WriteSheet();
sheet.setSheetName("测试Sheet001" + i);
sheet.setSheetNo(i);
//循环写入次数: j的自增条件是当不是最后一个Sheet的时候写入次数为正常的每个Sheet写入的次数,如果是最后一个就需要使用计算的次数lastSheetWriteCount
for (int j = 0; j < (i != sheetNum - 1 ? oneSheetWriteCount : lastSheetWriteCount); j++) {
//分页查询一次20w
List
if (i > 0) {
// 集合截取起始下标计算
int startIndex = i * sheetDataRows + writeDataRows * j;
// 计算是否是最后一次截取集合
int stepValue = queryToExcel().size() - (startIndex) >= writeDataRows ? writeDataRows : queryToExcel().size() - (startIndex);
list = queryToExcel().subList(startIndex, startIndex + stepValue);
}
// Page
// List
List
for (ExcelTemplate emp : list) {
ExcelTemplate empVo = new ExcelTemplate();
BeanUtils.copyProperties(emp, empVo);
empVoList.add(empVo);
}
WriteSheet writeSheet = EasyExcel.writerSheet(i, FILE_NAME + (i + 1)).head(ExcelTemplate.class)
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();
//写数据
excelWriter.write(empVoList, writeSheet);
}
}
/*// 下载EXCEL
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止浏览器端导出excel文件名中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("员工信息", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");*/
excelWriter.finish();
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} catch (BeansException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
outputStream.close();
}
}
}
}
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
* @ClassName CustomerImportClass
* @Descripition 导入模版类
* @Author admin
* @Date 2023/10/10 15:44
*/
@Data
public class CustomerImportClass {
@ExcelProperty(index = 0)
private String column1;
@ExcelProperty(index = 1)
private String column2;
@ExcelProperty(index = 2)
private String column3;
@ExcelProperty(index = 3)
private String column4;
@ExcelProperty(index = 4)
private String column6;
@ExcelProperty(index = 5)
private String column5;
@ExcelProperty(index = 6)
private String column7;
}
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import java.util.List;
import java.util.Map;
/**
* @ClassName CustomListener
* @Descripition 导入Excel监听解析表格数据
* @Author admin
* @Date 2023/10/9 15:40
*/
@Slf4j
public class CustomListener extends AnalysisEventListener
// 处理数据: 分批导入阈值
private static final Long size = 8L;
// private List
//获取excel表头信息
@Override
public void invokeHeadMap(Map
log.info("获取excel表头信息 data : {}", JSON.toJSONString(headMap));
System.out.println(JSON.toJSONString(headMap));
System.out.println();
System.out.println();
}
// 每解析一行数据,该方法会被调用一次
@Override
public void invoke(Map
log.info("Excel每解析一行数据,该方法(invoke)会被调用一次 data : {}", JSON.toJSONString(map));
// int size = analysisContext.readRowHolder().getCellMap().entrySet().size();
// System.out.println(size);
list.add(map);
if(list.size() >= CustomListener.size){
for (Object o1 : list) {
System.out.println(o1);
}
System.out.println("处理数据: 分批导入阈值: " + size);
System.out.println();
System.out.println();
list.clear();
}
}
// 全部解析完成被调用
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
System.out.println("最后剩余数据;不够分割 长度 : " + list.size());
if(CollectionUtils.isNotEmpty(list)){
for (Object o : list) {
System.out.println(o);
}
System.out.println();
list.clear();
}
System.out.println("解析数据完成!!!");
// System.out.println("解析数据完成!!!");
}
}
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.*;
import com.alibaba.excel.enums.poi.BorderStyleEnum;
import com.alibaba.excel.enums.poi.HorizontalAlignmentEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @ClassName ExcelTemplate
* @Descripition 导出模版
* @Author admin
* @Date 2023/10/9 18:14
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@HeadRowHeight(value = 50) // 头部行高
@ContentRowHeight(value = 25) // 内容行高
@ColumnWidth(value = 25) // 列宽
// 头背景设置成红色 IndexedColors.RED.getIndex()
// @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 10)
// 头字体设置成20, 字体默认宋体
@HeadFontStyle(fontName = "仿宋", fontHeightInPoints = 20)
// 头部边框实线
@HeadStyle(borderTop = BorderStyleEnum.THICK,
borderBottom = BorderStyleEnum.THICK,
borderLeft = BorderStyleEnum.THICK,
borderRight = BorderStyleEnum.THICK)
// 内容的背景设置成绿色 IndexedColors.GREEN.getIndex()
// @ContentStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 17)
// 内容字体设置成20, 字体默认宋体
@ContentFontStyle(fontName = "楷体", fontHeightInPoints = 20)
// Excel设置内容字体是否水平居中、边框实线
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER,
borderTop = BorderStyleEnum.MEDIUM,
borderBottom = BorderStyleEnum.MEDIUM,
borderLeft = BorderStyleEnum.DOUBLE,
borderRight = BorderStyleEnum.DOUBLE)
public class ExcelTemplate {
// 字符串的头背景设置成粉红 IndexedColors.PINK.getIndex()
// @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 14)
// 字符串的头字体设置成20
// @HeadFontStyle(fontHeightInPoints = 20)
// 字符串的内容背景设置成天蓝 IndexedColors.SKY_BLUE.getIndex()
// @ContentStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 40)
// 字符串的内容字体设置成20,默认宋体
// @ContentFontStyle(fontName = "宋体", fontHeightInPoints = 20)
// 设置是否水平居中
// @ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.LEFT)
@ExcelProperty("订单编码")
private Long orderNum;
@ExcelProperty("订单名称")
private String orderName;
@ExcelProperty("商品名称")
private String goodsName;
@ExcelProperty("商品编码")
private String goodsNum;
@ExcelProperty("价格")
private Long price;
@ExcelProperty("数量")
private Long num;
@ExcelProperty("用户名称")
private String userName;
@ColumnWidth(value = 80) // 列宽
@ExcelProperty("收货地址")
private String address;
}