一、起因
由于工作需要,我需要为20多个商家制作打分表。其中商家数据已登记在系统之中,打分表包括商家的名称、联系人、联系电话、地址等信息,已有一个现成的word模板。
二、解决方案
1. 升级商家管理系统
系统由第三方公司开发,暂不具备修改升级的可能性。一方面这个需求很小众,应用范围很窄;另一方面,没有经费支持(穷)。
2. 手动硬刚
步骤大概是这样的,将模板复制20多份,修改文件名为对应商家的名称,逐一打开word文档填充需要的数据。
3. 写个小工具
根据“模板+数据=>输出”的思路,可以读取模板,然后遍历商家数据填充进模板,最终得到我想要的输出结果。
三、技术选型
作为一名合格(懒)的程序员,能用代码实现的事情那肯定坚决不手动完成。我采用写个小工具的方案,由于我主要使用的还是Java语言,所以优先考虑使用Java语言实现。如果有其他更好的解决方案,请在评论区留言讨论。
1. POI
Apache POI 是基于 Office Open XML 标准(OOXML)和 Microsoft 的 OLE 2 复合文档格式(OLE2)处理各种文件格式的开源项目。 简而言之,您可以使用 Java 读写 MS Excel 文件,可以使用 Java 读写 MS Word 和 MS PowerPoint 文件。
使用Apache POI组件读取word模板,然后在表格固定的位置写入数据,最终保存。此方案优点不多,但缺点很明显。
- poi使用纯Java代码操作word文件,不直观。
- 在word里面解析表格会遇到一些不可预料到的问题,比如行列与所见不一致。
- 需要熟悉poi一整套的api使用方案
2. Freemarker
FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。
Freemarker是专业的模板引擎,首先需要将word模板转为我们能识别修改的word 2007 xml格式,然后在对应的内容位置放置变量。 我早期在开发word文档导出、数据库文档生成工具时采用的就是这个方案。
缺点:
- word模板转出来的xml文件标签众多、内容超长,不方便查找替换变量。
- 如果想要修改模板,只能从头来过,简直就是一个噩梦。
3. Velocity
和Freemarker同理
4. poi-tl
Word 模板引擎,基于Microsoft Word模板和数据生成新的文档,并且支持用户自定义函数,函数可以在Word模板的任何位置执行。
poi-tl可以直接在模板文件内放置变量标签,代码也极为简洁。
四、代码
经过上述解决方案的对比,我最终选择了poi-tl作为word模板引擎,数据通过json文件存储。
package org.example;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.deepoove.poi.XWPFTemplate;
import java.io.File;
import java.io.FileOutputStream;
import java.net.URL;
import java.util.Map;
public class Main {
public static void main(String[] args) throws Exception {
URL url = Main.class.getClassLoader().getResource("data.json");
JSONArray arr = JSON.parseArray(url);
url = Main.class.getClassLoader().getResource("template.docx");
File file = new File(url.getFile());
XWPFTemplate template = XWPFTemplate.compile(file);
for (int i = 0; i < arr.size(); i++) {
JSONObject item = arr.getJSONObject(i);
Map<String, Object> params = JSONObject.parseObject(arr.getString(i), new TypeReference<Map<String, Object>>() {});
template.render(params).write(new FileOutputStream(String.format("%s-打分表.docx", item.getString("enterName"))));
}
}
}
五、最后
本以为给我的打分表模板就是最终版本,结果把每个商家的打分表交去给领导看的时候,领导对局部的文字换行、打分项分值和顺序做了调整,幸好我使用了模板+代码方式生成最终的文件,只需要修改下模板重新运行下程序就可以了,如果是手工硬刚出来的,我想我怕是会跳起来打人!