个人博客 个人博客

2020 记录精彩的程序人生

目录
使用 iTextPDF 实现 Java 在线预览 PDF 并分页
/  

使用 iTextPDF 实现 Java 在线预览 PDF 并分页

输出 PDF 表格

前端部分

printReport(houseCustomQuotationOrder: HouseCustomQuotationOrder) {
	return this.http.put(this.url + '/print-report', houseCustomQuotationOrder, {
		headers: new HttpHeaders().set('content-type', 'application/json; charset=utf-8'),
		responseType: 'blob',
	}).map(response => {
		return response;
	}).catch(handleError);
}

后端部分
controller:

@PutMapping(value = "/print-report", consumes = "application/json;charset=UTF-8", produces = "application/pdf")
public ResponseEntity<byte[]> printReport(@RequestBody HouseCustomQuotationOrder houseCustomQuotationOrder) {
	return printReportService.printReport(houseCustomQuotationOrder);
}

service:

import org.springframework.http.ResponseEntity;

public interface PrintReportService {
    ResponseEntity<byte[]> printReport(HouseCustomQuotationOrder houseCustomQuotationOrder);
}

serviceImpl:

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import com.intelliwserp.cupboard.util.LoggerUtil;
import com.intelliwserp.cupboard.util.PdfUtil;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;

@Service
@Transactional
public class PrintReportServiceImpl implements PrintReportService {

	@Override
	public ResponseEntity<byte[]> printReport(HouseCustomQuotationOrder houseCustomQuotationOrder) {
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.parseMediaType("application/pdf"));
		String pdfName = "报价单.pdf";
		headers.setContentDispositionFormData(pdfName, pdfName);
		byte[] contents = genePdfDocument(houseCustomQuotationOrder);
		ResponseEntity<byte[]> response = new ResponseEntity<>(contents, headers, HttpStatus.OK);
		return response;
	}

	private byte[] genePdfDocument(HouseCustomQuotationOrder houseCustomQuotationOrder) {
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		try {
			Document document = new Document(PageSize.A4.rotate(), 20, 20, 20, 0);
			Rectangle rectangle = document.getPageSize();
			BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
			PdfWriter writer = PdfWriter.getInstance(document, os);
			writer.setPageEvent(new PdfUtil.ItextPdfHeaderFooter(12, rectangle, bfChinese));
			document.open();
			PdfContentByte cb = writer.getDirectContent();

			Font contentFont = new Font(bfChinese, 11, Font.NORMAL);
			PdfUtil.setTitle(document, rectangle, cb, new Font(bfChinese, 24, Font.NORMAL), "报价单");
			float startYPos = setHeaderTable(document, cb, contentFont, houseCustomQuotationOrder);
			startYPos = setCabElementsTable(document, cb, contentFont, houseCustomQuotationOrder, startYPos);
			startYPos = setTotalAmountTable(document, cb, contentFont, houseCustomQuotationOrder, startYPos);
			document.close();
		} catch (Exception e) {
			LoggerUtil.log(HouseCustomQuotationOrderException.class, "打印报价单", e);
		}
		return os.toByteArray();
	}

	private float setHeaderTable(Document document, PdfContentByte cb, Font contentFont,
			HouseCustomQuotationOrder houseCustomQuotationOrder) {
		PdfPTable table = PdfUtil.createTable(2, 800, new float[] { 420, 380 });
		String[] headerElements = new String[] { "客户名称:", "订单类型:", "终端客户:", "订单编号:" };
		String[] headerContents = new String[] { houseCustomQuotationOrder.getCustomerName(),
				houseCustomQuotationOrder.getOrderTypeName(), houseCustomQuotationOrder.getTerminalCustomer(),
				houseCustomQuotationOrder.getOrderNo() };
		for (int i = 0; i < headerElements.length; i++) {
			Paragraph paragraph = PdfUtil.createParagraph(new Chunk(headerElements[i], contentFont),
					new Chunk(headerContents[i], contentFont));
			PdfPCell receiptCell = PdfUtil.createLeftCell(paragraph, 18, 0.5f);
			table.addCell(receiptCell);
		}
		float startYPos = document.top() - 32;
		table.writeSelectedRows(0, -1, document.left(), startYPos, cb);
		return startYPos - table.getTotalHeight();
	}

	private float setCabElementsTable(Document document, PdfContentByte cb, Font font,
			HouseCustomQuotationOrder houseCustomQuotationOrder, float startYPos) {
		float[] colsWidth = { 30, 120, 130, 50, 50, 40, 50, 50, 50, 50, 50, 50, 80 };
		int numColumns = colsWidth.length;
		float totalWidth = getTotalWidth(colsWidth);
		List<HouseCustomQuotationCabinet> quotationCabinets = new ArrayList<>(
				houseCustomQuotationOrder.getQuotationCabinets());
		quotationCabinets.add(new HouseCustomQuotationCabinet("合计", houseCustomQuotationOrder.calCabinetQuantity(),
				houseCustomQuotationOrder.calCabinetCountQty(), houseCustomQuotationOrder.calCabinetAmount(),
				houseCustomQuotationOrder.getSubCabinetActualAmount()));
		return this.setCabElementTableDetailsByPage(document, cb, startYPos, quotationCabinets, colsWidth, numColumns,
				totalWidth, font);
	}

	private float setTotalAmountTable(Document document, PdfContentByte cb, Font font,
			HouseCustomQuotationOrder houseCustomQuotationOrder, float startYPos) {
		float[] colsWidth = { 114, 114, 114, 114, 114, 115, 115 };
		PdfPTable table = PdfUtil.createTable(colsWidth.length, 800, colsWidth);
		float limitHeight = startYPos - document.bottom() - 10 - 15;
		String[] elements = new String[] { "报价汇总", "单元柜", "柜体", "门板", "五金电器", "其它费用", "小计" };
		createElementHeader(table, font, elements);
		createTotalAmountRow(table, font, "计算金额", houseCustomQuotationOrder.calUnitCabinetAmount(),
				houseCustomQuotationOrder.calCabinetAmount(), houseCustomQuotationOrder.calDoorPanelAmount(),
				houseCustomQuotationOrder.calHardwareAmount(), houseCustomQuotationOrder.calOtherAmount(),
				houseCustomQuotationOrder.getOrderAmount());
		createTotalAmountRow(table, font, "应付金额", houseCustomQuotationOrder.getSubUnitCabinetActualAmount(),
				houseCustomQuotationOrder.getSubCabinetActualAmount(),
				houseCustomQuotationOrder.getSubDoorPanelActualAmount(),
				houseCustomQuotationOrder.getSubHardwareActualAmount(),
				houseCustomQuotationOrder.getSubOtherActualAmount(), houseCustomQuotationOrder.getActualAmount());
		if (limitHeight - table.getTotalHeight() < 0) {
			table.getRows().clear();
			document.newPage();
			return this.setTotalAmountTable(document, cb, font, houseCustomQuotationOrder, document.top());
		}
		table.writeSelectedRows(0, -1, document.left(), startYPos, cb);
		return startYPos - table.getTotalHeight();
	}

	private float setCabElementTableDetailsByPage(Document document, PdfContentByte cb, float startYPos,
			List<HouseCustomQuotationCabinet> quotationCabinets, float[] colsWidth, int numColumns, float totalWidth,
			Font font) {
		if (quotationCabinets != null && !quotationCabinets.isEmpty()) {
			// 减15(下面页码的高度),减10(与下面页码保持一定的距离),减document.bottom()(下边距)
			float limitHeight = startYPos - document.bottom() - 10 - 15;
			boolean hasSecondPage = false;
			PdfPTable table = PdfUtil.createTable(numColumns, totalWidth, colsWidth);
			String[] elements = new String[] { "序号", "柜体名称", "规格材质", "宽", "高", "深", "数量", "计价数量", "计价单位", "单价", "计算金额",
					"应付金额", "备注" };
			createElementHeader(table, font, elements);
			int index = 0;
			for (HouseCustomQuotationCabinet quotationCabinet : quotationCabinets) {
				createRow(font, table, String.valueOf(index + 1), quotationCabinet.getCabinetItemName(),
						quotationCabinet.getSpec(), quotationCabinet.getWidth(), quotationCabinet.getHeight(),
						quotationCabinet.getDepth(), quotationCabinet.getQuantity(), quotationCabinet.getCountQty(),
						quotationCabinet.getUnitNo(), quotationCabinet.getQuotationUnitPrice(),
						quotationCabinet.getAmount(), quotationCabinet.getActualAmount(), quotationCabinet.getRemark());

				if (limitHeight - table.getTotalHeight() < 0) {
					table.deleteLastRow();
					hasSecondPage = true;
					break;
				}
				index++;
			}
			table.writeSelectedRows(0, -1, document.left(), startYPos, cb);
			startYPos = hasSecondPage ? document.top() : startYPos - table.getTotalHeight();
			if (hasSecondPage) {
				document.newPage();
				startYPos = this.setCabElementTableDetailsByPage(document, cb, startYPos,
						quotationCabinets.subList(index, quotationCabinets.size()), // 排除掉已写完的明细,递归
						colsWidth, numColumns, totalWidth, font);
			}
		}
		return startYPos;
	}

	private void createRow(Font font, PdfPTable table, String seqNo, String itemName, String spec, float width,
			float height, float depth, float quantity, float countQty, String unitNo, float quotationUnitPrice,
			float amount, float actualAmount, String remark) {
		addCell(table, font, seqNo);
		addCell(table, font, itemName);
		addCell(table, font, spec);
		addCell(table, font, String.valueOf(width == 0 ? "" : width));
		addCell(table, font, String.valueOf(height == 0 ? "" : height));
		addCell(table, font, String.valueOf(depth == 0 ? "" : depth));
		addCell(table, font, quantity == 0 ? "" : String.format("%.1f", quantity));
		addCell(table, font, countQty == 0 ? "" : String.format("%.3f", countQty));
		addCell(table, font, unitNo);
		addCell(table, font, String.valueOf(quotationUnitPrice == 0 ? "" : quotationUnitPrice));
		addCell(table, font, amount == 0 ? "" : String.format("%.2f", amount));
		addCell(table, font, actualAmount == 0 ? "" : String.format("%.2f", actualAmount));
		addCell(table, font, remark);
	}

	private void createTotalAmountRow(PdfPTable table, Font font, String amount, float unitCabAmount, float cabAmount,
			float dpAmount, float hardwareAmount, float otherAmount, float totalAmount) {
		addCell(table, font, amount);
		addCell(table, font, String.valueOf(unitCabAmount));
		addCell(table, font, String.valueOf(cabAmount));
		addCell(table, font, String.valueOf(dpAmount));
		addCell(table, font, String.valueOf(hardwareAmount));
		addCell(table, font, String.valueOf(otherAmount));
		addCell(table, font, String.valueOf(totalAmount));
	}

	private void createElementHeader(PdfPTable table, Font font, String[] elements) {
		for (String element : elements) {
			addCell(table, font, element);
		}
	}

	private void addCell(PdfPTable table, Font font, String content) {
		PdfPCell cell1 = PdfUtil.createCenterCell(new Paragraph(content, font), 16, 0.5f);
		table.addCell(cell1);
	}

	private float getTotalWidth(float[] colsWidth) {
		float totalWidth = 0;
		for (float width : colsWidth) {
			totalWidth += width;
		}
		return totalWidth;
	}
}

显示效果:
3.png
以上就是 iTexPdf 的基本使用。