深圳网站的建设,wordpress 禁用自动保存,汕头网站设计价格,大馆陶网站最近在做word模板导出的需求#xff0c;本来意为是很简单#xff0c;做起来才发现细节上有很多东西处理起来还是比较麻烦的#xff08;客户要求太多#xff01;#xff01;#xff01;#xff09;
因此我把涉及到基于word模板导出的这部分整理了一下#xff0c;大家直…最近在做word模板导出的需求本来意为是很简单做起来才发现细节上有很多东西处理起来还是比较麻烦的客户要求太多
因此我把涉及到基于word模板导出的这部分整理了一下大家直接取经内容有点多分了三部分写文本段落、图表、表格。这三部分应该涵盖大部分应用场景了。
Poi实现根据word模板导出-图表篇
Poi实现根据word模板导出-表格篇
需要完整代码的直接看最后位置
前言
poi操作word原理同excel一样先获取word对象通过对象操作文件内容。poi实际上是将word解析成xml然后在读取里面的内容。
逻辑
1、获取word对象
// 获取docx解析对象
//获取word模板
InputStream is WordController.class.getResourceAsStream(/template/wordChartTemplate.docx);
XWPFDocument document new XWPFDocument(is);
2、修改word模板将需要封装的数据通过占位符代替 比如这里的${xxxx}就是占位符我们通过代码可以将这部分替换成我们需要的内容。注意格式是自己定义的并不是固定这种自己选择什么格式就按照对应格式处理下面给指出。
3、封装我们的业务数据根据你的具体业务填充数据Map中的key是我们占位符中的值value就是要展示在页面的值
// 替换word模板中占位符数据根据业务自行封装
MapString, String params new HashMap();
params.put(area1, 山东省);
params.put(area2, 河南省);
params.put(area3, 北京市);
params.put(area4, 天津市);
params.put(area5, 陕西省);
params.put(areaRate1, 42.15);
params.put(areaRate2, 22.35);
params.put(areaRate3, 42.35);
params.put(areaRate4, 23.11);
params.put(areaRate5, 15.34);
4、操作document文件对象先获取段落在获取段落中每段内容根据我们的占位符格式判断是否存在存在则更新我们占位符位置的内容。
private void changeText(XWPFDocument document, MapString, String params) {//获取段落集合ListXWPFParagraph paragraphs document.getParagraphs();for (XWPFParagraph paragraph : paragraphs) {//判断此段落时候需要进行替换String text paragraph.getText();if(checkText(text)){ListXWPFRun runs paragraph.getRuns();for (XWPFRun run : runs) {//替换模板原来位置String value changeValue(run.toString(), params);if (Objects.nonNull(value)) {run.setText(value, 0);}}}}
}/*** 匹配传入信息集合与模板* param value 模板需要替换的区域* param textMap 传入信息集合* return 模板需要替换区域信息集合对应值*/
public static String changeValue(String value, MapString, String textMap){SetMap.EntryString, String textSets textMap.entrySet();for (Map.EntryString, String textSet : textSets) {//匹配模板与替换值 格式${key}String key ${textSet.getKey()};if(value.indexOf(key)! -1){value value.replace(key, textSet.getValue());}}//模板未匹配到区域替换为空if(checkText(value)){value ;}return value;
}/*** 判断文本中时候包含$* param text 文本* return 包含返回true,不包含返回false*/
public static boolean checkText(String text){boolean check false;if(text.indexOf($)! -1){check true;}return check;
}
解释String key ${textSet.getKey()};这段代码就是我们自定义的占位符格式如果你是其他格式在这里做相应修改
ok完成
但是这时大部分情况可能会遇到下面问题 可以看到有的成功、有的失败。之前说过poi本质就是把word解析成xml那我们直接把word导出为xml看一下用office可以快速把word导出为xml格式这里我们把我们的模板导出为xml看下同样的占位符有啥不同 在idea里打开看一下发现即使我们占位符都是通过复制粘贴在word里他的xml格式还是会发生变化。 有两种解决方案 1、最简单的办法把模板里的占位符粘贴到文本在复制粘贴到word。 2、或者直接修改xml在把xml导出为word。可以在idea中看xml文件格式化一下这种方式只要没有把xml格式改错基本解析就不会再出问题了。 修改后再次执行程序 成功 完整代码
package com.javacoding.controller;import cn.hutool.core.util.RandomUtil;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.XWPFChart;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.openxmlformats.schemas.drawingml.x2006.chart.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.io.*;
import java.util.*;RestController
RequestMapping(/word)
public class WordController {RequestMapping(/export)public void exportWord() throws Exception {//获取word模板InputStream is WordController.class.getResourceAsStream(/template/wordChartTemplate.docx);try {ZipSecureFile.setMinInflateRatio(-1.0d);// 获取docx解析对象XWPFDocument document new XWPFDocument(is);// 解析替换文本段落对象// 替换word模板中占位符数据根据业务自行封装MapString, String params new HashMap();params.put(area1, 山东省);params.put(area2, 河南省);params.put(area3, 北京市);params.put(area4, 天津市);params.put(area5, 陕西省);params.put(areaRate1, 42.15);params.put(areaRate2, 22.35);params.put(areaRate3, 42.35);params.put(areaRate4, 23.11);params.put(areaRate5, 15.34);changeText(document, params);// 输出新文件FileOutputStream fos new FileOutputStream(D:\\test\\test.docx);document.write(fos);document.close();fos.close();} catch (Exception e) {e.printStackTrace();}}private void changeText(XWPFDocument document, MapString, String params) {//获取段落集合ListXWPFParagraph paragraphs document.getParagraphs();for (XWPFParagraph paragraph : paragraphs) {//判断此段落时候需要进行替换String text paragraph.getText();if(checkText(text)){ListXWPFRun runs paragraph.getRuns();for (XWPFRun run : runs) {//替换模板原来位置String value changeValue(run.toString(), params);if (Objects.nonNull(value)) {run.setText(value, 0);}}}}}/*** 判断文本中时候包含$* param text 文本* return 包含返回true,不包含返回false*/public static boolean checkText(String text){boolean check false;if(text.indexOf($)! -1){check true;}return check;}/*** 匹配传入信息集合与模板* param value 模板需要替换的区域* param textMap 传入信息集合* return 模板需要替换区域信息集合对应值*/public static String changeValue(String value, MapString, String textMap){SetMap.EntryString, String textSets textMap.entrySet();for (Map.EntryString, String textSet : textSets) {//匹配模板与替换值 格式${key}String key ${textSet.getKey()};if(value.indexOf(key)! -1){value value.replace(key, textSet.getValue());}}//模板未匹配到区域替换为空if(checkText(value)){value ;}return value;}}