使用Apache POI往word模板中插入数据并转换文档格式

发布时间 2023-10-13 13:36:23作者: 冲冲不会啊

word模板报告数据插入及格式转换

1. 向模板内写入数据

1.1 单文本插入

//通过查询得到数据用参数或者对象接收后,与模板内参数对应完成文本插入
String code = usersService.findByCode().getCode();
TestUsers byCode = usersService.findByCode();
Map<String, Object> data = new HashMap<>();
data.put("${barcode}", code);
data.put("${barcode}", byCode.getCode());

效果

image-20231012142506258

1.2 图片插入

1.2.1 根据文件路径插入

 Map<String, Object> picData = new HashMap<>();
        String inspection = "张三";
        String audit = "C:\\Users\\chongchong\\Desktop\\repositories\\img\\shenhe.jpg";
        String source = inspection + File.separator;
        String targer = audit + File.separator;
//判断字符串是否是文件路径,调用不同的文本插入方法,且与模板内设计参数对应
        if(source.matches("^[A-z]:\\\\(.+?\\\\)*$") && targer.matches("^[A-z]:\\\\(.+?\\\\)*$")){
            picData.put("${inspection}", source);
            picData.put("${audit}", targer);
        } else if (source.matches("^[A-z]:\\\\(.+?\\\\)*$")){
            picData.put("${inspection}",source);
            data.put("${audit}",targer.substring(0,targer.length() - 1));
        } else if (targer.matches("^[A-z]:\\\\(.+?\\\\)*$")){
            data.put("${inspection}",source.substring(0,source.length() - 1));
            picData.put("${audit}",targer);
        } else {
            data.put("${inspection}",source);
            data.put("${audit}",targer);
        }

效果

image-20231012142518124

1.2.2 根据网络链接插入

/**
    * @Author: chongchong
    * @Description: 通过获取网络链接图片存储到本地,然后选择插入数据
    * @DateTime: 2023/10/13 9:47
    * @Params: imageUrl:网络链接 localImagePath:本地存储地址
    * @Return void
    */
    public static void UrlImg(String imageUrl,String localImagePath) throws IOException {
        URL url = new URL(imageUrl);
        InputStream in = url.openStream();
        FileOutputStream out = new FileOutputStream(localImagePath);

        byte[] buffer = new byte[1024];
        int length;
        while ((length = in.read(buffer)) != -1) {
            out.write(buffer, 0, length);
        }
        in.close();
        out.close();
    }

效果

image-20231013095501759

1.3 批量文本插入

//通过选中的itemId查询对应的数据 
List<TestItemsDetail> byItemId = itemsDetailService.getByItemId(Long.valueOf(29));
//遍历获取的对象数据,然后向表格内插入数据,此处知23条数据,剔除单独数据插入,具体使用时可以先判断再插入
for (int i = 0; i < byItemId.size() / 2; i++) {
                arrearsList.add(Arrays.asList(byItemId.get(i).getName(),byItemId.get(i).getRefRangeStart(),
                        byItemId.get(byItemId.size() - i - 1).getName(),byItemId.get(byItemId.size() - i -1).getRefRangeStart()));
            }
            arrearsList.add(Arrays.asList(byItemId.get(byItemId.size()/2).getName(),byItemId.get(byItemId.size()/2).getRefRangeStart()));

效果

image-20231012142430656

1.4 写入新的模板

/**
调用创建新报告方法,往其中插入对应的文本、图片等数据,
modelWord:模板word所在路径;
replaceWord:插入数据生成路径;
data:单文本;
picData:图片;
1:默认为1,代表的是批量插入文本所在的第几个表格(从0开始),此处批量插入数据的表格是第二个表格;
arrearsList:批量插入文本;
**/
ReplaceWord.operateWord(modelWord,replaceWord,data, picData,1,arrearsList);

2.根据文件路径转换格式

2.1 转换格式

调用AsposeUtil方法wordToPdf方法进行格式转换

getLicense方法是将格式转换的水印不生成

/**
wordPath:需要转换格式的文件路径("C:\\Users\\chongchong\\Desktop\\repositories\\word\\23分型报告单模板1.docx")
pdfPath:转换格式后的路径("C:\\Users\\chongchong\\Desktop\\repositories\\23分型报告单.pdf")
**/
AsposeUtil.wordToPdf(wordPath,pdfPath);

效果

image-20231012144445138

3.代码

向模板内写入数据方法

import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;

import java.io.*;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @Author: chongchong
 * @DateTime: 2023/10/11 17:10
 * @Description: word模板数据填充
 */
public class ReplaceWordService {

    /**
    * @Author: chongchong
    * @Description: 替换段落文本
    * @DateTime: 2023/10/11 17:11
    * @Params: document docx解析对象 textMap  需要替换的信息集合
    * @Return void
    */
    public static void changeText(XWPFDocument document, Map<String, Object> textMap) {
        // 获取段落集合
        Iterator<XWPFParagraph> iterator = document.getParagraphsIterator();
        XWPFParagraph paragraph = null;
        while (iterator.hasNext()) {
            paragraph = iterator.next();
            // 判断此段落是否需要替换
            if (checkText(paragraph.getText())) {
                replaceValue(paragraph, textMap);
            }
        }
    }

    /**
    * @Author: chongchong
    * @Description: 检查文本中是否包含指定的字符(此处为“$”)
    * @DateTime: 2023/10/11 17:12
    * @Params: text
    * @Return boolean
    */
    public static boolean checkText(String text) {
        boolean check = false;
        if (text.contains("$")) {
            check = true;
        }
        return check;
    }

    /**
    * @Author: chongchong
    * @Description: 替换图片
    * @DateTime: 2023/10/11 17:12
    * @Params: document picData
    * @throws: Exception
    * @Return 
    */
    public static void changePic(XWPFDocument document, Map<String, Object> picData) throws Exception {
        // 获取段落集合
        Iterator<XWPFParagraph> iterator = document.getParagraphsIterator();
        XWPFParagraph paragraph;
        while (iterator.hasNext()) {
            paragraph = iterator.next();
            // 判断此段落是否需要替换
            String text = paragraph.getText();
            if (checkText(text)) {
                replacePicValue(paragraph, picData);
            }
        }
    }

    /**
    * @Author: chongchong
    * @Description: 替换表格内的文字
    * @DateTime: 2023/10/11 17:14
    * @Params: document data
    * @Return void
    */
    public static void changeTableText(XWPFDocument document, Map<String, Object> data) {
        // 获取文件的表格
        Iterator<XWPFTable> tableList = document.getTablesIterator();
        XWPFTable table;
        List<XWPFTableRow> rows;
        List<XWPFTableCell> cells;
        // 循环所有需要进行替换的文本,进行替换
        while (tableList.hasNext()) {
            table = tableList.next();
            if (checkText(table.getText())) {
                rows = table.getRows();
                // 遍历表格,并替换模板
                for (XWPFTableRow row : rows) {
                    cells = row.getTableCells();
                    for (XWPFTableCell cell : cells) {
                        // 判断单元格是否需要替换
                        if (checkText(cell.getText())) {
                            List<XWPFParagraph> paragraphs = cell.getParagraphs();
                            for (XWPFParagraph paragraph : paragraphs) {
                                replaceValue(paragraph, data);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
    * @Author: chongchong
    * @Description: 替换表格内图片
    * @DateTime: 2023/10/11 17:14
    * @Params: document picData
    * @Return void
    */
    public static void changeTablePic(XWPFDocument document, Map<String, Object> picData) throws Exception {
        // 获取文件的表格
        Iterator<XWPFTable> tableList = document.getTablesIterator();
        XWPFTable table;
        List<XWPFTableRow> rows;
        List<XWPFTableCell> cells;
        // 循环所有需要进行替换的文本,进行替换
        while (tableList.hasNext()) {
            table = tableList.next();
            if (checkText(table.getText())) {
                rows = table.getRows();
                // 遍历表格,并替换模板
                for (XWPFTableRow row : rows) {
                    cells = row.getTableCells();
                    for (XWPFTableCell cell : cells) {
                        // 判断单元格是否需要替换
                        if (checkText(cell.getText())) {
                            List<XWPFParagraph> paragraphs = cell.getParagraphs();
                            for (XWPFParagraph paragraph : paragraphs) {
                                replacePicValue(paragraph, picData);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
    * @Author: chongchong
    * @Description: 替换内容
    * @DateTime: 2023/10/11 17:15
    * @Params: paragraph textMap
    * @Return void
    */
    public static void replaceValue(XWPFParagraph paragraph, Map<String, Object> textMap) {
        XWPFRun run, nextRun;
        String runsText;
        List<XWPFRun> runs = paragraph.getRuns();
        for (int i = 0; i < runs.size(); i++) {
            run = runs.get(i);
            runsText = run.getText(0);
            if (runsText.contains("${") || (runsText.contains("$") && runs.get(i + 1).getText(0).substring(0, 1).equals("{"))) {
                while (!runsText.contains("}")) {
                    nextRun = runs.get(i + 1);
                    runsText = runsText + nextRun.getText(0);
                    //删除该节点下的数据
                    paragraph.removeRun(i + 1);
                }
                Object value = changeValue(runsText, textMap);
                //判断key在Map中是否存在
                if (textMap.containsKey(runsText)) {
                    run.setText(value.toString(), 0);
                } else {
                    //如果匹配不到,则不修改
                    run.setText(runsText, 0);
                }
            }
        }
    }

    /**
    * @Author: chongchong
    * @Description: 替换图片内容
    * @DateTime: 2023/10/11 17:15
    * @Params: paragraph picData
    * @Return void
    */
    public static void replacePicValue(XWPFParagraph paragraph, Map<String, Object> picData) throws Exception {
        List<XWPFRun> runs = paragraph.getRuns();
        for (XWPFRun run : runs) {
            Object value = changeValue(run.toString(), picData);
            if (picData.containsKey(run.toString())) {
                //清空内容
                run.setText("", 0);
                FileInputStream is = new FileInputStream((String) value);
                //规定图片宽度、高度
                int width = Units.toEMU(30), height = Units.toEMU(30);
                //添加图片信息,段落高度需要在模板中自行调整
                run.addPicture(is, XWPFDocument.PICTURE_TYPE_PNG, (String) value, width, height);
            }
        }
    }

    /**
    * @Author: chongchong
    * @Description: 匹配参数
    * @DateTime: 2023/10/11 17:16
    * @Params: value textMap
    * @Return java.lang.Object
    */
    public static Object changeValue(String value, Map<String, Object> textMap) {
        Object valu = "";
        for (Map.Entry<String, Object> textSet : textMap.entrySet()) {
            // 匹配模板与替换值 格式${key}
            String key = textSet.getKey();
            if (value.contains(key)) {
                valu = textSet.getValue();
            }
        }
        return valu;
    }

    /**
    * @Author: chongchong
    * @Description: 批量替换表格内容
    * @DateTime: 2023/10/11 17:16
    * @Params: index(表格索引:第几个表格) tableList(批量增加的数据源)
    * @Return void
    */
    public static void replaceTable(XWPFDocument document,int index, List<List<String>> tableList) {
        XWPFTable table = document.getTables().get(index);
        //创建行,根据需要插入的数据添加新行,不处理表头
        /*for (int i = 1; i <= tableList.size(); i++) {
            table.createRow();
        }*/
        //遍历表格插入数据
        List<XWPFTableRow> rows = table.getRows();
        for (int i = 1; i < tableList.size()+1; i++) {
            XWPFTableRow newRow = table.getRow(i);
            List<XWPFTableCell> cells = newRow.getTableCells();
            List<String> rowData = tableList.get(i - 1);
            for (int j = 0; j < rowData.size(); j++) {
                XWPFTableCell cell = cells.get(j);
                String text = rowData.get(j);
                cell.setText(text);
                if (text.equals("阳性")){
                    cell.setColor("ff0000");
                }
                //表格样式一致-->没有此段表格会默认左对齐
                //有此段会使表格格式一致
                /*CTTc cttc = cell.getCTTc();
                CTTcPr ctPr = cttc.addNewTcPr();
                ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);
                cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);*/
            }
        }
    }

    /**
    * @Author: chongchong
    * @Description: 根据模板所需替换的形式调用不同的方法向模板中添加信息,然后导出写入数据的新的文档
    * @DateTime: 2023/10/11 17:18
    * @Params: data(表格内单文本插入) picData(表格内图片) index(默认:1,即批量插入文本数据的表格) tableList(批量插入文本数据集)
    * @Return void
    */
    public static void operateWord(String modelWord,String replaceWord,Map<String, Object> data,
                                   Map<String, Object> picData,
                                   int index,List<List<String>> tableList){
        try {
            //读取模板word的文件路径
            FileInputStream is = new FileInputStream(modelWord);
            XWPFDocument document = new XWPFDocument(is);
            if (data.size() > 0) {
                // 替换掉表格之外的文本(仅限文本)
                ReplaceWordService.changeText(document, data);
                // 替换表格内的文本对象
                ReplaceWordService.changeTableText(document, data);
            }
            if (picData.size() > 0) {
                // 替换内容图片
                ReplaceWordService.changePic(document, picData);
                // 替换表格内的图片对象
                ReplaceWordService.changeTablePic(document, picData);
            }
            if (tableList.size() > 0) {
                //往表格中批量插入文本
                ReplaceWordService.replaceTable(document,index,tableList);
            }
            //写入数据后的模板存储文件路径
            FileOutputStream out = new FileOutputStream(replaceWord);
            document.write(out);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @Author: chongchong
     * @Description: 通过获取网络链接图片存储到本地,然后选择插入数据
     * @DateTime: 2023/10/13 9:47
     * @Params: imageUrl:网络链接 localImagePath:本地存储地址
     * @Return void
     */
    public static void UrlImg(String imageUrl,String localImagePath) throws IOException {
        URL url = new URL(imageUrl);
        InputStream in = url.openStream();
        FileOutputStream out = new FileOutputStream(localImagePath);

        byte[] buffer = new byte[1024];
        int length;
        while ((length = in.read(buffer)) != -1) {
            out.write(buffer, 0, length);
        }
        in.close();
        out.close();
    }

}

word文档格式转换pdf方法参考上一篇文章word转pdf:https://www.cnblogs.com/chongchongstyle/p/17761878.html