使用word模板生成新的PDF文件

摘要

本文通过使用word模板文件,替换文件中的参数,转化为PDF文件放入response流实现PDF下载。话不多说,进入正题

导入依赖

<dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-scratchpad</artifactId>
            <version>4.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>4.1.2</version>
        </dependency>
        <dependency>
            <groupId>fr.opensagres.xdocreport</groupId>
            <artifactId>xdocreport</artifactId>
            <version>1.0.6</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>ooxml-schemas</artifactId>
            <version>1.3</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf.tool</groupId>
            <artifactId>xmlworker</artifactId>
            <version>5.5.11</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.10</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.11.3</version>
        </dependency>

工具类

package com.solvay.utils.file;

import com.alibaba.nacos.common.http.HttpUtils;
import com.itextpdf.text.Document;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.ContentType;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.converter.PicturesManager;
import org.apache.poi.hwpf.converter.WordToHtmlConverter;
import org.apache.poi.hwpf.usermodel.PictureType;
import org.apache.poi.ooxml.POIXMLDocument;
import org.apache.poi.xwpf.usermodel.*;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Entities;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @author syb
 * @date 2022/9/24
 */
public class OfficeToPdfUtil {
    private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);

    /**
     * html转为pdf
     * @param html
     * @return
     */
    public static byte[] htmlToPdf(String html) {
        com.itextpdf.text.Document document = null;
        ByteArrayInputStream bais = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] resBytes = null;
        try {
            document = new com.itextpdf.text.Document(PageSize.A4);
            PdfWriter writer = PdfWriter.getInstance(document, baos);
            document.open();
            bais = new ByteArrayInputStream(html.getBytes());
            XMLWorkerHelper.getInstance().parseXHtml(writer, document, bais, Charset.forName("UTF-8"), new FontProvider() {
                @Override
                public boolean isRegistered(String s) {
                    return false;
                }
                @Override
                public Font getFont(String s, String s1, boolean embedded, float size, int style, BaseColor baseColor) {
                    // 配置字体
                    Font font = null;
                    try {
                        BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
                        font = new Font(bf, size, style, baseColor);
                        font.setColor(baseColor);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return font;
                }
            });
            document.close();
            writer.close();
            resBytes = baos.toByteArray();
        } catch (Exception e) {
            log.error("html转pdf异常:{}",e);
        } finally {
            if (document != null) {
                document.close();
            }
            if (bais != null) {
                try {
                    bais.close();
                } catch (IOException e) {
                    log.error("html转pdf关闭io流异常:{}",e);
                }
            }
        }
        return resBytes;
    }

    /**
     * doc文件转为html
     * @param inputStream
     * @return
     * */
    public static String doc2Html(InputStream inputStream) {
        String content = null;
        ByteArrayOutputStream baos = null;
        try {
            HWPFDocument wordDocument = new HWPFDocument(inputStream);
            WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument());
            wordToHtmlConverter.setPicturesManager(new PicturesManager() {
                @Override
                public String savePicture(byte[] content, PictureType pictureType, String suggestedName, float widthInches, float heightInches) {
                    return null;
                }
            });
            wordToHtmlConverter.processDocument(wordDocument);
            org.w3c.dom.Document htmlDocument = wordToHtmlConverter.getDocument();
            DOMSource domSource = new DOMSource(htmlDocument);
            baos = new ByteArrayOutputStream();
            StreamResult streamResult = new StreamResult(baos);
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer serializer = tf.newTransformer();
            serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
            serializer.setOutputProperty(OutputKeys.INDENT, "yes");
            serializer.setOutputProperty(OutputKeys.METHOD, "html");
            serializer.transform(domSource, streamResult);
        } catch (Exception e) {
            log.error("doc转html异常:{}",e);
        } finally {
            try {
                if (baos != null) {
                    content = new String(baos.toByteArray(), "utf-8");
                    baos.close();
                }
            } catch (Exception e) {
                log.error("doc转html关闭io流异常:{}",e);
            }
        }
        return content;
    }
    /**
     * 使用jsoup规范化html
     * @param html html内容
     * @return 规范化后的html
     */
    public static String formatHtml(String html) {
        org.jsoup.nodes.Document doc = Jsoup.parse(html);
        // 去除过大的宽度
        String style = doc.attr("style");
        if (StringUtils.isNotEmpty(style) && style.contains("width")) {
            doc.attr("style", "");
        }
        Elements divs = doc.select("div");
        for (org.jsoup.nodes.Element div : divs) {
            String divStyle = div.attr("style");
            if (StringUtils.isNotEmpty(divStyle) && divStyle.contains("width")) {
                div.attr("style", "");
            }
        }
        // jsoup生成闭合标签
        doc.outputSettings().syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml);
        doc.outputSettings().escapeMode(Entities.EscapeMode.xhtml);
        return doc.html();
    }

    //docx转PDF
    public static byte[] docxToPdf(InputStream src) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] resBytes = null;
        String result;
        try {
            // pdf文件的尺寸
            Document pdfDocument = new Document(PageSize.A3, 72, 72, 72, 72);
            PdfWriter pdfWriter = PdfWriter.getInstance(pdfDocument, baos);
            XWPFDocument doc = new XWPFDocument(src);
            pdfWriter.setInitialLeading(20);
            java.util.List<XWPFParagraph> plist = doc.getParagraphs();
            pdfWriter.open();
            pdfDocument.open();
            for (int i = 0; i < plist.size(); i++) {
                XWPFParagraph pa = plist.get(i);
                java.util.List<XWPFRun> runs = pa.getRuns();
                for (int j = 0; j < runs.size(); j++) {
                    XWPFRun run = runs.get(j);
                    java.util.List<XWPFPicture> piclist = run.getEmbeddedPictures();
                    Iterator<XWPFPicture> iterator = piclist.iterator();
                    while (iterator.hasNext()) {
                        XWPFPicture pic = iterator.next();
                        XWPFPictureData picdata = pic.getPictureData();
                        byte[] bytepic = picdata.getData();
                        Image imag = Image.getInstance(bytepic);
                        pdfDocument.add(imag);
                    }
                    // 中文字体的解决
                    BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
                    Font font = new Font(bf, 11.0f, Font.NORMAL, BaseColor.BLACK);
                    String text = run.getText(-1);
                    byte[] bs;
                    if (text != null) {
                        bs = text.getBytes();
                        String str = new String(bs);
                        Chunk chObj1 = new Chunk(str, font);
                        pdfDocument.add(chObj1);
                    }
                }
                pdfDocument.add(new Chunk(Chunk.NEWLINE));
            }
            //需要关闭,不然无法获取到输出流
            pdfDocument.close();
            pdfWriter.close();
            resBytes = baos.toByteArray();
        } catch (Exception e) {
            log.error("docx转pdf文件异常:{}",e);
        }finally {
            try{
                if(baos != null){
                    baos.close();
                }
            }catch (IOException e){
                log.error("docx转pdf关闭io流异常:{}",e);
            }
        }
        return resBytes;
    }


    //word参数填充
    public static XWPFDocument newWord(Map<String, String> map, String srcPath) {
        XWPFDocument document = null;
        try {
            URL url = new URL(srcPath);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            document = new XWPFDocument(conn.getInputStream());
//            document = new XWPFDocument(POIXMLDocument.openPackage(srcPath));
        } catch (IOException e) {
            e.printStackTrace();
        }
        Iterator<XWPFParagraph> itPara = document.getParagraphsIterator();
        while (itPara.hasNext()) {
            XWPFParagraph paragraph = (XWPFParagraph) itPara.next();
            List<XWPFRun> runs = paragraph.getRuns();
            for (XWPFRun run : runs) {
                String oneparaString = run.getText(run.getTextPosition());
                if (StringUtils.isBlank(oneparaString) || !oneparaString.contains("$")){
                    continue;
                }
                for (Map.Entry<String, String> entry :
                        map.entrySet()) {
                    oneparaString = oneparaString.replace(entry.getKey(), entry.getValue());
                }
                run.setText(oneparaString, 0);
            }
        }
        return document;
    }


    //docx转PDF
    public static byte[] docxToPdf(XWPFDocument doc) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] resBytes = null;
        String result;
        try {
            // pdf文件的尺寸
            Document pdfDocument = new Document(PageSize.A3, 72, 72, 72, 72);
            PdfWriter pdfWriter = PdfWriter.getInstance(pdfDocument, baos);
            pdfWriter.setInitialLeading(20);
            java.util.List<XWPFParagraph> plist = doc.getParagraphs();
            pdfWriter.open();
            pdfDocument.open();
            for (int i = 0; i < plist.size(); i++) {
                XWPFParagraph pa = plist.get(i);
                java.util.List<XWPFRun> runs = pa.getRuns();
                for (int j = 0; j < runs.size(); j++) {
                    XWPFRun run = runs.get(j);
                    java.util.List<XWPFPicture> piclist = run.getEmbeddedPictures();
                    Iterator<XWPFPicture> iterator = piclist.iterator();
                    while (iterator.hasNext()) {
                        XWPFPicture pic = iterator.next();
                        XWPFPictureData picdata = pic.getPictureData();
                        byte[] bytepic = picdata.getData();
                        Image imag = Image.getInstance(bytepic);
                        pdfDocument.add(imag);
                    }
                    // 中文字体的解决
                    BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
                    Font font = new Font(bf, 11.0f, Font.NORMAL, BaseColor.BLACK);
                    String text = run.getText(-1);
                    byte[] bs;
                    if (text != null) {
                        bs = text.getBytes();
                        String str = new String(bs);
                        Chunk chObj1 = new Chunk(str, font);
                        pdfDocument.add(chObj1);
                    }
                }
                pdfDocument.add(new Chunk(Chunk.NEWLINE));
            }
            //需要关闭,不然无法获取到输出流
            pdfDocument.close();
            pdfWriter.close();
            resBytes = baos.toByteArray();
        } catch (Exception e) {
            log.error("docx转pdf文件异常:{}",e);
        }finally {
            try{
                if(baos != null){
                    baos.close();
                }
            }catch (IOException e){
                log.error("docx转pdf关闭io流异常:{}",e);
            }
        }
        return resBytes;
    }

    //byte转MultipartFile
    //名字的后缀千万不能少,根据名称的后缀来判断文件格式
    public static MultipartFile byteToMultipartFile(byte[] bytes){
        try {
            InputStream inputStream = new ByteArrayInputStream(bytes);
            return new MockMultipartFile("text.pdf","wordToPdf.pdf",ContentType.APPLICATION_OCTET_STREAM.toString(), inputStream);
        } catch (IOException e) {
            log.error("byte转MultipartFile:{}",e);
            return null;
        }
    }

    /**
     * XWPFDocument 转 MultipartFile(CommonsMultipartFile)
     *
     * @param document 文档对象
     * @param fileName 文件名
     * @return
     */
    public static MultipartFile xwpfDocumentToCommonsMultipartFile(XWPFDocument document, String fileName) {
        //XWPFDocument转FileItem
        FileItemFactory factory = new DiskFileItemFactory(16, null);
        FileItem fileItem = factory.createItem("textField", "text/plain", true, fileName);
        try {
            OutputStream os = fileItem.getOutputStream();
            document.write(os);
            os.close();
            //FileItem转MultipartFile
            MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
            return multipartFile;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

使用示例

OutputStream bos = new BufferedOutputStream(response.getOutputStream());
//map为替换参数,如替换文件中的${name},map中存放key为${name}value为测试。即可替换掉文件中的参数为测试
//filePath为模板文件存放的url地址
XWPFDocument xwpfDocument = OfficeToPdfUtil.newWord(map, filePath);
bos.write(OfficeToPdfUtil.docxToPdf(xwpfDocument));
bos.flush();

第二种方式word2Pdf

手动加入jar包到项目文件目录(文件地址如下获取)

链接:https://pan.baidu.com/s/19mKCEqNDQECrtGxWCThSvw?pwd=2haw 
提取码:2haw

工具类

package com.solvay.utils;

import com.aspose.words.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;

@Slf4j
public class WordToPDFUtil {

    static {
        try {
            ClassPathResource classPathResource = new ClassPathResource("pdflicense.xml");
            License aposeLic = new License();
            aposeLic.setLicense(classPathResource.getInputStream());

            ClassPathResource fontsFolder = new ClassPathResource("fonts");
            FontSettings.setFontsFolder(fontsFolder.getURL().getPath(),true);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("初始化aspose.words异常",e);
        }
    }

    public static void convertDoc2Pdf(InputStream inputStream, OutputStream outputStream) throws Exception {
        Document doc = new Document(inputStream);
        doc.save(outputStream, SaveFormat.PDF);

    }

    public static void convertDoc2Pdf(Map<String,String> map,InputStream inputStream, OutputStream outputStream) throws Exception {
        Document doc = new Document(inputStream);
        map.forEach((key,value)->{
            try {
                doc.getRange().replace("${"+key+"}",value,false,false);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("word2PDF时,替换{}:{}文本报错",key,value,e);
            }
        });
        doc.save(outputStream, SaveFormat.PDF);
    }

    /**
     * 预览word转pdf
     * @param map
     * @param inputStream
     * @throws Exception
     */
    public static void previewConvertDoc2Pdf(Map<String,String> map,InputStream inputStream) throws Exception {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        response.reset();
        BufferedOutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
        convertDoc2Pdf(map,inputStream,outputStream);
        response.setHeader("Content-Disposition", "inline;filename=file.pdf");
        response.setContentType("application/pdf; charset=UTF-8");
        outputStream.flush();
    }

    /**
     * 下载word转pdf
     * @param map
     * @param inputStream
     * @throws Exception
     */
    public static void downConvertDoc2Pdf(Map<String,String> map,InputStream inputStream) throws Exception {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        response.reset();
        BufferedOutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
        convertDoc2Pdf(map,inputStream,outputStream);
        response.setHeader("Content-Disposition", "attachment;filename=file.pdf");
        response.setContentType("application/octet-stream; charset=UTF-8");
        outputStream.flush();
    }

    /**
     * 预览word转pdf
     * @param inputStream
     * @throws Exception
     */
    public static void previewConvertDoc2Pdf(InputStream inputStream) throws Exception {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        response.reset();
        BufferedOutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
        convertDoc2Pdf(inputStream,outputStream);
        response.setHeader("Content-Disposition", "inline;filename=file.pdf");
        response.setContentType("application/pdf; charset=UTF-8");
        outputStream.flush();
    }

    /**
     * 下载word转pdf
     * @param inputStream
     * @throws Exception
     */
    public static void downConvertDoc2Pdf(InputStream inputStream) throws Exception {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        response.reset();
        BufferedOutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
        convertDoc2Pdf(inputStream,outputStream);
        response.setHeader("Content-Disposition", "attachment;filename=file.pdf");
        response.setContentType("application/octet-stream; charset=UTF-8");
        outputStream.flush();
    }


}

使用方式

WordToPDFUtil.previewConvertDoc2Pdf(map,inputStream);//map为所需要替换的参数map,inputSream为模板文件流
posted @   Cv工程师120621号  阅读(437)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示

目录导航