平時我們導入導出Excel的時候如果用poi導出,會發現光設置格式都要很多代碼,看起來非常的不優雅。后來業務中遇到了需要導入非常巨大的Excel的需求。如果繼續用poi的方式,因為poi把所有excel數據都緩存到內存中,服務器資源又是有限的,所以就有可能導致內存溢出,為了解決這個問題,我發現阿里的EasyExcel導出可以完美的解決這個問題,並且實現方式更加優雅。
如果業務中需要標紅重復的數據,先列一下大致代碼。
/** * 導出重復的數據 * * @param planId * @param stream * @param tenaId * @param fileId * @param response * @throws IOException */ public void screeningExport(Long planId, InputStream stream, Long tenaId, Long fileId, HttpServletResponse response) throws IOException { response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); // 這里URLEncoder.encode可以防止中文亂碼 當然和easyexcel沒有關系 String fileName = URLEncoder.encode("重復項", "UTF-8"); response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); EasyExcel.write(response.getOutputStream(), ScreeningEasyExcelVo.class) .registerWriteHandler(new CustomCellWriteHandle()) .sheet("模板" + Constant.fileIdSeparator + fileId).doWrite(data(stream, planId, tenaId, fileId)); }
大致的來說,就是我們傳入excel文件流,和對應的業務字段就可以導出了。
但是如果想標紅某一單元格的數據,那我們就需要自己定義攔截器,同時我們需要知道到底是哪行是重復的,具體校驗重復行就不在這里寫了,
得到重復行之后,我們把行數存入redis,並且在攔截器中和excel中的行數做對比,如果驗證為同一行,那我們就可以對這一行做標紅處理,
具體的代碼如下
package com.guantong.seeing.screening.common; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; import com.guantong.seeing.screening.util.SpringContextHelper; import org.apache.poi.ss.usermodel.*; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.util.StringUtils; import java.util.List; import java.util.stream.Stream; /** * @author cuixinxin * @desc easyExcel 自定義攔截器 */ public class CustomCellWriteHandle implements CellWriteHandler { public CustomCellWriteHandle() { } @Override public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) { } @Override public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) { } /** * 重寫單元格格式--》通過修改每一個單元格格式達到整列標紅的效果 * @param writeSheetHolder * @param writeTableHolder * @param list * @param cell * @param head * @param integer * @param aBoolean */ @Override public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) { Workbook workbook = writeSheetHolder.getSheet().getWorkbook(); CellStyle cellStyle = cellStyle(workbook); //根據校驗結果設置單元格文字顏色 String sheetName = writeSheetHolder.getSheet().getSheetName(); Long fileId = Long.valueOf(sheetName.substring(sheetName.indexOf(Constant.fileIdSeparator) + 8)); writeSheetHolder.setSheetName(sheetName.substring(0, sheetName.indexOf(Constant.fileIdSeparator))); int rowIndex = cell.getRowIndex(); if (isExistRepeatData(rowIndex, fileId)) { //設置單元格背景色 Font font = workbook.createFont(); font.setColor(IndexedColors.RED.getIndex()); cellStyle.setFont(font); } cell.setCellStyle(cellStyle); } private boolean isExistRepeatData(Integer rowNow, Long fileId) { StringRedisTemplate stringRedisTemplate = SpringContextHelper.getBean(StringRedisTemplate.class); String value = stringRedisTemplate.opsForValue().get(fileId.toString()); if (StringUtils.isEmpty(value)) { return false; } return Stream.of(value.split(",")) .anyMatch(k -> k.equals(rowNow.toString())); } /** * 通用樣式 * * @param workbook * @return */ public static CellStyle cellStyle(Workbook workbook) { CellStyle cellStyle = workbook.createCellStyle(); //居中 cellStyle.setAlignment(HorizontalAlignment.LEFT); cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); cellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex()); //設置邊框 cellStyle.setBorderBottom(BorderStyle.THIN); cellStyle.setBorderLeft(BorderStyle.THIN); cellStyle.setBorderRight(BorderStyle.THIN); cellStyle.setBorderTop(BorderStyle.THIN); return cellStyle; } }
整體來看,代碼邏輯分工更加清晰,只有標紅的攔截器和獲取數據以及導出三部分,更加優雅