阅读 126

程序员必备小知识系列--使用JasperReport报表工具,做出Java项目报表打印功能(三)

上一篇做出来的效果是这样的

在这里插入图片描述

在这里插入图片描述

报表里面有很多功能,你们根据需要来弄。 接下来,是要讲如何在java项目中应用。会在前后端代码实现。

一:前端代码(这里是angular前端,我也不是很擅长前端) 1.页面

 <button type="button" class="btn btn-primary" (click)="previewReport(prodProcessCabinetOrder)">预览</button>  <button type="button" class="btn btn-primary" (click)="printReport(prodProcessCabinetOrder)">打印</button>      <button type="button" class="btn btn-primary" (click)="update(prodProcessCabinetOrder)">修改</button> // 中间省略了一些其他代码 <div class="modal fade" id="pdfViewerModel" role="dialog" tabindex="-1" aria-labelledby="pdfViewerModelLabel">         <div class="modal-dialog modal-lg" role="document" style="width: 60%">             <div class="modal-content">                 <div class="modal-header">                     <button type="button" (click)="close()" class="close" aria-label="Close">                         <span aria-hidden="true">&times;</span>                     </button>                     <h4 class="modal-title" id="pdfViewerModelLabel">打印预览</h4>                 </div>                 <div class="modal-body" style="height: 800px;">                     <ng2-pdfjs-viewer #pdfViewerOnDemand></ng2-pdfjs-viewer>                 </div>             </div>         </div>     </div> 复制代码

2.前端需要导入pdf的模块什么的,这一点不是很了解,不擅长前端

import { PdfJsViewerModule } from 'ng2-pdfjs-viewer'; 复制代码

3.angular也有实体类,跟后台代码一样,不过其他前端框架是没有实体类的(用其他前端框架的,可以忽略)

export class ProdProcessCabinetOrder {     id: number;     orderNo: string;     orderType: string;     drawingNo: string;     productType: string;     customerNo: string;     customerName: string;     consignee: string;     consigneePhone: string;     consigneeAddr: string;     terminalCustomer: string;     documentMakerNo: string;     documentMakerName: string;     documentMakeDate: string;     deliveryDate: string;     orderStatus: number;     processCabinetDetails: ProdProcessCabinetDetail[];     downloadExceled: boolean;     grain: number;     processOrderRouting: ProcessOrderRouting;     refOrderNo: string; } 复制代码

4.前端实现功能(这个类似于ajax什么的)

@ViewChild('pdfViewerOnDemand', { static: false }) pdfViewerOnDemand;   previewReport(prodProcessCabinetOrder: ProdProcessCabinetOrder) {         let fileName = '柜体生产流程单' + prodProcessCabinetOrder.refOrderNo + '.pdf';//给文件名赋值         //根据id找到prodProcessCabinetOrder对象         this.prodProcessCabinetOrderService.getReportById(prodProcessCabinetOrder.id).subscribe(             res => {              //下面几个是给pdfViewerOnDemand属性赋值                 this.pdfViewerOnDemand.pdfSrc = res;                 this.pdfViewerOnDemand.downloadFileName = fileName;                 this.pdfViewerOnDemand.refresh();                 $('#pdfViewerModel').modal({                     backdrop: 'static',                     keyboard: false,                     show: true                 });             },             error => this.errorMessage = <any>error         );     } //打印报表功能     printReport(prodProcessCabinetOrder: ProdProcessCabinetOrder) {         this.prodProcessCabinetOrderService.printReportById(prodProcessCabinetOrder.id).subscribe(             any => { },             error => this.errorMessage = <any>error         );     } //关闭报表     close() {         $('#pdfViewerModel').modal('hide');     } 复制代码

不同于layui,easyui这些前端框架,用的ajax会不一样(思路可以这样:根据id找到该对象,如何就触发其具体功能,把需要的参数传给后端)

二:编译文件以及所需要的文件 jrxml文件,右击,选择Compile Report

在这里插入图片描述

文件编译之后,生成的jasper文件,把需要的jasper文件放到java项目工程里

在这里插入图片描述

我把编译的文件放在resources包下,stsong是字体文件,jasperreports_extension.properties是报表的配置文件

在这里插入图片描述

报表中,我用的是华文字体 在这里插入图片描述

stsong文件下的fonts.xml代码:

<?xml version="1.0" encoding="UTF-8"?> <fontFamilies>          <fontFamily name="华文宋体">         <normal>stsong/stsong.TTF</normal>         <bold>stsong/stsong.TTF</bold>         <italic>stsong/stsong.TTF</italic>         <boldItalic>stsong/stsong.TTF</boldItalic>         <pdfEncoding>Identity-H</pdfEncoding>         <pdfEmbedded>true</pdfEmbedded>         <exportFonts>             <export key="net.sf.jasperreports.html">'华文宋体', Arial, Helvetica, sans-serif</export>             <export key="net.sf.jasperreports.xhtml">'华文宋体', Arial, Helvetica, sans-serif</export>         </exportFonts>             </fontFamily> </fontFamilies> 复制代码

stsong.TTF文件(双击打开是这样的)

在这里插入图片描述

jasperreports_extension.properties文件

net.sf.jasperreports.extension.registry.factory.simple.font.families=net.sf.jasperreports.engine.fonts.SimpleFontExtensionsRegistryFactory net.sf.jasperreports.extension.simple.font.families.lobstertwo=stsong/fonts.xml 复制代码

至于上面说的文件,网上都有,都是下载下来的

三:后端代码(新建javaweb项目那些就不演示了) 记得导入相关的jar包 1.实体类

@Entity public class ProdProcessCabinetOrder { @Id @GeneratedValue private Integer id; private String orderNo; private String orderType; private String drawingNo; private String productType; private String customerNo; private String customerName; private String consignee; private String consigneePhone; private String consigneeAddr; private String terminalCustomer; private String documentMakerNo; private String documentMakerName; private Date documentMakeDate; private Date deliveryDate; @ColumnDefault("0") private int grain; private int orderStatus; @ElementCollection(fetch = FetchType.EAGER) @CollectionTable(name = "prod_process_cabinet_order_process_cabinet_details", joinColumns = @JoinColumn(name = "prod_process_cabinet_order_id")) private List<ProdProcessCabinetDetail> processCabinetDetails;//这个是子对象 private boolean downloadExceled; @ManyToOne private ProcessOrderRouting processOrderRouting; @ColumnDefault("false") private boolean done; private String refOrderNo; } 复制代码

2.子对象

@Embeddable public class ProdProcessCabinetDetail { private String cabinetComponentNo; private String cabinetComponentName; private float cabinetComponentWidth; private float cabinetComponentHeight; @ColumnDefault("0") private float thick; private int cabinetComponentQuantity; private String cabinetComponentItemNo; private String cabinetComponentItemName; private float cabinetComponentItemWidth; private float cabinetComponentItemHeight; private String cabinetEdgeItemNo; private String cabinetEdgeItemName; private String cabinetEdgeItemNo2; private String cabinetEdgeItemName2; private int widthEdgeQty; private int heightEdgeQty; @ColumnDefault("0") private float edge1ItemSize; @ColumnDefault("0") private float edge2ItemSize; private String slot; private String remark; @ColumnDefault("false") private boolean packinged; } 复制代码

3.报表类

public class ProdProcessCabinetReport { private Integer index; private String cabinetComponentName; private float cabinetComponentWidth; private float cabinetComponentHeight; private float cabinetComponentItemWidth; private float cabinetComponentItemHeight; private int cabinetComponentQuantity; private float thick; private String cabinetComponentItemName; private String cabinetEdgeItemName; private String cabinetEdgeItemName2; private String remark; //省略getter,setter } 复制代码

注意:我这里需要多个对象,所以,把代码放出来了。你们根据自己的实际情况,一个实体类也可以的

4.service层代码:

 @Override public ResponseEntity<byte[]> getReportById(Integer id) { ProdProcessCabinetOrder prodProcessCabinetOrder = this.getProdProcessCabinetOrder(id);//根据id找到ProdProcessCabinetOrder对象 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.parseMediaType("application/pdf"));//报表的格式 String pdfName = "柜体生产流程单" + prodProcessCabinetOrder.getRefOrderNo() + ".pdf";//文件名字 headers.setContentDispositionFormData(pdfName, pdfName);//调用HttpHeaders方法 byte[] contents = buildPdfDocument(prodProcessCabinetOrder);//具体实现功能 ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(contents, headers, HttpStatus.OK); prodProcessCabinetOrder.setDownloadExceled(true);//设置相关属性 processCabinetOrderRepository.save(prodProcessCabinetOrder);//保存 return response; } private byte[] buildPdfDocument(ProdProcessCabinetOrder prodProcessCabinetOrder) { ByteArrayOutputStream os = new ByteArrayOutputStream(); try { Resource resource = new ClassPathResource("jasperreport/productionprocess/cabinet/cabinet.jasper");//编译文件的路径 FileInputStream fis = new FileInputStream(resource.getFile()); Resource subReportResource = new ClassPathResource( "jasperreport/productionprocess/cabinet/cabinet_footer.jasper");//第二个编译文件的路径 String footerSubReportPath = subReportResource.getFile().getPath(); fillReportData(prodProcessCabinetOrder, fis, os, footerSubReportPath);//处理文件的具体功能 } catch (IOException | JRException e) { e.printStackTrace(); } return os.toByteArray(); } private void fillReportData(ProdProcessCabinetOrder prodProcessCabinetOrder, FileInputStream fis, ByteArrayOutputStream os, String footerSubReportPath) throws JRException { List<ProdProcessCabinetDetail> prodProcessCabinetDetails = prodProcessCabinetOrder.getProcessCabinetDetails();//获得prodProcessCabinetOrder对象的子对象ProdProcessCabinetDetail Map<String, Object> parameters = fillReportParametersData(prodProcessCabinetOrder, prodProcessCabinetDetails, footerSubReportPath);//生成参数的方法,这些参数是报表里面的那些Parameters,就是从这里赋值的 List<ProdProcessCabinetReport> reportFields = fillReportFieldsData(prodProcessCabinetDetails);//这个是Fields的方法,后台的对应报表里面的Fields JasperRunManager.runReportToPdfStream(fis, os, parameters, new JRBeanCollectionDataSource(reportFields));//报表工具提供的方法,这个方法具体实现可以网上了解一些 } //这个方法是对应报表里面的Parameters,这里赋值,传给报表 private Map<String, Object> fillReportParametersData(ProdProcessCabinetOrder prodProcessCabinetOrder, List<ProdProcessCabinetDetail> prodProcessCabinetDetails, String footerSubReportPath) { String qrCodePic = QRCodeUtil.genQRCodePic(OrderType.PROCESS_CABINET_ORDER.getIndex(), prodProcessCabinetOrder.getOrderNo(), prodProcessCabinetOrder.getRefOrderNo(), qrCodeFileProps);//这个是获得图片路径 Map<String, Object> parameters = new HashMap<String, Object>(); parameters.put("reportTitle", "柜体生产流程单"); parameters.put("qrCodePic", qrCodePic); parameters.put("refOrderNo", prodProcessCabinetOrder.getRefOrderNo()); parameters.put("orderType", prodProcessCabinetOrder.getOrderType()); parameters.put("productType", prodProcessCabinetOrder.getProductType()); parameters.put("drawingNo", prodProcessCabinetOrder.getDrawingNo()); parameters.put("deliveryDate", DateFormat.formatDate("yyyy-MM-dd", prodProcessCabinetOrder.getDeliveryDate())); parameters.put("terminalCustomer", prodProcessCabinetOrder.getTerminalCustomer()); double sumComponItemsArea = prodProcessCabinetOrder.sumComponItemsArea(); parameters.put("sumComponItemsArea", (double) (Math.round(sumComponItemsArea * 100)) / 100); parameters.put("sumQty", prodProcessCabinetOrder.sumQty()); parameters.put("customerName", prodProcessCabinetOrder.getCustomerName()); parameters.put("documentMakeDate", DateFormat.formatDate("yyyy-MM-dd", prodProcessCabinetOrder.getDocumentMakeDate())); parameters.put("documentMakerName", prodProcessCabinetOrder.getDocumentMakerName()); parameters.put("cabinet_footer_report_path", footerSubReportPath); return parameters; } //这个方法和下面的方法是生成Fields数据,对应报表的Fields private List<ProdProcessCabinetReport> fillReportFieldsData( List<ProdProcessCabinetDetail> prodProcessCabinetDetails) { List<ProdProcessCabinetReport> reportFields = new ArrayList<ProdProcessCabinetReport>(); if (prodProcessCabinetDetails != null && prodProcessCabinetDetails.size() > 0) { int index = 1; for (ProdProcessCabinetDetail detail : prodProcessCabinetDetails) { fillReportFieldData(detail, reportFields, index); index++; } } return reportFields; } //获得Fields数据 private void fillReportFieldData(ProdProcessCabinetDetail detail, List<ProdProcessCabinetReport> reportFields, int index) { ProdProcessCabinetReport processCabinetReport = new ProdProcessCabinetReport(); processCabinetReport.setIndex(index); processCabinetReport.setCabinetComponentName(detail.getCabinetComponentName()); processCabinetReport.setCabinetComponentWidth(detail.getCabinetComponentWidth()); processCabinetReport.setCabinetComponentHeight(detail.getCabinetComponentHeight()); processCabinetReport.setCabinetComponentItemWidth(detail.getCabinetComponentItemWidth()); processCabinetReport.setCabinetComponentItemHeight(detail.getCabinetComponentItemHeight()); processCabinetReport.setCabinetComponentQuantity(detail.getCabinetComponentQuantity()); processCabinetReport.setThick(detail.getThick()); processCabinetReport.setCabinetComponentItemName(detail.getCabinetComponentItemName()); processCabinetReport.setCabinetEdgeItemName(detail.getCabinetEdgeItemName()); processCabinetReport.setCabinetEdgeItemName2(detail.getCabinetEdgeItemName2()); processCabinetReport.setRemark(detail.getRemark()); reportFields.add(processCabinetReport); } @Override public void printReportById(Integer id) { ProdProcessCabinetOrder processCabinetOrder = this.getProdProcessCabinetOrder(id); byte[] pdfByte = this.buildPdfDocument(processCabinetOrder); PdfPrintUtil pdfPrintUtil = new PdfPrintUtil(); pdfPrintUtil.printPdf(pdfByte, "######"); } 复制代码

打印方法

public class PdfPrintUtil { public void printPdf(byte[] pdfByte, String printerName) { PDDocument document = null; try { document = PDDocument.load(pdfByte); PrinterJob job = setPrinterJonParas(document, printerName); job.print(); } catch (IOException | PrinterException e) { System.out.println("打印pdf文件出错"); e.printStackTrace(); } finally { if (document != null) { try { document.close(); } catch (IOException e) { System.out.println("关闭pdf-document出错"); e.printStackTrace(); } } } } /***  *   * @param document  * @param printerName  *            打印机名称  * @return 没有指定则找默认的打印机  * @throws PrinterException  */ private PrinterJob setPrinterJonParas(PDDocument document, String printerName) throws PrinterException { // 设置纸张及缩放 PDFPrintable pdfPrintable = new PDFPrintable(document, Scaling.ACTUAL_SIZE); PageFormat pageFormat = new PageFormat(); // 设置打印方向(横向) pageFormat.setOrientation(PageFormat.LANDSCAPE); // 设置纸张属性 pageFormat.setPaper(this.getPaper()); Book book = new Book(); book.append(pdfPrintable, pageFormat, document.getNumberOfPages()); PrinterJob job = PrinterJob.getPrinterJob(); job.setPrintService(this.getPrinter(printerName)); job.setPageable(book); // 设置打印份数 job.setCopies(1); return job; } private Paper getPaper() { Paper paper = new Paper(); // 默认为A4纸张,对应像素宽和高分别为595,842 int width = 595; int height = 842; // 设置边距,单位是像素 int marginLeft = 0, marginRight = 0, marginTop = 0, marginBottom = 0; paper.setSize(width, height); paper.setImageableArea(marginLeft, marginTop, width - (marginLeft + marginRight), height - (marginTop + marginBottom)); return paper; } private PrintService getPrinter(String printerName) { DocFlavor psInFormat = DocFlavor.INPUT_STREAM.PDF; PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet(); // A4纸 pras.add(MediaSizeName.ISO_A4); // 单页 pras.add(Sides.ONE_SIDED); PrintService[] printServices = PrintServiceLookup.lookupPrintServices(psInFormat, pras); PrintService myPrinter = null; for (PrintService printService : printServices) { System.out.println("打印机名字" + printService.getName()); if (printService.getName().contains(printerName)) { myPrinter = printService; break; } } if (myPrinter == null) { myPrinter = PrintServiceLookup.lookupDefaultPrintService(); } return myPrinter; } } 复制代码

可以参考我写的方法,但不一定适合。总结来说,从实体类对象把值赋给了对应的报表

参考效果:

在这里插入图片描述

点击预览,效果如下 在这里插入图片描述

打印功能也是可以的。记得连接打印机

更多功能,这里就不一 一展示了。


作者:exodus3
链接:https://juejin.cn/post/7020798085534056462


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐