一、添加依賴:java
<!-- 如今已經更新到1.1.2-beta5 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>1.1.1</version> </dependency>
導入:git
二、添加監聽:github
package com.aikucun.goods.biz.easyexcel; import com.aikucun.goods.dao.model.vo.SkuModel; import com.aikucun.goods.dao.model.vo.SkuUploadFailModel; import com.aikucun.sc.common.utils.BeanUtils; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.google.common.collect.Lists; import org.apache.commons.lang3.StringUtils; import java.util.List; public class SkuUploadListener extends AnalysisEventListener { private List<SkuUploadFailModel> uploadFailList = Lists.newArrayList(); private List<SkuModel> skuModelList = Lists.newArrayList(); private int totalSize = 0; /** * 每解析一行,執行一次該方法 */ @Override public void invoke(Object object, AnalysisContext context) { totalSize++; SkuModel skuModel = (SkuModel) object; if (!checkData(skuModel)) { return; } skuModelList.add(skuModel); } @Override public void doAfterAllAnalysed(AnalysisContext context) { } private boolean checkData(SkuModel skuModel) { // 失敗緣由 String failMessage = ""; // itemCode String itemCode = skuModel.getItemCode(); if (null == skuModel) { failMessage = "數據爲空"; } // 驗證sku if (StringUtils.isEmpty(itemCode)) { failMessage = "itemCode爲空!"; } else { if (skuModelList.contains(itemCode)) { failMessage = failMessage + "itemCode重複!"; } } //品牌名稱 if (StringUtils.isEmpty(skuModel.getBrandName())) { failMessage = failMessage + "品牌名稱爲空!"; } //條碼必填 if (StringUtils.isEmpty(skuModel.getBarCode())) { failMessage = failMessage + "條碼爲空!"; } if (StringUtils.isNotEmpty(failMessage)) { SkuUploadFailModel failModel = new SkuUploadFailModel(); //數量校驗??? BeanUtils.convert(skuModel, failModel); failModel.setFailMessage(failMessage); uploadFailList.add(failModel); return false; } return true; } public List<SkuUploadFailModel> getUploadFailList(){ return uploadFailList; } public List<SkuModel> getSkuModelList(){ return skuModelList; } public int getTotalSize() { return totalSize; } }
三、導入商品controller:web
@PostMapping("/import-sku-list-async") @ApiOperation("批量導入商品(異步)") public Result importSkuListAsync(@RequestBody MultipartFile file) { return skuService.importSkuListAsync(file); }
四、ServiceImpl數據庫
@Override public Result importSkuListAsync(MultipartFile file) { //1.參數校驗 if (file == null || file.isEmpty()) { throw new GoodsException("導入文件爲空"); } // 判斷文件格式 String filename = file.getOriginalFilename(); String suffixName = filename.substring(filename.indexOf(".")); if (!".xlsx".equalsIgnoreCase(suffixName) && !".xls".equalsIgnoreCase(suffixName)) { throw new GoodsException("文件格式要求:.xlsx/.xls"); } dealDataAsync(file, suffixName); return Result.success(); } /** * 異步處理excel數據校驗、落庫、上傳文件服務器等 * * @param file */ @Async public void dealDataAsync(MultipartFile file, String suffixName) { InputStream inputStream = null; try { inputStream = file.getInputStream(); } catch (Exception e) { e.printStackTrace(); } //1.註冊任務 String dataFlag = System.currentTimeMillis() + ""; // 任務註冊 Long id = reg("{\"service\":\"goods-web\"}", getUserName(), dataFlag, getRealName(), DataFileTaskTypeEnum.IMPORT.getType()); if (id == null) { log.error("【導入商品】 uploadSkuFile 數據版本號:" + dataFlag + ", 註冊導入任務失敗"); return; } //2.excel數據校驗 SkuUploadListener listener = new SkuUploadListener(); dealExcel(listener, suffixName, id, dataFlag, inputStream); //3.把錯誤數據分裝集合中,正確數據封裝集合中 // 驗證失敗的數據 List<SkuUploadFailModel> uploadFailList = listener.getUploadFailList(); // 驗證經過的數據 List<SkuModel> skuModeList = listener.getSkuModelList(); // 總數量 int totalSize = listener.getTotalSize(); //4.把成功集合插入數據庫,錯誤數據上傳文件服務器 try { for (SkuModel skuModel : skuModeList) { Sku sku = new Sku(); BeanUtils.copyProperties(skuModel, sku); saveOrUpdateSku(sku); } }catch (Exception e){ log.error("【導入商品】 數據版本號:{},保存採購單報錯:{},錯誤詳情:{}", dataFlag, e.getMessage(), e); finish(id, DataFileTaskStatusEnum.FAIL.getType(), "", totalSize, 0, "保存到數據庫報錯", dataFlag); return; } //5.完成任務(上傳失敗數據到文件服務器) // 導入狀態 int status = DataFileTaskStatusEnum.SUCCESS.getType(); String fileUrl = ""; // 導入失敗的數據,生成異常文件 if (!CollectionUtils.isEmpty(uploadFailList)) { if (CollectionUtils.isEmpty(skuModeList)) { status = DataFileTaskStatusEnum.FAIL.getType(); } else { status = DataFileTaskStatusEnum.PART_SUCCESS.getType(); } fileUrl = createErrFile(uploadFailList, dataFlag); } finish(id, status, fileUrl, totalSize, skuModeList.size(), "導入結束", dataFlag); } private void dealExcel(SkuUploadListener listener, String suffixName, Long id, String dataFlag, InputStream file) { ExcelTypeEnum excelTypeEnum; if (ExcelTypeEnum.XLSX.getValue().equalsIgnoreCase(suffixName)) { excelTypeEnum = ExcelTypeEnum.XLSX; } else if (ExcelTypeEnum.XLS.getValue().equalsIgnoreCase(suffixName)) { excelTypeEnum = ExcelTypeEnum.XLS; } else { log.error("【導入採購單】 uploadPurchaseFile 數據版本號:" + dataFlag + ",上傳文件格式不是 " + ExcelTypeEnum.XLSX.getValue() + "/" + ExcelTypeEnum.XLS.getValue()); finish(id, DataFileTaskStatusEnum.FAIL.getType(), "", 0, 0, "文件格式不正確", dataFlag); return; } // 解析文件 try { ExcelReader excelReader = new ExcelReader(file, excelTypeEnum, null, listener); excelReader.read(new Sheet(1, 1, SkuModel.class)); } catch (Exception e) { log.error("【導入採購單】 uploadPurchaseFile 數據版本號:{},解析文件報錯:{},錯誤詳情:{}", dataFlag, e.getMessage(), e); finish(id, DataFileTaskStatusEnum.FAIL.getType(), "", 0, 0, "解析文件報錯", dataFlag); return; } } /** * 導入商品,異常文件生成 * * @param modelList * @param dataFlag */ private String createErrFile(List<SkuUploadFailModel> modelList, String dataFlag) { // 生成文件類型 ByteArrayOutputStream out = null; String fileUrl = ""; try { out = new ByteArrayOutputStream(); ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX); if (modelList.size() > FILE_SIZE) { List<List<SkuUploadFailModel>> splitList = Lists.partition(modelList, FILE_SIZE); for (int i = 0; i < splitList.size(); i++) { //寫一個sheet, Sheet sheet = new Sheet(i + 1, 0, SkuUploadFailModel.class); writer.write(splitList.get(i), sheet); } } else { //寫一個sheet, Sheet sheet = new Sheet(1, 0, SkuUploadFailModel.class); writer.write(modelList, sheet); } writer.finish(); CloudStorageService oss = oSSFactory.build(); String path = oss.getDefaultPath("/導入商品異常反饋.xlsx"); fileUrl = oss.upload((out).toByteArray(), path); log.info("【導入商品】 createErrFile 數據版本號:" + dataFlag + ",生成文件url:" + fileUrl); } catch (Exception e) { log.error("【導入商品】 createErrFile 數據版本號:" + dataFlag + ",導出報錯: " + e.getMessage(), e); } finally { try { if (out != null) { out.close(); } } catch (Exception e) { e.printStackTrace(); } } return fileUrl; } private Long reg(String param, String userName, String dataFlag, String realName, Integer type) { DataFileTaskDTO dataFileTaskDTO = new DataFileTaskDTO(); dataFileTaskDTO.setParams(param); dataFileTaskDTO.setDataType(SystemModuleEnum.DOWNLOAD_GOODS.getType()); dataFileTaskDTO.setType(type); dataFileTaskDTO.setRemark(SystemModuleEnum.DOWNLOAD_GOODS.getTypeName() + ",數據版本號:" + dataFlag); dataFileTaskDTO.setSource(SystemModuleEnum.DOWNLOAD_GOODS.getSystem()); dataFileTaskDTO.setCreateUser(realName); dataFileTaskDTO.setCreateUserJobNumber(userName); log.info("【導入商品】推送到磐石註冊任務參數,dataFileTaskDTO:{}", JSONObject.toJSONString(dataFileTaskDTO)); Result ret = remote.reg(dataFileTaskDTO); log.info("【導入商品】推送到磐石註冊任務返回結果,ret:{}", JSONObject.toJSONString(ret)); if (!CheckUtils.isNull(ret) && ret.isSuccess() && ret.getData() != null) { return Long.parseLong( ret.getData().toString()); } return null; } private Long finish(Long id, Integer taskStatus, String fileUrl, Integer total, Integer successTotal, String remark, String dataFlag) { DataFileTaskDTO taskDTO = new DataFileTaskDTO(); taskDTO.setId(id); taskDTO.setTaskStatus(taskStatus); taskDTO.setFileUrl(fileUrl); taskDTO.setTotal(total == null ? 0 : total); taskDTO.setSuccessTotal(successTotal == null ? 0 : successTotal); taskDTO.setRemark(remark + ",數據版本號:" + dataFlag); log.info("【導入商品】推送到磐石完成任務參數,dataFileTaskDTO:{}", JSONObject.toJSONString(taskDTO)); Result ret = remote.finsh(taskDTO); log.info("【導入商品】推送到磐石完成任務返回結果,ret:{}", JSONObject.toJSONString(ret)); if (!CheckUtils.isNull(ret) && ret.isSuccess()) { return (Long) ret.getData(); } return null; } /** * 獲取用戶名 * * @return */ private String getUserName() { // 獲取當前用戶 String userName = ""; LoginUserVo loginUserVo = UserVoThreadLocal.get(); if (Objects.nonNull(loginUserVo)) { userName = loginUserVo.getUserName(); } return userName; } /** * 獲取真實姓名 * * @return */ private String getRealName() { // 獲取當前用戶 String realName = ""; LoginUserVo loginUserVo = UserVoThreadLocal.get(); if (Objects.nonNull(loginUserVo)) { realName = loginUserVo.getRealName(); } return realName; }
導出:apache
一、導出controller服務器
/** * 導出維護記錄 * @param vo */ @PostMapping("/download") @ApiOperation(value = "採購單下載") public Result<String> exportRecord(@RequestBody PurchaseOrderHeadVO vo) { purchaseManageService.exportRecord(vo); return Result.success("導出成功"); }
二、serviceImplapp
@Async public void createRecordFile(PurchaseOrderHeadVO vo, String currentUserName, String realName,Long id,String dataFlag) { log.info("【導出採購單】 createRecordFile 開始,參數:{},用戶:{},開始時間:{} ,數據版本號:{}", JSON.toJSONString(vo), currentUserName, System.currentTimeMillis(), dataFlag); // 任務註冊 if (id == null) { return; } // 生成文件類型 ByteArrayOutputStream out = null; Map<String, Object> map = getStringObjectMap(vo); // 根據條件查詢 List<PurchaseOrderModel> list = purchaseOrderExtendMapper.listForEceport(map); if (CollectionUtils.isEmpty(list)) { log.info("【導出採購單】 createRecordFile 未查詢到須要導出的數據,數據版本號:" + dataFlag); finish(id, DataFileTaskStatusEnum.FAIL.getType(), "", 0, 0, "查詢數據爲空", dataFlag); return; } try { // 批量生成文件,每一個文件數據,最多 6萬 List<PurchaseDownloadModel> modelList = new ArrayList<>(); for (PurchaseOrderModel entity : list) { PurchaseDownloadModel model = new PurchaseDownloadModel(); BeanUtils.copyProperties(entity, model); // 採購模型 model.setPurchaseMode(PurchaseModeDictEnum.getNameByCode(model.getPurchaseMode())); // 採購類型 model.setPurchaseType(PurchaseTypeDictEnum.getNameByCode(model.getPurchaseType())); // 採購狀態 model.setStatus(PurchaseStatusEnum.getNameByCode(model.getStatus())); // 業務線 model.setBusinessLine(PurchaseBusinessDictEnum.getNameByCode(model.getBusinessLine())); modelList.add(model); } out = new ByteArrayOutputStream(); ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX); if (modelList.size() > FILE_SIZE) { List<List<PurchaseDownloadModel>> splitList = Lists.partition(modelList, FILE_SIZE); for (int i = 0; i < splitList.size(); i++) { //寫一個sheet, Sheet sheet = new Sheet(i + 1, 0, PurchaseDownloadModel.class); writer.write(splitList.get(i), sheet); } } else { //寫一個sheet, Sheet sheet = new Sheet(1, 0, PurchaseDownloadModel.class); writer.write(modelList, sheet); } writer.finish(); CloudStorageService oss = oSSFactory.build(); String path = oss.getDefaultPath("/採購單導出.xlsx"); String url = oss.upload((out).toByteArray(), path); finish(id, DataFileTaskStatusEnum.SUCCESS.getType(), url, list.size(), list.size(), "導出成功", dataFlag); log.info("【導出採購單】 createRecordFile 數據版本號:" + dataFlag + ",生成文件url:" + url); } catch (Exception e) { log.error("【導出採購單】 createRecordFile 數據版本號:" + dataFlag + ",導出報錯: " + e.getMessage(), e); // 發生異常,刪除文件 finish(id, DataFileTaskStatusEnum.FAIL.getType(), "", list.size(), 0, "導出報錯,數版本號:" + dataFlag, dataFlag); } finally { try { if (out != null) { out.close(); } } catch (Exception e) { e.printStackTrace(); } } log.info("【導出採購單】 createRecordFile 數據版本號:" + dataFlag + ",結束,時間:" + System.currentTimeMillis()); }
另外建議參考:https://github.com/HowieYuan/easyexcel-encapsulation異步