添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
奔跑的鼠标垫  ·  PSA: New stable ...·  1 周前    · 
坚强的韭菜  ·  技术|如何在 Centos 8 / ...·  4 月前    · 
性感的鸵鸟  ·  TypeError: Failed to ...·  4 月前    · 
爽快的莲藕  ·  .NET Excel API | ...·  5 月前    · 

README.MD

File metadata and controls

文档转换示例工程(Document -> PDF)

此工程是一个示例工程,用于演示 Document PDF 的转换。其中 Document 包括了 doc docx odt 。转换前需要将模板待替换的内容使用 Velocity 模板引擎进行替换。

Spike解决方案

针对开源的库doc4xj、xdocreport、jodconverter以及非开源的库aspose进行了Spike,每种解决方案各有利弊。

docx4j(docx -> pdf)

  • 转换效果不堪入目,果断不采取
  • xdocreport + xwpf(docx -> pdf)

  • 依赖简单,可以单独运行在JVM
  • 模板替换率不高。
  • 转换后中文丢失。
  • xdocreport + odfdom(odt -> pdf)

  • 依赖简单,可以单独运行在JVM
  • 模板替换率高。
  • 转换后中文丢失。
  • jodconverter + openoffice(odt -> pdf)

  • 转换率高。
  • 可以使用Openoffice客户端可视化编辑。
  • 依赖额外的OpenOffice服务,而服务又不稳定。
  • jodconverter 没有继续维护。
  • aspose (doc, docx, odt -> pdf)

  • 可以转换多种格式,转换率高。
  • 开发代码很少,易于集成。
  • 收费昂贵,单开发者单部署的标准Support就收费 $1599
  • 黑盒转换,团队无法自己控制,依赖官方团队。
  • docx4j

    Dependency

    dependencies {
    	compile ('org.docx4j:docx4j:2.8.1')
    

    Java Code

    public class Doc4JDoc2PDF {
        public static void main(String[] args) throws Exception {
            InputStream in = Doc4JDoc2PDF.class.getClassLoader().getResourceAsStream("input/doc4J-input.docx");
            OutputStream out = new FileOutputStream(new File("src/main/resources/output/doc4J-output.pdf"));
            long start = System.currentTimeMillis();
            createPDF(in, out);
            out.close();
            System.err.println("*********Take " + (System.currentTimeMillis() - start) + " ms*********");
        private static void createPDF(InputStream inputStream, OutputStream out) throws Exception {
            WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(inputStream);
            PdfSettings pdfSettings = new PdfSettings();
            PdfConversion converter = new org.docx4j.convert.out.pdf.viaXSLFO.Conversion(
                    wordMLPackage);
            converter.output(out, pdfSettings);
    // *********Take 8934 ms*********

    xdocreport + xwpf

    Dependency

    dependencies{
        compile('fr.opensagres.xdocreport:fr.opensagres.xdocreport.template.velocity:2.0.1')
        compile('fr.opensagres.xdocreport:fr.opensagres.xdocreport.document.docx:2.0.1')
        compile('fr.opensagres.xdocreport:fr.opensagres.poi.xwpf.converter.pdf:2.0.1')
    

    Java Code

    public class XWPFDoc2PDF {
        public static void main(String[] args) throws Exception {
            InputStream in = XWPFDoc2PDF.class.getClassLoader().getResourceAsStream("input/xwpf-input.docx");
            File outputFile = new File("src/main/resources/output/xwpf-output.docx");
            OutputStream out = new FileOutputStream(outputFile);
            long start = System.currentTimeMillis();
            replaceTemplate(in, out);
            out.close();
            InputStream in1 = XWPFDoc2PDF.class.getClassLoader().getResourceAsStream("output/xwpf-output.docx");
            OutputStream out1 = new FileOutputStream(new File("src/main/resources/output/xwpf-output.pdf"));
            docToPDF(in1, out1);
            out1.close();
            System.err.println("*********Take " + (System.currentTimeMillis() - start) + " ms*********");
            System.exit(0);
        private static void replaceTemplate(InputStream in, OutputStream out) throws Exception {
            IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in, TemplateEngineKind.Velocity);
            IContext context = report.createContext();
            context.put("current_date", "2017-09-09");
            context.put("buyer_name", "袁慎建");
            report.process(context, out);
            out.close();
        public static void docToPDF(InputStream in, OutputStream out) throws Exception {
            XWPFDocument document = new XWPFDocument(in);
            PdfOptions options = PdfOptions.create().fontEncoding("utf-8");
            PdfConverter.getInstance().convert(document, out, options);
    // *********Take 4756 ms*********

    xdocreport + odfdom

    Dependency

    dependencies{
    	compile('fr.opensagres.xdocreport:fr.opensagres.xdocreport.document.odt:2.0.1')
    	compile('fr.opensagres.xdocreport:fr.opensagres.xdocreport.template.velocity:2.0.1')
    	compile('fr.opensagres.xdocreport:fr.opensagres.xdocreport.converter.odt.odfdom:2.0.1')
    

    Java Code

    public class XDocReportDoc2PDF {
        public static void main(String[] args) throws Exception {
            InputStream in = XDocReportDoc2PDF.class.getClassLoader().getResourceAsStream("input/xdocreport-input.odt");
            OutputStream out = new FileOutputStream(new File("src/main/resources/output/xdocreport-output.pdf"));
            long start = System.currentTimeMillis();
            odtToPDFWithVelocity(in, out);
            out.close();
            System.err.println("*********Take " + (System.currentTimeMillis() - start) + " ms*********");
            System.exit(0);
        private static void odtToPDFWithVelocity(InputStream in, OutputStream out) throws Exception {
            IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in, TemplateEngineKind.Velocity);
            IContext ctx = report.createContext();
            Invoice invoice = generateInvoice();
            User sender = generateUser();
            User to = generateUser();
            ctx.put("invoice", invoice);
            ctx.put("StringUtils", StringUtils.class);
            ctx.put("to", to);
            ctx.put("sender", sender);
            List<InvoiceRow> rows = new ArrayList<>();
            rows.add(generateInvoiceRow());
            rows.add(generateInvoiceRow());
            ctx.put("rows", rows);
            Options options = Options.getTo(ConverterTypeTo.PDF).via(ConverterTypeVia.ODFDOM);
            report.convert(ctx, options, out);
    // *********Take 13696 ms*********

    jodconverter + openoffice

    Dependency

    dependencies{
        compile files('libs/jodconverter-core-3.0-beta-4.jar')
    

    jodconverter依赖下载地址: https://code.google.com/archive/p/jodconverter/downloads

    Java Code

    public class OpenOfficeToPDF {
        public static void main(String[] args) throws Exception {
            DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration();
            configuration.setPortNumber(8100);
            configuration.setRetryTimeout(1000);
            configuration.setOfficeHome("/Applications/OpenOffice.app/Contents");
            OfficeManager officeManager = configuration.buildOfficeManager();
            OfficeDocumentConverter documentConverter = new OfficeDocumentConverter(officeManager);
            officeManager.start();
            File sourceFile = new File("/Users/sjyuan/Personal-sjyuan/IdeaProjects/springboot-html-pdf/src/main/resources/input/openoffice-input.odt");
            File outputFile = new File("src/main/resources/output/openoffice-output.pdf");
            createPDF(documentConverter, sourceFile, outputFile);
            officeManager.stop();
        private static void createPDF(OfficeDocumentConverter converter, File sourceFile, File outputFile) throws Exception {
            long start = System.currentTimeMillis();
            converter.convert(sourceFile, outputFile);
            System.err.println("Generate pdf/HelloWorld.pdf with "
                    + (System.currentTimeMillis() - start) + "ms");
    

    安装 Openoffice

    进入安装目录

  • $ /Applications/OpenOffice.app/Contents/program
  • $ ./soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard
  • Aspose

    Dependency

    dependencies{
    	compile files('libs/aspose-words-17.10-jdk16.jar')
    

    aspose依赖下载地址: https://www.aspose.com/community/getting-started.aspx

    Java Code

    public class AsposeDoc2PDF {
        public static void main(String[] args) throws Exception {
            documentToPDFWithAspose("/Users/sjyuan/Personal-sjyuan/IdeaProjects/springboot-html-pdf/src/main/resources/input/aspose-input.odt",
                    "src/main/resources/output/aspose-output.pdf");
        public static void documentToPDFWithAspose(String absoluteSourceFilePath, String savedFilePath) throws Exception {
            Document doc = new Document(absoluteSourceFilePath);
            doc.save(savedFilePath, SaveFormat.PDF); //Save the document in PDF format.
    

    另辟蹊径(XHTML/HTML -> PDF)

    thymeleaf + flying-saucer-pdf?

  • 利于开发者维护。
  • 可以并行修改文件。
  • 商业合同对尺寸要求苛刻,css样式较难调整。
  • thymeleaf + wkhtmltopdf?

  • 利于开发者维护。
  • 可以并行修改文件。
  • 已经有成功的生产实践。
  • 合同对尺寸要求苛刻,css样式较难调整。
  • How to convert docx/odt to pdf/html with Java?
  • How to Run LibreOffice in AWS Lambda for Dirty-Cheap PDFs at Scale
  •