1 前言
导入的功能,想必大家都做过,大家肯定也都遇到过比如我的模板变化了(比如新增一列、删除一列等),客户在使用的时候可能还是用的老模板进行导入,那么我们在写代码的时候,应该怎么快速识别到呢?
比如可以比较客户导入的 Excel 一列一列的去比较或者列的个数等是可以的。
我想的一个是能不能给 Excel 写入一个版本信息,类型属性信息这种,这样在导入的时候,我可以比较一下这个版本号,来提示用户当前版本,最新版本让客户下载新的模板。
当时没空整,这不是空了,那我们本节就来小小的研究一下。
Excel 官网:官方文档我看了,没有关于这种属性信息、作者信息这种的写入、读取
Excel 依赖:
<!--工具 excel--> <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>4.0.2</version><exclusions><exclusion><artifactId>poi-ooxml-schemas</artifactId><groupId>org.apache.poi</groupId></exclusion></exclusions> </dependency>
2 实现
我这里就直接贴代码了哈:
主类:
package com.virtuous.demo.laboratory.excel;import com.alibaba.excel.EasyExcel; import com.alibaba.excel.util.ListUtils;import java.util.Date; import java.util.List;/*** @author: kuku* @description*/ public class TemplateDownload {public static void main(String[] args) {// 文件名String fileName = "test.xlsx";// 写 excel EasyExcel.write(fileName).registerWriteHandler(new CustomSheetWriteHandler()).sheet("模板").doWrite(dataList());// 读 excelEasyExcel.read("test.xlsx", new ReadDataListener()).sheet().doRead();}private static List<List<Object>> dataList() {List<List<Object>> list = ListUtils.newArrayList();for (int i = 0; i < 10; i++) {List<Object> data = ListUtils.newArrayList();data.add("字符串" + i);data.add(0.56);data.add(new Date());list.add(data);}return list;} }
写入的拦截器,用于对 Excel 进行一些特定的写入:
package com.virtuous.demo.laboratory.excel;import com.alibaba.excel.write.handler.SheetWriteHandler; import com.alibaba.excel.write.handler.context.SheetWriteHandlerContext; import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.poi.ooxml.POIXMLProperties; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.lang.reflect.Field;/*** 写 ExceL 拦截器* @author kuku*/ @Slf4j public class CustomSheetWriteHandler implements SheetWriteHandler {@SneakyThrows@Overridepublic void afterSheetCreate(SheetWriteHandlerContext context) {// 获取到当前的 workbookWriteWorkbookHolder writeWorkbookHolder = context.getWriteWorkbookHolder();// 由于没有直接的获取方式 我们这里用反射Field workbookField = WriteWorkbookHolder.class.getDeclaredField("workbook");workbookField.setAccessible(true);SXSSFWorkbook sxssfWorkbook = (SXSSFWorkbook)workbookField.get(writeWorkbookHolder);XSSFWorkbook xssfWorkbook = sxssfWorkbook.getXSSFWorkbook();// 获取属性对象POIXMLProperties properties = xssfWorkbook.getProperties();POIXMLProperties.CoreProperties coreProperties = properties.getCoreProperties();String creator = "酷酷2024";String description = "订单导入模板";String version = "2.0";// 设置作者信息 coreProperties.setCreator(creator);// 设置描述信息 coreProperties.setDescription(description);// 设置版本号 coreProperties.setVersion(version);log.info("写入作者:{},描述:{},版本:{}", creator, description, version);} }
读取的监听器:
package com.virtuous.demo.laboratory.excel;import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackageProperties;import java.lang.reflect.Field; import java.util.Map;/*** 读 Excel 监听器* @author kuku*/ @Slf4j public class ReadDataListener extends AnalysisEventListener<Map<Integer, String>> {@Overridepublic void invoke(Map<Integer, String> data, AnalysisContext context) {}@SneakyThrows@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {ReadWorkbookHolder readWorkbookHolder = context.readWorkbookHolder();if (readWorkbookHolder instanceof XlsxReadWorkbookHolder) {Field opcPackageField = XlsxReadWorkbookHolder.class.getDeclaredField("opcPackage");opcPackageField.setAccessible(true);OPCPackage opcPackage = (OPCPackage) opcPackageField.get(readWorkbookHolder);PackageProperties packageProperties = opcPackage.getPackageProperties();String creator = packageProperties.getCreatorProperty().orElse(null);String description = packageProperties.getDescriptionProperty().orElse(null);String version = packageProperties.getVersionProperty().orElse(null);log.info("读取作者:{},描述:{},版本:{}", creator, description, version);}}}
最后说一下:这种属性信息比如版本、作者信息等是可以自己编辑的,哈哈哈,当然这种概率比较小,我估计影响不大,如果要非常严谨的话,还是一列一列的去比较校验。
另外 POI 方式的就不写了哈,写入和读取基本都是用的 POI 里的对象,方式是一样的。
还有有的一些反射以及类型的校验,大家可以再严谨点,我这里主要是测试下看看行不行,所以直接 @SneakyThrows 来大包大揽了哈。
3 小结
好啦,本节就看到这里,有理解不对的地方欢迎指正哈。