事件背景

由于项目需要,最新开始研究起word转pdf了,本以为应该是一件很简单的事情,网络上应该已经有很成熟的解决方案了,毕竟在电脑上使用wps或office操作只需要另存为pdf即可,结果一顿百度,发现目前开源的方案还真没有几个能完美的解决这个问题。

实现方案

目前大家有使用的方案大概有这么几种:

aspose-words和spire.doc都是商业软件,需要花钱购买,如果是大公司,并且对生成的pdf格式保真有要求,那使用这两款收费软件无疑是最好的选择。

documents4j这种方式只适合在window上运行,对于部署在Linux服务器上的应用来说很不友好。

OpenOffice需要在服务器安装OpenOffice软件,不是很方便。

docx4j和poi这两种都是开源的,都不挑操作系统,在window和Linux上都能进行转换,但相比较poi比docx4j转换速度和保真方面都要好。

各组件的具体代码实现

poi

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.17</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <version>3.17</version>
</dependency>
<dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>fr.opensagres.poi.xwpf.converter.pdf-gae</artifactId>
    <version>2.0.1</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-scratchpad</artifactId>
    <version>3.17</version>
</dependency>
@Test
	public void wordToPdfTest4() throws IOException {
		XWPFDocument document;
		InputStream doc = Files.newInputStream(Paths.get("D:\\home\\test2.docx"));
		document = new XWPFDocument(doc);
		PdfOptions options = PdfOptions.create();
		OutputStream out = Files.newOutputStream(Paths.get("D:\\home\\word模板转pdf4-2.pdf"));
		PdfConverter.getInstance().convert(document, out, options);
		doc.close();
		out.close();
	}

documents4j

切记,这种方式在Linux服务器不可用,所以除非你是window服务器,不然就不要使用该方案,别问我怎么知道,问就是我试过了(流泪)。

<dependency>
    <groupId>com.documents4j</groupId>
    <artifactId>documents4j-local</artifactId>
    <version>1.0.3</version>
</dependency>
<dependency>
    <groupId>com.documents4j</groupId>
    <artifactId>documents4j-transformer-msoffice-word</artifactId>
    <version>1.0.3</version>
</dependency>
@Test
	public void wordToPdfTest1() throws IOException {
		InputStream docxInputStream = null;
		OutputStream outputStream = null;
		try {
			// 原word地址
			docxInputStream = Files.newInputStream(Paths.get("D:\\home\\test3.doc"));
			// 转换后pdf生成地址
			outputStream = Files.newOutputStream(Paths.get("D:\\home\\word模板转pdf1.pdf"));
			IConverter converter = LocalConverter.builder().build();
			converter.convert(docxInputStream)
					.as(DocumentType.DOC)
					.to(outputStream)
					.as(DocumentType.PDF).execute();
			// 关闭
			converter.shutDown();
			// 关闭
			outputStream.close();
			// 关闭
			docxInputStream.close();
		} catch (Exception e) {
			System.out.println("[documents4J] word转pdf失败:" + e.toString());
		} finally {
			if (outputStream != null) {
				outputStream.close();
			}
			if (docxInputStream != null) {
				docxInputStream.close();
			}
		}
	}

spire.doc

这里我测试时,一开始是从网上下载的jar包,本地引入的,因为一直提示找不到包,后来发现它没有发布到maven中心仓库,而是在自己仓库,毕竟它是收费的嘛。所以如果要使用maven下载需要添加maven仓库地址:

<repositories>
    <repository>
        <id>e-iceblue</id>
        <url>https://repo.e-iceblue.cn/repository/maven-public/</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
            <updatePolicy>always</updatePolicy>
        </snapshots>
    </repository>
</repositories>
<dependency>
     <groupId>e-iceblue</groupId>
     <artifactId>spire.doc.free</artifactId>
     <version>5.2.0</version>
     <!-- <systemPath>D:/workspace/java/java-base/lib/spire.doc.free-5.2.0.jar</systemPath>-->
</dependency>
@Test
	public void wordToPdfTest2() throws IOException {
		// 参考:https:
		//www.cnblogs.com/Carina-baby/p/16665310.html
		//实例化Document类的对象
		Document doc = new Document();
		//加载Word
		doc.loadFromFile("D:\\home\\test3.docx");
		//保存为PDF格式
		doc.saveToFile("D:\\home\\word模板转pdf2-2.pdf", FileFormat.PDF);
	}

由于本人目前需要转换的word比较简单,使用POI的方案也可以满足需求,所以目前我采用的是POI的方案。