使用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;
	}
}

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

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

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

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

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

exodus3

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值