java 解析word模板(2024-01-25)

本文主要功能是解析word模板

       这是一个word解析类,因为我做的系统用到了而且没有可用的帮助类,只能自己写。之前的实现方式是freemarker 模板解析。但是这次要求用poi不在使用freemarker。实现功能比较少,主要是满足开发需求即可,没有实现其它功能。实现功能如下:

1、word内文本内容解析

2、word内表格内容解析

3、word内图片内容解析

4、word脚注内容解析

     功能实现的比较匆忙没有好好设计,如果可以将图标,图片,脚注等设置为实体类,便于配置管理。

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Base64;
import java.util.List;
import java.util.Properties;

import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFFootnote;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFPicture;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.drawingml.x2006.main.STSchemeColorVal;
import org.springframework.util.PropertyPlaceholderHelper;

import com.alibaba.cloud.commons.lang.StringUtils;

/**
 * 通过word模板生成新的word工具类
 **
 */
public class WordUtil {
    public static final PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${", "}");

    /**
     * 根据模板生成新word文档 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
     * 
     * @param textMap 需要替换的信息集合
     * @return 成功返回true,失败返回false
     */
    public static void changWord(InputStream inputStream, Properties properties, int height, int width) {

        // InputStream in = null;
        try {
            // 获取docx解析对象
            XWPFDocument document = new XWPFDocument(inputStream);
            // 解析替换文本段落对象
            WordUtil.changeText(document, properties);
            // 解析替换表格对象
            WordUtil.changeTable(document, properties);
            // 替换文本中的图片
            WordUtil.changePicture(document, properties, height, width);
            // 脚注/尾注解析 footnote
            WordUtil.changeFootNote(document, properties);

            File file = new File("I://实体文件.docx");
            FileOutputStream stream = new FileOutputStream(file);
            document.write(stream);
            stream.close();
            document.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 尾注解析
     * 
     * @param document
     * @param properties
     */
    public static void changeFootNote(XWPFDocument document, Properties properties) {
        List footNoteList = document.getFootnotes();
        for (XWPFFootnote footnote : footNoteList) {
            List paragraphs = footnote.getParagraphs();
            for (XWPFParagraph paragraph : paragraphs) {
                String text = paragraph.getText();
                if (checkText(text)) {
                    List runs = paragraph.getRuns();
                    String key = keyParam(runs);
                    for (XWPFRun run : runs) {
                        run.setText("", 0);
                    }
                    // 替换模板原来位置
                    String value = changeValue(key, properties);
                    // 字符串中有可能是图片转换的字符串
                    if (StringUtils.isNotEmpty(value)) {
                        runs.get(0).setText(value, 0);
                    }

                }
            }
        }
    }

    /***
     * 指定替换模板中的图片
     * 
     * @param document
     * @param filePath
     * @param height
     * @param width
     */
    public static void changePicture(XWPFDocument document, Properties properties, Integer height, Integer width) {

        // 获取段落集合
        List paragraphs = document.getParagraphs();
        for (XWPFParagraph paragraph : paragraphs) {
            // 判断此段落时候需要进行替换
            String text = paragraph.getText();
            if (checkText(text)) {
                List runs = paragraph.getRuns();
                String key = keyParam(runs);
                for (XWPFRun run : runs) {
                    // 字符串中有可能是图片转换的字符串
                    String value = changeValue(key, properties);
                    if (value.startsWith("data:image")) {
                        byte[] imageBytes = Base64.getDecoder().decode(value.split(",")[1]); // 获取Base64编码后的图像数据部分

                        try(ByteArrayInputStream in = new ByteArrayInputStream(imageBytes); ){// 创建ByteArrayInputStream对象
                        // 添加图片
                        XWPFPicture xwpfPicture = run.addPicture(in, XWPFDocument.PICTURE_TYPE_JPEG, "图片1.jpg",
                                Units.toEMU(width), Units.toEMU(height));
                        // 为图片添加边框
                        xwpfPicture.getCTPicture().getSpPr().addNewLn().addNewSolidFill().addNewSchemeClr()
                                .setVal(STSchemeColorVal.Enum.forString("tx1"));
                        }catch(Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    public static String keyParam(List runs) {
        if (runs.isEmpty()) {
            return "";
        }
        StringBuffer st = new StringBuffer();
        // 转换为一个字符串 [${E_002, 1, }${E_002, 2, }${E_002, 3, }]
        for (XWPFRun run : runs) {
            st.append(run.text());
        }
        return st.toString().replace(",", "");
    }

    /**
     * 替换段落文本
     * 
     * @param document docx解析对象
     * @param textMap  需要替换的信息集合
     */
    public static void changeText(XWPFDocument document, Properties properties) {
        // 获取段落集合
        List paragraphs = document.getParagraphs();
        for (XWPFParagraph paragraph : paragraphs) {
            // 判断此段落时候需要进行替换
            String text = paragraph.getText();
            if (checkText(text)) {
                List runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
                    // 替换模板原来位置
                    String value = changeValue(run.toString(), properties);
                    // 字符串中有可能是图片转换的字符串
                    if (StringUtils.isNotEmpty(value) && !value.startsWith("data:image")) {
                        run.setText(value, 0);
                    }
                }
            }
        }

    }

    /**
     * 替换表格对象方法
     * 
     * @param document docx解析对象
     * @param textMap  需要替换的信息集合
     */
    public static void changeTable(XWPFDocument document, Properties properties) {
        // 获取表格对象集合
        List tables = document.getTables();
        for (int i = 0; i < tables.size(); i++) {
            // 只处理行数大于等于2的表格,且不循环表头
            XWPFTable table = tables.get(i);
            if (table.getRows().size() > 1) {
                // 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
                if (checkText(table.getText())) {
                    List rows = table.getRows();
                    // 遍历表格,并替换模板
                    eachTable(rows, properties);
                }
            }
        }
    }

    /**
     * 遍历表格
     * 
     * @param rows    表格行对象
     * @param textMap 需要替换的信息集合
     */
    public static void eachTable(List rows, Properties properties) {
        for (XWPFTableRow row : rows) {
            List cells = row.getTableCells();
            for (XWPFTableCell cell : cells) {
                // 判断单元格是否需要替换
                if (checkText(cell.getText())) {
                    // 基本一个单元格,都是size=1,如果预防意外,可以增加判断,或者添加循环
                    List paragraphs = cell.getParagraphs();
                    // System.out.println(String.format("text:%s,paragraphs:%d",cell.getText(),
                    // paragraphs.size()));
                    // for (XWPFParagraph paragraph : paragraphs) {
                    // List runs = paragraph.getRuns();
                    // 替换模板原来位置
                    XWPRunValue(paragraphs.get(0).getRuns(), properties);
                    // }
                }
            }
        }
    }

    /**
     * 这个方法是一次处理一个单元格,一个单元格内,被解析成了 XWPFRun, 只给第一个 XWPFRun赋值即可,其它都赋值""
     * 
     * @param runs
     * @param textMap
     */
    public static void XWPRunValue(List runs, Properties properties) {
        if (runs.size() == 1) {
            runs.get(0).setText(changeValue(runs.get(0).toString(), properties), 0);
            return;
        }
        StringBuffer st = new StringBuffer();
        // 转换为一个字符串 [${E_002, 1, }${E_002, 2, }${E_002, 3, }]
        for (XWPFRun run : runs) {
            //
            st.append(run.text());
            run.setText("", 0);
        }
        String value = st.toString().replace(",", "");
        value = changeValue(value, properties);
        // 一次性替换全部的值
        runs.get(0).setText(value, 0);
    }

    /**
     * 判断文本中时候包含$
     * 
     * @param text 文本
     * @return 包含返回true,不包含返回false
     */
    public static boolean checkText(String text) {
        return (text.indexOf("$") != -1);
    }

    /**
     * 匹配传入信息集合与模板
     * 
     * @param value   模板需要替换的区域
     * @param textMap 传入信息集合
     * @return 模板需要替换区域信息集合对应值
     */
    public static String changeValue(String value, Properties properties) {
        if (!checkText(value)) {
            return value;
        }
        return helper.replacePlaceholders(value, properties);
    }


    public static void main(String[] args) throws Exception {
        // 从FTP读取文件模板
        InputStream is = new FileInputStream(new File("I://模板文件.docx"));

        // 填充文本和表格需要替换的数据
        Properties properties = new Properties();
        properties.put("E_0001", "2000年01月01日");
        properties.put("E_0002", "第一行");
        properties.put("E_0003", "脚注解析异常");
        // 图片字符串
        properties.put("P01", "data:image/jpg;base64,"+"图片转换的字符串") ;
        WordUtil.changWord(is, properties, 140, 400);

    }

}
 

你可能感兴趣的:(java,java,开发语言)