由于libreoffice的soffice不支持多进程,只允许同时有一个进程来转换docx文件为pdf文件,因此无法多线程并发执行转换操作。
为实现并发转换操作,有两种方案:
方案一:将转换代码部署到不同的服务器上,此种方案需要单独服务器,对资源要求较高,部署也麻烦;
方案二:利用docker对资源的隔离特性,把libreoffice 放到docker中,然后启用多个libreoffice容器,java代码调用不同容器的soffice命令来并发转换docx文件。
1、安装docker相关程序
CentOS7已经缺省支持docker
yum install docker
service docker start
chkconfig docker on
简单的安装使用可以参考 https://linux.cn/article-4340-1.html
2、把缺省的docker镜像仓库换成国内的网易镜像
echo "DOCKER_OPTS=\"\$DOCKER_OPTS –registry-mirror=http://hub-mirror.c.163.com\"" >> /etc/default/docker
service docker restart
3、下载centos docker镜像
docker pull centos
4、启动centos的docker镜像
docker run -it centos /bin/bash
5、进入docker容器
docker run -it centos -v /root/install:/root/install /bin/bash
由于生产镜像时候,可能需要与宿主主机共享一些文件,例如中文ttf文件,因此在run 时候使用了-v参数,用于宿主主机与docker container之间的共享目录。
假设docker 容器与宿主机的共享目录为/root/install 。
Docker容器和主机之间共享数据,可以参考 https://www.howtoing.com/how-to-share-data-between-the-docker-container-and-the-host/
6、安装libreoffice、中文字体库等所需的软件
yum install libreoffice-writer.x86_64
yum groupinstall "Fonts"
yum groupinstall "Input Methods"
7、生成安装了libreoffice、中文字体等软件的docker 镜像
docker commit CONTAINER_ID liang/libreoffice1
其中:
CONTAINER_ID是docker ps -a得到了容器id docker ps -a|grep "centos"|awk ‘{print $1}’
liang/libreoffice1 是我们生成的docker镜像
8、停掉刚才启动的centos容器
docker stop CONTAINER_ID
9、启动我们新生成的docker 镜像
根据并发转换docx为pdf文件的需要,基于我们自己生成的docker镜像,启动多个docker的容器,利用docker容器对资源的隔离,调用不同容器中的soffice来并发处理不同的pdf文件
docker run –name office1 -it -d -v /root/pdf1:/root/pdf1 liang/libreoffice1
docker run –name office2 -it -d -v /root/pdf1:/root/pdf1 liang/libreoffice1
镜像文件与宿主机的共享目录为/root/pdf1和/root/pdf2,在共享目录中放入要转换的docx文件
docker exec -it office1 /bin/bash
10、调用soffice命令行,将docx转为pdf
docker exec -it office1 /bin/soffice –headless –invisible –norestore –nodefault –nolockcheck –nofirststartwizard –convert-to pdf:writer_pdf_Export –outdir /root/pdf1 /root/pdf1/liang1.docx
docker exec -it office2 /bin/soffice –headless –invisible –norestore –nodefault –nolockcheck –nofirststartwizard –convert-to pdf:writer_pdf_Export –outdir /root/pdf2 /root/pdf2/liang2.docx
以上命令行放到java代码中,同时可以在多个线程中并发调用。