導入的話比較簡單了,參照官方文檔,有好幾個Demo。
我這里主要考慮幾個情況: ①數據量較大,分批讀取 ②數據格式需要校驗,因為導入的數據有可能存在格式問題,但是需要給前端提醒一下哪里出錯了.
一、Excel數據
這里在數字格式的地方用字符串導入,引起出錯~
二、API 調用
這里參考官方文檔,修改的地方在DemoExceptionListener監聽類里面
/** * 數據轉換等異常處理 * * <p> * 1. 創建excel對應的實體對象 參照{@link ExceptionDemoData} * <p> * 2. 由於默認異步讀取excel,所以需要創建excel一行一行的回調監聽器,參照{@link DemoExceptionListener} * <p> * 3. 直接讀即可 */ @Test public void exceptionRead() { String fileName = "I:\\temp\\readDemo1.xlsx"; // 這里 需要指定讀用哪個class去讀,然后讀取第一個sheet EasyExcel.read(fileName, ExceptionDemoData.class, new DemoExceptionListener()).sheet().doRead(); }
/** * 基礎數據類.這里的排序和excel里面的排序一致 * **/ @Data public class ExceptionDemoData { private String string; private Date date; private Double doubleData; }
三、DemoExceptionListener監聽類
主要內部定義一個存儲異常信息的StringBuffer,用於收集異常,並在讀取完Excel之后可以用於校驗是否轉換數據出錯~
/** * 讀取轉換異常 * */ public class DemoExceptionListener extends AnalysisEventListener<ExceptionDemoData> { private static final Logger LOGGER = LoggerFactory.getLogger(DemoExceptionListener.class); /** * 每隔5條存儲數據庫,實際使用中可以3000條,然后清理list ,方便內存回收 */ private static final int BATCH_COUNT = 5; List<ExceptionDemoData> list = new ArrayList<ExceptionDemoData>(); //定義接收異常 private StringBuffer errorMsg; /** * 在轉換異常 獲取其他異常下會調用本接口。拋出異常則停止讀取。如果這里不拋出異常則 繼續讀取下一行。 * * @param exception * @param context * @throws Exception */ @Override public void onException(Exception exception, AnalysisContext context) { LOGGER.error("解析失敗,但是繼續解析下一行:{}", exception.getMessage()); // 如果是某一個單元格的轉換異常 能獲取到具體行號 // 如果要獲取頭的信息 配合invokeHeadMap使用 if (exception instanceof ExcelDataConvertException) { ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception; LOGGER.error("第{}行,第{}列解析異常,數據為:{}", excelDataConvertException.getRowIndex(), excelDataConvertException.getColumnIndex(), excelDataConvertException.getCellData()); String msg="第"+excelDataConvertException.getRowIndex()+"行,第"+excelDataConvertException.getColumnIndex()+"列解析異常,數據為:"+
excelDataConvertException.getCellData(); if(errorMsg==null){ errorMsg=new StringBuffer(); } //拼接報錯信息 errorMsg.append(msg).append(System.lineSeparator()); } } /** * 這里會一行行的返回頭 * * @param headMap * @param context */ @Override public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) { LOGGER.info("解析到一條頭數據:{}", JSON.toJSONString(headMap)); } @Override public void invoke(ExceptionDemoData data, AnalysisContext context) { LOGGER.info("解析到一條數據:{}", JSON.toJSONString(data)); if (list.size() >= BATCH_COUNT) { //操作數據之前統一判斷異常信息,可以直接拋異常 if (errorMsg != null && errorMsg.length() > 0) { // throw new RuntimeException("解析數據異常!!信息:"+errorMsg.toString()); LOGGER.error("解析數據異常!!信息:" + errorMsg.toString()); } saveData(); list.clear(); } } @Override public void doAfterAllAnalysed(AnalysisContext context) { ////操作數據之前統一判斷異常信息 /*if (errorMsg != null && errorMsg.length() > 0) { // throw new RuntimeException("解析數據異常!!信息:"+errorMsg.toString()); LOGGER.error("解析數據異常!!信息:" + errorMsg.toString()); }else{ LOGGER.info("所有數據解析完成!"); //解析完成無錯誤保存數據 saveData(); }*/ } /** * 加上存儲數據庫 */ private void saveData() { LOGGER.info("{}條數據,開始存儲數據庫!", list.size()); LOGGER.info("存儲數據庫成功!"); } }
結果:
我這里每次讀5行數據,如果調成讀10條,這兩個異常會合並到一起。
四、總結
這里不知道有沒有線程安全和變量未回收問題。