赞
踩
第一步:先导包。网上很多版本,我用的1.1版本
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>${poi.version}</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>${poi.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>1.1.2-beta5</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.2</version> </dependency>
第二步:工具类,里面包含了两个版本的工具类,1.1版本和3.02版本,这个可以不用看,下面的方法,不用它
package com.tufang.erp.util; import com.alibaba.excel.EasyExcelFactory; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.metadata.BaseRowModel; import com.alibaba.excel.metadata.Sheet; import lombok.Data; import lombok.Getter; import lombok.Setter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.io.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * excel工具类 * easyexcel使用的3.0.2版本,跟以前版本有很大区别,且不兼容1.x版本 * * @author */ public class EasyExcelUtil{ private static final Logger LOGGER = LoggerFactory.getLogger(EasyExcelUtil.class); // // public static <T> List<T> read(String filePath, final Class<?> clazz) { // File f = new File(filePath); // try (FileInputStream fis = new FileInputStream(f)) { // return read(fis, clazz); // } catch (FileNotFoundException e) { // LOGGER.error("文件{}不存在", filePath, e); // } catch (IOException e) { // LOGGER.error("文件读取出错", e); // } // // return null; // } // // public static <T> List<T> read(InputStream inputStream, final Class<?> clazz) { // if (inputStream == null) { // throw new BusinessException("解析出错了,文件流是null"); // } // // // 有个很重要的点 DataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去 // DataListener<T> listener = new DataListener<>(); // // // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭 // EasyExcel.read(inputStream, clazz, listener).sheet().doRead(); // return listener.getRows(); // } // // public static void write(String outFile, List<?> list) { // Class<?> clazz = list.get(0).getClass(); // // 新版本会自动关闭流,不需要自己操作 // EasyExcel.write(outFile, clazz).sheet().doWrite(list); // } // // public static void write(String outFile, List<?> list, String sheetName) { // Class<?> clazz = list.get(0).getClass(); // // 新版本会自动关闭流,不需要自己操作 // EasyExcel.write(outFile, clazz).sheet(sheetName).doWrite(list); // } // // public static void write(OutputStream outputStream, List<?> list, String sheetName) { // Class<?> clazz = list.get(0).getClass(); // // 新版本会自动关闭流,不需要自己操作 // // sheetName为sheet的名字,默认写第一个sheet // EasyExcel.write(outputStream, clazz).sheet(sheetName).doWrite(list); // } // // /** // * 文件下载(失败了会返回一个有部分数据的Excel),用于直接把excel返回到浏览器下载 // */ // public static void download(HttpServletResponse response, List<?> list, String sheetName) throws IOException { // Class<?> clazz = list.get(0).getClass(); // // // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman // response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); // response.setCharacterEncoding("utf-8"); // // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 // String fileName = URLEncoder.encode(sheetName, "UTF-8").replaceAll("\\+", "%20"); // response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); // EasyExcel.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(list); // } private static Sheet initSheet; static { initSheet = new Sheet(1, 0); initSheet.setSheetName("sheet"); //设置自适应宽度 initSheet.setAutoWidth(Boolean.TRUE); } /** * 读取少于1000行数据 * @param filePath 文件绝对路径 * @return */ public static List<Object> readLessThan1000Row(String filePath){ return readLessThan1000RowBySheet(filePath,null); } /** * 读小于1000行数据, 带样式 * filePath 文件绝对路径 * initSheet : * sheetNo: sheet页码,默认为1 * headLineMun: 从第几行开始读取数据,默认为0, 表示从第一行开始读取 * clazz: 返回数据List<Object> 中Object的类名 */ public static List<Object> readLessThan1000RowBySheet(String filePath, Sheet sheet){ if(!StringUtils.hasText(filePath)){ return null; } sheet = sheet != null ? sheet : initSheet; InputStream fileStream = null; try { fileStream = new FileInputStream(filePath); return EasyExcelFactory.read(fileStream, sheet); } catch (FileNotFoundException e) { LOGGER.info("找不到文件或文件路径错误, 文件:{}", filePath); }finally { try { if(fileStream != null){ fileStream.close(); } } catch (IOException e) { LOGGER.info("excel文件读取失败, 失败原因:{}", e); } } return null; } /** * 读大于1000行数据 * @param filePath 文件觉得路径 * @return */ public static List<Object> readMoreThan1000Row(String filePath){ return readMoreThan1000RowBySheet(filePath,null); } /** * 读大于1000行数据, 带样式 * @param filePath 文件觉得路径 * @return */ public static List<Object> readMoreThan1000RowBySheet(String filePath, Sheet sheet){ if(!StringUtils.hasText(filePath)){ return null; } sheet = sheet != null ? sheet : initSheet; InputStream fileStream = null; try { fileStream = new FileInputStream(filePath); ExcelListener excelListener = new ExcelListener(); EasyExcelFactory.readBySax(fileStream, sheet, excelListener); return excelListener.getDatas(); } catch (FileNotFoundException e) { LOGGER.error("找不到文件或文件路径错误, 文件:{}", filePath); }finally { try { if(fileStream != null){ fileStream.close(); } } catch (IOException e) { LOGGER.error("excel文件读取失败, 失败原因:{}", e); } } return null; } /** * 生成excle * @param filePath 绝对路径, 如:/home/chenmingjian/Downloads/aaa.xlsx * @param data 数据源 * @param head 表头 */ public static void writeBySimple(String filePath, List<List<Object>> data, List<String> head){ writeSimpleBySheet(filePath,data,head,null); } /** * 生成excle * @param filePath 绝对路径, 如:/home/chenmingjian/Downloads/aaa.xlsx * @param data 数据源 * @param sheet excle页面样式 * @param head 表头 */ public static void writeSimpleBySheet(String filePath, List<List<Object>> data, List<String> head, Sheet sheet){ sheet = (sheet != null) ? sheet : initSheet; if(head != null){ List<List<String>> list = new ArrayList<>(); head.forEach(h -> list.add(Collections.singletonList(h))); sheet.setHead(list); } OutputStream outputStream = null; ExcelWriter writer = null; try { outputStream = new FileOutputStream(filePath); writer = EasyExcelFactory.getWriter(outputStream); writer.write1(data,sheet); } catch (FileNotFoundException e) { LOGGER.error("找不到文件或文件路径错误, 文件:{}", filePath); }finally { try { if(writer != null){ writer.finish(); } if(outputStream != null){ outputStream.close(); } } catch (IOException e) { LOGGER.error("excel文件导出失败, 失败原因:{}", e); } } } /** * 生成excle * @param filePath 绝对路径, 如:/home/chenmingjian/Downloads/aaa.xlsx * @param data 数据源 */ public static void writeWithTemplate(String filePath, List<? extends BaseRowModel> data){ writeWithTemplateAndSheet(filePath,data,null); } /** * 生成excle * @param filePath 绝对路径, 如:/home/chenmingjian/Downloads/aaa.xlsx * @param data 数据源 * @param sheet excle页面样式 */ public static void writeWithTemplateAndSheet(String filePath, List<? extends BaseRowModel> data, Sheet sheet){ if(CollectionUtils.isEmpty(data)){ return; } sheet = (sheet != null) ? sheet : initSheet; sheet.setClazz(data.get(0).getClass()); OutputStream outputStream = null; ExcelWriter writer = null; try { outputStream = new FileOutputStream(filePath); writer = EasyExcelFactory.getWriter(outputStream); writer.write(data,sheet); } catch (FileNotFoundException e) { LOGGER.error("找不到文件或文件路径错误, 文件:{}", filePath); }finally { try { if(writer != null){ writer.finish(); } if(outputStream != null){ outputStream.close(); } } catch (IOException e) { LOGGER.error("excel文件导出失败, 失败原因:{}", e); } } } /** * 生成多Sheet的excle * @param filePath 绝对路径, 如:/home/chenmingjian/Downloads/aaa.xlsx * @param multipleSheelPropetys */ public static void writeWithMultipleSheel(String filePath,List<MultipleSheelPropety> multipleSheelPropetys){ if(CollectionUtils.isEmpty(multipleSheelPropetys)){ return; } OutputStream outputStream = null; ExcelWriter writer = null; try { outputStream = new FileOutputStream(filePath); writer = EasyExcelFactory.getWriter(outputStream); for (MultipleSheelPropety multipleSheelPropety : multipleSheelPropetys) { Sheet sheet = multipleSheelPropety.getSheet() != null ? multipleSheelPropety.getSheet() : initSheet; if(!CollectionUtils.isEmpty(multipleSheelPropety.getData())){ sheet.setClazz(multipleSheelPropety.getData().get(0).getClass()); } writer.write(multipleSheelPropety.getData(), sheet); } } catch (FileNotFoundException e) { LOGGER.error("找不到文件或文件路径错误, 文件:{}", filePath); }finally { try { if(writer != null){ writer.finish(); } if(outputStream != null){ outputStream.close(); } } catch (IOException e) { LOGGER.error("excel文件导出失败, 失败原因:{}", e); } } } /*********************匿名内部类开始,可以提取出去******************************/ @Data public static class MultipleSheelPropety{ private List<? extends BaseRowModel> data; private Sheet sheet; } /** * 解析监听器, * 每解析一行会回调invoke()方法。 * 整个excel解析结束会执行doAfterAllAnalysed()方法 * * @author: chenmingjian * @date: 19-4-3 14:11 */ @Getter @Setter public static class ExcelListener extends AnalysisEventListener { private List<Object> datas = new ArrayList<>(); /** * 逐行解析 * object : 当前行的数据 */ @Override public void invoke(Object object, AnalysisContext context) { //当前行 // context.getCurrentRowNum() if (object != null) { datas.add(object); } } /** * 解析完所有数据后会调用该方法 */ @Override public void doAfterAllAnalysed(AnalysisContext context) { //解析结束销毁不用的资源 } } }
第三步,监听类,必须写。这是监听和获取数据的
package com.tufang.erp.manage.controller.excel; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.tufang.erp.dao.object.ManagePurchaseSupplierPriceDO; import com.tufang.erp.dao.object.excel.PriceExcelInputRequest; import com.tufang.erp.util.BeanUtil; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.List; /*** * 监听器 */ public class PurchasePriceExcelListener extends AnalysisEventListener<PriceExcelInputRequest> { /** * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 */ private static final int BATCH_COUNT = 5; List<PriceExcelInputRequest> list = new ArrayList<PriceExcelInputRequest>(); private static int count = 1; @Override @Transactional public void invoke(PriceExcelInputRequest inputRequest, AnalysisContext context) { //新建采购价目表对象 ManagePurchaseSupplierPriceDO priceDO = new ManagePurchaseSupplierPriceDO(); priceDO.setPurchasePrice(inputRequest.getPurchasePrice()); BeanUtil.copy(inputRequest,priceDO); System.out.println("解析到一条数据:{ "+ inputRequest.toString() +" }"); list.add(inputRequest); count ++; // if (list.size() >= BATCH_COUNT){ // saveData( count ); // list.clear(); // } } @Override public void doAfterAllAnalysed(AnalysisContext context) { // priceMapper.insertPurchasePriceList(priceDOList); saveData( count ); // System.out.println("所有数据解析完成!"); // System.out.println(" count :" + count); } /** * 加上存储数据库 */ private void saveData(int count) { // System.out.println("{ "+ count +" }条数据,开始存储数据库!" + list.size()); // System.out.println("存储数据库成功!"); } //通过这个方法获取数据 public List<PriceExcelInputRequest> getDatas() { // System.out.println("{ "+ count +" hahahahhahahhah }条数据,开始存储数据库!" + list.size()); return list; } }
PriceExcelInputRequest 是自定义的类,根据业务需求新建。
第四步,控制层(controller层)
@PostMapping("addPurchasePriceExcelInput") @ApiOperation(value = "excel数据导入", httpMethod = "POST") @PublicInterface public ResultResponse<String> addPurchasePriceExcelInput(@RequestBody MultipartFile file) throws IOException { //获取登录信息 ManageUserDO user = tokenService.getLoginUser(ServletUtils.getRequest()).getUser(); //上传过来excel文件 Sheet sheet = new Sheet(1,1, PriceExcelInputRequest.class); //监听器 PurchasePriceExcelListener listener = new PurchasePriceExcelListener(); //读取数据 EasyExcelFactory.readBySax(file.getInputStream(),sheet,listener); //数据 List<PriceExcelInputRequest> datas = listener.getDatas(); //数据校验 List<ManagePurchaseSupplierPriceDO> priceDOS = checkExcelDatas(datas, user.getId()); //新增数据库 priceService.insertPurchasePriceList(priceDOS); return ResultResponse.successResponse(); }
第五步,获取到数据,必须进行数据校验(校验很繁琐,但必须写,没办法),操作自己的数据库,这个就不用教了吧。
下面是我的数据校验,你们要根据自己的写。
/** * 数据校验 * 并返回值 */ public List<ManagePurchaseSupplierPriceDO> checkExcelDatas(List<PriceExcelInputRequest> datas, Long id){ //返回集合 List<ManagePurchaseSupplierPriceDO> priceDOList = new ArrayList<ManagePurchaseSupplierPriceDO>(); //循环 for (PriceExcelInputRequest inputRequest :datas){ ManagePurchaseSupplierPriceDO priceDO = new ManagePurchaseSupplierPriceDO(); BigDecimal purchasePrice = inputRequest.getPurchasePrice(); Long supplierId = inputRequest.getSupplierId(); String supplierName = inputRequest.getSupplierName(); String materialName = inputRequest.getMaterialName(); Date startTime = inputRequest.getStartTime(); Date endTime = inputRequest.getEndTime(); Long materialId = inputRequest.getMaterialId(); //校验数据类型 //必填项校验 if (supplierId ==null || materialId==null || startTime==null || endTime==null || purchasePrice==null ){ throw new BusinessException("供应商编码,产品编码,采购价格,生效日期,失效日期,为必填"); } //第一步,校验供应商id 本库有无 if (supplierId !=null){ ManageBasicSupplierDO manageBasicSupplierDO = supplierMapper.selectByPrimaryKey(supplierId); if (Objects.isNull(manageBasicSupplierDO)){ throw new BusinessException("请填写正确的供应商编码 "+supplierName+"的编码 "+supplierId+"错误"); }else if (manageBasicSupplierDO.getStatus()!=1){ throw new BusinessException("供应商名称为 "+supplierName+"未审核通过 "); } }else { throw new BusinessException("供应商编码,必填"); } //第二步,校验商品id正确否 if (materialId !=null){ ManageBasicMaterialDO manageBasicMaterialDO = materialMapper.selectByPrimaryKey(materialId); if (Objects.isNull(manageBasicMaterialDO)){ throw new BusinessException("产品编码为"+materialId+"填写错误"); }else if (!materialName.equals(manageBasicMaterialDO.getName())){ throw new BusinessException("产品编码和产品名称必须对应"); }else if (!"2".equals(manageBasicMaterialDO.getStatus())){ throw new BusinessException("产品id 为"+materialId+"商品库审核未通过"); } }else { throw new BusinessException("产品编码,必填"); } //生效时间和失效时间校验 Date nowDate = Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()); if (startTime ==null || endTime==null){ throw new BusinessException("生效时间和失效时间必填"); } if (startTime.getTime() > endTime.getTime()){ throw new BusinessException("失效时间必须小于生效时间"); }else if (endTime.getTime()<nowDate.getTime() ){ throw new BusinessException("失效时间必须大于当前时间"); } //校验之前是否已经存在该商品 List<ManagePurchasePriceMaterialDO> managePurchasePriceMaterialDOS = priceExtMapper.selectMaterialListByMaterialId(supplierId, materialId); if (managePurchasePriceMaterialDOS !=null && managePurchasePriceMaterialDOS.size()>0){ throw new BusinessException("供应商名称 "+supplierName+" 对应的产品 "+materialName+" 已经存在"); } priceDO.setPurchasePrice(inputRequest.getPurchasePrice()); BeanUtil.copy(inputRequest,priceDO); //获取登录信息 // list.add(inputRequest); priceDO.setCreateUserId(id); priceDO.setUpdateUserId(id); priceDO.setCreateTime(Date.from(LocalDateTime.now().atZone( ZoneId.systemDefault()).toInstant())); priceDOList.add(priceDO); } return priceDOList; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。