Browse Source

feat:添加自适应列宽处理器并替换默认列宽策略

YunaiV 10 months ago
parent
commit
77193102a2

+ 78 - 0
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/ColumnWidthMatchStyleStrategy.java

@@ -0,0 +1,78 @@
+package cn.iocoder.yudao.framework.excel.core.handler;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.idev.excel.enums.CellDataTypeEnum;
+import cn.idev.excel.metadata.Head;
+import cn.idev.excel.metadata.data.WriteCellData;
+import cn.idev.excel.util.MapUtils;
+import cn.idev.excel.write.metadata.holder.WriteSheetHolder;
+import cn.idev.excel.write.style.column.AbstractColumnWidthStyleStrategy;
+import cn.idev.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
+import org.apache.poi.ss.usermodel.Cell;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Excel 自适应列宽处理器
+ *
+ * 相比 {@link LongestMatchColumnWidthStyleStrategy} 来说,额外处理了 DATE 类型!
+ *
+ * @see <a href="https://github.com/YunaiV/yudao-cloud/pull/196/">添加自适应列宽处理器,并替换默认列宽策略</a>
+ * @author hmb
+ */
+public class ColumnWidthMatchStyleStrategy extends AbstractColumnWidthStyleStrategy {
+
+    private static final int MAX_COLUMN_WIDTH = 255;
+
+    private final Map<Integer, Map<Integer, Integer>> cache = MapUtils.newHashMapWithExpectedSize(8);
+
+    @Override
+    protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell,
+                                  Head head, Integer relativeRowIndex, Boolean isHead) {
+        boolean needSetWidth = isHead || CollUtil.isNotEmpty(cellDataList);
+        if (!needSetWidth) {
+            return;
+        }
+        Map<Integer, Integer> maxColumnWidthMap = cache.computeIfAbsent(writeSheetHolder.getSheetNo(),
+                key -> new HashMap<>(16));
+        Integer columnWidth = dataLength(cellDataList, cell, isHead);
+        if (columnWidth < 0) {
+            return;
+        }
+        if (columnWidth > MAX_COLUMN_WIDTH) {
+            columnWidth = MAX_COLUMN_WIDTH;
+        }
+        Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());
+        if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
+            maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);
+            writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 256);
+        }
+    }
+
+    @SuppressWarnings("EnhancedSwitchMigration")
+    private Integer dataLength(List<WriteCellData<?>> cellDataList, Cell cell, Boolean isHead) {
+        if (isHead) {
+            return cell.getStringCellValue().getBytes().length;
+        }
+        WriteCellData<?> cellData = cellDataList.get(0);
+        CellDataTypeEnum type = cellData.getType();
+        if (type == null) {
+            return -1;
+        }
+        switch (type) {
+            case STRING:
+                return cellData.getStringValue().getBytes().length;
+            case BOOLEAN:
+                return cellData.getBooleanValue().toString().getBytes().length;
+            case NUMBER:
+                return cellData.getNumberValue().toString().getBytes().length;
+            case DATE:
+                return cellData.getDateValue().toString().getBytes().length;
+            default:
+                return -1;
+        }
+    }
+
+}

+ 1 - 1
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java

@@ -86,7 +86,7 @@ public class SelectSheetWriteHandler implements SheetWriteHandler {
 
     /**
      * 判断字段是否是静态的、最终的、 transient 的
-     * 原因:EasyExcel 默认是忽略 static final 或 transient 的字段,所以需要判断
+     * 原因:FastExcel 默认是忽略 static final 或 transient 的字段,所以需要判断
      *
      * @param field 字段
      * @return 是否是静态的、最终的、transient 的

+ 6 - 6
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java

@@ -1,10 +1,10 @@
 package cn.iocoder.yudao.framework.excel.core.util;
 
+import cn.idev.excel.FastExcelFactory;
+import cn.idev.excel.converters.longconverter.LongStringConverter;
 import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
+import cn.iocoder.yudao.framework.excel.core.handler.ColumnWidthMatchStyleStrategy;
 import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler;
-import cn.idev.excel.EasyExcel;
-import cn.idev.excel.converters.longconverter.LongStringConverter;
-import cn.idev.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
 import jakarta.servlet.http.HttpServletResponse;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -32,9 +32,9 @@ public class ExcelUtils {
     public static <T> void write(HttpServletResponse response, String filename, String sheetName,
                                  Class<T> head, List<T> data) throws IOException {
         // 输出 Excel
-        EasyExcel.write(response.getOutputStream(), head)
+        FastExcelFactory.write(response.getOutputStream(), head)
                 .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理
-                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度
+                .registerWriteHandler(new ColumnWidthMatchStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度
                 .registerWriteHandler(new SelectSheetWriteHandler(head)) // 基于固定 sheet 实现下拉框
                 .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度
                 .sheet(sheetName).doWrite(data);
@@ -44,7 +44,7 @@ public class ExcelUtils {
     }
 
     public static <T> List<T> read(MultipartFile file, Class<T> head) throws IOException {
-        return EasyExcel.read(file.getInputStream(), head, null)
+        return FastExcelFactory.read(file.getInputStream(), head, null)
                 .autoCloseStream(false)  // 不要自动关闭,交给 Servlet 自己处理
                 .doReadAllSync();
     }

+ 1 - 1
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/package-info.java

@@ -1,4 +1,4 @@
 /**
- * 基于 EasyExcel 实现 Excel 相关的操作
+ * 基于 FastExcel 实现 Excel 相关的操作
  */
 package cn.iocoder.yudao.framework.excel;