add easyExcel
This commit is contained in:
22
src/main/java/com/pancm/excel/DemoData.java
Normal file
22
src/main/java/com/pancm/excel/DemoData.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package com.pancm.excel;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author pancm
|
||||
* @Title: pancm_project
|
||||
* @Description:
|
||||
* @Version:1.0.0
|
||||
* @Since:jdk1.8
|
||||
* @date 2023/3/23
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode
|
||||
public class DemoData {
|
||||
private String string;
|
||||
private Date date;
|
||||
private Double doubleData;
|
||||
}
|
||||
208
src/main/java/com/pancm/excel/EasyExcelMergeTest.java
Normal file
208
src/main/java/com/pancm/excel/EasyExcelMergeTest.java
Normal file
@@ -0,0 +1,208 @@
|
||||
package com.pancm.excel;
|
||||
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.excel.ExcelWriter;
|
||||
import com.alibaba.excel.metadata.Head;
|
||||
import com.alibaba.excel.support.ExcelTypeEnum;
|
||||
import com.alibaba.excel.util.CollectionUtils;
|
||||
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
|
||||
import com.alibaba.excel.write.metadata.WriteSheet;
|
||||
import com.alibaba.excel.write.metadata.WriteTable;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author pancm
|
||||
* @Title: pancm_project
|
||||
* @Description: 多行合并
|
||||
* 合并单元格
|
||||
* @Version:1.0.0
|
||||
* @Since:jdk1.8
|
||||
* @date 2023/3/23
|
||||
*/
|
||||
public class EasyExcelMergeTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
writeExcel();
|
||||
writeExcel01();
|
||||
writeExcel02();
|
||||
writeExcel03();
|
||||
}
|
||||
|
||||
|
||||
private static String getPath(String s) {
|
||||
return System.getProperty("user.dir") + "/" + s+"_"+System.currentTimeMillis() + ".xlsx";
|
||||
}
|
||||
|
||||
private static List<DemoData> data1() {
|
||||
List<DemoData> list = Lists.newArrayList();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
DemoData data = new DemoData();
|
||||
data.setString("字符串" + 1);
|
||||
data.setDate(new Date());
|
||||
data.setDoubleData(0.56);
|
||||
list.add(data);
|
||||
}
|
||||
for (int i = 0; i < 3; i++) {
|
||||
DemoData data = new DemoData();
|
||||
data.setString("字符串" + 2);
|
||||
data.setDate(new Date());
|
||||
data.setDoubleData(0.56);
|
||||
list.add(data);
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
DemoData data = new DemoData();
|
||||
data.setString("字符串" + 3);
|
||||
data.setDate(new Date());
|
||||
data.setDoubleData(0.57);
|
||||
list.add(data);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 自定义合并策略 该类继承了AbstractMergeStrategy抽象合并策略,需要重写merge()方法
|
||||
public static class CustomMergeStrategy extends AbstractMergeStrategy {
|
||||
|
||||
/**
|
||||
* 分组,每几行合并一次
|
||||
*/
|
||||
private List<Integer> exportFieldGroupCountList;
|
||||
|
||||
/**
|
||||
* 目标合并列index
|
||||
*/
|
||||
private Integer targetColumnIndex;
|
||||
|
||||
// 需要开始合并单元格的首行index
|
||||
private Integer rowIndex;
|
||||
|
||||
// exportDataList为待合并目标列的值
|
||||
public CustomMergeStrategy(List<String> exportDataList, Integer targetColumnIndex) {
|
||||
this.exportFieldGroupCountList = getGroupCountList(exportDataList);
|
||||
this.targetColumnIndex = targetColumnIndex;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
|
||||
|
||||
if (null == rowIndex) {
|
||||
rowIndex = cell.getRowIndex();
|
||||
}
|
||||
// 仅从首行以及目标列的单元格开始合并,忽略其他
|
||||
if (cell.getRowIndex() == rowIndex && cell.getColumnIndex() == targetColumnIndex) {
|
||||
mergeGroupColumn(sheet);
|
||||
}
|
||||
}
|
||||
|
||||
private void mergeGroupColumn(Sheet sheet) {
|
||||
int rowCount = rowIndex;
|
||||
for (Integer count : exportFieldGroupCountList) {
|
||||
if (count == 1) {
|
||||
rowCount += count;
|
||||
continue;
|
||||
}
|
||||
// 合并单元格
|
||||
CellRangeAddress cellRangeAddress = new CellRangeAddress(rowCount, rowCount + count - 1, targetColumnIndex, targetColumnIndex);
|
||||
sheet.addMergedRegionUnsafe(cellRangeAddress);
|
||||
rowCount += count;
|
||||
}
|
||||
}
|
||||
|
||||
// 该方法将目标列根据值是否相同连续可合并,存储可合并的行数
|
||||
private List<Integer> getGroupCountList(List<String> exportDataList) {
|
||||
if (CollectionUtils.isEmpty(exportDataList)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
List<Integer> groupCountList = new ArrayList<>();
|
||||
int count = 1;
|
||||
|
||||
for (int i = 1; i < exportDataList.size(); i++) {
|
||||
if (exportDataList.get(i).equals(exportDataList.get(i - 1))) {
|
||||
count++;
|
||||
} else {
|
||||
groupCountList.add(count);
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
// 处理完最后一条后
|
||||
groupCountList.add(count);
|
||||
return groupCountList;
|
||||
}
|
||||
}
|
||||
|
||||
// 单列多行合并
|
||||
public static void writeExcel() {
|
||||
String fileName = getPath("单列多行");
|
||||
ExcelWriter excelWriter = EasyExcel.write(fileName).excelType(ExcelTypeEnum.XLSX).build();
|
||||
|
||||
List<DemoData> demoDataList = data1();
|
||||
// 写sheet的时候注册相应的自定义合并单元格策略
|
||||
WriteSheet writeSheet = EasyExcel.writerSheet("模板1").head(DemoData.class)
|
||||
.registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(DemoData::getString).collect(Collectors.toList()), 0))
|
||||
.build();
|
||||
excelWriter.write(demoDataList, writeSheet);
|
||||
excelWriter.finish();
|
||||
}
|
||||
|
||||
//多列多行合并
|
||||
public static void writeExcel01() {
|
||||
String fileName = getPath("多行多列");
|
||||
ExcelWriter excelWriter = EasyExcel.write(fileName).excelType(ExcelTypeEnum.XLSX).build();
|
||||
|
||||
List<DemoData> demoDataList = data1();
|
||||
WriteSheet writeSheet = EasyExcel.writerSheet("模板1").head(DemoData.class)
|
||||
.registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(DemoData::getString).collect(Collectors.toList()), 0))
|
||||
.registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(o -> o.getDoubleData().toString()).collect(Collectors.toList()), 2))
|
||||
.build();
|
||||
excelWriter.write(demoDataList, writeSheet);
|
||||
excelWriter.finish();
|
||||
}
|
||||
//多sheet
|
||||
public static void writeExcel02() {
|
||||
String fileName = getPath("多sheet");
|
||||
ExcelWriter excelWriter = EasyExcel.write(fileName).excelType(ExcelTypeEnum.XLSX).build();
|
||||
|
||||
List<DemoData> demoDataList = data1();
|
||||
WriteSheet writeSheet = EasyExcel.writerSheet("模板1").head(DemoData.class)
|
||||
.registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(DemoData::getString).collect(Collectors.toList()), 0))
|
||||
.registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(o -> o.getDoubleData().toString()).collect(Collectors.toList()), 2))
|
||||
.build();
|
||||
excelWriter.write(demoDataList, writeSheet);
|
||||
|
||||
WriteSheet writeSheet1 = EasyExcel.writerSheet("模板2").head(DemoData.class).build();
|
||||
excelWriter.write(data1(), writeSheet1);
|
||||
excelWriter.finish();
|
||||
}
|
||||
|
||||
//多表
|
||||
public static void writeExcel03() {
|
||||
String fileName = getPath("多表");
|
||||
ExcelWriter excelWriter = EasyExcel.write(fileName).excelType(ExcelTypeEnum.XLSX).build();
|
||||
WriteSheet writeSheet = EasyExcel.writerSheet("模板").needHead(Boolean.FALSE).build();
|
||||
|
||||
List<DemoData> demoDataList = data1();
|
||||
// 需要表头设置为true,WriteTable一些属性会继承自WriteSheet
|
||||
WriteTable writeTable = EasyExcel.writerTable(1).head(DemoData.class).needHead(Boolean.TRUE)
|
||||
.registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(DemoData::getString).collect(Collectors.toList()), 0))
|
||||
.registerWriteHandler(new CustomMergeStrategy(demoDataList.stream().map(o -> o.getDoubleData().toString()).collect(Collectors.toList()), 2))
|
||||
.build();
|
||||
excelWriter.write(demoDataList, writeSheet, writeTable);
|
||||
|
||||
WriteTable writeTable1 = EasyExcel.writerTable(2).head(DemoData.class).needHead(Boolean.TRUE).build();
|
||||
excelWriter.write(data1(), writeSheet, writeTable1);
|
||||
excelWriter.finish();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,288 @@
|
||||
package com.pancm.excel;
|
||||
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.excel.ExcelReader;
|
||||
import com.alibaba.excel.context.AnalysisContext;
|
||||
import com.alibaba.excel.metadata.CellData;
|
||||
import com.alibaba.excel.metadata.CellExtra;
|
||||
import com.alibaba.excel.read.listener.ReadListener;
|
||||
import com.alibaba.excel.read.metadata.ReadSheet;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author pancm
|
||||
* @Title: pancm_project
|
||||
* @Description:
|
||||
* 参考: https://www.yuque.com/easyexcel/doc
|
||||
* @Description: 参考: https://www.yuque.com/easyexcel/doc
|
||||
* @Version:1.0.0
|
||||
* @Since:jdk1.8
|
||||
* @date 2021/1/26
|
||||
*/
|
||||
@Slf4j
|
||||
public class EasyExcelTest {
|
||||
|
||||
|
||||
/**
|
||||
* 最简单的读
|
||||
* <p>
|
||||
* 1. 创建excel对应的实体对象 参照{@link DemoData}
|
||||
* <p>
|
||||
* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}
|
||||
* <p>
|
||||
* 3. 直接读即可
|
||||
*/
|
||||
@Test
|
||||
public void simpleRead() {
|
||||
// 写法1:JDK8+ ,不用额外写一个DemoDataListener
|
||||
// since: 3.0.0-beta1
|
||||
String fileName = "/home" + "demo" + File.separator + "demo.xlsx";
|
||||
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
|
||||
// 这里每次会读取3000条数据 然后返回过来 直接调用使用数据就行
|
||||
// EasyExcel.read(fileName, DemoData.class, new PageReadListener<DemoData>(dataList -> {
|
||||
// for (DemoData demoData : dataList) {
|
||||
// log.info("读取到一条数据{}", JSON.toJSONString(demoData));
|
||||
// }
|
||||
// })).sheet().doRead();
|
||||
|
||||
// 写法2:
|
||||
// 匿名内部类 不用额外写一个DemoDataListener
|
||||
fileName = "/home" + "demo" + File.separator + "demo.xlsx";
|
||||
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
|
||||
EasyExcel.read(fileName, DemoData.class, new ReadListener<DemoData>() {
|
||||
/**
|
||||
* 单次缓存的数据量
|
||||
*/
|
||||
public static final int BATCH_COUNT = 100;
|
||||
/**
|
||||
*临时存储
|
||||
*/
|
||||
private List<DemoData> cachedDataList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* All listeners receive this method when any one Listener does an error report. If an exception is thrown here, the
|
||||
* entire read will terminate.
|
||||
*
|
||||
* @param exception
|
||||
* @param context
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void onException(Exception exception, AnalysisContext context) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* When analysis one head row trigger invoke function.
|
||||
*
|
||||
* @param headMap
|
||||
* @param context
|
||||
*/
|
||||
@Override
|
||||
public void invokeHead(Map<Integer, CellData> headMap, AnalysisContext context) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(DemoData data, AnalysisContext context) {
|
||||
cachedDataList.add(data);
|
||||
if (cachedDataList.size() >= BATCH_COUNT) {
|
||||
saveData();
|
||||
// 存储完成清理 list
|
||||
cachedDataList = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The current method is called when extra information is returned
|
||||
*
|
||||
* @param extra extra information
|
||||
* @param context
|
||||
*/
|
||||
@Override
|
||||
public void extra(CellExtra extra, AnalysisContext context) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAfterAllAnalysed(AnalysisContext context) {
|
||||
saveData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that there is another piece of data.You can stop the read by returning false
|
||||
*
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean hasNext(AnalysisContext context) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加上存储数据库
|
||||
*/
|
||||
private void saveData() {
|
||||
log.info("{}条数据,开始存储数据库!", cachedDataList.size());
|
||||
log.info("存储数据库成功!");
|
||||
}
|
||||
}).sheet().doRead();
|
||||
|
||||
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
|
||||
// 写法3:
|
||||
fileName = "/home" + "demo" + File.separator + "demo.xlsx";
|
||||
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
|
||||
EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
|
||||
|
||||
// 写法4:
|
||||
fileName = "/home" + "demo" + File.separator + "demo.xlsx";
|
||||
// 一个文件一个reader
|
||||
ExcelReader excelReader = null;
|
||||
try {
|
||||
excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build();
|
||||
// 构建一个sheet 这里可以指定名字或者no
|
||||
ReadSheet readSheet = EasyExcel.readSheet(0).build();
|
||||
// 读取一个sheet
|
||||
excelReader.read(readSheet);
|
||||
} finally {
|
||||
if (excelReader != null) {
|
||||
// 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
|
||||
excelReader.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode
|
||||
class DemoData {
|
||||
private String string;
|
||||
private Date date;
|
||||
private Double doubleData;
|
||||
}
|
||||
|
||||
|
||||
class DemoDataListener implements ReadListener<DemoData> {
|
||||
|
||||
/**
|
||||
* 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
|
||||
*/
|
||||
private static final int BATCH_COUNT = 100;
|
||||
/**
|
||||
* 缓存的数据
|
||||
*/
|
||||
private List<DemoData> cachedDataList = new ArrayList<>();
|
||||
/**
|
||||
* 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
|
||||
*/
|
||||
// private DemoDAO demoDAO;
|
||||
//
|
||||
// public DemoDataListener() {
|
||||
// // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
|
||||
// demoDAO = new DemoDAO();
|
||||
// }
|
||||
|
||||
/**
|
||||
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
|
||||
*
|
||||
* @param demoDAO
|
||||
*/
|
||||
// public DemoDataListener(DemoDAO demoDAO) {
|
||||
// this.demoDAO = demoDAO;
|
||||
// }
|
||||
|
||||
/**
|
||||
* All listeners receive this method when any one Listener does an error report. If an exception is thrown here, the
|
||||
* entire read will terminate.
|
||||
*
|
||||
* @param exception
|
||||
* @param context
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void onException(Exception exception, AnalysisContext context) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* When analysis one head row trigger invoke function.
|
||||
*
|
||||
* @param headMap
|
||||
* @param context
|
||||
*/
|
||||
@Override
|
||||
public void invokeHead(Map<Integer, CellData> headMap, AnalysisContext context) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 这个每一条数据解析都会来调用
|
||||
*
|
||||
* @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}
|
||||
* @param context
|
||||
*/
|
||||
@Override
|
||||
public void invoke(DemoData data, AnalysisContext context) {
|
||||
log.info("解析到一条数据:{}", JSON.toJSONString(data));
|
||||
cachedDataList.add(data);
|
||||
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
|
||||
if (cachedDataList.size() >= BATCH_COUNT) {
|
||||
saveData();
|
||||
// 存储完成清理 list
|
||||
// cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The current method is called when extra information is returned
|
||||
*
|
||||
* @param extra extra information
|
||||
* @param context
|
||||
*/
|
||||
@Override
|
||||
public void extra(CellExtra extra, AnalysisContext context) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有数据解析完成了 都会来调用
|
||||
*
|
||||
* @param context
|
||||
*/
|
||||
@Override
|
||||
public void doAfterAllAnalysed(AnalysisContext context) {
|
||||
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
|
||||
saveData();
|
||||
log.info("所有数据解析完成!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that there is another piece of data.You can stop the read by returning false
|
||||
*
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean hasNext(AnalysisContext context) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加上存储数据库
|
||||
*/
|
||||
private void saveData() {
|
||||
log.info("{}条数据,开始存储数据库!", cachedDataList.size());
|
||||
// demoDAO.save(cachedDataList);
|
||||
log.info("存储数据库成功!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
110
src/main/java/com/pancm/excel/EasyExcelUtils.java
Normal file
110
src/main/java/com/pancm/excel/EasyExcelUtils.java
Normal file
@@ -0,0 +1,110 @@
|
||||
package com.pancm.excel;
|
||||
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class EasyExcelUtils {
|
||||
|
||||
public static void main(String[] args) {
|
||||
String[] headMap = { "项目名称", "楼栋名称", "单元名称", "楼层名称", "房间名称", "业主/租户姓名", "房间状态", "房间功能","认证人数","测试" };
|
||||
String[] dataStrMap={"hName","bName","uName","fName","pName","cName","pState","pFunction","pNum"};
|
||||
NoModelWriteData d = new NoModelWriteData();
|
||||
d.setFileName("认证统计");
|
||||
d.setHeadMap(headMap);
|
||||
d.setDataStrMap(dataStrMap);
|
||||
List<JSONObject> listDatas = new ArrayList<>();
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("hName","项目1");
|
||||
jsonObject.put("bName","二楼");
|
||||
jsonObject.put("aa","测试");
|
||||
d.setDataList(listDatas);
|
||||
EasyExcelUtils easyExcelUtils = new EasyExcelUtils();
|
||||
// easyExcelUtils.jsonWrite(d, response);
|
||||
}
|
||||
|
||||
//不创建对象的导出
|
||||
public void jsonWrite(NoModelWriteData data, HttpServletResponse response) throws IOException {
|
||||
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
|
||||
try {
|
||||
// response.setContentType("application/vnd.ms-excel");
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
|
||||
String fileName = URLEncoder.encode(data.getFileName(), "UTF-8");
|
||||
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
|
||||
// 这里需要设置不关闭流
|
||||
EasyExcel.write(response.getOutputStream()).head(head(data.getHeadMap())).sheet(data.getFileName()).doWrite(dataList(data.getDataList(), data.getDataStrMap()));
|
||||
} catch (Exception e) {
|
||||
// 重置response
|
||||
response.reset();
|
||||
response.setContentType("application/json");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
map.put("status", "failure");
|
||||
map.put("message", "下载文件失败" + e.getMessage());
|
||||
response.getWriter().println(JSON.toJSONString(map));
|
||||
}
|
||||
}
|
||||
|
||||
//创建对象的导出
|
||||
public <T> void simpleWrite(SimpleWriteData data,Class<T> clazz, HttpServletResponse response) throws IOException {
|
||||
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
|
||||
// response.setContentType("application/vnd.ms-excel");
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
|
||||
String fileName = URLEncoder.encode(data.getFileName(), "UTF-8");
|
||||
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
|
||||
EasyExcel.write(response.getOutputStream(), clazz).sheet(data.getFileName()).doWrite(data.getDataList());
|
||||
}
|
||||
|
||||
//设置表头
|
||||
private List<List<String>> head(String[] headMap) {
|
||||
List<List<String>> list = new ArrayList<List<String>>();
|
||||
|
||||
for (String head : headMap) {
|
||||
List<String> headList = new ArrayList<String>();
|
||||
headList.add(head);
|
||||
list.add(headList);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
//设置导出的数据内容
|
||||
private List<List<Object>> dataList(List<JSONObject> dataList, String[] dataStrMap) {
|
||||
List<List<Object>> list = new ArrayList<List<Object>>();
|
||||
for (JSONObject map : dataList) {
|
||||
List<Object> data = new ArrayList<Object>();
|
||||
for (int i = 0; i < dataStrMap.length; i++) {
|
||||
data.add(map.get(dataStrMap[i]));
|
||||
}
|
||||
list.add(data);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
class NoModelWriteData implements Serializable {
|
||||
private String fileName;//文件名
|
||||
private String[] headMap;//表头数组
|
||||
private String[] dataStrMap;//对应数据字段数组
|
||||
private List<JSONObject> dataList;//数据集合
|
||||
}
|
||||
|
||||
@Data
|
||||
class SimpleWriteData implements Serializable {
|
||||
private String fileName;//文件名
|
||||
private List<?> dataList;//数据列表
|
||||
}
|
||||
115
src/main/java/com/pancm/excel/EasyExcelWriteTest.java
Normal file
115
src/main/java/com/pancm/excel/EasyExcelWriteTest.java
Normal file
@@ -0,0 +1,115 @@
|
||||
package com.pancm.excel;
|
||||
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.excel.ExcelWriter;
|
||||
import com.alibaba.excel.annotation.ExcelIgnore;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.alibaba.excel.write.metadata.WriteSheet;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author pancm
|
||||
* @Title: pancm_project
|
||||
* @Description: excel写模块测试
|
||||
* @Version:1.0.0
|
||||
* @Since:jdk1.8
|
||||
* @date 2022/3/2
|
||||
*/
|
||||
@Slf4j
|
||||
public class EasyExcelWriteTest {
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
List<JSONObject> jsonObjectList = new ArrayList<>();
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("t1",1);
|
||||
jsonObject.put("t2","2");
|
||||
JSONObject jsonObject2 = new JSONObject();
|
||||
jsonObject2.put("t1",11);
|
||||
jsonObject2.put("t2","22");
|
||||
jsonObjectList.add(jsonObject);
|
||||
jsonObjectList.add(jsonObject2);
|
||||
|
||||
String fileName = "simpleWrite" + System.currentTimeMillis() + ".xlsx";
|
||||
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
|
||||
// 如果这里想使用03 则 传入excelType参数即可
|
||||
EasyExcel.write(fileName).sheet("模板").doWrite(jsonObjectList);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void excludeOrIncludeWrite() {
|
||||
// 注意 simpleWrite在数据量不大的情况下可以使用(5000以内,具体也要看实际情况),数据量大参照 重复多次写入
|
||||
|
||||
// 写法1 JDK8+
|
||||
// since: 3.0.0-beta1
|
||||
String fileName = "/home"+ "simpleWrite" + System.currentTimeMillis() + ".xlsx";
|
||||
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
|
||||
// 如果这里想使用03 则 传入excelType参数即可
|
||||
// EasyExcel.write(fileName, DemoData.class)
|
||||
// .sheet("模板")
|
||||
// .doWrite(
|
||||
// () -> {
|
||||
// // 分页查询数据
|
||||
// return data();
|
||||
// });
|
||||
|
||||
// 写法2
|
||||
fileName = "/home"+ "simpleWrite" + System.currentTimeMillis() + ".xlsx";
|
||||
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
|
||||
// 如果这里想使用03 则 传入excelType参数即可
|
||||
EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
|
||||
|
||||
// 写法3
|
||||
fileName = "/home"+ "/simpleWrite" + System.currentTimeMillis() + ".xlsx";
|
||||
// 这里 需要指定写用哪个class去写
|
||||
ExcelWriter excelWriter = null;
|
||||
try {
|
||||
excelWriter = EasyExcel.write(fileName, DemoData.class).build();
|
||||
WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
|
||||
excelWriter.write(data(), writeSheet);
|
||||
} finally {
|
||||
// 千万别忘记finish 会帮忙关闭流
|
||||
if (excelWriter != null) {
|
||||
excelWriter.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private List<DemoData> data() {
|
||||
List<DemoData> list = new ArrayList<>();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
DemoData data = new DemoData();
|
||||
data.setString("字符串" + i);
|
||||
data.setDate(new Date());
|
||||
data.setDoubleData(0.56);
|
||||
list.add(data);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode
|
||||
class DemoData {
|
||||
@ExcelProperty("字符串标题")
|
||||
private String string;
|
||||
@ExcelProperty("日期标题")
|
||||
private Date date;
|
||||
@ExcelProperty("数字标题")
|
||||
private Double doubleData;
|
||||
/**
|
||||
* 忽略这个字段
|
||||
*/
|
||||
@ExcelIgnore
|
||||
private String ignore;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/**
|
||||
* @Title: package-info
|
||||
* @Description: excel相关包
|
||||
* @Version:1.0.0
|
||||
* @author pancm
|
||||
* @date 2019年2月28日
|
||||
*/
|
||||
* @Title: pancm_project
|
||||
* @Description: excel的工具类
|
||||
* @Version:1.0.0
|
||||
* @Since:jdk1.8
|
||||
* @author pancm
|
||||
* @date 2021/1/26
|
||||
*/
|
||||
package com.pancm.excel;
|
||||
Reference in New Issue
Block a user