Freemark 模板生成doc文件,xml doc文件转docx 文件,docx文件转pdf文件

freemark 模板生成doc文件,此doc文件为xml格式,无法直接转pdf

需要doc转docx文件,才能转pdf

方法1:docx4j 转 pdf

方法2: e-iceblue docx 转 pdf、xml-doc 转 pdf

打包方式,需要本地引入jar包,下载后,将lib里的jar包放入项目中

Free Spire.Doc for Java | 100% 免费 Java Word 组件

Freemark 模板生成doc文件,xml doc文件转docx 文件,docx文件转pdf文件_第1张图片

pom文件引入 ${project.basedir} 是系统变量,代表本目录,build配置是打包时,将本地文件加入项目


            e-iceblue
            spire.pdf
            5.2.0
            system
            ${project.basedir}/src/main/resources/lib/Spire.Doc.jar
        

 
        ${project.artifactId}
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                
                    true
                
            
        
    

​​​​​​​Freemark 模板生成doc文件,xml doc文件转docx 文件,docx文件转pdf文件_第2张图片

 

方法3:poi (可以自己搜教程)

依赖


            
                com.itextpdf
                itextpdf
                5.5.13
            

            
                org.xhtmlrenderer
                flying-saucer-pdf-itext5
                9.1.5
            

            
                org.freemarker
                freemarker
                2.3.31
            

            
                commons-io
                commons-io
                2.11.0
                compile
            

            
            
                org.docx4j
                docx4j
                6.1.2
                
                    
                        org.slf4j
                        slf4j-log4j12
                    
                
            

            
                org.docx4j
                docx4j-export-fo
                6.0.0
            

            
            
                e-iceblue
                spire.doc.free
                5.2.0
            

        
            public
            阿里云公共仓库
            https://maven.aliyun.com/repository/public/
            
                true
            
        
        
            com.e-iceblue
            https://repo.e-iceblue.cn/repository/maven-public/
        
    
/**
 * @Author: LiSaiHang
 * @Date: 2023/4/23 3:26 下午
 */
@RestController
@RequestMapping("/module/documents")
@Slf4j
public class FreeMarkController {

    @GetMapping("/generate")
    public void doc(HttpServletResponse response) {
        Map dataMap = new HashMap<>();
        ///姓名
        dataMap.put("name", "张三");
        dataMap.put("phone", "15532123328");
        dataMap.put("idCard", "130429199711113617");
        dataMap.put("sex", "男");
        String result = "";

        String docName = System.currentTimeMillis() + (int) (Math.random() * 90000 + 10000) + ".doc";
        String pdfName = System.currentTimeMillis() + (int) (Math.random() * 90000 + 10000) + ".pdf";

        response.setHeader("content-Type", "application/octet-stream");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename=" + pdfName);

        // 下载输出流
        ServletOutputStream outputStream = null;
        // doc文件输出流
        InputStream inputStream = null;
        // pdf文件输出流
        ByteArrayOutputStream fileOutputStream = null;

        try {
            // 获取渲染数据
            result = FreeMarkUtils.freemarkerRender(dataMap, "test.doc");
            inputStream = new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8));
            // 生成 doc 文件
            FileUtils.copyInputStreamToFile(inputStream, new File(docName));
            // doc 文件转docx文件
            final String docxFile = this.docToDocx(docName);
            // 方法1:docx文件转pdf文件
            // this.docx4jWordToPdf(docxFile, pdfName);
            
            // 方法2:docx文件转pdf文件
            // com.spire.doc.Document 实例化Document类的对象
            Document doc = new Document();
            // 加载Word
            doc.loadFromFile(docxFile);
            // 保存为PDF格式 com.spire.doc.FileFormat
            doc.saveToFile(pdfName, FileFormat.PDF);
            // pdf 缩放设置
            pdfPageSetting(pdfName);
            // 获取文件输出流
            fileOutputStream = FreeMarkUtils.getFileOutputStream(new File(pdfName));
            // 设置文件名
            outputStream = response.getOutputStream();
            outputStream.write(fileOutputStream.toByteArray());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

    /**
     * doc转docx
     * @param docPath doc文件路径
     * @return
     */
    private String docToDocx(String docPath) {
        String docxPath = docPath.replaceAll("(\\.docx)|(\\.doc)", ".docx");
        try (FileInputStream inputStream = new FileInputStream(docPath);) {
            WordprocessingMLPackage wmlPackage = Docx4J.load(inputStream);
            //转换为DOCX
            try (FileOutputStream docx = new FileOutputStream(docxPath);) {
                Docx4J.save(wmlPackage, docx, Docx4J.FLAG_SAVE_ZIP_FILE);
                docPath = docxPath;
            }
        } catch (Exception e) {
            System.out.println((docPath + ":不需要转换:" + e.getLocalizedMessage()));
        }
        return docPath;
    }

    /**
     * 通过docx4j 实现word转pdf
     *
     * @param sourcePath 源文件地址 如 /root/example.doc
     * @param targetPath 目标文件地址 如 /root/example.pdf
     */
    public String docx4jWordToPdf(String sourcePath, String targetPath) {
        try {
            WordprocessingMLPackage pkg = Docx4J.load(new File(sourcePath));
            Mapper fontMapper = new IdentityPlusMapper();
            fontMapper.put("隶书", PhysicalFonts.get("LiSu"));
            fontMapper.put("宋体", PhysicalFonts.get("SimSun"));
            fontMapper.put("微软雅黑", PhysicalFonts.get("Microsoft Yahei"));
            fontMapper.put("黑体", PhysicalFonts.get("SimHei"));
            fontMapper.put("楷体", PhysicalFonts.get("KaiTi"));
            fontMapper.put("新宋体", PhysicalFonts.get("NSimSun"));
            fontMapper.put("华文行楷", PhysicalFonts.get("STXingkai"));
            fontMapper.put("华文仿宋", PhysicalFonts.get("STFangsong"));
            fontMapper.put("仿宋", PhysicalFonts.get("FangSong"));
            fontMapper.put("幼圆", PhysicalFonts.get("YouYuan"));
            fontMapper.put("华文宋体", PhysicalFonts.get("STSong"));
            fontMapper.put("华文中宋", PhysicalFonts.get("STZhongsong"));
            fontMapper.put("等线", PhysicalFonts.get("SimSun"));
            fontMapper.put("等线 Light", PhysicalFonts.get("SimSun"));
            fontMapper.put("华文琥珀", PhysicalFonts.get("STHupo"));
            fontMapper.put("华文隶书", PhysicalFonts.get("STLiti"));
            fontMapper.put("华文新魏", PhysicalFonts.get("STXinwei"));
            fontMapper.put("华文彩云", PhysicalFonts.get("STCaiyun"));
            fontMapper.put("方正姚体", PhysicalFonts.get("FZYaoti"));
            fontMapper.put("方正舒体", PhysicalFonts.get("FZShuTi"));
            fontMapper.put("华文细黑", PhysicalFonts.get("STXihei"));
            fontMapper.put("宋体扩展", PhysicalFonts.get("simsun-extB"));
            fontMapper.put("仿宋_GB2312", PhysicalFonts.get("FangSong_GB2312"));
            fontMapper.put("新細明體", PhysicalFonts.get("SimSun"));
            PhysicalFonts.addPhysicalFonts("SimSun", WordUtils.class.getResource("/simsun.ttc"));
            pkg.setFontMapper(fontMapper);

            Docx4J.toPDF(pkg, new FileOutputStream(targetPath));
        } catch (Exception e) {
            log.error("[docx4j] word转pdf失败:{}", e.toString());
        }
        return targetPath;
    }

    /**
     * 对pdf页面设置,缩放比例设置
     * @param pdfName pdf文件名称
     */
    private void pdfPageSetting(String pdfName) {
        //创建PdfDocument实例
        PdfDocument originalDoc = new PdfDocument();
        //加载PDF文件
        originalDoc.loadFromFile(pdfName);

        //创建一个新的PdfDocument实例
        PdfDocument newDoc = new PdfDocument();

        //遍历所有PDF 页面
        for (int i = 0; i < originalDoc.getPages().getCount(); i++) {
            PdfPageBase page = originalDoc.getPages().get(i);
            //设置新文档的页边距为10
            PdfMargins margins = new PdfMargins(10);
            //设置新文档的页面大小为A2
            PdfPageBase newPage = newDoc.getPages().add(PdfPageSize.A2, margins);
            //调整画布,设置内容也根据页面的大小进行缩放
            double wScale = (PdfPageSize.A2.getWidth() - 20) /         PdfPageSize.A4.getWidth();
            double hScale = (PdfPageSize.A2.getHeight() - 20) / PdfPageSize.A4.getHeight();
            newPage.getCanvas().scaleTransform(wScale, hScale);
            //复制原文档的内容到新文档
            newPage.getCanvas().drawTemplate(page.createTemplate(), new Point2D.Float());
        }
        //保存PDF
        newDoc.saveToFile(pdfName);
    }
}

工具类

package com.dpxdata.framework.common.utils;

import com.itextpdf.text.*;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.*;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.stereotype.Component;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.ui.freemarker.SpringTemplateLoader;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import java.io.*;
import java.util.Map;

/**
 * @Description: pdf 导出工具类
 * @Author: LiSaiHang
 * @Date: 2022/1/7 11:30 上午
 */
@Component
@Slf4j
public class FreeMarkUtils {
    private FreeMarkUtils() {
    }

    private volatile static Configuration configuration;

    static {
        if (configuration == null) {
            synchronized (FreeMarkUtils.class) {
                if (configuration == null) {
                    configuration = new Configuration(Configuration.VERSION_2_3_28);
                }
            }
        }
    }

    /**
     * freemarker 引擎渲染 html
     *
     * @param dataMap  传入 html 模板的 Map 数据
     * @param fileName 模板文件名称
     *                 eg: "templates/template.ftl"
     * @return
     */
    public static String freemarkerRender(Map dataMap, String fileName) {
        configuration.setDefaultEncoding("UTF-8");
        configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        try {
            // TODO Jar包运行时,是无法读取classpath下资源文件,可以通过 SpringTemplateLoader 读取资源文件目录
            // 本地运行时,可以通过本地文件流读取资源文件
            final SpringTemplateLoader templateLoader = new SpringTemplateLoader(new DefaultResourceLoader(), "classpath:templates");
            configuration.setTemplateLoader(templateLoader);
            // 服务器运行时,可以通过目录,获取文件流读取资源文件
//            configuration.setDirectoryForTemplateLoading(new File("/Users/lisaihang/Documents/"));
            configuration.setLogTemplateExceptions(false);
            configuration.setWrapUncheckedExceptions(true);
            Template template = configuration.getTemplate(fileName);
            log.info("填充模板动态数据");
            return FreeMarkerTemplateUtils.processTemplateIntoString(template, dataMap);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 使用 iText 生成 PDF 文档
     *
     * @param htmlTmpStr html 模板文件字符串
     * @param fontFile   所需字体文件(相对路径+文件名)
     */
    public static byte[] createHtml2Pdf(String htmlTmpStr, String fontFile) {
        log.info("根据模板生成PDF文件");
        ByteArrayOutputStream outputStream = null;
        byte[] result = null;
        // 生成 字体临时文件
        // TODO jar包运行后,是无法直接读取 classpath 下的资源文件,需要通过文件流读取,生成临时文件
        final String tempFont = "simsun_temp_"+ ".ttc";
        File existFile = new File(tempFont);
        if (!existFile.exists()) {
            final File tempFile = getTempFile(fontFile, tempFont);
            existFile = tempFile;
        }
        // TODO jar包运行后,是无法直接读取 classpath 下的资源文件,需要通过文件流读取,生成临时文件
        try {
            outputStream = new ByteArrayOutputStream();
            ITextRenderer renderer = new ITextRenderer();
            renderer.setDocumentFromString(htmlTmpStr);
            ITextFontResolver fontResolver = renderer.getFontResolver();
            // 解决中文支持问题,需要所需字体(ttc)文件
            fontResolver.addFont(existFile.getAbsolutePath(), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            renderer.layout();
            renderer.createPDF(outputStream);
            // 对Html2Pdf 的文件插入水印图片
            final String fileName = System.currentTimeMillis() + (int) (Math.random() * 90000 + 10000) + ".pdf";
            addWaterMark(outputStream.toByteArray(), fileName);
            final ByteArrayOutputStream fileOutputStream = getFileOutputStream(new File(fileName));
            result = fileOutputStream.toByteArray();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.flush();
                    outputStream.close();
                }
//                if (tempFile.exists()) {
//                    tempFile.delete();
//                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 文件转字节输出流
     *
     * @param outFile 文件
     * @return
     */
    public static ByteArrayOutputStream getFileOutputStream(File outFile) {
        // 获取生成临时文件的输出流
        InputStream input = null;
        ByteArrayOutputStream bytestream = null;
        try {
            input = new FileInputStream(outFile);
            bytestream = new ByteArrayOutputStream();
            int ch;
            while ((ch = input.read()) != -1) {
                bytestream.write(ch);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                input.close();
                bytestream.close();
                log.info("删除临时文件");
                if (outFile.exists()) {
                    outFile.delete();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bytestream;
    }

    /**
     * 获取资源文件的临时文件
     * 资源文件打jar包后,不能直接获取,需要通过流获取生成临时文件
     *
     * @param fileName 文件路径 temp/temp.ftl
     * @return
     */
    public static File getTempFile(String fileName, String tempFont) {
        final File tempFile = new File(tempFont);
        InputStream fontTempStream = null;
        try {
            fontTempStream = FreeMarkUtils.class.getClassLoader().getResourceAsStream(fileName);
            FileUtils.copyInputStreamToFile(fontTempStream, tempFile);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (fontTempStream != null) {
                    fontTempStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return tempFile;
    }


    /**
     * 插入图片水印
     * @param srcByte 已生成PDF的字节数组(流转字节)
     * @param destFile 生成有水印的临时文件 temp.pdf
     * @return
     */
    public static FileOutputStream addWaterMark(byte[] srcByte, String destFile) {
        // 待加水印的文件
        PdfReader reader = null;
        // 加完水印的文件
        PdfStamper stamper = null;
        FileOutputStream fileOutputStream = null;
        try {
            reader = new PdfReader(srcByte);
            fileOutputStream = new FileOutputStream(destFile);
            stamper = new PdfStamper(reader, fileOutputStream);
            int total = reader.getNumberOfPages() + 1;
            PdfContentByte content;
            // 设置字体
            //BaseFont font = BaseFont.createFont();
            // 循环对每页插入水印
            for (int i = 1; i < total; i++) {
                final PdfGState gs = new PdfGState();
                // 水印的起始
                content = stamper.getUnderContent(i);
                // 开始
                content.beginText();
                // 设置颜色 默认为蓝色
                //content.setColorFill(BaseColor.BLUE);
                // content.setColorFill(Color.GRAY);
                // 设置字体及字号
                //content.setFontAndSize(font, 38);
                // 设置起始位置
                // content.setTextMatrix(400, 880);
                //content.setTextMatrix(textWidth, textHeight);
                // 开始写入水印
                //content.showTextAligned(Element.ALIGN_LEFT, text, textWidth, textHeight, 45);

                // 设置水印透明度
                // 设置笔触字体不透明度为0.4f
                gs.setStrokeOpacity(0f);
                Image image = null;
                image = Image.getInstance("https://dpxdata.oss-cn-beijing.aliyuncs.com/upload/kbt/null_1660715685801.png");
                // 设置坐标 绝对位置 X Y
                image.setAbsolutePosition(472, 785);
                // 设置旋转弧度
                image.setRotation(0);// 旋转 弧度
                // 设置旋转角度
                image.setRotationDegrees(0);// 旋转 角度
                // 设置等比缩放
                image.scalePercent(4);// 依照比例缩放
                // image.scaleAbsolute(200,100);//自定义大小
                // 设置透明度
                content.setGState(gs);
                // 添加水印图片
                content.addImage(image);
                // 设置透明度
                content.setGState(gs);
                //结束设置
                content.endText();
                content.stroke();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
            try {
                stamper.close();
                fileOutputStream.close();
                reader.close();
            } catch (DocumentException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return fileOutputStream;
    }
}

你可能感兴趣的:(xml,pdf,servlet)