在程序开发中经常需要将Office文件转换成PDF,著名的Aspose的三大组件可以很容易完成这个功能,但是Aspose的每个组件都单独收费,而且每个都卖的不便宜。在老大的提示下,换了一种思路来解决这个问题。
环境
dotNetCore:2.1
CentOS:7.5
Docker:18.06.1-ce
步骤
1、Docker中安装libreoffice和dotNetCore;
2、编写转换程序;
3、程序以服务的方式部署在Docker中。
配置Docker环境
因为需要部署dotNetCore的程序,开始的想法是依赖microsoft/dotnet:2.1-aspnetcore-runtime镜像创建容器,然后在容器中安装libreoffice,后来发现容器中没法执行yum命令(可能是没找到方法)。最后换了一种思路,依赖centos镜像创建容器,在容器中安装dotNetCore2.1和libreoffice。
安装libreofiicie
安装dotnetCore2.1
1 2 3
   | sudo rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm sudo yum update sudo yum install aspnetcore-runtime-2.1
   | 
 
转换程序编写
在C#中使用libreoffice转换office为pdf,网上有很多的代码示例,在这里还需要引入消息队列,整个程序是一个消息队列的消费者。简单说就是,用户上传了一个office文件,上传成功后会发一个消息,该程序中接收到消息就进行转换。
消息监听
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
   | class Program {     static IPowerPointConverter converter = new PowerPointConverter();
      static void Main(string[] args)     {
          var mqManager = new MQManager(new MqConfig         {             AutomaticRecoveryEnabled = true,             HeartBeat = 60,             NetworkRecoveryInterval = new TimeSpan(60),
              Host = ConfigurationManager.AppSettings["mqhostname"],              UserName = ConfigurationManager.AppSettings["mqusername"],             Password = ConfigurationManager.AppSettings["mqpassword"],             Port = ConfigurationManager.AppSettings["mqport"]         });
 
          if (mqManager != null && mqManager.Connected)         {             Console.WriteLine("RabbitMQ连接初始化成功。");             Console.WriteLine("RabbitMQ消息接收中...");
              mqManager.Subscribe<PowerPointConvertMessage>(message =>             {                 if (message != null)                 {                     converter.OnWork(message);                     Console.WriteLine(message.FileInfo);                 }             });         }         else         {             Console.WriteLine("RabbitMQ连接初始化失败,请检查连接。");             Console.ReadLine();         }     } }
   | 
 
文件转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
   | public bool OnWork(MQ.Messages Message) {     PowerPointConvertMessage message = (PowerPointConvertMessage)Message;     string sourcePath = string.Empty;     string destPath = string.Empty;     try     {         if(message == null)             return false;         Stream sourceStream = fileOperation.GetFile(message.FileInfo.FileId);         string filename = message.FileInfo.FileId;         string extension = System.IO.Path.GetExtension(message.FileInfo.FileName);         sourcePath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), filename + extension);         destPath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), string.Format("{0}.pdf", filename));
          if (!SaveToFile(sourceStream, sourcePath))             return false;         var psi = new ProcessStartInfo("libreoffice", string.Format("--invisible --convert-to pdf  {0}", filename + extension)) { RedirectStandardOutput = true };         // 启动         var proc = Process.Start(psi);         if (proc == null)         {             Console.WriteLine("不能执行.");             return false;         }         else         {             Console.WriteLine("-------------开始执行--------------");             //开始读取             using (var sr = proc.StandardOutput)             {                 while (!sr.EndOfStream)                 {                     Console.WriteLine(sr.ReadLine());                 }                 if (!proc.HasExited)                 {                     proc.Kill();                 }             }             Console.WriteLine("---------------执行完成------------------");             Console.WriteLine($"退出代码 : {proc.ExitCode}");         }     }     catch (Exception ex)     {         Console.WriteLine(ex.Message);         return false;     }     finally     {         if (File.Exists(destPath))         {             var destFileInfo = UploadFile(destPath, string.Format("{0}.pdf", Path.GetFileNameWithoutExtension(message.FileInfo.FileName)));         }         if (File.Exists(destPath))         {             System.IO.File.Delete(destPath);         }     }     return true; }
   | 
 
上面只是一些代码片段,完整示例会上传到Github上,文章末尾会给出地址。
部署代码到Docker
此程序是dotNetCore编写的控制台程序,希望以服务的方式在后台运行,下面介绍怎样将控制台程序以服务的方式运行:
1、将发布后的代码放在容器的/root/officetopdf/publish目录中
2、在 /lib/systemd/system目录中创建文件officetopdf.service;
3、文件内容如下:
1 2 3 4 5 6 7 8
   | [Unit] Description=office to pdf service
  [Service] ExecStart=/usr/bin/dotnet /root/officetopdf/publish/Office2PDF.dll
  [Install] WantedBy=default.target
   | 
 
4、使用下面命令创建和启动服务;
1 2
   | systemctrl daemon-reload systemctrl start officetopdf
   | 
 
示例
https://github.com/oec2003/StudySamples/tree/master/Office2PDF