springboot优雅的实现excel的导出(自适应列宽实现,中文也行),复制可用

springboot实现excel的导出(自适应列宽实现)

【说明】废话不多说,直接就是干,⛳️

首先是环境准备

1️⃣:这里我就直接贴出用到的相关maven坐标了

<dependency>
  <groupId>cn.hutoolgroupId>
  <artifactId>hutool-allartifactId>
  <version>5.3.8version>
dependency>
<dependency>
  <groupId>org.apache.poigroupId>
  <artifactId>poiartifactId>
  <version>4.1.2version>
dependency>
<dependency>
  <groupId>org.apache.poigroupId>
  <artifactId>poi-ooxmlartifactId>
  <version>4.1.2version>
dependency>

【警告】这里根据自己的需求确定版本号

接下来就是上正餐了

【说明】首先对于excel的导出,前端调用接口最后的响应类型要为blob,不然你导出的excel会显示损坏以及打不开

1️⃣: 直接贴代码如下:

public void exportFundOutExcel(HttpServletResponse response, @RequestBody Map<String, Object> data) {
  ExcelWriter writer = ExcelUtil.getBigWriter();
  // 设置默认的行高
  writer.setDefaultRowHeight(20);
  try {
    // 获取数据
    List<Map<String, Object>> list = service.getList(data);
    String messages = "这是excel的第一行(内容自己看)";
    // 这里正常情况是要放到常量类中的,这里为了大家看清楚,或者复制直接用,这里的key要对应上面查出来的Map中的key,这里的value对应的就是你的excel表头了
    public static final Map<String,String> FUNDS_OUT_EXCEL_MAP = new LinkedHashMap<>(3);
    static {
      FUNDS_OUT_EXCEL_MAP.put("projectName","所属项目");
      FUNDS_OUT_EXCEL_MAP.put("managementUnit","建设单位");
      FUNDS_OUT_EXCEL_MAP.put("constructionUnit","施工单位");
    }

    // 表头信息
    writer.merge(FUNDS_OUT_EXCEL_MAP.size() - 1
                 , messages
                 , true);
    FUNDS_OUT_EXCEL_MAP.forEach(writer::addHeaderAlias);
    // 仅仅获取取别名的字段
    writer.setOnlyAlias(true);
    // 一定要先进性写入数据,再设置列宽
    writer.write(list, true);
    // 获取当前工作表,需要注意的是,SXSSFSheet 在处理大数据量的 Excel 文件时非常有用,但对于小型文件,使用 XSSFSheet(基于内存)可能更为合适。
    SXSSFSheet sheet = (SXSSFSheet) writer.getSheet();

    // 这里的代码就是实现自适应列宽
    //--------------------------------

    writer.setSheet(sheet);
    // 这里默认会只显示后100行数据,所以在设置的时候会Row row = this.sheet.getRow(rownum);row为null
    //            writer.setRowHeight(3,30000);
    response.resetBuffer();
    response.setContentType("application/octet-stream;charset=utf-8");
    response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode("测试.xlsx", "UTF-8"));
    writer.flush(response.getOutputStream());

  } catch (Exception e) {
    // 异常处理
  } finally {
    // 关闭writer,释放内存
    writer.close();
  }
}

下面的两种方式都可以放到上面的代码的// 这里的代码就是实现自适应列宽
//--------------------------------这个下

2️⃣:如果是excel中没有涉及到中文的话,那么可以用这种方式实现

// 这里不进行追踪的话会报错,Could not auto-size column. Make sure the column was tracked prior to auto-sizing the column.
// 跟踪所有列
sheet.trackAllColumnsForAutoSizing();
for (int i = 0; i < LotConstants.FUNDS_OUT_EXCEL_MAP.size(); i++) {
  sheet.autoSizeColumn(i);
}
int columnCount = LotConstants.FUNDS_OUT_EXCEL_MAP.size();

上面的代码我也都做了注释,大致就是必须要先执行追踪,然后再执行下面的,这个对于非中文的excel还是能做到列宽自适应的,已验证

但是对于大部分的情况下,都是含有中文的,那么就需要自己去实现了,目前我还没发现有自带的,具体实现如下

// 获取最大列宽
for (int i = 0; i < columnCount; i++) {
  final int[] maxColumnWidth = {0};
  int finalI = i;
  // 流处理,异步设置最大列宽
  IntStream.range(0, sheet.getLastRowNum() + 1).parallel().forEach(rowIndex -> {
    Row row = sheet.getRow(rowIndex);
    Cell cell = row.getCell(finalI);
    if (cell != null) {
      // 这里选择将所有格式的都转化为String类型,防止报错->Cannot get a STRING value from a NUMERIC cell
      DataFormatter dataFormatter = new DataFormatter();
      String cellValue = dataFormatter.formatCellValue(cell);
      // String cellValue = cell.getStringCellValue();
      int cellWidth = cellValue.getBytes(StandardCharsets.UTF_8).length;
      if (cellWidth > maxColumnWidth[0]) {
        maxColumnWidth[0] = cellWidth;
      }
    }
  });
  // 设置列宽,这里之所以要乘256,点进去这个方法可以看到Set the width (in units of 1256th of a character width) The maximum column width for an individual cell is 255 characters.
  // 至于200就是偏移量
  sheet.setColumnWidth(i, maxColumnWidth[0] * 256 + 200);
}

完事收工,亲测可用,如果不行请call我,一定是你哪里cv错了

补充一下上面的FUNDS_OUT_EXCEL_MAP常量,这个其实就是为了设置excel的表头,以及对应我们查询出来的字段名,大致如下:

public static final Map<String,String> FUNDS_OUT_EXCEL_MAP = new LinkedHashMap<>(3);
static {
  FUNDS_OUT_EXCEL_MAP.put("projectName","所属项目");
  FUNDS_OUT_EXCEL_MAP.put("managementUnit","建设单位");
  FUNDS_OUT_EXCEL_MAP.put("constructionUnit","施工单位");
}

你可能感兴趣的:(#,springboot,spring,boot,excel,后端)