陈昶聿
14 小时以前 2d3b575ed96eee7ccd5b324baa3135d2236934ac
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
@@ -474,6 +474,67 @@
    }
    /**
     * 图表Sheet构建回调:由调用方在给定工作簿上追加一个(或多个)带图表的Sheet
     */
    public interface ChartSheetBuilder {
        void build(XSSFWorkbook workbook);
    }
    /**
     * 取底层 XSSFWorkbook(SXSSF 流式工作簿也支持挂原生图表),不支持时返回 null
     */
    public XSSFWorkbook getXssfWorkbook() {
        if (wb instanceof SXSSFWorkbook) {
            return ((SXSSFWorkbook) wb).getXSSFWorkbook();
        }
        if (wb instanceof XSSFWorkbook) {
            return (XSSFWorkbook) wb;
        }
        return null;
    }
    /**
     * 导出两个数据Sheet + 一个图表Sheet(图表内容由调用方通过 builder 追加)
     *
     * @param response   返回数据
     * @param list1      第一个Sheet的数据集合
     * @param sheetName1 第一个Sheet的名称
     * @param list2      第二个Sheet的数据集合
     * @param sheetName2 第二个Sheet的名称
     * @param clazz2     第二个Sheet数据对象的Class
     * @param chartBuilder 图表Sheet构建回调,可为空(为空时与两Sheet导出完全一样)
     */
    public void exportExcelTwoSheetWithChart(HttpServletResponse response,
                                             List<T> list1, String sheetName1,
                                             List<?> list2, String sheetName2, Class<?> clazz2,
                                             ChartSheetBuilder chartBuilder) {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 初始化并写入Sheet1
        this.init(list1, sheetName1, StringUtils.EMPTY, Type.EXPORT);
        writeSheet();
        // 追加写入Sheet2
        writeAdditionalSheet(list2, sheetName2, clazz2);
        // 追加图表Sheet
        if (chartBuilder != null) {
            XSSFWorkbook xssfWorkbook = getXssfWorkbook();
            if (xssfWorkbook != null) {
                chartBuilder.build(xssfWorkbook);
            } else {
                log.warn("当前工作簿不支持原生图表,跳过图表Sheet");
            }
        }
        // 输出到响应流
        try {
            wb.write(response.getOutputStream());
        } catch (Exception e) {
            log.error("导出Excel异常{}", e.getMessage());
        } finally {
            IOUtils.closeQuietly(wb);
        }
    }
    /**
     * 向当前工作簿追加写入一个Sheet
     *
     * @param dataList  数据集合
@@ -482,8 +543,11 @@
     */
    @SuppressWarnings("unchecked")
    public void writeAdditionalSheet(List<?> dataList, String sheetName, Class<?> dataClazz) {
        if (dataList == null) {
            dataList = new ArrayList<>();
        // 没有数据或没有行类型时跳过附加 Sheet:
        // SatisfactionExportBundle.empty() 的 rowClass 为 null,若继续执行会把 this.clazz 置空,
        // 随后 getFields() 调用 clazz.getSuperclass() 触发 NullPointerException。
        if (dataClazz == null || dataList == null || dataList.isEmpty()) {
            return;
        }
        // 保存原始状态
        Class<T> originClazz = this.clazz;
@@ -1281,6 +1345,11 @@
     */
    public List<Object[]> getFields() {
        List<Object[]> fields = new ArrayList<Object[]>();
        // 防御:clazz 为空时不再调用 getSuperclass(),避免 NullPointerException。
        if (clazz == null) {
            log.warn("ExcelUtil.clazz 为空,无法解析导出字段,跳过当前 Sheet");
            return fields;
        }
        List<Field> tempFields = new ArrayList<>();
        tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
        tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));