From 66dea774217f0d6378ecb1abb59e8f66632c0d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Mon, 1 Sep 2025 12:03:33 +0800 Subject: [PATCH] =?UTF-8?q?add=20=E6=96=B0=E5=A2=9E=20Excel=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E7=B1=BB=E6=94=AF=E6=8C=81=E6=9B=B4=E7=81=B5=E6=B4=BB?= =?UTF-8?q?=E7=9A=84=E8=87=AA=E5=AE=9A=E4=B9=89=E5=AF=BC=E5=87=BA=E6=96=B9?= =?UTF-8?q?=E5=BC=8F=EF=BC=8C=E4=BB=A5=E4=BE=BF=E7=94=A8=E6=88=B7=E5=88=86?= =?UTF-8?q?=E6=89=B9=E5=A4=84=E7=90=86=E5=AF=BC=E5=87=BA=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dromara/common/excel/utils/ExcelUtil.java | 39 ++++++ .../excel/utils/ExcelWriterWrapper.java | 127 ++++++++++++++++++ .../demo/controller/TestExcelController.java | 11 ++ .../demo/service/IExportExcelService.java | 9 ++ .../service/impl/ExportExcelServiceImpl.java | 61 +++++++++ 5 files changed, 247 insertions(+) create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelWriterWrapper.java diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java index 1b35e559..74dbccba 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java @@ -27,6 +27,7 @@ import java.io.UnsupportedEncodingException; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.function.Consumer; /** * Excel相关处理 @@ -203,6 +204,44 @@ public class ExcelUtil { builder.doWrite(list); } + /** + * 导出excel + * + * @param headType 带Excel注解的类型 + * @param os 输出流 + * @param options Excel下拉可选项 + * @param consumer 导出助手消费函数 + */ + public static void exportExcel(Class headType, OutputStream os, List options, Consumer> consumer) { + try (ExcelWriter writer = FastExcel.write(os, headType) + .autoCloseStream(false) + // 自动适配 + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + // 批注必填项处理 + .registerWriteHandler(new DataWriteHandler(headType)) + // 添加下拉框操作 + .registerWriteHandler(new ExcelDownHandler(options)) + .build()) { + // 执行消费函数 + consumer.accept(ExcelWriterWrapper.of(writer)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 导出excel + * + * @param headType 带Excel注解的类型 + * @param os 输出流 + * @param consumer 导出助手消费函数 + */ + public static void exportExcel(Class headType, OutputStream os, Consumer> consumer) { + exportExcel(headType, os, null, consumer); + } + /** * 单表多数据模板导出 模板格式为 {.属性} * diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelWriterWrapper.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelWriterWrapper.java new file mode 100644 index 00000000..396f3713 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelWriterWrapper.java @@ -0,0 +1,127 @@ +package org.dromara.common.excel.utils; + +import cn.idev.excel.ExcelWriter; +import cn.idev.excel.FastExcel; +import cn.idev.excel.context.WriteContext; +import cn.idev.excel.write.builder.ExcelWriterSheetBuilder; +import cn.idev.excel.write.builder.ExcelWriterTableBuilder; +import cn.idev.excel.write.metadata.WriteSheet; +import cn.idev.excel.write.metadata.WriteTable; +import cn.idev.excel.write.metadata.fill.FillConfig; + +import java.util.Collection; +import java.util.function.Supplier; + +/** + * ExcelWriterWrapper Excel写出包装器 + *
+ * 提供了一组与 ExcelWriter 一一对应的写出方法,避免直接提供 ExcelWriter 而导致的一些不可控问题(比如提前关闭了IO流等) + * + * @author 秋辞未寒 + * @see ExcelWriter + */ +public record ExcelWriterWrapper(ExcelWriter excelWriter) { + + public void write(Collection data, WriteSheet writeSheet) { + excelWriter.write(data, writeSheet); + } + + public void write(Supplier> supplier, WriteSheet writeSheet) { + excelWriter.write(supplier.get(), writeSheet); + } + + public void write(Collection data, WriteSheet writeSheet, WriteTable writeTable) { + excelWriter.write(data, writeSheet, writeTable); + } + + public void write(Supplier> supplier, WriteSheet writeSheet, WriteTable writeTable) { + excelWriter.write(supplier.get(), writeSheet, writeTable); + } + + public void fill(Object data, WriteSheet writeSheet) { + excelWriter.fill(data, writeSheet); + } + + public void fill(Object data, FillConfig fillConfig, WriteSheet writeSheet) { + excelWriter.fill(data, fillConfig, writeSheet); + } + + public void fill(Supplier supplier, WriteSheet writeSheet) { + excelWriter.fill(supplier, writeSheet); + } + + public void fill(Supplier supplier, FillConfig fillConfig, WriteSheet writeSheet) { + excelWriter.fill(supplier, fillConfig, writeSheet); + } + + public WriteContext writeContext() { + return excelWriter.writeContext(); + } + + /** + * 创建一个 ExcelWriterWrapper + * + * @param excelWriter ExcelWriter + * @return ExcelWriterWrapper + */ + public static ExcelWriterWrapper of(ExcelWriter excelWriter) { + return new ExcelWriterWrapper<>(excelWriter); + } + + // -------------------------------- sheet start + + public static WriteSheet buildSheet(Integer sheetNo, String sheetName) { + return sheetBuilder(sheetNo, sheetName).build(); + } + + public static WriteSheet buildSheet(Integer sheetNo) { + return sheetBuilder(sheetNo).build(); + } + + public static WriteSheet buildSheet(String sheetName) { + return sheetBuilder(sheetName).build(); + } + + public static WriteSheet buildSheet() { + return sheetBuilder().build(); + } + + public static ExcelWriterSheetBuilder sheetBuilder(Integer sheetNo, String sheetName) { + return FastExcel.writerSheet(sheetNo, sheetName); + } + + public static ExcelWriterSheetBuilder sheetBuilder(Integer sheetNo) { + return FastExcel.writerSheet(sheetNo); + } + + public static ExcelWriterSheetBuilder sheetBuilder(String sheetName) { + return FastExcel.writerSheet(sheetName); + } + + public static ExcelWriterSheetBuilder sheetBuilder() { + return FastExcel.writerSheet(); + } + + // -------------------------------- sheet end + + // -------------------------------- table start + + public static WriteTable buildTable(Integer tableNo) { + return tableBuilder(tableNo).build(); + } + + public static WriteTable buildTable() { + return tableBuilder().build(); + } + + public static ExcelWriterTableBuilder tableBuilder(Integer tableNo) { + return FastExcel.writerTable(tableNo); + } + + public static ExcelWriterTableBuilder tableBuilder() { + return FastExcel.writerTable(); + } + + // -------------------------------- table end + +} diff --git a/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestExcelController.java b/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestExcelController.java index d82ea3b0..3747da4d 100644 --- a/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestExcelController.java +++ b/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestExcelController.java @@ -14,6 +14,7 @@ import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -94,6 +95,16 @@ public class TestExcelController { exportExcelService.exportWithOptions(response); } + /** + * 自定义导出 + * + * @param response / + */ + @GetMapping("/customExport") + public void customExport(HttpServletResponse response) throws IOException { + exportExcelService.customExport(response); + } + /** * 多个sheet导出 */ diff --git a/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/service/IExportExcelService.java b/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/service/IExportExcelService.java index 4dfa5eff..ad2392b9 100644 --- a/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/service/IExportExcelService.java +++ b/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/service/IExportExcelService.java @@ -2,6 +2,8 @@ package org.dromara.demo.service; import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; + /** * 导出下拉框Excel示例 * @@ -15,4 +17,11 @@ public interface IExportExcelService { * @param response / */ void exportWithOptions(HttpServletResponse response); + + /** + * 自定义导出 + * + * @param response / + */ + void customExport(HttpServletResponse response) throws IOException; } diff --git a/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/ExportExcelServiceImpl.java b/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/ExportExcelServiceImpl.java index ebb6ac68..cbc62766 100644 --- a/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/ExportExcelServiceImpl.java +++ b/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/ExportExcelServiceImpl.java @@ -2,17 +2,22 @@ package org.dromara.demo.service.impl; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; +import cn.idev.excel.write.metadata.WriteSheet; import jakarta.servlet.http.HttpServletResponse; import lombok.Data; import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; import org.dromara.common.core.enums.UserStatus; import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.file.FileUtils; import org.dromara.common.excel.core.DropDownOptions; import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.excel.utils.ExcelWriterWrapper; import org.dromara.demo.domain.vo.ExportDemoVo; import org.dromara.demo.service.IExportExcelService; import org.springframework.stereotype.Service; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -233,4 +238,60 @@ public class ExportExcelServiceImpl implements IExportExcelService { this.name = name; } } + + @Override + public void customExport(HttpServletResponse response) throws IOException { + String filename = ExcelUtil.encodingFilename("自定义导出"); + FileUtils.setAttachmentResponseHeader(response, filename); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8"); + + ExcelUtil.exportExcel(ExportDemoVo.class, response.getOutputStream(), wrapper -> { + // 创建表格数据,业务中一般通过数据库查询 + List excelDataList = new ArrayList<>(); + for (int i = 0; i < 30; i++) { + // 模拟数据库中的一条数据 + ExportDemoVo everyRowData = new ExportDemoVo(); + everyRowData.setNickName("用户-" + i); + everyRowData.setUserStatus(SystemConstants.NORMAL); + everyRowData.setGender("1"); + everyRowData.setPhoneNumber(String.format("175%08d", i)); + everyRowData.setEmail(String.format("175%08d", i) + "@163.com"); + everyRowData.setProvinceId(i); + everyRowData.setCityId(i); + everyRowData.setAreaId(i); + excelDataList.add(everyRowData); + } + + // 创建表格 + WriteSheet sheet = ExcelWriterWrapper.sheetBuilder("自定义导出demo") + // 合并单元格 + // .registerWriteHandler(new CellMergeStrategy(excelDataList, true)) + .build(); + + + wrapper.write(excelDataList, sheet); + + List excelDataList2 = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + int index = 1000 + i; + // 模拟数据库中的一条数据 + ExportDemoVo everyRowData = new ExportDemoVo(); + everyRowData.setNickName("用户-" + index); + everyRowData.setUserStatus(SystemConstants.NORMAL); + everyRowData.setGender("1"); + everyRowData.setPhoneNumber(String.format("175%08d", index)); + everyRowData.setEmail(String.format("175%08d", index) + "@163.com"); + everyRowData.setProvinceId(index); + everyRowData.setCityId(index); + everyRowData.setAreaId(index); + excelDataList2.add(everyRowData); + } + + wrapper.write(excelDataList2, sheet); + + // 或者在同一个excel中创建多个表格 + // WriteSheet sheet2 = ExcelWriterWrapper.sheetBuilder("自定义导出demo2").build(); + // wrapper.write(excelDataList2, sheet2); + }); + } }