Newer
Older
newfiber-termite / newfiber-common / newfiber-common-office / src / main / java / com / newfiber / utils / WordUtil.java
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));
            }
        }
    }
}