Design patterns used by the JODConverter framework

JODConverter 是Java OpenDocument文件转换器库,可以进行许多文件格式的转换。它依赖于OpenOffice或LibreOffice 提供的服务来进行转换,它能将Microsoft Office文档(Word,Excel,PowerPoint)转换为PDF格式

JODConverter is used in the project. Understand the source code briefly, there are several design patterns, this article shares the builder pattern.

Design pattern introduction

The builder mode is simply to create an object. So what is a design pattern to create an object? If there are many attributes in a class, you can pass parameters through the constructor or set through the set method when creating the object. In order to avoid that the parameter list of the constructor is too long, which affects the readability and ease of use of the code, we can solve it through the constructor with the set() method. Passing more parameters through the constructor is a headache. It is also a headache if there is a certain dependency between the attributes of the class or the constraints are set through the set method. So there is a builder mode to solve the problem of objects with many parameters.

Code demo

The locally used version is:


        <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>

According to the official document example , the general operation process is as follows. First, create an OfficeManager service. Start, call JodConverter.convert to convert the file, and finally stop the service.

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);
}

In the example, a default configuration of LocalOfficeManager is created through the LocalOfficeManager.install() method. Then creating a LocalOfficeManager requires the following configuration.

   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;

The main code structure of LocalOfficeManager is as follows. Mainly keep the builder mode code.

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;
    }
     ......//省略不是主要的
  }
}

It can be seen that there is an internal class Builder in LocalOfficeManager. The Builder class is almost like the usual Entity VO, including parameters and set methods. The set method here returns the current object.

The LocalOfficeManager construction method is private and cannot be directly new externally. The construction method is also private and cannot be directly new. The build method of all Builder classes is where the objects are actually created.

For example, you don't want to use the default method to create LocalOfficeManager. It can be created by chain setting

//指定officehome和应用端口
OfficeManager officeManager =   LocalOfficeManager.builder().officeHome(officeHome).portNumbers(123,456).install().build();

The Builder.buid method does not rely on judgment and is relatively simple.

Official website address

Guess you like

Origin blog.csdn.net/samz5906/article/details/106506902