基于easyexcel基于模板实现复杂的导出

easyexcel可以很容易实现基于模板的一些常见导出

image-20221015162924972

对于一些常见的列表、对象可以快速实现,但是做项目中遇到了一个需求,easyexcel无法完美满足,但是不用easyexcel的基于模板导出,只能用poi原始的一个单元格一个单元格的方式又显得特别繁琐,最终经过实践,想到了一套特殊的方案进行解决。

1、效果

image-20221015164216527

页面选择多个订单进行下载

订单按照商家进行分组

每一个商家对应多个订单形成一个sheet页(上述样例)

每一个sheet页有商家信息、订单汇总信息、以及每个订单的详细信息

2、解决方案

image-20221015165636640

image-20221015165656933

1、通过复制sheet的方式 ,如果有多个供应商,就将商家汇总页面复制多少个,

2、有多少个订单,就讲订单详情复制成多个sheet,

3、再利用EasyExcel将订单详情和商家汇总的所有sheet数据填充,

4、最后利用poi框架提供的复制功能,将供应商对应的订单详情一个一个拷贝到相应的商家汇总sheet,

5、最后删除所有的订单详情sheet,只保留商家汇总

核心思想就是拆分、填充、再复制、最后删除

代码

package com.taoge.easyexcel.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.enums.WriteDirectionEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.taoge.easyexcel.bean.ExportResult;
import com.taoge.easyexcel.bean.OrderDetailExportModel;
import com.taoge.easyexcel.bean.OrderExportModel;
import com.taoge.easyexcel.mapper.OrderDetailMapper;
import com.taoge.easyexcel.mapper.OrderMapper;
import com.taoge.easyexcel.model.OrderDetailModel;
import com.taoge.easyexcel.model.OrderModel;
import com.taoge.easyexcel.service.IOrderDownloadService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.CellCopyPolicy;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author txf
 * @since 2022-10-15
 */
@Service
@Slf4j
public class OrderDownloadServiceImpl implements IOrderDownloadService {

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private OrderDetailMapper orderDetailMapper;

    @Override
    public ExportResult downloadOrderInfo(String startTime, String endTime) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        QueryWrapper<OrderModel> orderQuery = new QueryWrapper<>();
        try {
            Date time1 = format.parse(startTime);
            Date time2 = format.parse(endTime);
            orderQuery.gt("date", time1);
            orderQuery.lt("date", time2);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        List<OrderModel> orderModels = orderMapper.selectList(orderQuery);
        if (CollectionUtils.isNotEmpty(orderModels)) {
            List<Long> collect = orderModels.stream().map(OrderModel::getId).collect(Collectors.toList());
            LambdaQueryWrapper<OrderDetailModel> detailQuery = new LambdaQueryWrapper<>();
            detailQuery.in(OrderDetailModel::getOrderId, collect);
            List<OrderDetailModel> detailModels = orderDetailMapper.selectList(detailQuery);
            if (CollectionUtils.isNotEmpty(detailModels)) {
                String export = export(orderModels, detailModels);
                return ExportResult.builder().downloadUrl(export).build();
            }
        }
        return ExportResult.builder().downloadUrl("").build();
    }

    public String export(List<OrderModel> orderModels, List<OrderDetailModel> detailModels) {
        String format = new Date().getTime() + "";
        String fileName = "订单下载" + format + ".xlsx";
        String dirPath = "D:\\Downloads\\";
        //下载文件地址
        File file = new File(dirPath + fileName);
        //模板地址
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("订单.xlsx");
        OutputStream os = null;
        try {
            os = new FileOutputStream(file);
            List<OrderExportModel> orderExportModels = convertOrder(orderModels);
            List<OrderDetailExportModel> orderDetailExportModels = convertDetailOrder(detailModels);
            exportExcelWithTemplate(orderExportModels, orderDetailExportModels, os, inputStream);
            mergeSheet(file.getAbsolutePath(), orderExportModels, orderDetailExportModels);
        } catch (Exception e) {
            log.error("download failed", e);
        }
        return file.getAbsolutePath();
    }

    private boolean exportExcelWithTemplate(List<OrderExportModel> orderExportModelList, List<OrderDetailExportModel> detailExportModelList,
                                            OutputStream outputStream, InputStream templateInputStream) {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            XSSFWorkbook workbook = new XSSFWorkbook(templateInputStream);
            List<String> sellerNameList = orderExportModelList.stream().map(OrderExportModel::getSellerName).distinct().collect(Collectors.toList());
            workbook.setSheetName(0, sellerNameList.get(0));
            for (int i = 1; i < sellerNameList.size(); i++) {
                workbook.cloneSheet(0, sellerNameList.get(i));
            }
            workbook.setSheetName(1, orderExportModelList.get(0).getId());
            //原模板只有一个订单sheet,通过poi复制出需要的sheet个数的模板
            for (int i = 1; i < orderExportModelList.size(); i++) {
                workbook.cloneSheet(1, orderExportModelList.get(i).getId());
            }

            Map<String, Integer> indexMap = new HashMap<>();
            int numberOfSheets = workbook.getNumberOfSheets();
            for (int i = 0; i < numberOfSheets; i++) {
                indexMap.put(workbook.getSheetAt(i).getSheetName(), i);
            }

            //写到流里
            workbook.write(bos);
            byte[] bArray = bos.toByteArray();
            InputStream is = new ByteArrayInputStream(bArray);

            ExcelWriter excelWriter = EasyExcel.write(outputStream).withTemplate(is).build();
            FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.VERTICAL).forceNewRow(Boolean.TRUE).build();

            Map<String, List<OrderExportModel>> sellerOrderMap = orderExportModelList.stream().collect(Collectors.groupingBy(OrderExportModel::getSellerCode));
            Map<String, OrderExportModel> collect = orderExportModelList.stream().collect(Collectors.toMap(OrderExportModel::getId, Function.identity(), (a, b) -> a));
            Map<String, List<OrderDetailExportModel>> detailMap = detailExportModelList.stream().collect(Collectors.groupingBy(OrderDetailExportModel::getOrderId));

            for (Map.Entry<String, List<OrderExportModel>> entry : sellerOrderMap.entrySet()) {
                List<OrderExportModel> exportModels = entry.getValue();
                OrderExportModel model = exportModels.get(0);
                WriteSheet writeSheet = EasyExcel.writerSheet(indexMap.get(model.getSellerCode())).build();
                excelWriter.fill(exportModels, fillConfig, writeSheet);
                excelWriter.fill(BeanUtils.describe(model), fillConfig, writeSheet);
            }

            for (int i = 0; i < orderExportModelList.size(); i++) {
                OrderExportModel orderExportModel = orderExportModelList.get(i);
                WriteSheet writeSheet = EasyExcel.writerSheet(indexMap.get(orderExportModel.getId())).build();
                List<OrderDetailExportModel> orderDetailExportModels = detailMap.get(orderExportModel.getId());
                excelWriter.fill(orderDetailExportModels, fillConfig, writeSheet);
                excelWriter.fill(orderExportModel, fillConfig, writeSheet);
            }
            excelWriter.finish();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("导出失败!", e);
        }
        return false;
    }

    private void mergeSheet(String filePath, List<OrderExportModel> orderExportModelList, List<OrderDetailExportModel> detailExportModelList) {

        try {
            FileInputStream fis = new FileInputStream(filePath);
            XSSFWorkbook source = new XSSFWorkbook(fis);

            Map<String, List<OrderExportModel>> sellerOrderMap = orderExportModelList.stream().collect(Collectors.groupingBy(OrderExportModel::getSellerName));

            int numberOfSheets = source.getNumberOfSheets();

            for (int i = 0; i < numberOfSheets; i++) {
                XSSFSheet to = source.getSheetAt(i);
                String sheetName = to.getSheetName();
                if (sellerOrderMap.containsKey(sheetName)) {
                    List<OrderExportModel> orderExportModels = sellerOrderMap.get(sheetName);
                    for (OrderExportModel model : orderExportModels) {
                        XSSFSheet from = source.getSheet(model.getId());
                        merge(from, to);
                    }
                }
            }

            while (true) {
                int num = source.getNumberOfSheets();
                boolean hasDel = false;
                for (int i = 0; i < num; i++) {
                    XSSFSheet sheetAt = source.getSheetAt(i);
                    if (!sellerOrderMap.containsKey(sheetAt.getSheetName())) {
                        source.removeSheetAt(i);
                        hasDel = true;
                        break;
                    }
                }
                if (!hasDel) {
                    break;
                }
            }

            FileOutputStream fos = new FileOutputStream(filePath);
            source.write(fos);
            fis.close();
        } catch (Exception e) {
            log.error("merge sheet error", e);
        }
    }

    private void merge(XSSFSheet from, XSSFSheet to) {
        int len = to.getPhysicalNumberOfRows() + 3;
        int cnt = from.getPhysicalNumberOfRows();
        for (int i = 0; i < cnt; i++) {
            XSSFRow row = to.createRow(len + i);
            row.copyRowFrom(from.getRow(i), new CellCopyPolicy());
        }
    }

    private List<OrderExportModel> convertOrder(List<OrderModel> orderModels) {
        return orderModels.stream().map(order -> {
            return OrderExportModel.builder()
                    .id(order.getId() + "")
                    .title(order.getTitle())
                    .sellerCode(order.getSellerCode())
                    .sellerName(order.getSellerName())
                    .date(order.getDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                    .address(order.getAddress())
                    .userName(order.getUserName())
                    .price(order.getPrice().toString())
                    .build();
        }).collect(Collectors.toList());
    }

    private List<OrderDetailExportModel> convertDetailOrder(List<OrderDetailModel> orderDetailModels) {
        return orderDetailModels.stream().map(order -> {
            return OrderDetailExportModel.builder()
                    .skuCode(order.getSkuCode())
                    .skuName(order.getSkuName())
                    .orderId(order.getOrderId() + "")
                    .num(order.getNum() + "")
                    .unitPrice(order.getUnitPrice().toString())
                    .price(order.getPrice().toString())
                    .build();
        }).collect(Collectors.toList());
    }

}

results matching ""

    No results matching ""