抱歉,您的瀏覽器無法訪問本站
本頁面需要瀏覽器支持(啟用)JavaScript
了解詳情 >

前言

最近在一个接的私活中,甲方提出一个点击按钮,浏览器显示评价详情报表并打印的需求。这个需求乍一听的时候有点懵,不知从何下手,如何导出?如何适配多种报表格式、如何让浏览器打印?

经过一整子的资料收集,理清了技术的可行性以及所要使用的相关框架,下面先来看下最终实现的效果~

image-20230401162036334

即PDF的每一页都是上图的模样,同时刚刚进入该页面时会打开浏览器的打印功能,例如下图的样子,功能的实现主要工作量都在后台完成,这就是我们最终实现的效果

image-20230401162240113

技术栈

名称 版本
SpringBoot 2.4.5
poi-tl 1.12.1
aspose-words 15.8

思路

生成PDF

可以看到上图的内容是一个表格数据,因此我们先考虑如何生成动态表格,可以通过poi-tl框架来实现表格的生成,具体的使用可以看之前写的水文

通过继承DynamicTableRenderPolicy类来实现复杂word表格的实现,该类的使用可以去框架官网查看,这里就不复制了。

当word文档生成成功后,就会发现这只是一个docx的文档,因此我们需要将其转换为PDF的类型,为此我们需要一个能够将word文档转换为PDF的框架。

网上大致有两种推荐

  • fr.opensagres.poi.xwpf.converter.pdf
  • aspose-words

先说fr.opensagres.poi.xwpf.converter.pdf框架,自己实测Word文档转换为PDF格式会出现错位,表格布局尤其明显,但他的使用十分简单,只需要引入Jar包便可以使用。

1
2
3
String wordPath ="demo.docx";
String pdfPath = "demo.pdf";
PdfConverter.getInstance().convert(new XWPFDocument(FileUtil.getInputStream(wordPath)), FileUtil.getOutputStream(pdfPath), PdfOptions.create());

如果不在意转换后错位的问题,或者内容只有纯文本等可以考虑使用该框架。

说回本需求,由于甲方不能接受PDF不美观的问题,因此我们需要使用另一种框架aspose-words

aspose-words是需要购买的,但他提供了很好的无损转换效果,因此我们需要使用一些手段来获得,这些网上有很多资源提供。当我们引入jar包执行对应的转换方法后,就会发现几乎无损的转换为PDF了。

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
@Slf4j
public class PdfUtils {

private static boolean getLicense() {
boolean result = false;
try {
InputStream inputStream = PdfUtils.class.getClassLoader().getResourceAsStream("license.xml");
License license = new License();
license.setLicense(inputStream);
result = true;
} catch (Exception e) {
throw new OperateException("获得license文件出错:{}", ExceptionUtil.stacktraceToString(e));
}
return result;
}

public static void doc2pdf(String wordPath, String pdfPath) {
// 验证License 若不验证则转化出的pdf文档会有水印产生
if (BooleanUtil.isFalse(getLicense())) {
return;
}
File file = new File(pdfPath);
try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
long old = System.currentTimeMillis();
Document doc = new Document(wordPath);
doc.save(fileOutputStream, SaveFormat.PDF);
long now = System.currentTimeMillis();
log.info("{}转换为{}共耗时{}秒", wordPath, pdfPath, ((now - old) / 1000.0));
} catch (Exception e) {
throw new OperateException("转换{}为{}时出错:{}", wordPath, pdfPath, ExceptionUtil.stacktraceToString(e));
}
}
}

open+print实现打印

当我们成功将word文档转换为PDF后,就可以开始前端打印的工作了,JavaScript提供了window.print()方法来调用浏览器的打印功能,因此就很简单啦。

前端核心代码如下,后台返回对应PDF的链接,浏览器通过open方法在新页面打开,随后等待其加载完后调用print方法。

1
2
3
4
const pdfWindow = window.open(baseUrl+response)
pdfWindow.window.onload = function(){
pdfWindow.window.print()
}