Files
flowable_management/base-fast/Word模板配置说明.md

244 lines
9.9 KiB
Markdown
Raw Normal View History

2026-01-31 15:51:23 +08:00
# Word合同模板配置说明
## 📋 问题原因
Word模板中的动态列表数据渲染失败主要原因是
1. 没有配置 `LoopRowTableRenderPolicy` 循环行渲染策略
2. 数据格式不匹配直接传JSONArray而不是List<Map>
3. 模板语法使用不正确
## ✅ 解决方案
### 1. Word模板正确语法
在Word模板的表格中需要使用以下格式
```
┌─────────┬──────────┬──────────┬──────┬──────┬──────────┬──────────┬──────┐
│ 序号 │ 产品名称 │ 型号 │ 数量 │ 单位 │ 单价(元) │ 总价(元) │ 备注 │
├─────────┼──────────┼──────────┼──────┼──────┼──────────┼──────────┼──────┤
│{{#rows}}│ │ │ │ │ │ │ │
├─────────┼──────────┼──────────┼──────┼──────┼──────────┼──────────┼──────┤
│{{seq}} │{{materialName}}│{{materialSpec}}│{{qty}}│{{unitName}}│{{salePrice}}│{{amount}}│{{remark}}│
├─────────┼──────────┼──────────┼──────┼──────┼──────────┼──────────┼──────┤
│{{/rows}}│ │ │ │ │ │ │ │
└─────────┴──────────┴──────────┴──────┴──────┴──────────┴──────────┴──────┘
```
**重要说明**
- `{{#rows}}` 必须单独占一行(表格的一行)
- 数据行包含所有字段:`{{seq}}`, `{{materialName}}`
- `{{/rows}}` 必须单独占一行(表格的一行)
- 这三行构成一个完整的循环结构
### 2. 模板文件位置
将模板文件放在以下位置之一:
**方式1放在resources目录推荐**
```
src/main/resources/templates/contract_template.docx
```
**方式2使用绝对路径**
```java
/Users/mima0000/Desktop/合同.docx
```
### 3. 后端代码关键点
#### 3.1 配置循环行策略
```java
LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
Configure config = Configure.builder()
.bind("rows", policy) // 绑定rows标签
.build();
```
#### 3.2 数据格式转换
```java
// 错误方式 ❌
dataMap.put("rows", JSONArray.parseArray(materialJson));
// 正确方式 ✅
List<Map<String, Object>> rowsList = new ArrayList<>();
for (int i = 0; i < materialArray.size(); i++) {
JSONObject item = materialArray.getJSONObject(i);
Map<String, Object> rowData = new HashMap<>();
rowData.put("seq", i + 1);
rowData.put("materialName", item.getString("materialName"));
// ... 其他字段
rowsList.add(rowData);
}
dataMap.put("rows", rowsList);
```
#### 3.3 使用配置渲染
```java
XWPFTemplate template = XWPFTemplate.compile(templateStream, config)
.render(dataMap);
```
## 🎯 完整的Word模板示例
### 模板结构
```
服务合同
需方:{{clientName}} 合同编号:{{contractCode}}
供方:上海诺力智能科技有限公司 签订时间:{{effectiveDate}}
一、产品明细单
┌─────────┬──────────┬──────────┬──────┬──────┬──────────┬──────────┬──────┐
│ 序号 │ 产品名称 │ 型号 │ 数量 │ 单位 │ 单价(元) │ 总价(元) │ 备注 │
├─────────┼──────────┼──────────┼──────┼──────┼──────────┼──────────┼──────┤
│{{#rows}}│ │ │ │ │ │ │ │
├─────────┼──────────┼──────────┼──────┼──────┼──────────┼──────────┼──────┤
│{{seq}} │{{materialName}}│{{materialSpec}}│{{qty}}│{{unitName}}│{{salePrice}}│{{amount}}│{{remark}}│
├─────────┼──────────┼──────────┼──────┼──────┼──────────┼──────────┼──────┤
│{{/rows}}│ │ │ │ │ │ │ │
├─────────┴──────────┴──────────┴──────┴──────┴──────────┼──────────┼──────┤
│ 共计: │{{totalPrice}}│ │
└──────────────────────────────────────────────┴──────────┴──────┘
二、质量要求:{{qc}}
三、交货时间、地点:货期:{{delivery}},交货地:{{place}}
四、运输方式:{{transport}}
五、包装标准:{{packaging}}
六、结算方式:{{pay}},付款方式:{{payment}}
七、违约责任:{{breach}}
八、解决合同纠纷的方式:{{solve_dispute}}
九、其它约定事项:{{supplement}}
┌──────────────────────────────┬──────────────────────────────┐
│ 需方: │ 供方: │
├──────────────────────────────┼──────────────────────────────┤
│单位名称:{{clientName}} │单位名称:上海诺力智能科技有限公司│
│地址:{{clientAdd}} │地址:上海青浦区徐泾镇... │
│委托代理人:{{juridicalPerson}}│委托代理人: │
│电话:{{clientTel}} │电话: │
│传真:{{clientFax}} │传真: │
│开户银行:{{clientBank}} │开户银行:招商银行虹桥支行 │
│帐号:{{clientCard}} │帐号12191702501091 │
└──────────────────────────────┴──────────────────────────────┘
```
## 📝 字段说明
### 基本信息字段
| 字段名 | 说明 | 示例 |
|--------|------|------|
| clientName | 客户名称 | XX公司 |
| contractCode | 合同编号 | HT20250101 |
| effectiveDate | 生效日期 | 2025年01月01日 |
| totalPrice | 总价 | 100000.00 |
### 列表字段rows
| 字段名 | 说明 | 示例 |
|--------|------|------|
| seq | 序号 | 1, 2, 3... |
| materialName | 产品名称 | 叉车 |
| materialSpec | 型号 | CPD15 |
| qty | 数量 | 10 |
| unitName | 单位 | 台 |
| salePrice | 单价 | 50000.00 |
| amount | 总价 | 500000.00 |
| remark | 备注 | 含税 |
### 合同条款字段
| 字段名 | 说明 |
|--------|------|
| qc | 质量要求 |
| delivery | 交货时间 |
| place | 交货地点 |
| transport | 运输方式 |
| packaging | 包装标准 |
| pay | 结算方式 |
| payment | 付款方式 |
| breach | 违约责任 |
| solve_dispute | 解决纠纷方式 |
| supplement | 其它约定 |
### 客户信息字段
| 字段名 | 说明 |
|--------|------|
| clientAdd | 客户地址 |
| juridicalPerson | 法人代表 |
| clientTel | 客户电话 |
| clientFax | 客户传真 |
| clientBank | 客户开户行 |
| clientCard | 客户账号 |
## 🔧 常见问题
### 1. 列表数据不显示
**原因**:没有配置 `LoopRowTableRenderPolicy`
**解决**:在代码中添加配置
```java
Configure config = Configure.builder()
.bind("rows", policy)
.build();
```
### 2. 列表只显示一行
**原因**:模板中 `{{#rows}}``{{/rows}}` 没有单独占一行
**解决**:确保循环标签单独占表格的一行
### 3. 数据格式错误
**原因**直接传JSONArray而不是List<Map>
**解决**转换为List<Map<String, Object>>格式
### 4. 中文乱码
**原因**:文件名编码问题
**解决**使用URLEncoder编码文件名
```java
String fileName = java.net.URLEncoder.encode("合同.docx", "UTF-8");
```
## 🎉 测试步骤
1. **准备模板文件**
- 按照上述格式创建Word模板
- 保存为 `contract_template.docx`
- 放到 `src/main/resources/templates/` 目录
2. **测试导出**
- 访问:`GET /flow/contract/export?contractId=1`
- 检查下载的Word文档
- 验证列表数据是否正确显示
3. **验证数据**
- 打开导出的Word文档
- 检查产品明细表是否有多行数据
- 检查所有字段是否正确填充
## 💡 最佳实践
1. **模板管理**
- 将模板文件放在resources目录
- 使用版本控制管理模板
- 为不同类型合同创建不同模板
2. **错误处理**
- 添加try-catch捕获异常
- 记录详细的错误日志
- 返回友好的错误提示
3. **性能优化**
- 缓存模板对象
- 使用流式处理大文件
- 异步处理导出任务
## 📚 参考资料
- poi-tl官方文档http://deepoove.com/poi-tl/
- 循环行表格http://deepoove.com/poi-tl/#_loop-row-table
- GitHub示例https://github.com/Sayi/poi-tl
---
**更新时间**: 2026-01-30
**版本**: v1.0