package com.newfiber.utils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.xwpf.usermodel.*; import org.springframework.util.CollectionUtils; import java.io.*; import java.lang.reflect.Field; import java.util.*; /** * Word公共工具 * date: 2023/3/23 下午 07:09 * * @author: LuFan * @since JDK 1.8 */ public class WordUtil { private static Log log = LogFactory.getLog(WordUtil.class); /** * 装载模板所对应的对象 * * @param object * @return map */ public static Map<String, Object> setMapObject(Object object) { Map<String, Object> mapObject = new HashMap<String, Object>(); if (object != null) { Field[] fields = object.getClass().getDeclaredFields(); log.info("fields" + fields.length); for (Field field : fields) { try { field.setAccessible(true); String str = "${" + field.getName() + "}"; Object objValue = field.get(object); if (objValue != null) { log.info(str + "----" + objValue.toString()); mapObject.put(str, objValue); } else { mapObject.put(str, ""); } } catch (Exception e) { log.error("模板对象出现错误", e); } } } else { log.error("模板对象不是对应的一个类对象"); } return mapObject; } /** * 根据指定的参数值、模板,生成 word 文档 * * @param param 需要替换的变量 * @return XWPFDocument * @throws IOException * @throws InvalidFormatException */ public static XWPFDocument generateWord(Map<String, Object> param, InputStream is) throws IOException, InvalidFormatException { XWPFDocument xwpfDocument = null; try { xwpfDocument = new XWPFDocument(is); if (param.size() > 0) { //替换业务数据到模板段落对应位置 List<XWPFParagraph> paragraphList = xwpfDocument.getParagraphs(); processParagraphs(paragraphList, param); //替换业务数据到模板里面的固定表格对应数据 Iterator<XWPFTable> it = xwpfDocument.getTablesIterator(); while (it.hasNext()) { XWPFTable table = it.next(); List<XWPFTableRow> rows = table.getRows(); for (XWPFTableRow row : rows) { List<XWPFTableCell> cells = row.getTableCells(); for (XWPFTableCell cell : cells) { List<XWPFParagraph> paragraphListTable = cell.getParagraphs(); processParagraphs(paragraphListTable, param); } } } // 插入动态表格数据到模板里面 changeTable(xwpfDocument, param); } } catch (IOException e) { log.error("文件处理异常", e); throw (e); } catch (InvalidFormatException e) { log.error("文档中内容处理异常", e); throw (e); } return xwpfDocument; } /** * 处理段落 * * @param paragraphList * @param param * @throws InvalidFormatException * @throws FileNotFoundException */ public static void processParagraphs(List<XWPFParagraph> paragraphList, Map<String, Object> param) throws InvalidFormatException, FileNotFoundException { if (paragraphList != null && paragraphList.size() > 0) { for (XWPFParagraph paragraph : paragraphList) { List<XWPFRun> runs = paragraph.getRuns(); for (XWPFRun run : runs) { String text = run.getText(0); if (text != null) { boolean isSetText = false; for (Map.Entry<String, Object> entry : param.entrySet()) { String key = entry.getKey(); if (text.indexOf(key) != -1) { isSetText = true; Object value = entry.getValue(); if (value instanceof String) { //文本替换 log.info(key + "模板中需要转化的属性对应的值:" + value); text = text.replace(key, value.toString()); } else if (value instanceof List) { //图片替换 text = text.replace(key, ""); List picList = (List) value; insertPicture(run, picList); } } } if (isSetText) { run.setText(text, 0); } } } } } } /** * @param run * @param picList 图片数据 * @throws InvalidFormatException * @throws FileNotFoundException */ private static void insertPicture(XWPFRun run, List<Map> picList) { picList.forEach(pic -> { int width = Integer.parseInt(pic.get("width").toString()); int height = Integer.parseInt(pic.get("height").toString()); String imgPath = (String) pic.get("imgPath"); log.info("模板中模要转化的图片" + pic); InputStream inputStream = OfficeUtil.getFile(imgPath); int pictureType = getPictureType(imgPath); int EMU = 9525; width *= EMU; height *= EMU; try { run.addPicture(inputStream, pictureType, "", width, height); inputStream.close(); } catch (IOException e) { throw new RuntimeException(e); } catch (InvalidFormatException e) { throw new RuntimeException(e); } }); } /** * 根据图片类型,取得对应的图片类型代码 * * @param picType * @return int */ private static int getPictureType(String picType) { int res = XWPFDocument.PICTURE_TYPE_PICT; if (picType != null) { if (picType.equalsIgnoreCase("png")) { res = XWPFDocument.PICTURE_TYPE_PNG; } else if (picType.equalsIgnoreCase("dib")) { res = XWPFDocument.PICTURE_TYPE_DIB; } else if (picType.equalsIgnoreCase("emf")) { res = XWPFDocument.PICTURE_TYPE_EMF; } else if (picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")) { res = XWPFDocument.PICTURE_TYPE_JPEG; } else if (picType.equalsIgnoreCase("wmf")) { res = XWPFDocument.PICTURE_TYPE_WMF; } } return res; } /** * 替换表格对象方法 * * @param document docx解析对象 * @param wordData 需要插入的表格数据集合 */ public static void changeTable(XWPFDocument document, Map<String, Object> wordData) { List<List<String>> tableData = (List<List<String>>) wordData.get("${tableData}"); //获取表格对象集合 List<XWPFTable> tables = document.getTables(); tables.forEach(table -> { //判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入 //排除掉模板里面带 ${xxx}的表格,这样的表格用数据替换而不是插入新数据。 if (table.getText().indexOf("$") == -1) { //插入数据到模板的表格里面 if (!CollectionUtils.isEmpty(tableData)) { insertTable(table, tableData); } } }); } /** * 为表格插入数据,行数不够添加新行 * * @param table 需要插入数据的表格 * @param tableList 插入数据集合 */ public static void insertTable(XWPFTable table, List<List<String>> tableList) { //创建行,根据需要插入的数据添加新行,不处理表头 for (int i = 1; i < tableList.size(); i++) { table.createRow(); } //遍历表格插入数据 List<XWPFTableRow> rows = table.getRows(); for (int i = 1; i < rows.size(); i++) { XWPFTableRow newRow = table.getRow(i); List<XWPFTableCell> cells = newRow.getTableCells(); for (int j = 0; j < cells.size(); j++) { XWPFTableCell cell = cells.get(j); cell.setText(tableList.get(i - 1).get(j)); } } } }