java导出占位符word模板

发布时间 2023-10-16 13:35:57作者: HeavenTang

实际项目中,便于维护模板,采用直接 word里面制作占位符 来导出更为直观,而不是 将word做成tpl模板。

使用XWPFDocument (这种解析xlsx或者docx)和 HWPFDocument(这种解析xls或者doc)。 代码如下:

写磁盘代码: 点击查看代码
// 创建Word模板文件:在开始代码编写之前,我们需要准备一个Word模板文件,模板文件中的文本可以是固定的,也可以使用占位符来表示需要动态填充的内容
        //读取Word模板文件
        // 我们需要使用Apache POI库来读取Word模板文件,并将其加载到内存中进行后续的操作。代码如下
        FileInputStream fis = null;
        try {
            File sPath = new File("D:/opt/jwxt/file/uploadfile/ly-edu-core-svc-thx/testWord.docx");
//            File sPath = new File("/template/testword.doc");
            fis = new FileInputStream(sPath);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
//        HWPFDocument 支持doc  XWPFDocument支持docx
 
        XWPFDocument document = null;
        FileOutputStream fos = null;
        try {
            document = new XWPFDocument(fis);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }

        // 替换模板中的占位符
        //在模板文件中,我们可以使用占位符来表示需要动态填充的内容,比如使用${placeholder}来表示占位符。我们需要遍历Word文档的所有段落和表格,找到包含占位符的位置,并将其替换为实际的内容。代码如下

        List<XWPFParagraph> paragraphs = document.getParagraphs();
        for (XWPFParagraph paragraph : paragraphs) {
            List<XWPFRun> runs = paragraph.getRuns();
            for (XWPFRun run : runs) {
                String text = run.getText(0);
                if (text != null && text.contains("${{成果名称}}")) {
                    text = text.replace("${{成果名称}}", "替换后的内容");
                    run.setText(text, 0);
                }
            }
        }

        // 表格处理方式
        List<XWPFTable> tables = document.getTables();
        for (XWPFTable table : tables) {
            List<XWPFTableRow> rows = table.getRows();
            for (XWPFTableRow row : rows) {
                List<XWPFTableCell> cells = row.getTableCells();
                for (XWPFTableCell cell : cells) {
                    List<XWPFParagraph> cellParagraphs = cell.getParagraphs();
                    for (XWPFParagraph cellParagraph : cellParagraphs) {
                        List<XWPFRun> runs = cellParagraph.getRuns();
                        for (XWPFRun run : runs) {
                            String text = run.getText(0);
                            if (text != null && text.contains("${{完成人姓名1}}")) {
                                text = text.replace("${{完成人姓名1}}", "替换后的内容");
                                run.setText(text, 0);
                            }
                            if (text != null && text.contains("${{成果名称}}")) {
                                text = text.replace("${{成果名称}}", "替换后的内容2222");
                                run.setText(text, 0);
                            }
                        }
                    }
                }
            }
        }

        // 导出word文档
            File outFile = new File("D:\\opt\\jwxt\\file\\uploadfile\\ly-edu-core-svc-thx\\占位符完成打印.docx");
        fos = new FileOutputStream(outFile);

    } catch (Exception e) {
        log.error( "获取word文档失败,原因是:"   + e.getMessage());
    } finally {
        try {
            document.write(fos);
            if(fos != null) {
                fos.close();
            }
//            document.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

与前端配合弹出流,使用response,代码如下

点击查看代码
/**
     * 我们可以实现Java Word模板打印的功能。首先,我们需要引入Apache POI库,并创建一个Word模板文件。然后,我们需要读取模板文件并将其加载到内存中。
     * 接下来,我们需要遍历Word文档,找到包含占位符的位置,并将其替换为实际的内容。最后,我们可以将生成的Word文档导出为文件。
     * <p>
     * 在实际应用中,我们可以根据具体需求扩展这个功能,比如支持更复杂的模板替换、添加图片和表格等。同时,我们也可以使用其他的库来实现类似的功能,比如Docx4j等
     *
     * 
     */

    @Autowired
    private HttpServletResponse response;

    @Autowired
    private HttpServletRequest request;

    @Override
    public void testWordPrint(ReviewTemplateDto reviewTemplateDto) { 


        // 创建Word模板文件:在开始代码编写之前,我们需要准备一个Word模板文件,模板文件中的文本可以是固定的,也可以使用占位符来表示需要动态填充的内容
        //读取Word模板文件
        // 我们需要使用Apache POI库来读取Word模板文件,并将其加载到内存中进行后续的操作。代码如下
        FileInputStream fis = null;
        try {
            File sPath = new File("D:/opt/jwxt/file/uploadfile/tt/模板.docx");
//            File sPath = new File("/template/testword.doc");
            fis = new FileInputStream(sPath);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
//        HWPFDocument 支持doc  XWPFDocument支持docx
        XWPFDocument document = null;
        FileOutputStream fos = null;
        try {
            document = new XWPFDocument(fis); 

            // 替换模板中的占位符
            //在模板文件中,我们可以使用占位符来表示需要动态填充的内容,比如使用${placeholder}来表示占位符。我们需要遍历Word文档的所有段落和表格,找到包含占位符的位置,并将其替换为实际的内容。代码如下

            List<XWPFParagraph> paragraphs = document.getParagraphs();
            for (XWPFParagraph paragraph : paragraphs) {
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
                    String text = run.getText(0);
                    if (text != null && text.contains("${{成果名称}}")) {
                        text = text.replace("${{成果名称}}", "替换后的内容");
                        run.setText(text, 0);
                    }
                }
            }

            // 表格处理方式
            List<XWPFTable> tables = document.getTables();
            for (XWPFTable table : tables) {
                List<XWPFTableRow> rows = table.getRows();
                for (XWPFTableRow row : rows) {
                    List<XWPFTableCell> cells = row.getTableCells();
                    for (XWPFTableCell cell : cells) {
                        List<XWPFParagraph> cellParagraphs = cell.getParagraphs();
                        for (XWPFParagraph cellParagraph : cellParagraphs) {
                            List<XWPFRun> runs = cellParagraph.getRuns();
                            for (XWPFRun run : runs) {
                                String text = run.getText(0);
                                if (text != null && text.contains("${{完成人姓名1}}")) {
                                    text = text.replace("${{完成人姓名1}}", "替换后的内容");
                                    run.setText(text, 0);
                                }
                                if (text != null && text.contains("${{成果名称}}")) {
                                    text = text.replace("${{成果名称}}", "替换后的内容2222");
                                    run.setText(text, 0);
                                }
                            }
                        }
                    }
                }
            }

            // 导出word文档
//            File outFile = new File("D:\\opt\\jwxt\\file\\uploadfile\\tt\\tt.docx");// 直接写磁盘
//            fos = new FileOutputStream(outFile);
//
////            document.write(fos);//
            String filePath = request.getSession().getServletContext().getRealPath("/");
            String fileName = "tt.docx";
//            response.setHeader("Content-Disposition", "attachment;fileName=" + stringToUnicode(fileName));
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.setContentType("multipart/form-data");

            OutputStream outputStream = null;
            try {
                outputStream = response.getOutputStream();
            } catch (IOException e) {
                e.printStackTrace();
            }
            document.write(outputStream);

        } catch (Exception e) {
            log.error("获取word文档失败,原因是:" + e.getMessage());
        } finally {
            try {

                if (fos != null) {
                    fos.close();
                } 
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
前端
点击查看代码

// 导出占位符word
export function exportZwfWord (url,params,id,callback){
    exportDataExcel(url,params,{
        header:{ },responseType:"blob"
    }).then(response=>{

        if (response.status==200){
            let fileName = response.headers["content-disposition"].split(";")[1].split("filename=")[1];
            const aLink = document.createElement("a");
            document.body.appendChild(aLink);
            aLink.style.display = "none";
            const objectUrl = window.URL.createObjectURL(new Blob([response.data], { type: 'application/docx; charset=utf-8' }));
            aLink.href = objectUrl;
            aLink.download = decodeURI(fileName);
            aLink.click();
            document.body.removeChild(aLink);
            message.success('导出成功')
            callback(response.data);
            return;
        }else{
            if (response.message) {
                message.error(response.message);
            } else {
                message.error("没有数据");
            }
            callback();
        }
    })
}

遇到问题:
1。Java使用POI技术导出Word文档,报错Package should contain a content type part [M1.13]
解决方案:
因为XWPFDocument只支持docx,所以需要将doc文件另存为 docx. 切记不能直接改后缀,否则不生效的。
image
2。问题2:response的Content-Disposition写文件名要与前端对应,否则,导出undefined.

效果:
image

image