EasyExcel是当前性能最佳的Excel导出工具,本篇少侠将带领大家一起在后台开发中优雅的使用EasyExcel。
后台接口读取文档通常使用MultipartFile类型,通过该类型可以构造出InputStream流。
利用EasyExcel读取Excel需要先构造一个监听器,暖男露飞已经帮你们准备好啦:
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import java.util.ArrayList;
import java.util.List;
/**
* @author Carson
* @date 2020/6/4 21:26
*/
public class ExcelReaderListener<T> extends AnalysisEventListener<T> {
/**
* 返回的数据集
*/
private List<T> list = new ArrayList<>(1 << 6);
/**
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
*/
public ExcelReaderListener() {
}
/**
* 这个每一条数据解析都会来调用
*
* @param data 数据
* @param context Excel读取上下文
*/
@Override
public void invoke(T data, AnalysisContext context) {
System.out.printf("解析到一条数据:{%s}", JSON.toJSONString(data));
System.out.println();
list.add(data);
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context Excel读取上下文
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
}
创建好监听器之后,就需要手动写一个工具类,专门用于读取Excel的,少侠这里准备了两种读取方式:
import com.alibaba.excel.EasyExcel;
import java.io.InputStream;
import java.util.List;
/**
* @author Carson
* @date 2020/6/4 21:31
*/
public class ExcelReaderUtil<T> {
private Class<T> clazz;
public ExcelReaderUtil(Class<T> clazz) {
this.clazz = clazz;
}
public List<T> readByStream(InputStream inputStream) {
ExcelReaderListener<T> readerListener = new ExcelReaderListener<>();
EasyExcel.read(inputStream, clazz, readerListener).sheet().doRead();
return readerListener.getList();
}
public List<T> readByPath(String fileName) {
ExcelReaderListener<T> readerListener = new ExcelReaderListener<>();
EasyExcel.read(fileName, clazz, readerListener).sheet().doRead();
return readerListener.getList();
}
}
备注:少侠这里的代码用的都是泛型,觉得不想细看的可以直接复制过去使用。
基本读取工具类已经实现完成,然后就是模板类的创建啦,什么是模板类呢,就是根据每个Excel表头有不同的参数表示的类,每个参数用@ExcelProperty注解修饰,注解的括号里的内容就是Excel里的表头。
@Data
public class GoodsReaderModel {
@ExcelProperty("商品SKU")
public Long skuId;
@ExcelProperty("活动开始时间")
public String startTime;
@ExcelProperty("活动结束时间")
public String finishTime;
}
然后在接口里进行读取:
@RequestMapping(value = "/import", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"})
@ApiOperation(value = "导入商品信息", httpMethod = "POST", notes = "导入商品信息")
@ResponseBody
public List<GoodsReaderModel > importGoodsFromExcel(@RequestParam("excel") MultipartFile multipartFile, HttpServletRequest request) {
if (multipartFile == null) {
LOGGER.info("输入的Excel信息为空");
return null;
}
ExcelReaderUtil<GoodsReaderModel> excelReader = new ExcelReaderUtil<>(GoodsReaderModel.class);
List<GoodsReaderModel> modelList = Lists.newArrayList();
try {
InputStream inputStream = multipartFile.getInputStream();
modelList = excelReader.readByStream(inputStream);
} catch (IOException e) {
LOGGER.info("对不起,未找到文件");
return null;
}
//后续数据处理逻辑
}
在接口中下载Excel同样也可以优雅,先附上通用格式处理类:
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.handler.WriteHandler;
import com.alibaba.excel.write.metadata.WriteWorkbook;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.google.common.collect.Lists;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import javax.servlet.ServletOutputStream;
import java.util.List;
/**
* @author Carson
* @date 2020/6/5 19:39
*/
public class ExcelWriterUtil {
public WriteWorkbook workbookGenerator(ServletOutputStream outputStream) {
WriteWorkbook workbook = new WriteWorkbook();
workbook.setOutputStream(outputStream);
workbook.setExcelType(ExcelTypeEnum.XLSX);
workbook.setNeedHead(true);
// 头的策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
//设置表头左对齐
headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
headWriteCellStyle.setBorderTop(BorderStyle.THIN);
headWriteCellStyle.setBorderBottom(BorderStyle.THIN);
headWriteCellStyle.setBorderLeft(BorderStyle.THIN);
headWriteCellStyle.setBorderRight(BorderStyle.THIN);
headWriteCellStyle.setFillBackgroundColor(IndexedColors.SKY_BLUE.getIndex());
// 内容的策略
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
//设置内容靠左对齐
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
WriteFont writeFont = new WriteFont();
writeFont.setFontName("宋体");
contentWriteCellStyle.setWriteFont(writeFont);
contentWriteCellStyle.setFillPatternType(FillPatternType.NO_FILL);
contentWriteCellStyle.setFillBackgroundColor(IndexedColors.SKY_BLUE.getIndex());
// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
List<WriteHandler> customWriteHandlerList = Lists.newArrayList();
customWriteHandlerList.add(horizontalCellStyleStrategy);
workbook.setCustomWriteHandlerList(customWriteHandlerList);
return workbook;
}
}
然后在接口请求里就可以这么写了:
@RequestMapping(value = "export", method = RequestMethod.GET, produces = {"application/json;charset=UTF-8"})
@ApiOperation(value = "数据导出", httpMethod = "GET", notes = "数据导出")
@ResponseBody
public void exportData() {
//根据自己实际业务获取数据,注意每行数据是一个List
List<List<String>> resList = Lists.newArrayList();
try{
ServletOutputStream outputStream = response.getOutputStream();
WriteWorkbook workbook = new ExcelWriterUtil().workbookGenerator(outputStream);
ExcelWriter writer = new ExcelWriter(workbook);
String fileName = new String("data");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
WriteSheet writeSheet = new WriteSheet();
writeSheet.setSheetName("数据明细");
writeSheet.setAutoTrim(true);
writer.write(resList, writeSheet);
writer.finish();
} catch (IOException e) {
LOGGER.error("导出数据异常", e);
}
}
EasyExcel只是个工具类,个人感觉,比起线程池、消息队列等内容重要性低很多,但是开发中能熟练使用也是真香。个人感觉这是我们用过最好用、效率最高的Excel工具类。少侠曾经做过测试,EasyExcel导出百万条 数据只需要60秒左右(目前Excel最多容纳104万条数据),而传统的POI技术则需要数小时,并且内存优化很差,大对象不能及时回收,很容易造成JVM的FULL GC。