pdf.js 是一块将pdf文件进行再加工然后页面展示的小插件,可以实现自定义水印、编辑下载打印权限等功能。
开发过程遇到很多问题,可以直接看最后一部分。
show time
1、下载 http://mozilla.github.io/pdf.js/getting_started/#download
下载后的文件这样
附一个下载地址 https://files.cnblogs.com/files/xiufengd/pdfjs-2.16.105-dist.zip?t=1667295509
2、服务端提供二进制流的文件 代码如下
@GetMapping("/show") @ResponseBody public void showReportPDF(String id, @RequestHeader("Referer") String referer){ HttpServletResponse response = ApplicationContextUtil.getHttpServletResponse(); String Host = profiles.equals("test")? "testurl" : profiles.equals("prod")? "produrl" : "";
// 来源检测,文件一般都是比较重要的 所以想要检测同源 if(referer.indexOf(Host)==-1&&referer.indexOf("localhost:8080")==-1){ throw new BusinessException(GsonUtil.toJson(new Message(MessageCode.NOAUTH.getCode(),"无权限"))); } try {
// reportService.getReportInputStream 是返回一个InputStream类型的方法 用于从数据库或者其他地方获取文件的InputStream流 BufferedInputStream br = new BufferedInputStream(reportService.getReportInputStream(id)); byte[] buf = new byte[1024]; int len = 0; response.reset(); // 非常重要 response.setContentType("application/pdf");
// 处理直接请求跨域问题 一定注意是用addHeader 而不是setHeader response.addHeader("Access-Control-Allow-Origin", "*"); response.addHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE"); response.addHeader("Content-Disposition", "inline; filename=" + java.net.URLEncoder.encode(id+".pdf", "UTF-8")); // 将文件流输出到response中 OutputStream out = response.getOutputStream(); while ((len = br.read(buf)) != -1) { out.write(buf, 0, len); out.flush(); } br.close(); out.close(); } catch (IOException e) { throw new RuntimeException(e); } }
3、前端 注意 调用要用原生的ajax 否则会造成展示的文件页面正确但是内容为空的情况!!!
var xhr = new XMLHttpRequest(); xhr.open( "get","http://localhost:8000/report/show?id=22222", true );
// 注意类型是blob xhr.responseType = "blob";
// 如果有权限校验 记得添加header xhr.setRequestHeader("token", "222222"); xhr.onload = function() {
// 将返回的response构建URL 然后传输到插件里 const url = window.URL.createObjectURL(this.response); window.open("/pdf/web/viewer.html?file=" + url);
//展示2秒钟后 将链接失效 方式连接泄露 setTimeout(() => window.URL.revokeObjectURL(url), 2000); }; xhr.send();
4、个性化设置
如果想禁用下载、打印、复制之类的工作,想要编辑 pdf\web\viewer.html 这个文件 在header里添加以下代码
<script> // 禁止右键、区域选择和复制 oncontextmenu="window.event.returnValue=false" oncopy ="window.event.returnValue=false" ondragstart ="window.event.returnValue=false" onselectstart="window.event.returnValue=false" // 禁止键盘操作 window.onkeydown = window.onkeyup = window.onkeypress = function (event) { event.preventDefault(); // 阻止默认事件行为 window.event.returnValue = false; } // 屏蔽功能按钮 function onBodyLoad(){ var appConfig = PDFViewerApplication.appConfig; appConfig.toolbar.viewBookmark.setAttribute('hidden', 'true'); appConfig.secondaryToolbar.viewBookmarkButton.setAttribute('hidden', 'true'); appConfig.toolbar.openFile.setAttribute('hidden', 'true'); appConfig.secondaryToolbar.openFileButton.setAttribute('hidden', 'true'); appConfig.toolbar.download.setAttribute('hidden', 'true'); appConfig.secondaryToolbar.downloadButton.setAttribute('hidden', 'true'); appConfig.toolbar.print.setAttribute('hidden', 'true'); appConfig.secondaryToolbar.printButton.setAttribute('hidden', 'true'); } // 禁止右键下载,打印 function stop(){ return false; } document.oncontextmenu = stop; </script>
5、问题点
5.1 打开新页面后一片空白,但是接口返回正常
不能用axios来调用,要用最原始的ajax来调用
5.2 页面正常打开,表格展示正常,但是文字不显示
字体没有正确加载 ,将viewer.js的cMapUrl内容"../web/cmaps/"修改为“https://cdn.jsdelivr.net/npm/pdfjs-dist@2.16.105/cmaps/”
5.3 工具栏图标没有正常加载,单独访问提示跨域
pdf/web/images下的svg图片加载失败,转换成png图片并修改viewer.css里的引用即可