Vue+Spring实现无打印弹窗多打印机指定打印问题求助
无弹窗多模块指定打印机打印问题排查
我在Spring Boot + Vue.js项目中需实现:无打印弹窗打印应用内三个独立模块内容,且每个模块对应不同打印机。因浏览器限制无法在前端实现,故采用后端处理方案:前端使用html2pdf插件将指定HTML元素转换为PDF,以MultipartFile形式发送至后端;后端采用PDFBox的PrinterJob类执行打印操作,但运行时出现Error: End-of-File, expected line错误,提示文件为空,因Java经验不足,无法定位问题,寻求帮助。
前端HTML转PDF代码
let that = this; html2pdf() .set({ filename: "test.pdf", margin: 4, jsPDF: { orientation: "portrait", }, }) .from(document.getElementById("voucher-body")) .toPdf() .output("datauristring") .then(function(pdfAsString) { const file = new File([pdfAsString], "voucher-body", { type: "application/pdf", lastModified: new Date().getTime(), }); console.log(file); const reader = new FileReader(); reader.readAsText(file); reader.onload = () => console.log(reader.result); const formData = new FormData(); formData.append("data", file); that.printForm({ eventId: that.event.id, doctorId: that.doctor.id, type: "voucher", formFile: formData, }); });
后端Spring处理MultipartFile打印代码
PDDocument document = PDDocument.load(file.getInputStream()); PrinterJob job = PrinterJob.getPrinterJob(); job.setJobName(file.getOriginalFilename()); for (PrintService ps : PrinterJob.lookupPrintServices()) { String psName = ps.toString(); // 选用指定打印机 if (psName.equals("XP-80C (copy 1)")) { job.setPrintService(ps); break; } } job.setPageable(new PDFPageable(document)); Paper paper = new Paper(); // 设置打印纸张大小 paper.setSize(598,842); // 1/72 inch // 设置打印位置 坐标 paper.setImageableArea(0, 0, paper.getWidth(), paper.getHeight()); // no margins // custom page format PageFormat pageFormat = new PageFormat(); pageFormat.setPaper(paper); // override the page format Book book = new Book(); // append all pages 设置一些属性 是否缩放 打印张数等 book.append(new PDFPrintable(document, Scaling.ACTUAL_SIZE), pageFormat, 1); job.setPageable(book); // 开始打印 job.print();
问题排查与修复方案
前端核心问题:Data URI未转成有效二进制PDF
output("datauristring")返回的是data:application/pdf;base64,...格式的字符串,直接用该字符串创建File对象,本质是存储了文本字符串而非PDF二进制数据,后端解析时自然判定文件为空。
修复后的前端代码:
.then(function(pdfAsString) { // 提取base64编码部分,剔除data URI前缀 const base64Content = pdfAsString.split(',')[1]; // 将base64解码为二进制数组 const byteArray = Uint8Array.from(atob(base64Content), char => char.charCodeAt(0)); // 用二进制数组创建合法的PDF文件对象 const file = new File([byteArray], "voucher-body.pdf", { type: "application/pdf", lastModified: new Date().getTime(), }); const formData = new FormData(); formData.append("pdfFile", file); // 统一参数名,方便后端接收 that.printForm({ eventId: that.event.id, doctorId: that.doctor.id, type: "voucher", formFile: formData, }); });
后端优化建议
- 参数名匹配:确保后端MultipartFile参数名与前端
formData.append的key一致(示例中为pdfFile) - 资源释放:打印完成后必须关闭
PDDocument,避免内存泄漏,使用try-with-resources自动管理:
try (PDDocument document = PDDocument.load(file.getInputStream())) { // 原有打印逻辑 job.print(); } catch (Exception e) { e.printStackTrace(); }
- 打印机名称校验:
ps.toString()返回的内容可能包含冗余信息,建议先打印所有打印机的真实名称确认:
for (PrintService ps : PrinterJob.lookupPrintServices()) { System.out.println("打印机真实名称:" + ps.getName()); }
内容的提问来源于stack exchange,提问作者omar kamal
相关产品推荐
相关产品推荐

