Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities.

The result of the previous article is this

There are many functions in the report, you can make them according to your needs. Next, I’ll show you how to use it in a Java project. Will be implemented in the back and forth code.

Front-end code (here’s the Angular front-end, which I’m not very good at either) 1. page

 <button type="button" class="btn btn-primary" (click) ="previewReport(prodProcessCabinetOrder)">preview</button>
 <button type="button" class="btn btn-primary" (click) ="printReport(prodProcessCabinetOrder)">print</button>    
 <button type="button" class="btn btn-primary" (click) ="update(prodProcessCabinetOrder)">Modify the</button>// Some other code is omitted<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">Print preview</h4>
                </div>
                <div class="modal-body" style="height: 800px;">
                    <ng2-pdfjs-viewer #pdfViewerOnDemand></ng2-pdfjs-viewer>
                </div>
            </div>
        </div>
    </div>
Copy the code

2. The front-end needs to import PDF modules, which is not very understanding, not good at the front-end

import { PdfJsViewerModule } from 'ng2-pdfjs-viewer';
Copy the code

3. Angular has entity classes, just like backend code, but other front-end frameworks do not have entity classes.

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;
}
Copy the code

4. Front-end implementation functionality (this is like Ajax or something)

@ViewChild('pdfViewerOnDemand', { static: false }) pdfViewerOnDemand;
 
previewReport(prodProcessCabinetOrder: ProdProcessCabinetOrder) {
        let fileName = 'Cabinet Production Process Sheet' + prodProcessCabinetOrder.refOrderNo + '.pdf';// Assign a value to the filename
        // Find the prodProcessCabinetOrder object based on its ID
        this.prodProcessCabinetOrderService.getReportById(prodProcessCabinetOrder.id).subscribe(
            res= > {
            	// The following attributes are assigned to the pdfViewerOnDemand attribute
                this.pdfViewerOnDemand.pdfSrc = res;
                this.pdfViewerOnDemand.downloadFileName = fileName;
                this.pdfViewerOnDemand.refresh();
                $('#pdfViewerModel').modal({
                    backdrop: 'static'.keyboard: false.show: true
                });
            },
            error= > this.errorMessage = <any>error
        );
    }

	// Print reports
    printReport(prodProcessCabinetOrder: ProdProcessCabinetOrder) {
        this.prodProcessCabinetOrderService.printReportById(prodProcessCabinetOrder.id).subscribe(
            any= >{},error= > this.errorMessage = <any>error
        );
    }
	// Close the report
    close(){$('#pdfViewerModel').modal('hide');
    }
Copy the code

Different from layui, Easyui and other front-end frameworks, ajax will be different (the idea can be as follows: find the object by ID, how to trigger its specific function, and pass the required parameters to the back-end).

Two: Compile file and the required file JRXML file, right click, select Compile Report

After the files are compiled, the generated Jasper files are put into the Java project

I put the compiled files in the Resources package, stsong is the font file and JasperReports_extension.properties is the configuration file for the report

In the report, I used a Chinese font

Fonts.xml code in stsong file:


      

<fontFamilies>

    
    <fontFamily name="Song Style in Chinese">
        <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">'Chinese Font style ', Arial, Helvetica, Sans-serif</export>
            <export key="net.sf.jasperreports.xhtml">'Chinese Font style ', Arial, Helvetica, Sans-serif</export>
        </exportFonts>
       
    </fontFamily>
</fontFamilies>
Copy the code

Stsong-ttf file (double-click to open it like this)

Jasperreports_extension. The properties file

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
Copy the code

As for the above mentioned documents, there are online, are downloaded down

Three: the back-end code (new JavaWeb project those will not be demonstrated) remember to import the relevant JAR package 1. Entity class

@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;// This is a child object
	private boolean downloadExceled;
	@ManyToOne
	private ProcessOrderRouting processOrderRouting;
	@ColumnDefault("false")
	private boolean done;
	private String refOrderNo;
}
Copy the code

2. Child objects

@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;
}
Copy the code

3. The report class

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;
	/ / omitted getters and setters
}
Copy the code

Note: I need more than one object here, so put the code out there. Depending on your situation, an entity class is fine

4. Service layer code:

	@Override
	public ResponseEntity<byte[]> getReportById(Integer id) {
		ProdProcessCabinetOrder prodProcessCabinetOrder = this.getProdProcessCabinetOrder(id);// Find the ProdProcessCabinetOrder object based on its ID
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.parseMediaType("application/pdf"));// Report format
		String pdfName = "Cabinet Production Process Sheet" + prodProcessCabinetOrder.getRefOrderNo() + ".pdf";// File name
		headers.setContentDispositionFormData(pdfName, pdfName);// Call the HttpHeaders method
		byte[] contents = buildPdfDocument(prodProcessCabinetOrder);// Specify the function
		ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(contents, headers, HttpStatus.OK);
		prodProcessCabinetOrder.setDownloadExceled(true);// Set the related properties
		processCabinetOrderRepository.save(prodProcessCabinetOrder);/ / save
		return response;
	}

	private byte[] buildPdfDocument(ProdProcessCabinetOrder prodProcessCabinetOrder) {
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		try {
			Resource resource = new ClassPathResource("jasperreport/productionprocess/cabinet/cabinet.jasper");// The path to the compiled file
			FileInputStream fis = new FileInputStream(resource.getFile());
			Resource subReportResource = new ClassPathResource(
					"jasperreport/productionprocess/cabinet/cabinet_footer.jasper");// The path to the second compiled file
			String footerSubReportPath = subReportResource.getFile().getPath();
			fillReportData(prodProcessCabinetOrder, fis, os, footerSubReportPath);// Handle file specific functions
		} 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();// Get the ProdProcessCabinetDetail, a child of the prodProcessCabinetOrder object
		Map<String, Object> parameters = fillReportParametersData(prodProcessCabinetOrder, prodProcessCabinetDetails,
				footerSubReportPath);// The method to generate the Parameters in the report from which the values are assigned
		List<ProdProcessCabinetReport> reportFields = fillReportFieldsData(prodProcessCabinetDetails);// This is the Fields method, which corresponds to the Fields in the background report
		JasperRunManager.runReportToPdfStream(fis, os, parameters, new JRBeanCollectionDataSource(reportFields));// Reporting tools provide a method, this method can be implemented on the web to learn some
	}
	
	// This method is the Parameters in the corresponding report, which is assigned to the report
	private Map<String, Object> fillReportParametersData(ProdProcessCabinetOrder prodProcessCabinetOrder, List
       
         prodProcessCabinetDetails, String footerSubReportPath)
        {
		String qrCodePic = QRCodeUtil.genQRCodePic(OrderType.PROCESS_CABINET_ORDER.getIndex(),
				prodProcessCabinetOrder.getOrderNo(), prodProcessCabinetOrder.getRefOrderNo(), qrCodeFileProps);// This is the path to get the image
		Map<String, Object> parameters = new HashMap<String, Object>();
		parameters.put("reportTitle"."Cabinet Production Process Sheet");
		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;
	}

	// This method and the following method generate Fields data corresponding to the Fields of the report
	private List<ProdProcessCabinetReport> fillReportFieldsData( List
       
         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;
	}
	
	// Get the Fields data
	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, "# # # # # #");
	}
Copy the code

Printing method

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("Error printing PDF file");
			e.printStackTrace();
		} finally {
			if(document ! =null) {
				try {
					document.close();
				} catch (IOException e) {
					System.out.println("Error closing PDF-document"); e.printStackTrace(); }}}}/ * * * * *@param document
	 * @paramPrinterName * printerName *@returnIf not specified, find the default printer *@throws PrinterException
	 */
	private PrinterJob setPrinterJonParas(PDDocument document, String printerName) throws PrinterException {
		// Set the paper and zoom
		PDFPrintable pdfPrintable = new PDFPrintable(document, Scaling.ACTUAL_SIZE);
		PageFormat pageFormat = new PageFormat();
		// Set the print direction (landscape)
		pageFormat.setOrientation(PageFormat.LANDSCAPE);
		// Set the paper property
		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);
		// Set the number of copies to print
		job.setCopies(1);
		return job;
	}

	private Paper getPaper(a) {
		Paper paper = new Paper();
		// Default is A4 paper, corresponding to the pixel width and height of 595,842
		int width = 595;
		int height = 842;
		// Set the margin in pixels
		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 paper
		pras.add(MediaSizeName.ISO_A4);
		/ / a single page
		pras.add(Sides.ONE_SIDED);
		PrintService[] printServices = PrintServiceLookup.lookupPrintServices(psInFormat, pras);
		PrintService myPrinter = null;
		for (PrintService printService : printServices) {
			System.out.println("Printer name" + printService.getName());
			if (printService.getName().contains(printerName)) {
				myPrinter = printService;
				break; }}if (myPrinter == null) {
			myPrinter = PrintServiceLookup.lookupDefaultPrintService();
		}
		returnmyPrinter; }}Copy the code

You can refer to the method I wrote, but not necessarily suitable. In summary, values are assigned to the corresponding report from the entity-class object

Reference effect:

Click preview to see the following effect

Printing is also available. Remember to connect the printer

More functions, which are not shown here.