前言
对于复杂的word模板导出场景,业界比较常用的方案是将word模板转化成xml格式,通过FreeMarker,Thymeleaf,Moustache等模板引擎生成xml最终导出word;上面的方案虽然能实现复杂的模板逻辑,但是如果业务方需要频繁修改模板样式,那么xml修改模板样式也是极为麻烦的且很不直观,这里我推荐一款国产开源的框架EasyPoi,直接在word中使用模板语法就能实现动态解析导出,所见即所得,对于需要频繁调整word模板样式的场景是非常适用的。
1.引入依赖
这里我推荐一个IDEA插件maven-search,方便快速搜索和复制maven依赖
对于word模板导出的场景,引入easypoi-base依赖即可
1 | <!-- 依赖版本号 --> |
2.模板语法介绍
- 三目运算 {{test ? obj:obj2}}
- 字符串长度 {{le:() > 8 ? obj1 : obj2}}
- 判空 {{le:(obj) > 0 ? obj : -}} (官方没有专门的判空语法,这里是替代方案)
- 格式化时间 {{fd:(obj;yyyy-MM-dd)}}
- 格式化数值 {{fn:(obj;#,##0.00)}}
- 遍历表格 {{$fe: list t.item }} 下面是示例{{}}内容将被遍历
名称 | 数值 | 占比 |
---|---|---|
{ {$fe: list t.item | fn:(t.value;#,##0.00) | fn:(t.ratio;#,##0.00%) } } |
其中list是map的k的名称 v是List<T>,item, value, ratio 是T的成员属性
更多用法见官方文档
3.集成工具类
工具类包含了导出word文件和web接口response导出,两种导出方式
1 | import cn.afterturn.easypoi.word.WordExportUtil; |
4.实战场景
包含文字表格和图片的报告模板案例
用EasyPoi模板语法填充后的报告模板
样例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147import cn.afterturn.easypoi.entity.ImageEntity;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import lombok.Data;
import lombok.experimental.FieldNameConstants;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.math.BigDecimal;
import java.util.*;
/**
* @author yinshuang
* @date 2024/1/25 10:31
* @description EasyPoiWordTemplateTest
* @copyright(c) chinacscs all rights reserved
*/
public class EasyPoiWordTemplateTest {
public static final String FILENAME_SUFFIX = "投前调查报告";
public static final String TEMPLATE_PATH = "/docx/invest_report.docx";
public void testCreateReport() {
// 组装报告数据
Map<String, Object> dataMap = getDataMap();
// 报告名称格式:企业名称 + 报告类型后缀 + 日期
String companyName = (String) dataMap.get(CompanyBasicInfoVO.Fields.companyName);
String today = DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
String filename = companyName + FILENAME_SUFFIX + today;
// 根据模板生成文件
File reportFile = WordTemplateUtil.createWordFile(dataMap, TEMPLATE_PATH, filename);
}
private Map<String, Object> getDataMap() {
Map<String, Object> dataMap = new HashMap<>(16);
// 企业基本信息
CompanyBasicInfoVO companyBasicInfo = getCompanyBasicInfo();
// 前十大股东信息
List<CompanySharehdInfoVO> sharehdInfos = getSharehdInfoList();
// 交易员电子签
ImageEntity traderImage = getTraderImage();
dataMap.put("today", new Date());
dataMap.putAll(BeanUtil.beanToMap(companyBasicInfo));
dataMap.put("sharehdlist", sharehdInfos);
dataMap.put("traderSignature", traderImage);
return dataMap;
}
private ImageEntity getTraderImage() {
ImageEntity traderImage = new ImageEntity();
traderImage.setType(ImageEntity.URL);
traderImage.setUrl("picture/img1.jpg");
traderImage.setWidth(65);
traderImage.setHeight(40);
traderImage.setLocationType(ImageEntity.EMBED);
return traderImage;
}
private CompanyBasicInfoVO getCompanyBasicInfo() {
CompanyBasicInfoVO companyBasicInfo = new CompanyBasicInfoVO();
companyBasicInfo.setCompanyName("万科企业股份有限公司");
companyBasicInfo.setReportDt(DateUtil.parse("2023-03-31"));
companyBasicInfo.setShareCapital(new BigDecimal("109.95"));
companyBasicInfo.setFirstSharehdName("深圳市地铁集团有限公司");
companyBasicInfo.setFirstSharehdRatio(new BigDecimal("0.2718"));
return companyBasicInfo;
}
private List<CompanySharehdInfoVO> getSharehdInfoList() {
List<CompanySharehdInfoVO> sharehdInfos = new ArrayList<>(10);
CompanySharehdInfoVO sharehdInfo = new CompanySharehdInfoVO();
sharehdInfo.setSharehdRank("1");
sharehdInfo.setSharehdName("深圳市地铁集团有限公司");
sharehdInfo.setSharehdNum(new BigDecimal("32.43"));
sharehdInfo.setSharehdRatio(new BigDecimal("0.2718"));
sharehdInfos.add(sharehdInfo);
return sharehdInfos;
}
public static class CompanyBasicInfoVO {
/**
* 企业名称
*/
private String companyName;
/**
* 财务指标最新报告期
*/
private Date reportDt;
/**
* 实收资本 (亿元)
*/
private BigDecimal shareCapital;
/**
* 实际控制人
*/
private String controllerName;
/**
* 第一大股东名称
*/
private String firstSharehdName;
/**
* 第一大股东持股比例
*/
private BigDecimal firstSharehdRatio;
}
public static class CompanySharehdInfoVO {
/**
* 排名
*/
private String sharehdRank;
/**
* 股东名称
*/
private String sharehdName;
/**
* 持股数量(亿股)
*/
private BigDecimal sharehdNum;
/**
* 持股比例(%)
*/
private BigDecimal sharehdRatio;
/**
* 实控人
*/
private String affilParty;
}
}企业样例数据来源
其中模板Url和图片Url的路径地址都是默认指向resources目录下word模板导出效果
- 本文作者: yinshuang
- 本文链接: https://yinshuang007.github.io/2024/01/25/EasyPoi实现word模板导出/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!