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方法沒有依賴判斷,比較簡單的。