From 5f612ab2f67b2c6f6894c624a7780799526d566d Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期四, 05 十一月 2026 20:20:05 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_business_新高电力' into dev_business_新高电力

---
 yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java |   96 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 94 insertions(+), 2 deletions(-)

diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java
index 5d65ac1..91e88c2 100644
--- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java
+++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java
@@ -1,10 +1,20 @@
 package cn.iocoder.yudao.framework.excel.core.util;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.exceptions.ExceptionUtil;
+import cn.hutool.core.util.StrUtil;
 import cn.idev.excel.ExcelWriter;
 import cn.idev.excel.FastExcelFactory;
 import cn.idev.excel.converters.longconverter.LongStringConverter;
+import cn.idev.excel.exception.ExcelAnalysisException;
+import cn.idev.excel.exception.ExcelCommonException;
+import cn.idev.excel.exception.ExcelDataConvertException;
 import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
+import cn.iocoder.yudao.framework.excel.core.convert.ListJsonStringConverter;
+import cn.iocoder.yudao.framework.excel.core.convert.LocalTimeStringConverter;
+import lombok.extern.slf4j.Slf4j;
 import cn.iocoder.yudao.framework.excel.core.handler.ColumnWidthMatchStyleStrategy;
+import cn.iocoder.yudao.framework.excel.core.handler.DateAsTextCellWriteHandler;
 import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler;
 import jakarta.servlet.http.HttpServletResponse;
 import org.springframework.web.multipart.MultipartFile;
@@ -13,11 +23,15 @@
 import java.io.InputStream;
 import java.util.List;
 
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.excel.core.enums.ExcelErrorCodeConstants.*;
+
 /**
  * Excel 宸ュ叿绫�
  *
  * @author 瓒呯骇绠$悊鍛�
  */
+@Slf4j
 public class ExcelUtils {
 
     /**
@@ -39,6 +53,8 @@
                 .registerWriteHandler(new ColumnWidthMatchStyleStrategy()) // 鍩轰簬 column 闀垮害锛岃嚜鍔ㄩ�傞厤銆傛渶澶� 255 瀹藉害
                 .registerWriteHandler(new SelectSheetWriteHandler(head)) // 鍩轰簬鍥哄畾 sheet 瀹炵幇涓嬫媺妗�
                 .registerConverter(new LongStringConverter()) // 閬垮厤 Long 绫诲瀷涓㈠け绮惧害
+                .registerConverter(new LocalTimeStringConverter()) // FastExcel 鍐呯疆鏃� LocalTime锛岀己灏戞椂浼氭姏 Can not find 'Converter'
+                .registerConverter(new ListJsonStringConverter()) // FastExcel 鍐呯疆鏃� List锛岀己灏戞椂浼氭姏 Can not find 'Converter'
                 .build();
         try {
             excelWriter.write(data, FastExcelFactory.writerSheet(sheetName).build());
@@ -55,13 +71,89 @@
         response.setContentType("application/vnd.ms-excel;charset=UTF-8");
     }
 
-    public static <T> List<T> read(MultipartFile file, Class<T> head) throws IOException {
+    /**
+     * 杈撳嚭 Excel 妯℃澘锛堟棩鏈熸寜鏂囨湰娓叉煋锛�
+     *
+     * <p>涓� {@link #write} 鐨勫尯鍒細棰濆娉ㄥ唽浜� {@link DateAsTextCellWriteHandler}锛�
+     * 鎶� LocalDate / LocalDateTime 鍐欐垚 yyyy-MM-dd 鏂囨湰锛岃�屼笉鏄� Excel 鏃ユ湡搴忓垪鍙枫��
+     * 浠呯敤浜庛�屼笅杞藉鍏ユā鏉裤�嶏紝瀵煎叆瑙f瀽浠嶈蛋 {@link #read}锛屼笉鍙楀奖鍝嶃��</p>
+     */
+    public static <T> void writeTemplate(HttpServletResponse response, String filename, String sheetName,
+                                         Class<T> head, List<T> data) throws IOException {
+        ExcelWriter excelWriter = FastExcelFactory.write(response.getOutputStream(), head)
+                .autoCloseStream(false)
+                .registerWriteHandler(new ColumnWidthMatchStyleStrategy())
+                .registerWriteHandler(new SelectSheetWriteHandler(head))
+                .registerWriteHandler(new DateAsTextCellWriteHandler())
+                .registerConverter(new LongStringConverter())
+                .registerConverter(new LocalTimeStringConverter())
+                .registerConverter(new ListJsonStringConverter())
+                .build();
+        try {
+            excelWriter.write(data, FastExcelFactory.writerSheet(sheetName).build());
+        } finally {
+            excelWriter.finish();
+            excelWriter.close();
+        }
+        response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename));
+        response.setContentType("application/vnd.ms-excel;charset=UTF-8");
+    }
+
+    /**
+     * 璇诲彇 Excel 鏂囦欢
+     *
+     * <p>鎵�鏈夊鍏ユ帴鍙i兘缁忚繃杩欓噷锛屽洜姝ゅ湪杩欓噷缁熶竴鎶娿�屽潖鏂囦欢 / 绌烘枃浠� / 妯℃澘涓嶅尮閰� / 鍗曞厓鏍兼牸寮忛敊銆�
+     * 绛夊悇绉嶅簳灞傚紓甯革紝杞崲鎴愬彲璇荤殑涓枃鎻愮ず锛圫erviceException锛夈��
+     * 杩欐牱涓氬姟鎺ュ彛涓嶅繀鍚勮嚜鍐� try-catch锛屼篃涓嶄細鍐嶅嚭鐜板惈绯婄殑銆岀郴缁熷紓甯搞��500銆�</p>
+     *
+     * @param file Excel 鏂囦欢
+     * @param head 琛ㄥご瀵瑰簲鐨� VO 绫�
+     * @return 瑙f瀽缁撴灉
+     */
+    public static <T> List<T> read(MultipartFile file, Class<T> head) {
+        // 1. 鏂囦欢鏈韩涓虹┖
+        if (file == null || file.isEmpty()) {
+            throw exception(EXCEL_FILE_EMPTY);
+        }
+        // 2. 瑙f瀽锛堥�愮被璇嗗埆寮傚父锛岀粰鍑哄彲璇绘彁绀猴級
+        List<T> list;
         // 鍙傝�� https://t.zsxq.com/zM77F 甯栧瓙锛屽鍔� try 澶勭悊锛屽吋瀹� windows 鍦烘櫙
         try (InputStream inputStream = file.getInputStream()) {
-            return FastExcelFactory.read(inputStream, head, null)
+            list = FastExcelFactory.read(inputStream, head, null)
                     .autoCloseStream(false) // 涓嶈鑷姩鍏抽棴锛屼氦缁� Servlet 鑷繁澶勭悊
                     .doReadAllSync();
+        } catch (IOException ex) {
+            log.warn("[read][Excel 鏂囦欢璇诲彇澶辫触锛屾枃浠跺悕({})]", file.getOriginalFilename(), ex);
+            throw exception(EXCEL_FILE_READ_FAILED);
+        } catch (ExcelDataConvertException ex) {
+            // 鍗曞厓鏍兼暟鎹牸寮忎笉瀵癸紝渚嬪鏂囨湰鍒楀~浜嗘暟瀛椼�佹棩鏈熷垪濉簡涔辩爜
+            String detail = StrUtil.blankToDefault(ex.getMessage(), "鍐呭涓庡垪绫诲瀷涓嶅尮閰�");
+            log.warn("[read][Excel 鍗曞厓鏍兼暟鎹牸寮忛敊璇紝琛�({}) 鍒�({})]", ex.getRowIndex(), ex.getColumnIndex(), ex);
+            throw exception(EXCEL_DATA_CONVERT_FAILED,
+                    (ex.getRowIndex() == null ? 0 : ex.getRowIndex()) + 1,
+                    (ex.getColumnIndex() == null ? 0 : ex.getColumnIndex()) + 1,
+                    StrUtil.maxLength(detail, 60));
+        } catch (ExcelAnalysisException ex) {
+            // 鏂囦欢鎹熷潖銆佸姞瀵嗐�佷笉鏄湡姝g殑 Excel銆佽〃澶翠笌妯℃澘瀵逛笉涓婄瓑
+            String rootMsg = StrUtil.blankToDefault(ExceptionUtil.getRootCauseMessage(ex), "");
+            log.warn("[read][Excel 瑙f瀽澶辫触锛屾枃浠跺悕({})锛屽師鍥�({})]", file.getOriginalFilename(), rootMsg, ex);
+            if (StrUtil.containsAnyIgnoreCase(rootMsg, "head", "Can not find", "autoTrim", "Convert")) {
+                throw exception(EXCEL_HEAD_NOT_MATCH);
+            }
+            throw exception(EXCEL_TEMPLATE_NOT_MATCH);
+        } catch (ExcelCommonException ex) {
+            log.warn("[read][Excel 閫氱敤寮傚父锛屾枃浠跺悕({})]", file.getOriginalFilename(), ex);
+            throw exception(EXCEL_FILE_READ_FAILED);
+        } catch (Exception ex) {
+            // 鍏滃簳锛氫换浣曟湭棰勬枡鐨勮В鏋愬紓甯搁兘杞垚鍙鎻愮ず锛岄伩鍏嶇洿鎺� 500銆岀郴缁熷紓甯搞��
+            log.warn("[read][Excel 瑙f瀽鍑虹幇鏈鏈熷紓甯革紝鏂囦欢鍚�({})]", file.getOriginalFilename(), ex);
+            throw exception(EXCEL_FILE_READ_FAILED);
         }
+        // 3. 瑙f瀽鍑烘潵鏄┖琛紙鍙湁琛ㄥご銆佹病鏈夋暟鎹锛�
+        if (CollUtil.isEmpty(list)) {
+            throw exception(EXCEL_FILE_EMPTY_CONTENT);
+        }
+        return list;
     }
 
 }

--
Gitblit v1.9.3