根据word模板导出pdf
根据word模板导出pdf
前两天接到一个需求,根据word模板导出pdf。
详细需求
依据模板替换相关参数之后,怕生成的word下载后被别人再改,故要求转成pdf。由于下载的文件较多,故需要在生成pdf之后再压缩成一个zip包,提供给用户下载。
实现思路:
- 将doc模板替换成最终结果word;
- 将最终结果word,转换为pdf,输出到某个目录中;
- 将pdf所在目录,打包成zip文件;
将doc模板替换成最终结果word
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.5.1</version>
</dependency>
网上找到了poi-tl,地址:http://deepoove.com/poi-tl/,实验了一波,完美替换模板中的变量。
将最终结果word,转换为pdf
这儿我网上找了好多个方法,有的转换支持不太好,有的依赖过重,有的只支持Windows。(具体有哪些方法,这个可以随时网上查询下)最终选择了使用aspose-words-16.8.0-jdk16.jar(这个包是个非开源的,网上找的。如果有侵犯到相关利益,可随时联系我,删除此博客。)
使用这个包,转换基本没问题,但是将东西打包至Linux中运行时,显示pdf为乱码。原因是,这个包中依赖的Windows中默认的字体,这些字体在Linux中没有所导致的。所以,需要将Windows中的字体安装到Linux中。
将Windows中的字体安装到Linux中
依据这篇博客操作 https://blog.csdn.net/huangpeigui/article/details/90900443
大概操作:
- 安装字体库,之后在/usr/share目录就可以看到fonts和fontconfig目录了(之前是没有的)
yum -y install fontconfig
- 在/usr/share/fonts下新建一个chinese目录
- 将C:\Windows\Fonts目录中的字体,上传至Linux刚才新建的chinese目录中
- 修改Chinese目录的权限
chmod -R 755 /usr/share/fonts/chinese
- 安装ttmkfdir来搜索目录中所有的字体信息
yum -y install ttmkfdir
ttmkfdir -e /usr/share/X11/fonts/encodings/encodings.dir
- 修改字体配置文件
vi /etc/fonts/fonts.conf
将中文字体位置加进去
<!-- Font directory list -->
<dir>/usr/share/fonts</dir>
<dir>/usr/share/X11/fonts/Type1</dir> <dir>/usr/share/X11/fonts/TTF</dir> <dir>/usr/local/share/fonts</dir>
<dir>/usr/share/fonts/chinese</dir><!--这句是我加的 -->
<dir prefix="xdg">fonts</dir>
<!-- the following element will be removed in the future -->
<dir>~/.fonts</dir>
- 刷新内存中字体
fc-cache
将文件夹打包成zip
hutool-all这个工具挺好用的,囊括了常用的utils。
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.1.0</version>
</dependency>
优化
- 由于要导出的文件较多,所以考虑用多线程实现,来提高生成速度。
- 模板文件可以缓存起来,下次用时可以不用再去盘里面读取。
- 中间生成的最终版word可以不持久化到盘中,直接在内存中转成pdf。
demo代码实现
WordTemplate2PdfZip
package com.hdj.test.poi;
import java.io.File;
import java.io.InputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.aspose.words.License;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
/**
* Hello world!
*
*/
public class WordTemplate2PdfZip {
public static void main(String[] args) throws Exception {
String prePath = "/root/";
getLicense();
String template = prePath+"template_02.docx";
byte[] readBytes = FileUtil.readBytes(template);
ExecutorService fixedExecutorService = Executors.newFixedThreadPool(8);
long start = System.currentTimeMillis();
for (int i = 0; i < 2; i++) {
Task task = new Task(i, readBytes, start, prePath);
fixedExecutorService.execute(task);
}
fixedExecutorService.shutdown();
boolean isFlag=true;
while (isFlag){
if (fixedExecutorService.isTerminated()){
isFlag=false;
ZipUtil.zip(new File(prePath+"a"));
System.out.println("总共用时:" + (System.currentTimeMillis() - start));
}
}
}
public static boolean getLicense() {
boolean result = false;
try {
InputStream license = App2.class.getClassLoader().getResourceAsStream("license.xml");
License aposeLic = new License();
aposeLic.setLicense(license);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
Task
package com.hdj.test.poi;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.HashMap;
import org.apache.commons.io.output.ByteArrayOutputStream;
import com.aspose.words.Document;
import com.aspose.words.SaveFormat;
import com.deepoove.poi.XWPFTemplate;
public class Task implements Runnable {
private int num;
private byte[] bytes;
private long start;
private String prePath;
public Task(int num, byte[] readBytes, long start, String prePath) {
this.num = num;
this.bytes = readBytes;
this.start = start;
this.prePath = prePath;
}
@Override
public void run() {
System.out.println("正在执行任务 " + num);
try {
// String outDocFile = prePath+"a/out_template{0}.docx";
String pdfFile = prePath+"a/out_template{0}.pdf";
// String thisOutDocFile = MessageFormat.format(outDocFile, String.valueOf(num));
InputStream inputStream = new ByteArrayInputStream(this.bytes);
ByteArrayOutputStream out = new ByteArrayOutputStream();
XWPFTemplate.compile(inputStream).render(new HashMap<String, Object>() {
private static final long serialVersionUID = 1L;
{
put("name", "张三");
put("sex", "男");
}
})
.write(out);
// .writeToFile(thisOutDocFile);
// FileInputStream thisOutDocFileInputStream = new FileInputStream(thisOutDocFile);// 待处理的文件
InputStream thisOutDocFileInputStream = new ByteArrayInputStream(out.toByteArray());
Document doc = new Document(thisOutDocFileInputStream);
File outputFile = new File(MessageFormat.format(pdfFile, String.valueOf(num)));// 输出路径
FileOutputStream fileOS = new FileOutputStream(outputFile);
doc.save(fileOS, SaveFormat.PDF);
inputStream.close();
out.close();
thisOutDocFileInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("线程" + num + "执行完毕,用时:"+ (System.currentTimeMillis() - start));
}
}
license.xml
<License>
<Data>
<Products>
<Product>Aspose.Total for Java</Product>
<Product>Aspose.Words for Java</Product>
</Products>
<EditionType>Enterprise</EditionType>
<SubscriptionExpiry>20991231</SubscriptionExpiry>
<LicenseExpiry>20991231</LicenseExpiry>
<SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber>
</Data>
<Signature>sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=</Signature>
</License>
pom中所有依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.5.1</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
aspose-words-16.8.0-jdk16.jar下载
链接: https://pan.baidu.com/s/1TK2GaOXa9ButHeeKouQBBA 提取码: cdgk