需求说明:如下图所示,excel中有4个sheet,每个sheet的数据格式都一样,有5列,第一列为订单id,现在要根据订单id到数据库中查询出其他几列的信息并补充到excel中。
代码如下:首先为service中的主方法
public void userMessage() {
// String path = this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
ApplicationHome h = new ApplicationHome(getClass());
File jarF = h.getSource();
String path = jarF.getParentFile().toString();
log.info("excel service jar2 path is:"+path+"==============================");
//获取附件1的excel
String adjunctOnePath = path+ File.separator+"1.xlsx";
String adjunctOneWritePath = path+ File.separator+"1_complete.xlsx";
File srcFile = new File(adjunctOnePath);
File destFile = new File(adjunctOneWritePath);
FileUtils.copyFile(srcFile,destFile);
ExcelReader excelReader = EasyExcel.read(adjunctOnePath)
.excelType(ExcelTypeEnum.XLSX)
.autoCloseStream(true)
.build();
// 新建一个ExcelWriterBuilder实例
ExcelWriter excelWriter = EasyExcel
.write(new FileOutputStream(destFile))
.excelType(ExcelTypeEnum.XLSX)
.autoCloseStream(true).build();
processSheet(0,excelReader,excelWriter,this::completeSheet1Data);
processSheet(1,excelReader,excelWriter,this::completeSheet2Data);
processSheet(2,excelReader,excelWriter,this::completeSheet2Data);
processSheet(3,excelReader,excelWriter,this::completeSheet4Data);
excelReader.finish();
excelWriter.finish();
}
上面首先我获取到了jar包的所在目录,因为我把excel和jar包放到了同一目录,其中1.xlsx是原始文件,1_complete.xlsx是要写入数据的文件,我这里直接复制了一份原文件。
然后我分别创建了ExcelReader 和ExcelWriter俩个对象,用于读和写excel。后面就是处理4个sheet的代码,我调用了4次方法,下面看下主要逻辑processSheet的代码:
private void processSheet(int sheetNo,ExcelReader excelReader, ExcelWriter excelWriter, Consumer<Map<Integer, String>> consumer) {
Map<Integer, String> head = new HashMap<>();
List<List<String>> data = new LinkedList<>();
// 构建输出的sheet
WriteSheet writeSheet = EasyExcel.writerSheet(sheetNo,"模板-"+sheetNo).build();
final int[] num = {0};
ReadSheet readSheet = EasyExcel.readSheet(sheetNo).registerReadListener(new AnalysisEventListener<Map<Integer, String>>() {
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
head.putAll(headMap);
List<List<String>> header = head.values().stream().map(Collections::singletonList).collect(Collectors.toList());
writeSheet.setHead(header);
}
@Override
public void invoke(Map<Integer, String> row, AnalysisContext analysisContext) {
num[0]++;
//补充数据
consumer.accept(row);
data.add( row.values().stream().collect(Collectors.toList()));
if(num[0]%50==0){
log.info("================read num is {}==============",num[0]);
excelWriter.write(data,writeSheet);
data.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
// 这里可以打印日志告知所有行读取完毕
System.out.println("读取完毕");
excelWriter.write(data,writeSheet);
}
}).build();
writeSheet.setSheetName(readSheet.getSheetName());
excelReader.read(readSheet);
}
可以看到有4个参数,分别是sheet的序号(从0开始),还有上面提到的ExcelReader 和ExcelWriter俩个对象,最后是一个Consumer对象主要用来根据orderid查询其他列的数据,这个consumer跟我的业务有关,不是重点。上面可以看到构造readSheet 对象的时候注册了一个AnalysisEventListener,这个对象内部有三个方法:
invokeHeadMap方法会读取到excel的标题行,我这里读取到之后直接设置到了writeSheet里。
invoke方法会没每一行数据都会触发一次,我这里对每一行数据调用了上面提到的Consumer进行了处理(主要是到数据库里查询其他的数据),将处理后的数据放到一个list里保存,同时每50条会写一次,防止内存数据过多。
doAfterAllAnalysed方法 读取完之后会触发,我这里接着把剩余的数据写入到writesheet。
下面是Consumer对象对应的方法,如下:主要是查询数据。
private void completeSheet2Data(Map<Integer, String> row) {
String outerId = row.get(0);
Condition condition = new Condition(BaixinCreditApply.class);
condition.createCriteria().andEqualTo("outerOrderId",outerId);
BaixinCreditApply baixinCreditApply = baixinCreditApplyMapper.selectOneByExample(condition);
if(Objects.isNull(baixinCreditApply)){
log.info("======根据outer id {} 未查询到数据========",outerId);
return ;
}
Long uid = baixinCreditApply.getUid();
//查询身份证号
String idCard = "-";
String idStartDate = "-";
String idEndDate = "-";
condition = new Condition(OcrIdCard.class);
condition.createCriteria().andEqualTo("uid",uid);
OcrIdCard ocrIdCard = ocrIdCardMapper.selectOneByExample(condition);
if(Objects.nonNull(ocrIdCard)){
String idNumberAes = ocrIdCard.getIdNumberAes();
idCard = BasicInfoEncryptUtil.decrypt(idNumberAes);
String validDate = ocrIdCard.getValidDate();
if(StringUtils.isNotBlank(validDate)&&validDate.indexOf("-")>=0){
idStartDate = validDate.split("-")[0];
idEndDate = validDate.split("-")[1];
}
}
row.put(1,String.valueOf(uid));
row.put(2,idStartDate);
row.put(3,idEndDate);
row.put(4,idCard);
}