返回

表格解析王牌:Springboot轻松驾驭Excel导入导出,搞定一对多、复合表格和合并单元格数据

后端

Springboot:Excel导入导出利器

解析一对多关系

一对多关系是数据建模中常见的结构,例如订单和订单明细、客户和订单等。在Excel导入时,如何将这些数据正确解析到对应的实体对象中呢?

// 订单实体类
public class Order {
    private Long id;
    private String orderNo;
    private Date orderDate;
    private List<OrderDetail> orderDetails;
}

// 订单明细实体类
public class OrderDetail {
    private Long id;
    private Long orderId;
    private String productName;
    private BigDecimal unitPrice;
    private Integer quantity;
}

// 解析Excel并转换为Order对象列表
public List<Order> parseExcel(InputStream inputStream) {
    Workbook workbook = WorkbookFactory.create(inputStream);
    Sheet sheet = workbook.getSheetAt(0);

    List<Order> orders = new ArrayList<>();
    for (int i = 1; i <= sheet.getLastRowNum(); i++) {
        Row row = sheet.getRow(i);

        Order order = new Order();
        order.setOrderNo(row.getCell(0).getStringCellValue());
        order.setOrderDate(row.getCell(1).getDateCellValue());

        List<OrderDetail> orderDetails = new ArrayList<>();
        for (int j = 2; j < row.getLastCellNum(); j++) {
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(order.getId());
            orderDetail.setProductName(row.getCell(j).getStringCellValue());
            orderDetail.setUnitPrice(new BigDecimal(row.getCell(j + 1).getNumericCellValue()));
            orderDetail.setQuantity((int) row.getCell(j + 2).getNumericCellValue());
            orderDetails.add(orderDetail);
        }
        order.setOrderDetails(orderDetails);

        orders.add(order);
    }

    return orders;
}

解析复合表格

复合表格是指在一个Excel文件中包含多个表格的数据。这些表格可能相互关联,也可能相互独立。在解析复合表格时,需要根据表格结构进行逐一解析。

// 解析Excel并转换为复合表格对象
public CompositeTable parseExcel(InputStream inputStream) {
    Workbook workbook = WorkbookFactory.create(inputStream);
    CompositeTable compositeTable = new CompositeTable();

    for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
        Sheet sheet = workbook.getSheetAt(i);

        // 获取表格名称
        String tableName = sheet.getSheetName();

        // 解析表格数据
        List<Map<String, Object>> data = new ArrayList<>();
        for (int j = 1; j <= sheet.getLastRowNum(); j++) {
            Row row = sheet.getRow(j);

            Map<String, Object> rowData = new HashMap<>();
            for (int k = 0; k < row.getLastCellNum(); k++) {
                rowData.put(row.getCell(k).getStringCellValue(), row.getCell(k + 1).getStringCellValue());
            }
            data.add(rowData);
        }

        // 将表格数据添加到复合表格对象中
        compositeTable.addTable(tableName, data);
    }

    return compositeTable;
}

解析合并单元格数据

合并单元格是Excel中常用的功能,可以使表格更加美观和简洁。但在解析合并单元格数据时,需要特别注意。

// 解析Excel并处理合并单元格数据
public List<Map<String, Object>> parseExcel(InputStream inputStream) {
    Workbook workbook = WorkbookFactory.create(inputStream);
    Sheet sheet = workbook.getSheetAt(0);

    List<Map<String, Object>> data = new ArrayList<>();
    for (int i = 1; i <= sheet.getLastRowNum(); i++) {
        Row row = sheet.getRow(i);

        Map<String, Object> rowData = new HashMap<>();
        for (int j = 0; j < row.getLastCellNum(); j++) {
            Cell cell = row.getCell(j);

            // 判断是否是合并单元格
            if (cell.isMergedCell()) {
                // 获取合并单元格的范围
                CellRangeAddress mergedRegion = cell.getMergedRegion();

                // 获取合并单元格的值
                String value = cell.getStringCellValue();

                // 将合并单元格的值添加到rowData中
                for (int k = mergedRegion.getFirstColumn(); k <= mergedRegion.getLastColumn(); k++) {
                    rowData.put(row.getCell(k).getStringCellValue(), value);
                }
            } else {
                // 将单元格的值添加到rowData中
                rowData.put(cell.getStringCellValue(), cell.getStringCellValue());
            }
        }
        data.add(rowData);
    }

    return data;
}

结论

Springboot结合Apache POI库,为我们提供了强大的Excel导入导出功能。通过本文的讲解,您已经掌握了一对多、复合表格和合并单元格数据的解析技巧。希望这些知识能够帮助您轻松应对数据交换的难题。

常见问题解答

  1. 如何将Excel数据导出为指定格式的文件?
// 导出Excel数据为指定格式的文件
public void exportExcel(List<Order> orders, OutputStream outputStream, String format) {
    Workbook workbook = new XSSFWorkbook();
    Sheet sheet = workbook.createSheet("Orders");

    // 创建表头
    Row headerRow = sheet.createRow(0);
    headerRow.createCell(0).setCellValue("订单号");
    headerRow.createCell(1).setCellValue("下单时间");
    headerRow.createCell(2).setCellValue("商品名称");
    headerRow.createCell(3).setCellValue("单价");
    headerRow.createCell(4).setCellValue("数量");

    // 填充数据
    int rowIndex = 1;
    for (Order order : orders) {
        Row row = sheet.createRow(rowIndex++);
        row.createCell(0).setCellValue(order.getOrderNo());
        row.createCell(1).setCellValue(order.getOrderDate());
        for (OrderDetail orderDetail : order.getOrderDetails()) {
            row.createCell(2).setCellValue(orderDetail.getProductName());
            row.createCell(3).setCellValue(orderDetail.getUnitPrice());
            row.createCell(4).setCellValue(orderDetail.getQuantity());
        }
    }

    // 根据指定格式导出文件
    switch (format) {
        case "xlsx":
            workbook.write(outputStream);
            break;
        case "xls":
            workbook.write(new XSSFWorkbook(outputStream));
            break;
    }
}
  1. 如何自定义Excel导出模板?
// 自定义Excel导出模板
public void exportExcel(List<Order> orders, OutputStream outputStream, String templatePath) {
    try {
        Workbook workbook = WorkbookFactory.create(new File(templatePath));
        Sheet sheet = workbook.getSheetAt(0);

        // 填充数据
        int rowIndex = 1;
        for (Order order : orders) {
            Row row = sheet.createRow(rowIndex++);
            row.createCell(0).setCellValue(order.getOrderNo());
            row.createCell(1).setCellValue(order.getOrderDate());
            for (OrderDetail orderDetail : order.getOrderDetails()) {
                row.createCell(2).setCellValue(orderDetail.getProductName());
                row.createCell(3).setCellValue(orderDetail.getUnitPrice());
                row.createCell(4).setCellValue(orderDetail.getQuantity());
            }
        }

        // 导出文件
        workbook.write(outputStream);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  1. 如何导入Excel数据时忽略空行?
// 导入Excel数据时忽略空行
public List<Order> parseExcel(InputStream inputStream, boolean ignoreEmptyRows) {
    Workbook workbook = WorkbookFactory.create(inputStream);
    Sheet sheet = workbook.getSheetAt(0);

    List<Order> orders = new ArrayList<>();
    int lastRowNum = ignoreEmptyRows ? sheet.getLastRowNum() : sheet.getPhysicalNumberOfRows();
    for (int i = 1; i <= lastRowNum; i++) {
        Row row = sheet.getRow(i);
        if (row.getCell(0) != null) {
            // 解析数据
            Order order = new Order();
            order.setOrderNo(row.getCell(0).getStringCellValue());
            order.setOrderDate(row.getCell(1).getDateCellValue());
            List<OrderDetail> orderDetails = new ArrayList<>();
            for (int j = 2; j < row.getLastCellNum(); j++) {
                OrderDetail orderDetail = new OrderDetail();
                orderDetail.setOrderId(order.getId());
                orderDetail.setProductName(row.getCell(j).getStringCellValue());
                orderDetail.setUnitPrice(new BigDecimal(row.getCell(j