JODConverter 是Java OpenDocument文件转换器库,可以进行许多文件格式的转换。它依赖于OpenOffice或LibreOffice 提供的服务来进行转换,它能将Microsoft Office文档(Word,Excel,PowerPoint)转换为PDF格式
在项目中使用了JODConverter。简单了解下源码,其中有几个设计模式,本篇文章分享下建造者模式。
设计模式介绍
建造者模式简单说就是创建一个对象。那创建一个对象什么要一个设计模式呢?如果一个类中有很多属性,创建对象时可以通过构造函数传参或通过set方法设置。为了避免构造函数的参数列表过长,影响代码的可读性和易用性,我们可以通过构造函数配合 set() 方法来解决。通过构造函数传参数多了很头痛。如果类的属性之间有一定的依赖关系或者约束条件通过set方式设置也很头痛。于是就有了建造者模式,来解决对象有很多参数的问题。
代码演示
本地使用的版本为:
<dependency>
<groupId>org.jodconverter</groupId>
<artifactId>jodconverter-core</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>org.jodconverter</groupId>
<artifactId>jodconverter-local</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>org.libreoffice</groupId>
<artifactId>ridl</artifactId>
<version>5.4.2</version>
</dependency>
按照官方文档例子,常规操作流程如下,先是创建一个OfficeManager服务。启动,转调用JodConverter.convert转换文件,最后停止服务。
File inputFile = new File("document.doc");
File outputFile = new File("document.pdf");
// Create an office manager using the default configuration.
// The default port is 2002. Note that when an office manager
// is installed, it will be the one used by default when
// a converter is created.
final LocalOfficeManager officeManager = LocalOfficeManager.install();
try {
// Start an office process and connect to the started instance (on port 2002).
officeManager.start();
// Convert
JodConverter
.convert(inputFile)
.to(outputFile)
.execute();
} finally {
// Stop the office process
OfficeUtils.stopQuietly(officeManager);
}
例子中是通过LocalOfficeManager.install()方法创建一个默认配置的LocalOfficeManager。那么创建一个LocalOfficeManager需要如下配置。
private String[] pipeNames;
private int[] portNumbers; //服务端口
private File officeHome; // libreaoffice or openoffice 安装路径
private ProcessManager processManager;
private String[] runAsArgs;
private File templateProfileDir; //转换的临时文件存放路径
private boolean killExistingProcess;
private long processTimeout; //转换任务超时
private long processRetryInterval;
private int maxTasksPerProcess;
private boolean disableOpengl;
LocalOfficeManager主要代码结构如下。主要保留建造者模式代码。
public final class LocalOfficeManager extends AbstractOfficeManagerPool {
/**
* Creates a new builder instance.
*
* @return A new builder instance.
*/
public static Builder builder() {
return new Builder();
}
private LocalOfficeManager(
final OfficeUrl[] officeUrls, final OfficeProcessManagerPoolConfig config) {
super(officeUrls.length, config);
this.officeUrls = Arrays.copyOf(officeUrls, officeUrls.length);
}
/**
* LocalOfficeManager 构造类
*
* @see LocalOfficeManager
*/
public static final class Builder extends AbstractOfficeManagerPoolBuilder<Builder> {
// LocalOfficeManager 对象参数值
private String[] pipeNames;
private int[] portNumbers;
private File officeHome;
private ProcessManager processManager;
private String[] runAsArgs;
private File templateProfileDir;
private boolean killExistingProcess = OfficeProcessConfig.DEFAULT_KILL_EXISTING_PROCESS;
// 默认参数值
private long processTimeout = OfficeProcessManagerConfig.DEFAULT_PROCESS_TIMEOUT;
private long processRetryInterval = OfficeProcessManagerConfig.DEFAULT_PROCESS_RETRY_INTERVAL;
private int maxTasksPerProcess = OfficeProcessManagerConfig.DEFAULT_MAX_TASKS_PER_PROCESS;
private boolean disableOpengl = OfficeProcessManagerConfig.DEFAULT_DISABLE_OPENGL;
// Private ctor so only LocalOfficeManager can initialize an instance of this builder.
private Builder() {
super();
}
//返回创建好的LocalOfficeManager
public LocalOfficeManager build() {
// 设置默认参数
if (officeHome == null) {
officeHome = LocalOfficeUtils.getDefaultOfficeHome();
}
// 设置默认参数
if (workingDir == null) {
workingDir = new File(System.getProperty("java.io.tmpdir"));
}
// 设置默认参数
if (processManager == null) {
processManager = LocalOfficeUtils.findBestProcessManager();
}
// Build the office URLs
final OfficeUrl[] officeUrls = LocalOfficeUtils.buildOfficeUrls(portNumbers, pipeNames);
//OfficeProcessManagerPoolConfig 是创建LocalOfficeManager对象需要传的参数
//参数都是通过 LocalOfficeManager.builder().officeHome("/user/aaa")方式传个builder。
final OfficeProcessManagerPoolConfig config =
new OfficeProcessManagerPoolConfig(officeHome, workingDir, processManager);
config.setRunAsArgs(runAsArgs);
config.setTemplateProfileDir(templateProfileDir);
config.setKillExistingProcess(killExistingProcess);
config.setProcessTimeout(processTimeout);
config.setProcessRetryInterval(processRetryInterval);
config.setMaxTasksPerProcess(maxTasksPerProcess);
config.setDisableOpengl(disableOpengl);
config.setTaskExecutionTimeout(taskExecutionTimeout);
config.setTaskQueueTimeout(taskQueueTimeout);
//LocalOfficeManager 需要OfficeProcessManagerPoolConfig,OfficeUrl两个构造参数。
final LocalOfficeManager manager = new LocalOfficeManager(officeUrls, config);
if (install) {
InstalledOfficeManagerHolder.setInstance(manager);
}
return manager;
}
/**
* 设置参数。返回是当前builder对象
* @return This builder instance.
*/
public Builder pipeNames(final String... pipeNames) {
Validate.isTrue(
pipeNames != null && pipeNames.length > 0, "The pipe name list must not be empty");
this.pipeNames = ArrayUtils.clone(pipeNames);
return this;
}
/**
* 设置参数。返回是当前builder对象
* Specifies the port numbers that will be use to communicate with office. An instance of office
* will be launched for each port number.
*
* @param portNumbers The port numbers to use.
* @return This builder instance.
*/
public Builder portNumbers(final int... portNumbers) {
Validate.isTrue(
portNumbers != null && portNumbers.length > 0, "The port number list must not be empty");
this.portNumbers = ArrayUtils.clone(portNumbers);
return this;
}
......//省略不是主要的
}
}
可以看出LocalOfficeManager里有个内部类Builder,Builder类差不多像是平时使用Entity VO,包括了参数和set方法。这里的set方法返回时当前对象。
LocalOfficeManager构造方法时私有的,外部不能直接new。构造方法也是私有的,不能直接new。所有Builder类的build方法是真正创建对象的地方。
比如不想使用默认方式创建LocalOfficeManager。可以通过如下方式,链式设值创建
//指定officehome和应用端口
OfficeManager officeManager = LocalOfficeManager.builder().officeHome(officeHome).portNumbers(123,456).install().build();
Builder.buid方法没有依赖判断,比较简单的。