思路
- 導入時,數據全部讀取完,進行參數校驗
- 如果參數校驗失敗后,將Excel導入的數據和校驗錯誤信息,存到Redis中,最后將數據導出
添加依賴
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.6</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.6</version> </dependency>
控制層
一個導入,一個下載模板,一個導出批注后的模板
@Autowired RedisUtil redisUtil; @Autowired GsonBuilder gsonBuilder; private static final String PREFIX = "easyExcel_"; public static final String SEND_LIST = "sendList_"; public static final String SEND_LIST_ERROR = "_error"; public static final Long EXPIRE_TIME = 60 * 10L; @GetMapping(value = "importExcel") @ApiOperation("導入") public Result importExcel( @RequestParam(value = "file", required = true) MultipartFile file ) throws IOException { SendListListener sendListListener = new SendListListener(); EasyExcel.read(file.getInputStream(), SendListExcel.class, sendListListener).sheet().doRead(); List<SendListExcel> listExcels = sendListListener.getListExcels(); Gson gson = gsonBuilder.create(); if (sendListListener.getExcelErrorMap().size() > 0) { String uuid = IdUtils.id32(); String key = PREFIX + SEND_LIST + uuid; redisUtil.set(key, gson.toJson(listExcels), EXPIRE_TIME); redisUtil.set(key + SEND_LIST_ERROR, gson.toJson(sendListListener.getExcelErrorMap()), EXPIRE_TIME); return Result.error(uuid); } listExcels.forEach(System.out::println); return Result.success(); } @GetMapping("downloadExcelTemplate") @ApiOperation("下載Excel模板") public void export(HttpServletResponse response) throws Exception { response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); String fileName = "發送名單管理模板.xlsx"; response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); EasyExcel.write(response.getOutputStream(), SendListExcel.class).sheet("sheet1").doWrite(new ArrayList<SendListExcel>()); } @GetMapping("downloadErrorExcel") @ApiImplicitParams(value = { @ApiImplicitParam(name = "uuid", dataType = "String", value = "校驗參數失敗后,返回的uuid") }) @ApiOperation("下載批注后到錯誤excel") public void downloadErrorExcel( HttpServletResponse response, @RequestParam(value = "uuid", required = true) String uuid ) throws IOException { SimpleDateFormat fDate = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); String fileName = fDate.format(new Date()) + ".xlsx"; response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); CommentWriteHandler commentWriteHandler = new CommentWriteHandler(); String key = PREFIX + SEND_LIST + uuid; String listExcelJson = (String) redisUtil.get(key); String listExcelErrorlJson = (String) redisUtil.get(key + SEND_LIST_ERROR); Gson gson = gsonBuilder.create(); if (listExcelJson != null && listExcelErrorlJson != null) { Type listExcelJsonType = new TypeToken<List<SendListExcel>>() { }.getType(); List<SendListExcel> sendListExcels = gson.fromJson(listExcelJson, listExcelJsonType); Type listExcelErrorlJsonType = new TypeToken<Map<Integer, List<ExcelError>>>() { }.getType(); Map<Integer, List<ExcelError>> errorMap = gson.fromJson(listExcelErrorlJson, listExcelErrorlJsonType); commentWriteHandler.setExcelErrorMap(errorMap); EasyExcel.write(response.getOutputStream(), SendListExcel.class) .inMemory(Boolean.TRUE) .sheet("sheet1") //注冊批注攔截器 .registerWriteHandler(commentWriteHandler) .doWrite(sendListExcels); } }
導出實體類
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ContentRowHeight; import com.alibaba.excel.annotation.write.style.HeadRowHeight; import lombok.Data; import java.io.Serializable; /** * @Description: * @Author:chenyanbin * @Date:2021/2/3 10:20 上午 * @Versiion:1.0 */ @Data @ExcelIgnoreUnannotated() @ContentRowHeight(10) @HeadRowHeight(20) public class SendListExcel implements Serializable { @ExcelProperty(value = "賬號",index = 0) @ColumnWidth(20) private String account; @ExcelProperty(value = "模板編號",index = 1) @ColumnWidth(30) private String templateCode; @ExcelProperty(value = "類型",index = 2) @ColumnWidth(15) private String accountType; }
EasyExcel監聽器
import com.alibaba.excel.context.AnalysisContext; import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.List; /** * @Description: * @Author:chenyanbin * @Date:2021/2/3 10:40 上午 * @Versiion:1.0 */ public class SendListListener extends AnalysisEventListenerAdapter<SendListExcel> { private List<SendListExcel> listExcels = new ArrayList<>(); public SendListListener() { super(); listExcels.clear(); excelErrorMap.clear(); } /** * 每一條數據解析都會調用 */ @Override public void invoke(SendListExcel sendListExcel, AnalysisContext analysisContext) { listExcels.add(sendListExcel); } /** * 所有數據解析完成都會調用 */ @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { SendListExcel sle = null; boolean isMatch = true; for (int i = 0; i < listExcels.size(); i++) { sle = listExcels.get(i); isMatch = true; Integer accountCellIndex = EasyExcelUtil.getCellIndex(sle, "account"); if (accountCellIndex != null) { if (StringUtils.isAllBlank(sle.getAccount())) { setExcelErrorMaps(i, accountCellIndex, "賬號不能為空!"); } } Integer templateCodeCellIndex = EasyExcelUtil.getCellIndex(sle, "templateCode"); if (templateCodeCellIndex != null) { if (StringUtils.isAllBlank(sle.getTemplateCode())) { setExcelErrorMaps(i, templateCodeCellIndex, "模板編號不能為空!"); } } Integer accountTypeCellIndex = EasyExcelUtil.getCellIndex(sle, "accountType"); if (accountTypeCellIndex != null) { if (StringUtils.isAllBlank(sle.getAccountType())) { setExcelErrorMaps(i, accountTypeCellIndex, "類型不能為空!"); } else { if ("sms".equals(sle.getAccountType()) || "email".equals(sle.getAccountType()) || "wechat".equals(sle.getAccountType())) { isMatch = false; } if (isMatch) { setExcelErrorMaps(i, accountTypeCellIndex, "類型只允許:sms、email、wechat"); } } } } } public List<SendListExcel> getListExcels() { return listExcels; } }
其他

import com.alibaba.excel.write.handler.AbstractRowWriteHandler; import org.apache.poi.ss.usermodel.*; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @Description:AbstractRowWriteHandler適配器 * @Author:chenyanbin * @Date:2021/2/3 10:04 上午 * @Versiion:1.0 */ public abstract class AbstractRowWriteHandlerAdapter extends AbstractRowWriteHandler { protected Map<Integer, List<ExcelError>> excelErrorMap = new HashMap<>(); public void setExcelErrorMap(Map<Integer, List<ExcelError>> excelErrorMap) { this.excelErrorMap = excelErrorMap; } /** * 設置單元格批注 * @param sheet sheet * @param rowIndex 行索引 * @param colIndex 列索引 * @param value 批注 */ protected void setCellCommon(Sheet sheet, int rowIndex, int colIndex, String value) { Workbook workbook = sheet.getWorkbook(); CellStyle cellStyle = workbook.createCellStyle(); cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); cellStyle.setFillForegroundColor(IndexedColors.RED.getIndex()); cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); Row row = sheet.getRow(rowIndex); if (row == null) { return; } Cell cell = row.getCell(colIndex); if (cell == null) { cell = row.createCell(colIndex); } if (value == null) { cell.removeCellComment(); return; } Drawing<?> drawing = sheet.createDrawingPatriarch(); CreationHelper factory = sheet.getWorkbook().getCreationHelper(); ClientAnchor anchor = factory.createClientAnchor(); Row row1 = sheet.getRow(anchor.getRow1()); if (row1 != null) { Cell cell1 = row1.getCell(anchor.getCol1()); if (cell1 != null) { cell1.removeCellComment(); } } Comment comment = drawing.createCellComment(anchor); RichTextString str = factory.createRichTextString(value); comment.setString(str); comment.setAuthor("admin"); cell.setCellComment(comment); cell.setCellStyle(cellStyle); } }

import com.alibaba.excel.event.AnalysisEventListener; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @Description:AnalysisEventListener適配器 * @Author:chenyanbin * @Date:2021/2/3 10:09 上午 * @Versiion:1.0 */ public abstract class AnalysisEventListenerAdapter<T> extends AnalysisEventListener<T> { protected Map<Integer, List<ExcelError>> excelErrorMap = new HashMap<>(); public Map<Integer, List<ExcelError>> getExcelErrorMap() { return excelErrorMap; } /** * 設置批注集合 * * @param rowsNum 行數 * @param cellIndex 單元格索引 * @param msg 錯誤信息 */ protected void setExcelErrorMaps(int rowsNum, int cellIndex, String msg) { if (excelErrorMap.containsKey(rowsNum)) { List<ExcelError> excelErrors = excelErrorMap.get(rowsNum); excelErrors.add(new ExcelError(rowsNum, cellIndex, msg)); excelErrorMap.put(rowsNum, excelErrors); } else { List<ExcelError> excelErrors = new ArrayList<>(); excelErrors.add(new ExcelError(rowsNum, cellIndex, msg)); excelErrorMap.put(rowsNum, excelErrors); } } }

import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import java.util.List; /** * @Description:將參數校驗失敗的Exccel,添加批注后導出 * @Author:chenyanbin * @Date:2021/2/3 10:38 上午 * @Versiion:1.0 */ public class CommentWriteHandler extends AbstractRowWriteHandlerAdapter { @Override public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) { if (!isHead){ Sheet sheet = writeSheetHolder.getSheet(); if (excelErrorMap.containsKey(relativeRowIndex)) { List<ExcelError> excelErrors = excelErrorMap.get(relativeRowIndex); excelErrors.forEach(obj -> { setCellCommon(sheet, obj.getRow() + 1, obj.getColumn(), obj.getErrorMsg()); }); } } } }

import java.io.Serializable; /** * @Description:批注錯誤實體類 * @Author:chenyanbin * @Date:2021/2/3 10:05 上午 * @Versiion:1.0 */ public class ExcelError implements Serializable { /** 第幾行 從1開始計數 */ private int row; /** 第幾列 從1開始計數 */ private int column; /** 錯誤消息 */ private String errorMsg; public ExcelError(int row, int column, String errorMsg) { this.row = row; this.column = column; this.errorMsg = errorMsg; } public int getRow() { return row; } public int getColumn() { return column; } public String getErrorMsg() { return errorMsg; } @Override public String toString() { return "ExcelError{" + "row=" + row + ", column=" + column + ", errorMsg='" + errorMsg + '\'' + '}'; } }

import com.alibaba.excel.annotation.ExcelProperty; import lombok.extern.slf4j.Slf4j; import java.lang.reflect.Field; /** * @Description:EasyExcel工具類 * @Author:chenyanbin * @Date:2021/2/3 10:01 上午 * @Versiion:1.0 */ @Slf4j public class EasyExcelUtil { /** * 獲取Excel單元格的索引 * * @param obj JavaBean對象 * @param fieldValue JavaBean字段值 * @return */ public static Integer getCellIndex(Object obj, String fieldValue) { try { Field declaredField = obj.getClass().getDeclaredField(fieldValue); ExcelProperty annotation = declaredField.getAnnotation(ExcelProperty.class); if (annotation == null) { return null; } return annotation.index(); } catch (NoSuchFieldException e) { log.error("error:", e); } return null; } }
功能演示