前言

版本:
SpringBoot:2.3.1.RELEASE
itextpdf:5.4.3

最近在做SpringBoot+Vue的项目,需要将委托单商品的数据导出为PDF文档。Java的PDF操作第三方工具类用的最多的应该是itextpdf了吧,当然以前也用过icepdf这种小众的。那现在就来看看用itextpdf怎么做,还是很简单的。
首先前端页面如下,可以导出箱单和发票两种格式的PDF文件:

一、引入itextpdf依赖
<!--PDF导出-->
<dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.4.3</version>
</dependency>

只需要这一个包就可以了。网上其他教程引了一大堆包,完全没必要。

二、主要业务代码
导出发票
 /*** 导出PDF格式发票** @param id* @return io.zbus.transport.Message* @author ZHANGCHAO* @date 2021/1/26 13:42**/public Message exportCommercialInvoiceOfPdf(String id) {Apply apply = baseMapper.selectById(id);if (isEmpty(apply)) {return null;}String tenantId = RequestKit.getRequestIn().getHeader(TENANT_ID);Message res = new Message();RequestKit.copyHeaders(false, TENANT_ID, HEADER_TOKEN, TENANT_TYPE);List<ApplyInvoices> applyInvoicesList = applyInvoicesMapper.selectList(new QueryWrapper<ApplyInvoices>().lambda().eq(ApplyInvoices::getApplyNumber, id).orderByAsc(ApplyInvoices::getSequence));apply.setApplyInvoicesList(applyInvoicesList);// pdf文件名String fileName = "发票_" + (isNotBlank(apply.getInvoiceNo()) ? apply.getInvoiceNo() : "无发票号") + ".pdf";String path = ProjectPath.getExportPdfPath() + File.separator;File file = new File(path);if (!file.exists()) { // 如果文件夹不存在file.mkdir(); // 创建文件夹}String filePath = path + fileName;/*****************创建PDF开始*********************//** 实例化文档对象 */Document document = new Document(PageSize.A4);log.info("A4的宽度:" + PageSize.A4.getWidth() + "高度:" + PageSize.A4.getHeight());try {/** 创建 PdfWriter 对象 */// 文档对象的引用// 为document创建一个监听,并把PDF流写到文件中PdfWriter.getInstance(document, new FileOutputStream(filePath)); // 文件的输出路径+文件的实际名称document.open();// 打开文档//            // 解决中文不显示问题
//            BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
//            // 设置字体大小
//            Font fontChina18_BOLD = new Font(bfChinese, 18, Font.BOLD);
//            Font fontChina12 = new Font(bfChinese, 12);
//            Font fontChina12_BOLD = new Font(bfChinese, 12, Font.BOLD);
//            Font fontChina8 = new Font(bfChinese, 8);//加粗 Font.BOLD
//            Font fontChina8_BOLD = new Font(bfChinese, 8, Font.BOLD); // 加粗 Font.BOLD//英文下字体
//            Font fontContent = new Font(Font.FontFamily.HELVETICA, 18, Font.BOLD|Font.ITALIC);// 用自己的字体BaseFont bf = BaseFont.createFont(ProjectPath.getFontPath(), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);Font titleFont = new Font(bf, 20, Font.BOLDITALIC); // 24号加粗斜体// 空格代码Paragraph blank = new Paragraph(" ");/**** 向文档添加内容 ***/// 标题String title = "";String kehuAddress = "";String kehuTelFax = "";// 境外收发货人抬头信息if (isNotBlank(apply.getConsignee())) {Customer customer = orderService.getCustomerByName(apply.getConsignee().trim(), tenantId, isNotEmpty(apply.getConsignorId()) ? apply.getConsignorId().toString() : null);if (isNotEmpty(customer) && isNotEmpty(customer.getCustomerAddressList())) {title = getHeaderInfo(customer.getCustomerAddressList());CustomerAddress ca = getAddress(customer.getCustomerAddressList());if (isNotEmpty(ca)) {kehuAddress = ca.getAddress();kehuTelFax = "TEL:" + ca.getPhone() + " FAX:" + ca.getFax();}}}Paragraph titleParagraph = new Paragraph(title, titleFont);document.add(titleParagraph); // 文档标题document.add(blank);Paragraph addressParagraph = new Paragraph(kehuAddress, new Font(bf, 15, Font.NORMAL));Paragraph telFaxParagraph = new Paragraph(kehuTelFax, new Font(bf, 15, Font.NORMAL));document.add(addressParagraph); // 客户地址document.add(telFaxParagraph); // 客户电话+传真document.add(blank);document.add(blank);document.add(blank);// 画横线//1.线宽度//2.直线长度,是个百分百,0-100之间//3.直线颜色//4.直线位置//5.上下移动位置LineSeparator line = new LineSeparator(2f, 100, BaseColor.BLACK, Element.ALIGN_CENTER, 0f);document.add(line); // 画横线Paragraph invoiceParagraph = new Paragraph("INVOICE", new Font(bf, 20, Font.BOLD));invoiceParagraph.setSpacingBefore(20);document.add(invoiceParagraph); // invoicedocument.add(blank);Paragraph billTo = new Paragraph("Bill To", new Font(bf, 12, Font.BOLD));document.add(billTo); // billto// 承运商委托单位企业信息String headerInfo = "";String address = "";String telFax = "";if (isNotBlank(apply.getConsignor())) {Customer customer = orderService.getCustomerByName(apply.getConsignor().trim(), tenantId, isNotEmpty(apply.getConsignorId()) ? apply.getConsignorId().toString() : null);if (isNotEmpty(customer) && isNotEmpty(customer.getCustomerAddressList())) {headerInfo = getHeaderInfo(customer.getCustomerAddressList());CustomerAddress ca = getAddress(customer.getCustomerAddressList());if (isNotEmpty(ca)) {address = ca.getAddress();telFax = "Tel:" + ca.getPhone() + " Fax:" + ca.getFax();}}}Paragraph headerInfoParagraph = new Paragraph(headerInfo, new Font(bf, 12, Font.NORMAL));headerInfoParagraph.setIndentationRight(PageSize.A4.getWidth() / 2 - 30);Paragraph addressParagraph_ = new Paragraph(address, new Font(bf, 12, Font.NORMAL));Paragraph telFaxParagraph_ = new Paragraph(telFax, new Font(bf, 12, Font.NORMAL));document.add(headerInfoParagraph);document.add(addressParagraph_);document.add(telFaxParagraph_);// 2021/2/1 13:57@ZHANGCHAO 追加/变更/完善:获取签名地址!!
//            if (isNotBlank(apply.getConsignor())) {
//                Customer customer = orderService.getCustomerByName(apply.getConsignor().trim(), tenantId, isNotEmpty(apply.getConsignorId()) ? apply.getConsignorId().toString() : null);
//                if (isNotEmpty(customer) && isNotEmpty(customer.getAttachmentList())) {
//                    // 获取已绑定的表单图片!
//                    List<Attachment> attachments = customer.getAttachmentList().stream()
//                            .filter(attachment -> "0".equals(attachment.getSubType())
//                                    && "1".equals(attachment.getStatus())).collect(Collectors.toList());
//                    if (isNotEmpty(attachments)) {
//                        Image yinzhang = Image.getInstance(ProjectPath.getImgPath() + attachments.get(0).getPath());
//                        yinzhang.setAlignment(Image.ALIGN_UNDEFINED);
yinzhang.scalePercent(75); // 依照比例缩放
Image类方法:
//                        yinzhang.scaleAbsolute(120, 120); // 将图像缩放到绝对宽度和绝对高度。
scaleAbsoluteHeight(float newHeight); // 将图像缩放到绝对高度。
scaleAbsoluteWidth(float newWidth); //将图像缩放到绝对宽度。
scalePercent(float percent); // 将图像缩放到一定百分比。
scalePercent(float percentX, float percentY); //将图像的宽度和高度缩放到一定百分比。
scaleToFit(float fitWidth, float fitHeight); //缩放图像,使其适合特定的宽度和高度。
yinzhang.scaleToFit(120, 120); // 依照比例缩放
//                        yinzhang.setSpacingBefore(200);
//                        yinzhang.setIndentationRight(150);
//                        document.add(yinzhang);
//                    }
//                }
//            }document.add(blank);// 2021/2/1 14:38@ZHANGCHAO 追加/变更/完善:获取供应商的签名章!!// 境外收发货人抬头信息if (isNotBlank(apply.getConsignee())) {Customer customer = orderService.getCustomerByName(apply.getConsignee().trim(), tenantId, isNotEmpty(apply.getConsignorId()) ? apply.getConsignorId().toString() : null);if (isNotEmpty(customer) && isNotEmpty(customer.getAttachmentList())) {// 获取已绑定的表单图片!List<Attachment> attachments = customer.getAttachmentList().stream().filter(attachment -> "0".equals(attachment.getSubType())&& "1".equals(attachment.getStatus())).collect(Collectors.toList());if (isNotEmpty(attachments)) {Image sign = Image.getInstance(ProjectPath.getImgPath() + attachments.get(0).getPath());sign.setAlignment(Image.ALIGN_RIGHT);
//                        sign.scalePercent(75); // 依照比例缩放sign.scaleToFit(120, 120); // 依照比例缩放sign.setIndentationRight(50);document.add(sign);}}}document.add(blank);LineSeparator line1 = new LineSeparator(1f, 100, BaseColor.BLACK, Element.ALIGN_CENTER, 0f);document.add(line1); // 画横线Paragraph pg = new Paragraph("TERMS OF DELIVERY", new Font(bf, 13, Font.NORMAL));document.add(pg);// 转化成交方式String transMode = "";if (isNotBlank(apply.getTransMode())) {DictQuery dictQuery = baseMapper.getDictInfo("CJFS", apply.getTransMode());if (isNotEmpty(dictQuery)) {transMode = dictQuery.getText();}}Paragraph transModePG = new Paragraph(transMode, new Font(bf, 13, Font.NORMAL));transModePG.setIndentationLeft(80);document.add(transModePG);Paragraph pg1 = new Paragraph("THIS PROFORMA INVOICE IS NOT ASSIGNABLE OR NEGOTIABLE", new Font(bf, 13, Font.ITALIC));document.add(pg1);Paragraph pg2 = new Paragraph("SUBJECT TO DELIVERY WHEN AVAILABLE AND AT PRICE IN EFFECT AT DATE OF SHIPMENT.", new Font(bf, 13, Font.ITALIC));document.add(pg2);// 处理表格if (isNotEmpty(applyInvoicesList)) {List<String> invoiceList = createInvoiceList(applyInvoicesList);float[] columnWidths = {1.2f, // 件号1.5f, // 英文品名1f, // 数量0.8f, // 单位1.1f, // 币制1.1f, // 单价1.5f, // 总价}; // 设置表格列宽参数getCiTableList(document, 7, columnWidths, invoiceList, applyInvoicesList, "CI", 100,new Font(bf, 13, Font.BOLD), new Font(bf, 13, Font.NORMAL));}// 关闭文档document.close();/*****************创建PDF结束*********************/// 2021/2/8 10:53@ZHANGCHAO 追加/变更/完善:设置印章!!boolean flag = false;String targetPath = "";if (isNotBlank(apply.getConsignor())) {Customer customer = orderService.getCustomerByName(apply.getConsignor().trim(), tenantId, isNotEmpty(apply.getConsignorId()) ? apply.getConsignorId().toString() : null);if (isNotEmpty(customer) && isNotEmpty(customer.getAttachmentList())) {// 获取已绑定的表单图片!List<Attachment> attachments = customer.getAttachmentList().stream().filter(attachment -> "0".equals(attachment.getSubType())&& "1".equals(attachment.getStatus())).collect(Collectors.toList());if (isNotEmpty(attachments)) {// 读取模板文件targetPath = path + "1-" + fileName;InputStream input = new FileInputStream(filePath);PdfReader reader = new PdfReader(input);PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(targetPath));// 获取操作的页面PdfContentByte under = stamper.getOverContent(1);Image image = Image.getInstance(ProjectPath.getImgPath() + attachments.get(0).getPath());// 根据域的大小缩放图片image.scaleToFit(120, 120);// 添加图片// 获取关键字的坐标List<float[]> positions = PDFUtil.findKeywordPostions(new FileInputStream(filePath), "Bill To");System.out.println("total:" + positions.size());if (isNotEmpty(positions)) {for (float[] position : positions) {System.out.print("pageNum: " + (int) position[0]);System.out.print("\tx: " + position[1]);System.out.println("\ty: " + position[2]);}}
//                        image.setAbsolutePosition(PageSize.A4.getWidth() / 3 - 95, PageSize.A4.getHeight() / 2 + 60);image.setAbsolutePosition(positions.get(0)[1] + 70, positions.get(0)[2] - 120);under.addImage(image);stamper.close();reader.close();flag = true;}}}String contentType = "application/octet-stream";res.setHeader(Http.CONTENT_TYPE, contentType);res.setStatus(RspCode.SUCCESS);// 将文件转为字节流输出if (flag) {res.setBody(fileConvertToByteArray(new File(targetPath)));// 删除文件FileUtil.deleteFile(filePath);FileUtil.deleteFile(targetPath);} else {res.setBody(fileConvertToByteArray(new File(filePath)));// 删除文件FileUtil.deleteFile(filePath);}return res;} catch (Exception e) {e.printStackTrace();ExceptionUtil.getFullStackTrace(e);}return null;}
导出箱单
 /*** 导出PDF格式箱单** @param id* @return io.zbus.transport.Message* @author ZHANGCHAO* @date 2021/1/26 13:43**/public Message exportPackingListOfPdf(String id) {Apply apply = baseMapper.selectById(id);if (isEmpty(apply)) {return null;}String tenantId = RequestKit.getRequestIn().getHeader(TENANT_ID);Message res = new Message();RequestKit.copyHeaders(false, TENANT_ID, HEADER_TOKEN, TENANT_TYPE);List<ApplyInvoices> applyInvoicesList = applyInvoicesMapper.selectList(new QueryWrapper<ApplyInvoices>().lambda().eq(ApplyInvoices::getApplyNumber, id).orderByAsc(ApplyInvoices::getSequence));apply.setApplyInvoicesList(applyInvoicesList);// pdf文件名String fileName = "箱单_" + (isNotBlank(apply.getInvoiceNo()) ? apply.getInvoiceNo() : "无发票号") + ".pdf";String path = ProjectPath.getExportPdfPath() + File.separator;File file = new File(path);if (!file.exists()) { // 如果文件夹不存在file.mkdir(); // 创建文件夹}String filePath = path + fileName;/*****************创建PDF开始*********************//** 实例化文档对象 */Document document = new Document(PageSize.A4);log.info("A4的宽度:" + PageSize.A4.getWidth() + "高度:" + PageSize.A4.getHeight());try {/** 创建 PdfWriter 对象 */// 文档对象的引用// 为document创建一个监听,并把PDF流写到文件中PdfWriter.getInstance(document, new FileOutputStream(filePath)); // 文件的输出路径+文件的实际名称document.open();// 打开文档// 用自己的字体BaseFont bf = BaseFont.createFont(ProjectPath.getFontPath(), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);Font titleFont = new Font(bf, 20, Font.BOLDITALIC); // 24号加粗斜体// 空格代码Paragraph blank = new Paragraph(" ");/**** 向文档添加内容 ***/// 标题String title = "";String kehuAddress = "";String kehuTelFax = "";// 境外收发货人抬头信息if (isNotBlank(apply.getConsignee())) {Customer customer = orderService.getCustomerByName(apply.getConsignee().trim(), tenantId, isNotEmpty(apply.getConsignorId()) ? apply.getConsignorId().toString() : null);if (isNotEmpty(customer) && isNotEmpty(customer.getCustomerAddressList())) {title = getHeaderInfo(customer.getCustomerAddressList());CustomerAddress ca = getAddress(customer.getCustomerAddressList());if (isNotEmpty(ca)) {kehuAddress = ca.getAddress();kehuTelFax = "TEL:" + ca.getPhone() + " FAX:" + ca.getFax();}}}Paragraph titleParagraph = new Paragraph(title, titleFont);document.add(titleParagraph); // 文档标题document.add(blank);Paragraph addressParagraph = new Paragraph(kehuAddress, new Font(bf, 15, Font.NORMAL));Paragraph telFaxParagraph = new Paragraph(kehuTelFax, new Font(bf, 15, Font.NORMAL));document.add(addressParagraph); // 客户地址document.add(telFaxParagraph); // 客户电话+传真document.add(blank);document.add(blank);Paragraph invoiceParagraph = new Paragraph("Packing list", new Font(bf, 20, Font.BOLD));invoiceParagraph.setSpacingBefore(20);document.add(invoiceParagraph); // invoicedocument.add(blank);// 2021/2/1 13:57@ZHANGCHAO 追加/变更/完善:获取签名地址!!
//            if (isNotBlank(apply.getConsignor())) {
//                Customer customer = orderService.getCustomerByName(apply.getConsignor().trim(), tenantId, isNotEmpty(apply.getConsignorId()) ? apply.getConsignorId().toString() : null);
//                if (isNotEmpty(customer) && isNotEmpty(customer.getAttachmentList())) {
//                    // 获取已绑定的表单图片!
//                    List<Attachment> attachments = customer.getAttachmentList().stream()
//                            .filter(attachment -> "0".equals(attachment.getSubType())
//                                    && "1".equals(attachment.getStatus())).collect(Collectors.toList());
//                    if (isNotEmpty(attachments)) {
//                        Image yinzhang = Image.getInstance(ProjectPath.getImgPath() + attachments.get(0).getPath());
//                        yinzhang.setAlignment(Image.ALIGN_UNDEFINED);
//                        yinzhang.scalePercent(75); // 依照比例缩放
//                        yinzhang.setIndentationRight(150);
//                        document.add(yinzhang);
//                    }
//                }
//            }Paragraph billTo = new Paragraph("Bill To", new Font(bf, 12, Font.BOLD));document.add(billTo); // billto// 承运商委托单位企业信息String headerInfo = "";String address = "";String telFax = "";if (isNotBlank(apply.getConsignor())) {Customer customer = orderService.getCustomerByName(apply.getConsignor().trim(), tenantId, isNotEmpty(apply.getConsignorId()) ? apply.getConsignorId().toString() : null);if (isNotEmpty(customer) && isNotEmpty(customer.getCustomerAddressList())) {headerInfo = getHeaderInfo(customer.getCustomerAddressList());CustomerAddress ca = getAddress(customer.getCustomerAddressList());if (isNotEmpty(ca)) {address = ca.getAddress();telFax = "Tel:" + ca.getPhone() + " Fax:" + ca.getFax();}}}Paragraph headerInfoParagraph = new Paragraph(headerInfo, new Font(bf, 12, Font.NORMAL));headerInfoParagraph.setIndentationRight(PageSize.A4.getWidth() / 2 - 30);Paragraph addressParagraph_ = new Paragraph(address, new Font(bf, 12, Font.NORMAL));Paragraph telFaxParagraph_ = new Paragraph(telFax, new Font(bf, 12, Font.NORMAL));document.add(headerInfoParagraph);document.add(addressParagraph_);document.add(telFaxParagraph_);document.add(blank);// 2021/2/1 14:38@ZHANGCHAO 追加/变更/完善:获取供应商的签名章!!// 境外收发货人抬头信息if (isNotBlank(apply.getConsignee())) {Customer customer = orderService.getCustomerByName(apply.getConsignee().trim(), tenantId, isNotEmpty(apply.getConsignorId()) ? apply.getConsignorId().toString() : null);if (isNotEmpty(customer) && isNotEmpty(customer.getAttachmentList())) {// 获取已绑定的表单图片!List<Attachment> attachments = customer.getAttachmentList().stream().filter(attachment -> "0".equals(attachment.getSubType())&& "1".equals(attachment.getStatus())).collect(Collectors.toList());if (isNotEmpty(attachments)) {Image sign = Image.getInstance(ProjectPath.getImgPath() + attachments.get(0).getPath());sign.setAlignment(Image.ALIGN_RIGHT);
//                        sign.scalePercent(75); // 依照比例缩放sign.scaleToFit(120, 120); // 依照比例缩放sign.setIndentationRight(50);document.add(sign);}}}document.add(blank);// 处理表格if (isNotEmpty(applyInvoicesList)) {PdfPTable table = new PdfPTable(6);// 设置列数table.setSpacingBefore(20);table.setWidthPercentage(100);// 表格宽度为100%float[] columnWidths = {1.5f, // 件号1.5f, // 英文品名1.1f, // 数量1.2f, // 净重1.3f, // 毛重1.3f, // 包装数}; // 设置表格列宽参数table.setWidths(columnWidths);/*表头*/getPlTableList(table, apply, new Font(bf, 13, Font.BOLD), new Font(bf, 13, Font.NORMAL));document.add(table);document.add(blank);}String lastStr = "";String packStr = "";if (isNotBlank(apply.getPacksKinds())) {DictQuery dictQuery = baseMapper.getDictInfo("BZZL", apply.getPacksKinds());if (isNotEmpty(dictQuery)) {packStr = dictQuery.getTable();}}lastStr = "TOTAL ON " + apply.getPacks() + " " + (isNotBlank(packStr) ? packStr : "");Paragraph last = new Paragraph(lastStr, new Font(bf, 12, Font.BOLD));document.add(last); // billto// 关闭文档document.close();/*****************创建PDF结束*********************/// 2021/2/8 10:54@ZHANGCHAO 追加/变更/完善:设置印章!!boolean flag = false;String targetPath = "";if (isNotBlank(apply.getConsignor())) {Customer customer = orderService.getCustomerByName(apply.getConsignor().trim(), tenantId, isNotEmpty(apply.getConsignorId()) ? apply.getConsignorId().toString() : null);if (isNotEmpty(customer) && isNotEmpty(customer.getAttachmentList())) {// 获取已绑定的表单图片!List<Attachment> attachments = customer.getAttachmentList().stream().filter(attachment -> "0".equals(attachment.getSubType())&& "1".equals(attachment.getStatus())).collect(Collectors.toList());if (isNotEmpty(attachments)) {// 读取模板文件targetPath = path + "1-" + fileName;InputStream input = new FileInputStream(filePath);PdfReader reader = new PdfReader(input);PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(targetPath));// 获取操作的页面PdfContentByte under = stamper.getOverContent(1);Image image = Image.getInstance(ProjectPath.getImgPath() + attachments.get(0).getPath());// 根据域的大小缩放图片image.scaleToFit(120, 120);// 添加图片// 获取关键字的坐标List<float[]> positions = PDFUtil.findKeywordPostions(new FileInputStream(filePath), "Bill To");System.out.println("total:" + positions.size());if (isNotEmpty(positions)) {for (float[] position : positions) {System.out.print("pageNum: " + (int) position[0]);System.out.print("\tx: " + position[1]);System.out.println("\ty: " + position[2]);}}
//                        image.setAbsolutePosition(PageSize.A4.getWidth() / 3 - 95, PageSize.A4.getHeight() / 2 + 60);image.setAbsolutePosition(positions.get(0)[1] + 70, positions.get(0)[2] - 120);under.addImage(image);stamper.close();reader.close();flag = true;}}}String contentType = "application/octet-stream";res.setHeader(Http.CONTENT_TYPE, contentType);res.setStatus(RspCode.SUCCESS);// 将文件转为字节流输出if (flag) {res.setBody(fileConvertToByteArray(new File(targetPath)));// 删除文件FileUtil.deleteFile(filePath);FileUtil.deleteFile(targetPath);} else {res.setBody(fileConvertToByteArray(new File(filePath)));// 删除文件FileUtil.deleteFile(filePath);}return res;} catch (Exception e) {e.printStackTrace();}return null;}
}
其他一些方法:
    /*** 把一个文件转化为byte字节数组。** @return*/private byte[] fileConvertToByteArray(File file) {byte[] data = null;try {FileInputStream fis = new FileInputStream(file);ByteArrayOutputStream bos = new ByteArrayOutputStream();int len;byte[] buffer = new byte[1024];while ((len = fis.read(buffer)) != -1) {bos.write(buffer, 0, len);}data = bos.toByteArray();fis.close();bos.close();} catch (Exception e) {e.printStackTrace();}return data;}/*** 按一定规则获取客户抬头信息* <p>* 委托单导出箱单发票,获取标签为1 的地址联系人。(如果找不到取0通用地址,如果没有则取默认地址,如果没有默认取第一条)** @param customerAddressList* @return java.lang.String* @author ZHANGCHAO* @date 2021/1/19 9:33**/private String getHeaderInfo(List<CustomerAddress> customerAddressList) {String headerInfo;// 1.取对应List<CustomerAddress> duiyings = customerAddressList.stream().filter(customerAddress -> "1".equals(customerAddress.getType())).collect(Collectors.toList());if (isNotEmpty(duiyings)) {headerInfo = duiyings.get(0).getHeaderInfo();} else {// 2.取通用List<CustomerAddress> tongyongs = customerAddressList.stream().filter(customerAddress -> "0".equals(customerAddress.getType())).collect(Collectors.toList());if (isNotEmpty(tongyongs)) {headerInfo = tongyongs.get(0).getHeaderInfo();} else {// 3.取默认List<CustomerAddress> morens = customerAddressList.stream().filter(CustomerAddress::getIsDefault).collect(Collectors.toList());if (isNotEmpty(morens)) {headerInfo = morens.get(0).getHeaderInfo();} else {// 4.取第一条headerInfo = customerAddressList.get(0).getHeaderInfo();}}}return headerInfo;}/*** 按一定规则获取客户地址信息* <p>* 委托单导出箱单发票,获取标签为1 的地址联系人。(如果找不到取0通用地址,如果没有则取默认地址,如果没有默认取第一条)** @param customerAddressList* @return java.lang.String* @author ZHANGCHAO* @date 2021/1/19 9:33**/private CustomerAddress getAddress(List<CustomerAddress> customerAddressList) {CustomerAddress ca;// 1.取对应List<CustomerAddress> duiyings = customerAddressList.stream().filter(customerAddress -> "1".equals(customerAddress.getType())).collect(Collectors.toList());if (isNotEmpty(duiyings)) {ca = duiyings.get(0);} else {// 2.取通用List<CustomerAddress> tongyongs = customerAddressList.stream().filter(customerAddress -> "0".equals(customerAddress.getType())).collect(Collectors.toList());if (isNotEmpty(tongyongs)) {ca = tongyongs.get(0);} else {// 3.取默认List<CustomerAddress> morens = customerAddressList.stream().filter(CustomerAddress::getIsDefault).collect(Collectors.toList());if (isNotEmpty(morens)) {ca = morens.get(0);} else {// 4.取第一条ca = customerAddressList.get(0);}}}return ca;}

主要思路是先根据委托单的流水号,查询出其下的商品数据,然后写入生成的PDF文件中。再读取生成的PDF文件,根据关键字“Bill To”的坐标插入印章,最后转为字节流输出给前端下载。

1. 处理商品数据的createInvoiceList方法:
 /*** 处理商品数据** @param applyInvoicesList* @return java.util.List<java.lang.String>* @author ZHANGCHAO* @date 2021/1/27 15:28**/public static List<String> createInvoiceList(List<ApplyInvoices> applyInvoicesList) {List<String> invoiceList = new ArrayList<>();/****标题行****/invoiceList.add("Part No.");invoiceList.add("DESCRIPTION");invoiceList.add("QTY.");invoiceList.add("UNIT");invoiceList.add("CURRENCY");invoiceList.add("Unit price");invoiceList.add("AMOUNT");/****每行的值****/applyInvoicesList.forEach(applyInvoices -> {invoiceList.add(isNotBlank(applyInvoices.getPn()) ? applyInvoices.getPn() : null); // 件号物料号invoiceList.add(isNotBlank(applyInvoices.getEnName()) ? applyInvoices.getEnName() : null); // 英文品名invoiceList.add(isNotEmpty(applyInvoices.getQty()) ? applyInvoices.getQty().toString() : null); // 数量invoiceList.add(isNotBlank(applyInvoices.getQunit()) ? applyInvoices.getQunit() : null); // 单位invoiceList.add(isNotBlank(applyInvoices.getCurrency()) ? applyInvoices.getCurrency() : null); // 币制invoiceList.add(isNotEmpty(applyInvoices.getDcluprcamt()) ? applyInvoices.getDcluprcamt().toString() : null); // 单价invoiceList.add(isNotEmpty(applyInvoices.getValue()) ? applyInvoices.getValue().toString() : null); // 总价});return invoiceList;}
2. 获取表格数据getCiTableList方法代码:
 /*** 创建表格** @param document* @param colspan* @param columnWidths* @param list* @param widthPercentage* @param headFont* @param childFont* @return void* @author ZHANGCHAO* @date 2021/1/27 15:44**/public static void getCiTableList(Document document, int colspan, float[] columnWidths, List<String> list,List<ApplyInvoices> applyInvoices, String type,float widthPercentage, Font headFont, Font childFont) throws DocumentException {PdfPTable table = new PdfPTable(colspan);// 设置列数table.setSpacingBefore(20);table.setWidthPercentage(widthPercentage);// 表格宽度为100%if (columnWidths != null) {//自定义列宽table.setWidths(columnWidths);}int number = 0;//设置打印行数for (int i = 0; i < list.size() / colspan; i++) {//打印条数 = 数据个数除以列数//每行每列生成一个单元格for (int j = 0; j < colspan; j++) { //打印列数PdfPCell cell = new PdfPCell(); //创建单元格cell.setMinimumHeight(30F);//表格高度cell.setUseAscender(true);cell.setHorizontalAlignment(Element.ALIGN_CENTER); //水平居中cell.setVerticalAlignment(Element.ALIGN_MIDDLE); //垂直居中if (i == 0) {//第一行标题栏cell.setPhrase(new Paragraph(list.get(number), headFont));} else {cell.setPhrase(new Paragraph(list.get(number), childFont));}table.addCell(cell);number++;}}// 处理最后一行if ("CI".equalsIgnoreCase(type)) {BigDecimal totalQty = new BigDecimal("0");BigDecimal totalAmount = new BigDecimal("0");for (ApplyInvoices a : applyInvoices) {totalQty = totalQty.add(isNotEmpty(a.getQty()) ? a.getQty() : new BigDecimal("0"));totalAmount = totalAmount.add(isNotEmpty(a.getValue()) ? a.getValue() : new BigDecimal("0"));}PdfPCell cell = new PdfPCell(); //创建单元格cell.setMinimumHeight(30F);//表格高度cell.setColspan(2);cell.setUseAscender(true); //开启单元格内文字位置设计cell.setHorizontalAlignment(Element.ALIGN_CENTER); //设置单元格的水平居中cell.setVerticalAlignment(Element.ALIGN_MIDDLE); //设置单元格的垂直居中cell.setPhrase(new Paragraph("TOTAL", headFont));table.addCell(cell);PdfPCell cell1 = new PdfPCell(); //创建单元格cell1.setMinimumHeight(30F);//表格高度cell1.setUseAscender(true); //开启单元格内文字位置设计cell1.setHorizontalAlignment(Element.ALIGN_CENTER); //设置单元格的水平居中cell1.setVerticalAlignment(Element.ALIGN_MIDDLE); //设置单元格的垂直居中cell1.setPhrase(new Paragraph(totalQty.toString(), headFont));table.addCell(cell1);PdfPCell cell2 = new PdfPCell(); //创建单元格cell2.setMinimumHeight(30F);//表格高度cell2.setUseAscender(true); //开启单元格内文字位置设计cell2.setHorizontalAlignment(Element.ALIGN_CENTER); //设置单元格的水平居中cell2.setVerticalAlignment(Element.ALIGN_MIDDLE); //设置单元格的垂直居中cell2.setPhrase(new Paragraph("", headFont));table.addCell(cell2);PdfPCell cell3 = new PdfPCell(); //创建单元格cell3.setMinimumHeight(30F);//表格高度cell3.setUseAscender(true); //开启单元格内文字位置设计cell3.setHorizontalAlignment(Element.ALIGN_CENTER); //设置单元格的水平居中cell3.setVerticalAlignment(Element.ALIGN_MIDDLE); //设置单元格的垂直居中cell3.setPhrase(new Paragraph("", headFont));table.addCell(cell3);PdfPCell cell4 = new PdfPCell(); //创建单元格cell4.setMinimumHeight(30F);//表格高度cell4.setUseAscender(true); //开启单元格内文字位置设计cell4.setHorizontalAlignment(Element.ALIGN_CENTER); //设置单元格的水平居中cell4.setVerticalAlignment(Element.ALIGN_MIDDLE); //设置单元格的垂直居中cell4.setPhrase(new Paragraph("", headFont));table.addCell(cell4);PdfPCell cell5 = new PdfPCell(); //创建单元格cell5.setMinimumHeight(30F);//表格高度cell5.setUseAscender(true); //开启单元格内文字位置设计cell5.setHorizontalAlignment(Element.ALIGN_CENTER); //设置单元格的水平居中cell5.setVerticalAlignment(Element.ALIGN_MIDDLE); //设置单元格的垂直居中cell5.setPhrase(new Paragraph(totalAmount.toString(), headFont));table.addCell(cell5);}document.add(table);}
3. 注意:箱单的话需要纵向合并单元格,而itextpdf的纵向合并简直是残废,这里需要单独处理下:
 /*** 创建箱单表格** @param table* @param apply* @param headFont* @param childFont* @return void* @author ZHANGCHAO* @date 2021/1/28 10:53**/public static void getPlTableList(PdfPTable table, Apply apply, Font headFont, Font childFont) {PdfPCell cell = new PdfPCell(); //创建单元格cell.setMinimumHeight(30F);//表格高度cell.setUseAscender(true); //开启单元格内文字位置设计cell.setHorizontalAlignment(Element.ALIGN_CENTER); //设置单元格的水平居中cell.setVerticalAlignment(Element.ALIGN_MIDDLE); //设置单元格的垂直居中cell.setPhrase(new Paragraph("Part No.", headFont));table.addCell(cell);PdfPCell cell1 = new PdfPCell(); //创建单元格cell1.setMinimumHeight(30F);//表格高度cell1.setUseAscender(true); //开启单元格内文字位置设计cell1.setHorizontalAlignment(Element.ALIGN_CENTER); //设置单元格的水平居中cell1.setVerticalAlignment(Element.ALIGN_MIDDLE); //设置单元格的垂直居中cell1.setPhrase(new Paragraph("DESCRIPTION", headFont));table.addCell(cell1);PdfPCell cell2 = new PdfPCell(); //创建单元格cell2.setMinimumHeight(30F);//表格高度cell2.setUseAscender(true); //开启单元格内文字位置设计cell2.setHorizontalAlignment(Element.ALIGN_CENTER); //设置单元格的水平居中cell2.setVerticalAlignment(Element.ALIGN_MIDDLE); //设置单元格的垂直居中cell2.setPhrase(new Paragraph("QTY.", headFont));table.addCell(cell2);PdfPCell cell3 = new PdfPCell(); //创建单元格cell3.setMinimumHeight(30F);//表格高度cell3.setUseAscender(true); //开启单元格内文字位置设计cell3.setHorizontalAlignment(Element.ALIGN_CENTER); //设置单元格的水平居中cell3.setVerticalAlignment(Element.ALIGN_MIDDLE); //设置单元格的垂直居中cell3.setPhrase(new Paragraph("N.WT(Kg)", headFont));table.addCell(cell3);PdfPCell cell4 = new PdfPCell(); //创建单元格cell4.setMinimumHeight(30F);//表格高度cell4.setUseAscender(true); //开启单元格内文字位置设计cell4.setHorizontalAlignment(Element.ALIGN_CENTER); //设置单元格的水平居中cell4.setVerticalAlignment(Element.ALIGN_MIDDLE); //设置单元格的垂直居中cell4.setPhrase(new Paragraph("G.WT(Kg)", headFont));table.addCell(cell4);PdfPCell cell5 = new PdfPCell(); //创建单元格cell5.setMinimumHeight(30F);//表格高度cell5.setUseAscender(true); //开启单元格内文字位置设计cell5.setHorizontalAlignment(Element.ALIGN_CENTER); //设置单元格的水平居中cell5.setVerticalAlignment(Element.ALIGN_MIDDLE); //设置单元格的垂直居中cell5.setPhrase(new Paragraph("Package", headFont));table.addCell(cell5);/****每行的值****/List<String> invoiceList = new ArrayList<>();apply.getApplyInvoicesList().forEach(applyInvoices -> {invoiceList.add(isNotBlank(applyInvoices.getPn()) ? applyInvoices.getPn() : null); // 件号物料号invoiceList.add(isNotBlank(applyInvoices.getEnName()) ? applyInvoices.getEnName() : null); // 英文品名invoiceList.add(isNotEmpty(applyInvoices.getQty()) ? applyInvoices.getQty().toString() : null); // 数量invoiceList.add(isNotEmpty(applyInvoices.getWeight()) ? applyInvoices.getWeight().toString() : null); // 净重invoiceList.add(isNotEmpty(apply.getGrosswt()) ? apply.getGrosswt().toString() : null); // 毛重invoiceList.add(isNotEmpty(apply.getPacks()) ? apply.getPacks().toString() + " CASES" : null); // 总价});log.info("invoiceList==> " + invoiceList);int line = 0;for (int i = 0; i < invoiceList.size() / 6; i++) {for (int j = 0; j < 6; j++) {PdfPCell cell_ = new PdfPCell(); //创建单元格cell_.setMinimumHeight(30F);//表格高度cell_.setUseAscender(true);cell_.setHorizontalAlignment(Element.ALIGN_CENTER); //水平居中cell_.setVerticalAlignment(Element.ALIGN_MIDDLE); //垂直居中if (i == 0) {if (j == 4 || j == 5) {cell_.setRowspan(apply.getApplyInvoicesList().size());String value = invoiceList.get(line);cell_.setPhrase(new Paragraph(value, childFont));table.addCell(cell_);}}if (j != 4 && j != 5) {cell_.setPhrase(new Paragraph(invoiceList.get(line), childFont));table.addCell(cell_);}line++;}}// 处理最后一行BigDecimal totalQty = new BigDecimal("0");BigDecimal totalWeight = new BigDecimal("0");for (ApplyInvoices a : apply.getApplyInvoicesList()) {totalQty = totalQty.add(isNotEmpty(a.getQty()) ? a.getQty() : new BigDecimal("0"));totalWeight = totalWeight.add(isNotEmpty(a.getWeight()) ? a.getWeight() : new BigDecimal("0"));}PdfPCell cellLast = new PdfPCell(); //创建单元格cellLast.setMinimumHeight(30F);//表格高度cellLast.setColspan(2);cellLast.setUseAscender(true); //开启单元格内文字位置设计cellLast.setHorizontalAlignment(Element.ALIGN_CENTER); //设置单元格的水平居中cellLast.setVerticalAlignment(Element.ALIGN_MIDDLE); //设置单元格的垂直居中cellLast.setPhrase(new Paragraph("TOTAL", headFont));table.addCell(cellLast);PdfPCell cellLast1 = new PdfPCell(); //创建单元格cellLast1.setMinimumHeight(30F);//表格高度cellLast1.setUseAscender(true); //开启单元格内文字位置设计cellLast1.setHorizontalAlignment(Element.ALIGN_CENTER); //设置单元格的水平居中cellLast1.setVerticalAlignment(Element.ALIGN_MIDDLE); //设置单元格的垂直居中cellLast1.setPhrase(new Paragraph(totalQty.toString(), headFont));table.addCell(cellLast1);PdfPCell cellLast2 = new PdfPCell(); //创建单元格cellLast2.setMinimumHeight(30F);//表格高度cellLast2.setUseAscender(true); //开启单元格内文字位置设计cellLast2.setHorizontalAlignment(Element.ALIGN_CENTER); //设置单元格的水平居中cellLast2.setVerticalAlignment(Element.ALIGN_MIDDLE); //设置单元格的垂直居中cellLast2.setPhrase(new Paragraph(totalWeight.toString(), headFont));table.addCell(cellLast2);PdfPCell cellLast3 = new PdfPCell(); //创建单元格cellLast3.setMinimumHeight(30F);//表格高度cellLast3.setUseAscender(true); //开启单元格内文字位置设计cellLast3.setHorizontalAlignment(Element.ALIGN_CENTER); //设置单元格的水平居中cellLast3.setVerticalAlignment(Element.ALIGN_MIDDLE); //设置单元格的垂直居中cellLast3.setPhrase(new Paragraph(isNotEmpty(apply.getGrosswt()) ? apply.getGrosswt().toString() : "", headFont));table.addCell(cellLast3);PdfPCell cellLast4 = new PdfPCell(); //创建单元格cellLast4.setMinimumHeight(30F);//表格高度cellLast4.setUseAscender(true); //开启单元格内文字位置设计cellLast4.setHorizontalAlignment(Element.ALIGN_CENTER); //设置单元格的水平居中cellLast4.setVerticalAlignment(Element.ALIGN_MIDDLE); //设置单元格的垂直居中cellLast4.setPhrase(new Paragraph(isNotEmpty(apply.getPacks()) ? apply.getPacks().toString() + " CASES" : null, headFont));table.addCell(cellLast4);}
三、测试
1. 导出的发票如下:

2. 导出的箱单如下:


总的来说用itextpdf导出PDF还是很简单的,需要其他功能可以自己研究。

以上!

SpringBoot+Vue项目的PDF导出及给PDF文件盖章的功能示例相关推荐

  1. 从零开始手写vue项目的webpack基础配置

    一.创建目录结构 执行yarn init, 生成package.json文件; 1.写入文件 建立目录结构可参考vue项目目录结构: 首先建立一个src文件夹,其中包含index.html,App.v ...

  2. vue 项目的I18n国际化之路

    I18n (internationalization ) ---未完善 产品国际化是产品后期维护及推广中重要的一环,通过国际化操作使得产品能更好适应不同语言和地区的需求 国际化重点: 1. 语言 语言 ...

  3. VUE项目的e2e自动化测试超详细安装过程(保姆级)

    目录 一.创建测试项目 二.配置Nightwatch(以chrome为演示) 一.创建测试项目 首先通过@vue/cli创建一个基于nightwatch的测试项目.(我这里使用的是@vue/cli 3 ...

  4. 从后端数据库获取数据并传值到前端vue项目的echarts柱状图/折线图/饼图里

    不同图表的数据获取有一定的区别 在这些区别上花了不少功夫试验,把最后成功的方法做个记录,如果有类似项目要做的话,也可看看当个参考. 后端 后端都大同小异,方法上没有区别,在这里以柱状图为例. sql: ...

  5. 关于vue项目的seo问题

    不可否定的是,vue现在火.但是在实际项目中,特别是像一下交互网站,我们不可避免会考虑到的是seo问题,这直接关系到我们网站的排名,很多人说用vue搭建的网站不能做优化,那我们真的要放弃vue,放弃前 ...

  6. 更改vue项目的title标题

    方法一:在vue.config.js中配置chainWebpack chainWebpack: config =>{config.plugin('html').tap(args => {a ...

  7. 关于修改vue项目的favicon.ico图标

    项目场景: 在vue项目中,在浏览器打开的favicon.ico样式是vue自带的logo样式,那么跟着我的步骤一起来换吧~ 在这里推荐一个在线做ico样式的网站:在线制作ico图标 步骤: 仅需一步 ...

  8. 关于前端Vue项目的env文件

    文章目录 关于.env文件(2021.2.3 初次接触) Vue配置生产.开发.测试环境至到package.json 拓:关于linux的几个小命令 关于.env文件(2021.2.3 初次接触) . ...

  9. 前端开发:基于移动端的Vue项目的Loading使用

    前言 在前端开发过程中,常用的组件有必要做一下使用的总结,尤其是对于刚入门的前端开发者来说既有利于知识点的掌握,又有利于总结归纳方便后期使用查看.不管是基于移动端还是PC端的前端Vue项目都是如此,那 ...

  10. 解决vue项目的 verbose stack Error: unable to resolve dependency tree问题

    项目场景: 安装vue插件的时候出现报错 verbose stack Error: unable to resolve dependency tree 在命令后面加入 –legacy-peer-dep ...

最新文章

  1. Pycharm + Anaconda 安装遇到的问题以及自己的理解
  2. 用C++对C++语法格式进行分析
  3. 模糊神经网络_神经网络模型:当网络开始产生类似于人类思维的过程
  4. LeetCode 979. 在二叉树中分配硬币(DFS)
  5. MATLAB把多行多列矩阵数据和文字写入txt文件
  6. VMware vRealize Operations Manager的内部版本号(2145975)
  7. 让C68平台“冷又静”
  8. 学校为什么要单位接收函_签了三方,想毁约怎么办?这几点你必须要知道!
  9. CentOS 手工编译、手动编译安装 MongoDB
  10. 阿里云 ubuntu 安装 curl
  11. crossplaform---Nodejs in Visual Studio Code 04.Swig模版
  12. 基于php的宠物领养系统
  13. navicat如何连接本地数据库
  14. ir指令、立即数的作用_计算机系统概论-笔记
  15. Mac键盘部分数字键和字母键失灵,无法使用怎么办?
  16. PDF 的命令行操作
  17. 显示具体化、显示实例化、隐式实例化
  18. Vmware14安装ubuntu18
  19. conver Json to map by fastJson
  20. 论文复现:用 CNN 进行文本分类

热门文章

  1. 迷惘一代、沉默一代、X世代、Z世代……美国的几代人
  2. 修复 Windows 10 设置界面里面混乱的语言翻译
  3. 双硬盘安装ubuntu
  4. VLAN与三层交换机
  5. 解决out.print()爆红问题
  6. android 通知写法_Android消息通知-Notifation
  7. 【MATLAB】报错:数组索引必须为正整数或逻辑值
  8. 微信公众号二维码在哪里看?如何查看自己的微信公众号二维码?
  9. tornado线程阻塞的解决
  10. 高通 thermal子系统