java根据word模板填充数据并导出
方法一(推荐):
1、文件处理
效果图:
说明:列表头部必须加标记如{{wordList}},子项必须是[xx];图片必须是{{@xx}}
所有的标签都是以 {{开始,以}} 结束。
-
{{template}} 文本
-
{{@template}} 图片
-
{{#template}} 表格
-
{{*template}} 列表
-
{{+template}} Word 文档合并
-
{{?template}}{{/template}} if 和 foreach 功能
2、引入包
<!-- POI 依赖 使用xlsx xml的格式(即XSSFWorkbook) --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>5.2.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-scratchpad</artifactId> <version>3.17</version> </dependency> <!-- poi模板导入,主力包 --> <dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <version>1.12.1</version> </dependency>
3、代码示例片段
HashMap<String, Object> finalMap = new HashMap<>();
finalMap.put("ProjectName","2342");
finalMap.put("PROJECT_CODE","中世e招4楼评标厅");
finalMap.put("AgentUnit","23423");
finalMap.put("OwnerUnit","20221321");
finalMap.put("type","20221321");
finalMap.put("Budget","20221321");
finalMap.put("OPEN_TIME","20221321");
finalMap.put("Is_Allowed_Extract_Same_Unit","20221321");
finalMap.put("Notice_type","20221321");
finalMap.put("ExtractTime","20221321");
ArrayList<Object> workList = CollUtil.newArrayList();
for (int i = 0; i < 3; i++) {
// 模拟从mysql查询列表数据
HashMap<String, Object> workItem = new HashMap<>();
workItem.put("NAME", i + 1);
workItem.put("ORG", "四川有限公司" + i);
workItem.put("ID_CARD", i + 10 + "小时");
workItem.put("PHONE", "800" + i);
workItem.put("EXPERT_TYPE_NAME", "项目经理" + i);
workItem.put("DNAME", "java工程师" + i);
workList.add(workItem);
}
finalMap.put("workList", workList);
// 插入图片
try {
//这里也可以是用文件服务器返回的网络文件流
String pictureUrl = "http://5b0988e595225.cdn.sohucs.com/images/20171013/fec49f59b98041a4a16886893447f746.jpeg";
pictureUrl = "D:\\xx\\Java项目\\xx\\sxsoft_expert\\staticfile\\下载.png";
// 从网络流读取图片,置入word模板,等待编译
if (Validator.isNotEmpty(pictureUrl)) {
//PictureRenderData picture = Pictures.ofUrl(pictureUrl).size(40, 30).create();//网络图片地址
PictureRenderData picture = Pictures.ofLocal(pictureUrl).size(40, 30).create();//本地图片地址
finalMap.put("signPicture", picture);
}
} catch (Exception e) {
e.printStackTrace();
}
// 从网络url 下载word模板到指定文件夹
File wordTemplate = new File("D:\\xx\\Java项目\\xx\\sxsoft_expert\\staticfile\\专家抽取信息 - 副本.doc");
// 此处使用了poi-tl的<表格行循环插件>,此处一定要进行参数bind,方便word模板参数替换
LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
Configure build = Configure.builder().bind(policy, "workList").build();
XWPFTemplate render = XWPFTemplate.compile(wordTemplate, build).render(finalMap);
// 此处是利用File,直接在本地创建文件,将参数替换后的文件流写入到该文件,word就是最终的结果
String fileName =File.separator +IdUtil.getSnowflake(1,1).nextId() + ".docx";
String path ="D:\\xx\\Java项目\\xx\\sxsoft_expert\\staticfile\\" + fileName;
File word = new File(path);
try {
render.writeToFile(word.getAbsolutePath());
} catch (IOException e) {
throw new RuntimeException(e);
}
//导出并删除本地文件
DownLoadFileUtil.downloadFile(response,path,fileName,true);
/** * 浏览器下载指定文件 * @param path 完整物理路径 * @param setFileName 文件名称 * @param isDel 导出后是否删除磁盘文件,方法调用之前的这个文件的流必须先关闭掉才有生效 * @return */ public static HttpServletResponse downloadFile(HttpServletResponse response, String path, String setFileName,boolean isDel) { InputStream fis = null; OutputStream toClient = null; File file = null; try { // path是指欲下载的文件的路径。 file = new File(path); // 取得文件名。 String filename = file.getName(); if(StringUtils.isEmpty(setFileName)){ setFileName = filename; } // 取得文件的后缀名。 String ext = filename.substring(filename.lastIndexOf(".") + 1).toUpperCase(); // 以流的形式下载文件。 fis = new BufferedInputStream(new FileInputStream(path)); byte[] buffer = new byte[fis.available()]; fis.read(buffer); // 清空response response.reset(); // 设置response的Header response.addHeader("Content-Disposition", "attachment;filename=" + java.net.URLDecoder.decode(setFileName, "UTF-8")); response.addHeader("Content-Length", "" + file.length()); toClient = new BufferedOutputStream(response.getOutputStream()); response.setContentType("application/octet-stream"); toClient.write(buffer); } catch (IOException ex) { ex.printStackTrace(); }finally { if(fis != null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } if(toClient != null){ try { toClient.flush(); toClient.close(); } catch (IOException e) { e.printStackTrace(); } } //下载之后删除 try { if(isDel && file.exists()){ file.delete(); } } catch (Exception e) { e.printStackTrace(); } } return response; }
方法二(ooxml有版本冲突时):
1、引入包
<!--freemarker word--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.28</version> </dependency>
2、代码示例片段
//region 把数据放进这个map里面进行填充 Map<String,Object> dataMap = new HashMap(); dataMap.put("ProjectName",PROJECT_NAME); dataMap.put("OpenAddress",OPEN_ADDRESS); dataMap.put("PROJECT_CODE",PROJECT_CODE); dataMap.put("ExtractTime",ExtractTime); dataMap.put("AgentUnit",AgentUnit); dataMap.put("type",type); dataMap.put("OPEN_TIME",OPEN_TIME); dataMap.put("OwnerUnit",OwnerUnit); dataMap.put("Notice_type",Notice_type); dataMap.put("Budget",Budget); dataMap.put("Is_Allowed_Extract_Same_Unit",Is_Allowed_Extract_Same_Unit); dataMap.put("TemporaryExpertList",dt_TemporaryExpert); dataMap.put("TemporaryExpertJoinList",dt_join); dataMap.put("TemporaryExpertNotJoinList",dt_Notjoin); //endregion //region 导出模板文件 参考 https://blog.csdn.net/yihuaiyan/article/details/87965887 //创建模板配置 Configuration configuration = new Configuration(); configuration.setDefaultEncoding("utf-8"); //模板文件的位置 String systemDir = System.getProperty("user.dir"); String sourcePath = systemDir + "\\staticfile"; configuration.setDirectoryForTemplateLoading(new File(sourcePath)); Template template = configuration.getTemplate("临时专家库抽取结果信息.ftl"); //加载---要装载的模板文件 //输出文档路径及名称,注意后缀一定要.doc!不然代码运行完后会打不开 String fileName = LocalDateTimeUtils.convert(LocalDateTime.now(),"yyyyMMddHHmmss") + ".doc"; String path = systemDir + basePath + "/临时专家"+ fileName; File outFile = new File(path); if (!outFile.getParentFile().exists()) { outFile.getParentFile().mkdirs(); } //写入模板 Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile))); template.process(dataMap, out); //导出并删除本地文件 out.close(); DownLoadFileUtil.downloadFile(response,path,fileName,true); //endregion
3、文件处理
第一步:先准备好一个模板,我使用的是比较复杂的模板,浪费了很多时间(建议各位大神制作一个简单的模板测试即可)
第二步:替换好了之后选择一个存储目录另存为 选择 WordXml 文档(*.xml) 这种格式进行存储
第三步:找到刚刚你存储的目录,以notepad++打开,刚才存储的.xml文件,*(最好格式化样式,不然很难找)删掉一些不必要的多余代码。
第四部,关于多行动态列表的处理
**最后:把改好的xml文档后缀修改成.ftl格式即可
吾乃代码搬运工,侵联删
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库