From 2309ba31977ea72988ba1d76d7062b8f977ab414 Mon Sep 17 00:00:00 2001 From: "zangch@mesnac.com" Date: Thu, 11 Dec 2025 19:23:46 +0800 Subject: [PATCH] =?UTF-8?q?chore(wms):=20=E4=BC=98=E5=8C=96=E5=8F=91?= =?UTF-8?q?=E8=B4=A7=E5=8D=95Word=E6=A8=A1=E6=9D=BF=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=94=AF=E6=8C=81=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E6=98=8E=E7=BB=86=E8=A1=A8=E6=A0=BC=E6=B8=B2=E6=9F=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 升级poi-tl版本至1.12.2,增强模板渲染能力 - 引入自定义DynamicTableRenderPolicy策略WmsShippingDetailTablePolicy - 在导出发货单Word功能中绑定自定义表格渲染策略 - 将发货单明细数据封装为RowRenderData列表供动态表格渲染使用 - 在WordTemplateUtil中新增支持自定义Configure配置的渲染方法 - 通过动态表格策略,自动删除模板示例行并插入实际明细行 --- pom.xml | 2 +- .../common/word/util/WordTemplateUtil.java | 51 ++++++++ .../controller/WmsShippingBillController.java | 12 +- .../impl/WmsShippingBillServiceImpl.java | 35 +++--- .../word/WmsShippingDetailTablePolicy.java | 109 ++++++++++++++++++ .../src/main/resources/发货单模板.docx | Bin 29530 -> 30192 bytes 6 files changed, 187 insertions(+), 22 deletions(-) create mode 100644 ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/word/WmsShippingDetailTablePolicy.java diff --git a/pom.xml b/pom.xml index dc304e2d..a9c55777 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 1.5.4 - 1.12.1 + 1.12.2 3.14.0 diff --git a/ruoyi-common/ruoyi-common-word/src/main/java/org/dromara/common/word/util/WordTemplateUtil.java b/ruoyi-common/ruoyi-common-word/src/main/java/org/dromara/common/word/util/WordTemplateUtil.java index 81e5413b..c04658de 100644 --- a/ruoyi-common/ruoyi-common-word/src/main/java/org/dromara/common/word/util/WordTemplateUtil.java +++ b/ruoyi-common/ruoyi-common-word/src/main/java/org/dromara/common/word/util/WordTemplateUtil.java @@ -1,6 +1,7 @@ package org.dromara.common.word.util; import com.deepoove.poi.XWPFTemplate; +import com.deepoove.poi.config.Configure; import jakarta.servlet.http.HttpServletResponse; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -105,6 +106,20 @@ public final class WordTemplateUtil { } } + /** + * 构建并渲染模板(支持自定义 Configure 配置) + * + * @param templatePath 模板路径(classpath) + * @param data 模板数据 Map + * @param config poi-tl 配置对象,可包含自定义 RenderPolicy + * @return 已完成占位符渲染的 XWPFTemplate 对象 + */ + private static XWPFTemplate buildTemplate(String templatePath, Map data, Configure config) throws IOException { + try (InputStream templateStream = getTemplateStream(templatePath)) { + return XWPFTemplate.compile(templateStream, config).render(data); + } + } + /** * 重置响应头,返回输出流 * @@ -122,6 +137,42 @@ public final class WordTemplateUtil { return response.getOutputStream(); } + /** + * 渲染模板并输出到 HttpServletResponse(支持自定义 Configure 配置) + *

+ * 适用于需要自定义渲染策略的场景,例如使用 DynamicTableRenderPolicy 动态生成表格。 + * + * @param templatePath classpath 下的模板路径(含文件名),如 "templates/wms_shipping_bill.docx" + * @param fileName 下载文件名(不含后缀),如 "发货单_X123",方法内部自动补全 .docx 后缀 + * @param data 模板数据 Map,业务自行约定占位符字段 + * @param config poi-tl 配置对象,可包含自定义 RenderPolicy(如 DynamicTableRenderPolicy) + * @param response HttpServletResponse,由 Spring MVC 自动注入 + */ + public static void renderToResponse(String templatePath, String fileName, Map data, + Configure config, HttpServletResponse response) { + Objects.requireNonNull(response, "HttpServletResponse must not be null"); + Objects.requireNonNull(config, "Configure must not be null"); + if (StringUtils.isBlank(templatePath)) { + throw new ServiceException("Word 模板路径不能为空"); + } + + String safeFileName = StringUtils.isBlank(fileName) ? "export" : fileName.trim(); + Map safeData = (data == null ? Collections.emptyMap() : data); + + log.info("Word模板导出开始(自定义Configure), templatePath={}, fileName={}, dataKeys={}", + templatePath, safeFileName, safeData.keySet()); + + try (XWPFTemplate template = buildTemplate(templatePath, safeData, config); + OutputStream os = resetResponse(safeFileName, response)) { + template.write(os); + os.flush(); + log.info("Word模板导出成功, fileName={}", safeFileName); + } catch (IOException e) { + log.error("Word 模板导出失败, templatePath={}, fileName={}", templatePath, safeFileName, e); + throw new ServiceException("Word 模板导出失败,请联系管理员").setDetailMessage(e.getMessage()); + } + } + /** * 渲染模板并输出到指定 OutputStream(不负责关闭 out) * 适用于非 HTTP 场景,例如: diff --git a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/controller/WmsShippingBillController.java b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/controller/WmsShippingBillController.java index 2667ae5d..ebc08281 100644 --- a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/controller/WmsShippingBillController.java +++ b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/controller/WmsShippingBillController.java @@ -1,6 +1,7 @@ package org.dromara.wms.controller; import cn.dev33.satoken.annotation.SaCheckPermission; +import com.deepoove.poi.config.Configure; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; @@ -19,6 +20,7 @@ import org.dromara.common.word.util.WordTemplateUtil; import org.dromara.wms.domain.bo.WmsShippingBillBo; import org.dromara.wms.domain.vo.WmsShippingBillVo; import org.dromara.wms.service.IWmsShippingBillService; +import org.dromara.wms.word.WmsShippingDetailTablePolicy; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -140,13 +142,17 @@ public class WmsShippingBillController extends BaseController { public void exportWord(@NotNull(message = "发货单ID不能为空") @PathVariable("shippingBillId") Long shippingBillId, HttpServletResponse response) { - // 组装模板数据 + // 组装模板数据(包含主表字段和 List 明细列表) Map data = wmsShippingBillService.buildWordExportData(shippingBillId); // 生成文件名(发货单号) WmsShippingBillVo vo = wmsShippingBillService.queryById(shippingBillId); String fileName = "发货单_" + (vo != null && vo.getShippingCode() != null ? vo.getShippingCode() : shippingBillId); - // 渲染并输出Word文档(模板路径为classpath根目录) - WordTemplateUtil.renderToResponse("发货单模板.docx", fileName, data, response); + // 配置自定义表格渲染策略,绑定 detailsTable 占位符到 WmsShippingDetailTablePolicy + Configure config = Configure.builder() + .bind("detailsTable", new WmsShippingDetailTablePolicy()) + .build(); + // 渲染并输出Word文档(使用自定义 Configure) + WordTemplateUtil.renderToResponse("发货单模板.docx", fileName, data, config, response); } } diff --git a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/impl/WmsShippingBillServiceImpl.java b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/impl/WmsShippingBillServiceImpl.java index 7b7a3dc1..ba57d569 100644 --- a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/impl/WmsShippingBillServiceImpl.java +++ b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/service/impl/WmsShippingBillServiceImpl.java @@ -6,6 +6,8 @@ import cn.hutool.core.map.MapUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.deepoove.poi.data.RowRenderData; +import com.deepoove.poi.data.Rows; import com.github.yulichang.toolkit.JoinWrappers; import com.github.yulichang.wrapper.MPJLambdaWrapper; import lombok.RequiredArgsConstructor; @@ -382,30 +384,27 @@ public class WmsShippingBillServiceImpl implements IWmsShippingBillService { // 发货方联系电话 data.put("contactNumber", StringUtils.blankToDefault(vo.getContactNumber(), "")); - // === 明细列表 === - // 对应 Word 模板中的 {{#details}}...{{/details}} 循环表格: - // - seq → {{seq}} (行号) - // - materialName → {{materialName}}(物料名称) - // - quantity → {{quantity}} (发货数量) - // - unit → {{unit}} (计量单位) - // - remark → {{remark}} (备注) - // 如需在模板中添加单价、金额、合计行等字段,可在此处扩展 row 中的字段,并在 data 中追加 totalQuantity、totalAmount 等汇总字段。 - List> details = new ArrayList<>(); + // === 明细列表(使用 DynamicTableRenderPolicy 动态表格渲染) === + // 对应 Word 模板中的 {{detailsTable}} 占位符,由 WmsShippingDetailTablePolicy 策略处理 + // 表格列顺序:序号、名称、数量、单位、备注 + List detailRows = new ArrayList<>(); List itemsVo = vo.getItemsVo(); if (CollUtil.isNotEmpty(itemsVo)) { int seq = 1; for (WmsShippingDetailsVo item : itemsVo) { - Map row = new HashMap<>(); - row.put("seq", String.valueOf(seq++)); - row.put("materialName", StringUtils.blankToDefault(item.getMaterialName(), "")); - row.put("quantity", item.getShippingStockAmount() != null ? item.getShippingStockAmount().toPlainString() : ""); - row.put("unit", StringUtils.blankToDefault(item.getUnitName(), "")); - row.put("remark", StringUtils.blankToDefault(item.getRemark(), "")); - details.add(row); + // 构建行数据:序号、名称、数量、单位、备注(poi-tl 1.12.x 使用 Rows.of().create()) + RowRenderData row = Rows.of( + String.valueOf(seq++), + StringUtils.blankToDefault(item.getMaterialName(), ""), + item.getShippingStockAmount() != null ? item.getShippingStockAmount().toPlainString() : "", + StringUtils.blankToDefault(item.getUnitName(), ""), + StringUtils.blankToDefault(item.getRemark(), "") + ).create(); + detailRows.add(row); } } - // poi-tl 列表占位符,对应 Word 模板中的 {{#details}}...{{/details}} - data.put("details", details); + // DynamicTableRenderPolicy 表格占位符,由 WmsShippingDetailTablePolicy 渲染 + data.put("detailsTable", detailRows); return data; } diff --git a/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/word/WmsShippingDetailTablePolicy.java b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/word/WmsShippingDetailTablePolicy.java new file mode 100644 index 00000000..bd100b77 --- /dev/null +++ b/ruoyi-modules/ruoyi-wms/src/main/java/org/dromara/wms/word/WmsShippingDetailTablePolicy.java @@ -0,0 +1,109 @@ +package org.dromara.wms.word; + +import cn.hutool.core.collection.CollUtil; +import com.deepoove.poi.data.RowRenderData; +import com.deepoove.poi.policy.DynamicTableRenderPolicy; +import com.deepoove.poi.policy.TableRenderPolicy; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.xwpf.usermodel.XWPFTable; +import org.apache.poi.xwpf.usermodel.XWPFTableCell; +import org.apache.poi.xwpf.usermodel.XWPFTableRow; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcBorders; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBorder; + +import java.util.List; + +/** + * 发货单明细表格渲染策略 + *

+ * 基于 poi-tl 的 DynamicTableRenderPolicy,用于在 Word 模板中动态渲染发货单明细表格。 + * 模板中只需放置一个占位符 {{detailsTable}},本策略会自动删除模板行并插入实际明细数据。 + *

+ * 使用方式: + * 1) Word 模板中画一个 5 列表格(序号/名称/数量/单位/备注),表头行 + 一行模板行(含 {{detailsTable}}) + * 2) Java 代码中将明细数据转换为 List,放入 data.put("detailsTable", rows) + * 3) 使用 Configure.builder().customPolicy("detailsTable", new WmsShippingDetailTablePolicy()).build() 绑定策略 + * + * @author Yinq + * @date 2025-12-11 + */ +@Slf4j +public class WmsShippingDetailTablePolicy extends DynamicTableRenderPolicy { + + /** + * 明细数据起始行索引(0=表头行,1=模板行/数据行) + */ + private static final int DETAIL_START_ROW = 1; + + /** + * 表格列数(序号、名称、数量、单位、备注) + */ + private static final int COLUMN_COUNT = 5; + + @Override + public void render(XWPFTable table, Object data) throws Exception { + if (data == null) { + log.warn("发货单明细数据为空,跳过表格渲染"); + // 删除模板行,保留表头 + if (table.getNumberOfRows() > DETAIL_START_ROW) { + table.removeRow(DETAIL_START_ROW); + } + return; + } + + @SuppressWarnings("unchecked") + List rows = (List) data; + if (CollUtil.isEmpty(rows)) { + log.warn("发货单明细列表为空,跳过表格渲染"); + if (table.getNumberOfRows() > DETAIL_START_ROW) { + table.removeRow(DETAIL_START_ROW); + } + return; + } + + log.info("开始渲染发货单明细表格,共 {} 行", rows.size()); + + // 1. 删除模板行(包含 {{detailsTable}} 占位符的那一行) + table.removeRow(DETAIL_START_ROW); + + // 2. 逐行插入明细数据 + for (int i = 0; i < rows.size(); i++) { + RowRenderData rowData = rows.get(i); + int rowIndex = DETAIL_START_ROW + i; + + // 插入新行 + XWPFTableRow newRow = table.insertNewTableRow(rowIndex); + + // 创建单元格并设置边框 + for (int j = 0; j < COLUMN_COUNT; j++) { + XWPFTableCell cell = newRow.createCell(); + // 设置单元格垂直居中 + cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); + // 设置单元格边框(单线边框) + setCellBorder(cell); + } + + // 渲染行数据到单元格(使用 poi-tl 官方 API) + TableRenderPolicy.Helper.renderRow(table.getRow(rowIndex), rowData); + } + + log.info("发货单明细表格渲染完成"); + } + + /** + * 设置单元格四边边框为单线 + * + * @param cell 单元格 + */ + private void setCellBorder(XWPFTableCell cell) { + // 确保 TcPr 存在 + if (cell.getCTTc().getTcPr() == null) { + cell.getCTTc().addNewTcPr(); + } + CTTcBorders borders = cell.getCTTc().getTcPr().addNewTcBorders(); + borders.addNewTop().setVal(STBorder.SINGLE); + borders.addNewBottom().setVal(STBorder.SINGLE); + borders.addNewLeft().setVal(STBorder.SINGLE); + borders.addNewRight().setVal(STBorder.SINGLE); + } +} diff --git a/ruoyi-modules/ruoyi-wms/src/main/resources/发货单模板.docx b/ruoyi-modules/ruoyi-wms/src/main/resources/发货单模板.docx index b2cbd22f4d66ba6b6a5649ef9a57fd0288b0740d..5c20c8ce97952631e3951127206d2cc56afc8b9d 100644 GIT binary patch delta 10978 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