Java使用itext生成復(fù)雜數(shù)據(jù)的pdf的示例代碼
首先,什么是Itext
Apache iText 是一個(gè)開(kāi)源 Java 庫(kù),支持 PDF 文檔的開(kāi)發(fā)和轉(zhuǎn)換。
在本教程中,我們將學(xué)習(xí)如何使用 iText 開(kāi)發(fā)可以創(chuàng)建、轉(zhuǎn)換和操作 PDF 文檔的 Java 程序。
Itext目前遵從AGPL開(kāi)源協(xié)議,AGPL 可以說(shuō)是最嚴(yán)格的 GPL 了,強(qiáng)傳染性,即使是 RPC 調(diào)用也會(huì)被感染,不發(fā)行軟件而是作為 web 服務(wù)對(duì)外提供也必須開(kāi)放源代碼
目前Itext有很多product開(kāi)始收費(fèi),但你所需的功能基本上open source都能滿足
特點(diǎn):
以下是 iText 庫(kù)的顯著特點(diǎn) −
- Interactive − iText 為你提供類(API)來(lái)生成交互式 PDF 文檔。使用這些,你可以創(chuàng)建地圖和書籍。
- Adding bookmarks, page numbers, etc − 使用 iText,你可以添加書簽、頁(yè)碼和水印。
- Split & Merge − 使用 iText,你可以將現(xiàn)有的 PDF 拆分為多個(gè) PDF,還可以向其中添加/連接其他頁(yè)面。
- Fill Forms − 使用 iText,你可以在 PDF 文檔中填寫交互式表單。
- Save as Image − 使用 iText,你可以將 PDF 保存為圖像文件,例如 PNG 或 JPEG。
- Canvas − iText 庫(kù)為您提供了一個(gè) Canvas 類,你可以使用它在 PDF 文檔上繪制各種幾何形狀,如圓形、線條等。
- Create PDFs − 使用 iText,你可以從 Java 程序創(chuàng)建新的 PDF 文件。你也可以包含圖像和字體。
下載地址:Examples
iText官網(wǎng): The Leading PDF Library for Developers | iText
一 上依賴
<!-- ITEXTPDF 依賴 --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>${com.itextpdf.version}</version> </dependency> <com.itextpdf.version>5.5.13.2</com.itextpdf.version>
二 ctroller層
HttpServletResponse
:用于將生成的 PDF 文件直接寫入 HTTP 響應(yīng)流中,以便客戶端可以下載或查看 PDF 文件。
目前,方法聲明拋出了 Exception
,這會(huì)導(dǎo)致所有未捕獲的異常都被拋出到客戶端。為了提高代碼的健壯性,建議捕獲特定的異常,并根據(jù)不同的異常類型返回適當(dāng)?shù)?HTTP 狀態(tài)碼和錯(cuò)誤信息。
例如,你可以使用 @ExceptionHandler
來(lái)捕獲常見(jiàn)的異常,如 IOException
、DocumentException
等,并返回 500 Internal Server Error 或其他適當(dāng)?shù)捻憫?yīng)。
@PostMapping(value = "print/sorting", produces = MediaType.APPLICATION_PDF_VALUE) @ApiOperation(value = "打印分揀清單(新)", produces = MediaType.APPLICATION_PDF_VALUE) public void printSortingNew(@Valid @RequestBody SortingPrintRequest request, HttpServletResponse response){ crossdockSortingService.printSortingNew(request,response); }
三 Service層
按照業(yè)務(wù)邏輯從數(shù)據(jù)庫(kù)獲取數(shù)據(jù)并處理數(shù)據(jù),放到合適的對(duì)象里
(這里主要是和業(yè)務(wù)相關(guān),不必深究里面內(nèi)容,最后能得出需要的數(shù)據(jù)傳出即可)
@Override public void printSorting(SortingPrintRequest request, HttpServletResponse response) throws IOException { Crossdock crossdock1 = crossdockService.getByFieldValue(request.getOrderNo(), Crossdock::getOrderNo); Set<String> idSet = Sets.newHashSet();idSet.add(crossdock1.getId()); // 集裝箱編號(hào)/柜號(hào)、柜型 List<Crossdock> crossdockList = crossdockService.listByFieldValueSet(idSet, Crossdock::getId); if (ObjectUtils.isEmpty(crossdockList)) { throw new ApiException(ResultCode.PARAMES_INVALID); } // 統(tǒng)計(jì)快遞、卡派、自提、存?zhèn)}數(shù)量 List<CrossdockPlan> crossdockPlanByOrderList = crossdockPlanService.listByFieldValueSet(idSet, CrossdockPlan::getOrderId); Map<String, List<CrossdockPlan>> crossdockPlanOrderIdMap = crossdockPlanByOrderList.stream().collect(Collectors.groupingBy(CrossdockPlan::getOrderId)); // 客戶id、公司 // 客戶(發(fā)件人)信息 customerVo Set<String> customerIdSet = crossdockList.stream().map(Crossdock::getCustomerId).collect(Collectors.toSet()); Map<String, Customer> customerMap = customerService.mapByFieldValueSet(customerIdSet, Customer::getId); // 箱數(shù)統(tǒng)計(jì),分揀表 List<CrossdockSorting> crossdockSortingList = listByFieldValueSet(idSet, CrossdockSorting::getOrderId); Map<String, List<CrossdockSorting>> crossdockSortingMap = crossdockSortingList.stream().collect(Collectors.groupingBy(CrossdockSorting::getOrderId)); Set<String> sortingIdSet = crossdockSortingList.stream().map(CrossdockSorting::getId).collect(Collectors.toSet()); List<CrossdockSortingItem> crossdockSortingItemList = crossdockSortingItemService.listByFieldValueSet(sortingIdSet, CrossdockSortingItem::getSortingId); Map<String, List<CrossdockSortingItem>> crossdockSortingItemMap = crossdockSortingItemList.stream().collect(Collectors.groupingBy(CrossdockSortingItem::getSortingId)); // 公司信息 Set<String> companySet = crossdockList.stream().map(Crossdock::getCompanyId).collect(Collectors.toSet()); Map<String, Company> companyMap = companyService.mapByFieldValueSet(companySet, Company::getId); // 拼接參數(shù) List<ExportSortingVo> exportSortingVoList = new ArrayList<>(); Map<String, List<ExportSortingDetailVo>> exportSortingDetailVoMap = new HashMap<>(16); for (Crossdock crossdock : crossdockList) { ExportSortingVo exportSortingVo = new ExportSortingVo(); exportSortingVo.setKey(crossdock.getOrderNo()); exportSortingVo.setCabinetType(crossdock.getContainerType()); exportSortingVo.setCtnr(crossdock.getContainerNo()); exportSortingVo.setCompany(companyMap.containsKey(crossdock.getCompanyId()) ? companyMap.get(crossdock.getCompanyId()).getName() : null); if (customerMap.containsKey(crossdock.getCustomerId())) { exportSortingVo.setCustomerCode(customerMap.get(crossdock.getCustomerId()).getCode()); } // 設(shè)置統(tǒng)計(jì)數(shù)量 if (crossdockPlanOrderIdMap.containsKey(crossdock.getId())) { List<CrossdockPlan> crossdockPlanList = crossdockPlanOrderIdMap.get(crossdock.getId()); // 快遞 Map<String, List<CrossdockPlan>> shippingTypeMap = crossdockPlanList.stream().collect(Collectors.groupingBy(CrossdockPlan::getShippingType)); if (shippingTypeMap.containsKey(CrossdockEnums.ShippingType.EXPRESS.name())) { List<CrossdockPlan> expressCrossdockPlanList = shippingTypeMap.get(CrossdockEnums.ShippingType.EXPRESS.name()); BigDecimal expressAmount = expressCrossdockPlanList.stream().filter(crossdockPlan -> !ObjectUtils.isEmpty(crossdockPlan.getTotalAmount())) .map(CrossdockPlan::getTotalAmount).reduce(BigDecimal.ZERO, BigDecimal::add); exportSortingVo.setUps(expressAmount); } // 卡車 if (shippingTypeMap.containsKey(CrossdockEnums.ShippingType.TRUCK.name())) { List<CrossdockPlan> truckCrossdockPlanList = shippingTypeMap.get(CrossdockEnums.ShippingType.TRUCK.name()); BigDecimal truckAmount = truckCrossdockPlanList.stream().filter(crossdockPlan -> !ObjectUtils.isEmpty(crossdockPlan.getTotalAmount())) .map(CrossdockPlan::getTotalAmount).reduce(BigDecimal.ZERO, BigDecimal::add); exportSortingVo.setTruck(truckAmount); } // 自提 if (shippingTypeMap.containsKey(CrossdockEnums.ShippingType.SELF.name())) { List<CrossdockPlan> selfCrossdockPlanList = shippingTypeMap.get(CrossdockEnums.ShippingType.SELF.name()); BigDecimal selfAmount = selfCrossdockPlanList.stream().filter(crossdockPlan -> !ObjectUtils.isEmpty(crossdockPlan.getTotalAmount())) .map(CrossdockPlan::getTotalAmount).reduce(BigDecimal.ZERO, BigDecimal::add); exportSortingVo.setSelf(selfAmount); } // 總數(shù) BigDecimal totalAmount = crossdockPlanList.stream().filter(crossdockPlan -> !ObjectUtils.isEmpty(crossdockPlan.getTotalAmount())) .map(CrossdockPlan::getTotalAmount).reduce(BigDecimal.ZERO, BigDecimal::add); exportSortingVo.setTotal(crossdock.getTotalAmount()); //這里設(shè)置的總箱數(shù)應(yīng)該是轉(zhuǎn)運(yùn)單里面的總箱數(shù) // 留倉(cāng)/hold BigDecimal warehouseAmount = crossdock.getTotalAmount().subtract(totalAmount); exportSortingVo.setWarehouse(warehouseAmount); } exportSortingVoList.add(exportSortingVo); // 設(shè)置分揀詳細(xì)信息 List<ExportSortingDetailVo> exportSortingDetailVoList = new ArrayList<>(); if (crossdockSortingMap.containsKey(crossdock.getId())) { List<CrossdockSorting> crossdockSortingByOrderIdList = crossdockSortingMap.get(crossdock.getId()); for (CrossdockSorting crossdockSorting : crossdockSortingByOrderIdList) { if (crossdockSortingItemMap.containsKey(crossdockSorting.getId())) { CrossdockPlan plan = crossdockPlanService.getByFieldValue(crossdockSorting.getSortingPlanRid(), CrossdockPlan::getSortingPlanRid); List<CrossdockPlanGoods> planGoodsList = null; if (plan != null) { planGoodsList = crossdockPlanGoodsService.list(new QueryWrapper<CrossdockPlanGoods>().lambda() .eq(CrossdockPlanGoods::getPlanId, plan.getId())); } // 箱子信息 List<CrossdockSortingItem> crossdockSortingItems = crossdockSortingItemMap.get(crossdockSorting.getId()); for (CrossdockSortingItem crossdockSortingItem : crossdockSortingItems) { ExportSortingDetailVo exportSortingDetailVo = new ExportSortingDetailVo(); exportSortingDetailVo.setInstructions(crossdockSortingItem.getNote()); exportSortingDetailVo.setOrderNo(crossdockSortingItem.getPlNo()); exportSortingDetailVo.setBoxesNo(crossdockSortingItem.getPackageNum()); exportSortingDetailVo.setCbm(BigDecimal.ZERO); if (CollectionUtils.isNotEmpty(planGoodsList)){ List<CrossdockPlanGoods> filterPlanGoodsList = planGoodsList.stream() .filter(Objects::nonNull) .filter(x -> Objects.equals(x.getFbaNumber(), crossdockSortingItem.getPlNo())) .collect(Collectors.toList()); exportSortingDetailVo.setCbm(CollectionUtils.isNotEmpty(filterPlanGoodsList) ? filterPlanGoodsList.get(0).getCbm() : BigDecimal.ZERO); } exportSortingDetailVo.setPalletsNo(crossdockSorting.getInboundPallet()); exportSortingDetailVo.setStorageLocation(null); exportSortingDetailVo.setSubtotalQuantity(crossdockSorting.getPackageNum()); if (plan != null && plan.getIsHold()) { exportSortingDetailVo.setWarehouseCode(crossdockSorting.getSortingNote() + "-HOLD"); } else { exportSortingDetailVo.setWarehouseCode(crossdockSorting.getSortingNote()); } exportSortingDetailVoList.add(exportSortingDetailVo); } exportSortingDetailVoMap.put(crossdock.getOrderNo(), exportSortingDetailVoList); } } } } complexFill(exportSortingVoList, exportSortingDetailVoMap, response); }
上面數(shù)據(jù)處理好放進(jìn)去然后繼續(xù)調(diào)用
public void complexFill(List<ExportSortingVo> baseInfoList, Map<String, List<ExportSortingDetailVo>> detailInfoMap, HttpServletResponse response) throws IOException { byte[] pdfBytes = convertExcelToPdf(baseInfoList,detailInfoMap); // 設(shè)置響應(yīng)頭 response.setContentType("application/pdf"); response.setHeader("Content-Disposition", "attachment; filename="+detailInfoMap.keySet().iterator().next()+".pdf"); // 獲取響應(yīng)輸出流 OutputStream outputStream = response.getOutputStream(); outputStream.write(pdfBytes); outputStream.flush(); outputStream.close(); //打印日志 PrintLogCreateRequest request = new PrintLogCreateRequest(); request.setPrintNo(detailInfoMap.keySet().iterator().next()); request.setPrintType(PrintEnums.type.SORTING.name()); printLogService.createPrintLog(request); }
捕獲特定異常:目前,方法聲明拋出了
IOException
,但沒(méi)有處理其他可能的異常(如NullPointerException
或IllegalArgumentException
)。建議捕獲特定的異常,并根據(jù)不同的異常類型返回適當(dāng)?shù)腻e(cuò)誤信息。
private byte[] convertExcelToPdf(List<ExportSortingVo> baseInfoList,Map<String, List<ExportSortingDetailVo>> detailInfoMap) throws IOException{ Document document = new Document(); ByteArrayOutputStream pdfOutputStream = new ByteArrayOutputStream(); try { PdfWriter writer = PdfWriter.getInstance(document, pdfOutputStream); BaseFont bf = BaseFont.createFont(TEMPLATE_FONT, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); // 設(shè)置頁(yè)邊距 document.setMargins(1, 1, 10, 10); document.open(); ExportSortingVo sorting = baseInfoList.get(0); PdfPTable table = new PdfPTable(8); // 有8列 // 第一行 PdfPCell cell1 = new PdfPCell(new Paragraph("客戶編號(hào):"+sorting.getCustomerCode(),new Font(bf,12,Font.NORMAL))); cell1.setColspan(1); cell1.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell1); PdfPCell cell2 = new PdfPCell(new Paragraph("總數(shù)",new Font(bf,12,Font.NORMAL))); cell2.setColspan(1); cell2.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell2); PdfPCell cell3 = new PdfPCell(new Paragraph(" ",new Font(bf,12,Font.NORMAL))); cell3.setColspan(1); cell3.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell3); PdfPCell cell4 = new PdfPCell(new Paragraph(ObjectUtils.isEmpty(sorting.getTotal()) ? StringUtils.EMPTY : sorting.getTotal().stripTrailingZeros().toPlainString(),new Font(bf,12,Font.NORMAL))); cell4.setColspan(3); cell4.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell4); PdfPCell cell5 = new PdfPCell(new Paragraph("拆柜公司",new Font(bf,12,Font.NORMAL))); cell5.setColspan(1); cell5.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell5); PdfPCell cell6 = new PdfPCell(new Paragraph(" ",new Font(bf,12,Font.NORMAL))); cell6.setColspan(1); cell6.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell6); // 第二行 PdfPCell cell7 = new PdfPCell(new Paragraph("公司:"+sorting.getCompany(),new Font(bf,12,Font.NORMAL))); cell7.setColspan(1); cell7.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell7); PdfPCell cell8 = new PdfPCell(new Paragraph("UPS/Fedex",new Font(bf,12,Font.NORMAL))); cell8.setColspan(1); cell8.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell8); PdfPCell cell9 = new PdfPCell(new Paragraph(" ", new Font(bf, 12, Font.NORMAL))); cell9.setColspan(1); cell9.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell9); PdfPCell cell10 = new PdfPCell(new Paragraph(ObjectUtils.isEmpty(sorting.getUps()) ? StringUtils.EMPTY : sorting.getUps().stripTrailingZeros().toPlainString(), new Font(bf, 12, Font.NORMAL))); cell10.setColspan(3); cell10.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell10); PdfPCell cell11 = new PdfPCell(new Paragraph("拆柜碼頭", new Font(bf, 12, Font.NORMAL))); cell11.setColspan(1); cell11.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell11); PdfPCell cell12 = new PdfPCell(new Paragraph(" ", new Font(bf, 12, Font.NORMAL))); cell12.setColspan(1); cell12.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell12); // 第三行 PdfPCell cell13 = new PdfPCell(new Paragraph("柜號(hào):"+sorting.getCtnr(),new Font(bf,12,Font.NORMAL))); cell13.setColspan(1); cell13.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell13); PdfPCell cell14 = new PdfPCell(new Paragraph("留倉(cāng)/Hold",new Font(bf,12,Font.NORMAL))); cell14.setColspan(1); cell14.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell14); PdfPCell cell15 = new PdfPCell(new Paragraph(" ", new Font(bf, 12, Font.NORMAL))); cell15.setColspan(1); cell15.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell15); PdfPCell cell16 = new PdfPCell(new Paragraph(ObjectUtils.isEmpty(sorting.getWarehouse()) ? StringUtils.EMPTY : sorting.getWarehouse().stripTrailingZeros().toPlainString(), new Font(bf, 12, Font.NORMAL))); cell16.setColspan(3); cell16.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell16); PdfPCell cell17 = new PdfPCell(new Paragraph("拆柜開(kāi)始時(shí)間", new Font(bf, 12, Font.NORMAL))); cell17.setColspan(1); cell17.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell17); PdfPCell cell18 = new PdfPCell(new Paragraph(" ", new Font(bf, 12, Font.NORMAL))); cell18.setColspan(1); cell18.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell18); // 第四行 PdfPCell cell19 = new PdfPCell(new Paragraph("柜式:"+sorting.getCabinetType(),new Font(bf,12,Font.NORMAL))); cell19.setColspan(1); cell19.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell19); PdfPCell cell20 = new PdfPCell(new Paragraph("卡派",new Font(bf,12,Font.NORMAL))); cell20.setColspan(1); cell20.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell20); PdfPCell cell21 = new PdfPCell(new Paragraph(" ", new Font(bf, 12, Font.NORMAL))); cell21.setColspan(1); cell21.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell21); PdfPCell cell22 = new PdfPCell(new Paragraph(ObjectUtils.isEmpty(sorting.getTruck()) ? StringUtils.EMPTY : sorting.getTruck().stripTrailingZeros().toPlainString(), new Font(bf, 12, Font.NORMAL))); cell22.setColspan(3); cell22.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell22); PdfPCell cell23 = new PdfPCell(new Paragraph("拆柜結(jié)束時(shí)間", new Font(bf, 12, Font.NORMAL))); cell23.setColspan(1); cell23.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell23); PdfPCell cell24 = new PdfPCell(new Paragraph(" ", new Font(bf, 12, Font.NORMAL))); cell24.setColspan(1); cell24.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell24); // 第五行 PdfPCell cell25 = new PdfPCell(new Paragraph(" ",new Font(bf,12,Font.NORMAL))); cell25.setColspan(1); cell25.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell25); PdfPCell cell26 = new PdfPCell(new Paragraph("自提",new Font(bf,12,Font.NORMAL))); cell26.setColspan(1); cell26.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell26); PdfPCell cell27 = new PdfPCell(new Paragraph(" ", new Font(bf, 12, Font.NORMAL))); cell27.setColspan(1); cell27.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell27); PdfPCell cell28 = new PdfPCell(new Paragraph(ObjectUtils.isEmpty(sorting.getSelf()) ? StringUtils.EMPTY : sorting.getSelf().stripTrailingZeros().toPlainString(), new Font(bf, 12, Font.NORMAL))); cell28.setColspan(1); cell28.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell28); PdfPCell cell29 = createBarcodeImage(writer, sorting.getKey()); cell29.setColspan(4); cell29.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell29); //第六行 PdfPCell cell31 = new PdfPCell(new Paragraph("訂單號(hào)", new Font(bf, 12, Font.NORMAL))); cell31.setColspan(1); cell31.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell31); PdfPCell cell32 = new PdfPCell(new Paragraph("箱子數(shù)量", new Font(bf, 12, Font.NORMAL))); cell32.setColspan(1); cell32.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell32); PdfPCell cell33 = new PdfPCell(new Paragraph("體積", new Font(bf, 12, Font.NORMAL))); cell33.setColspan(1); cell33.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell33); PdfPCell cell34 = new PdfPCell(new Paragraph("倉(cāng)庫(kù)代碼", new Font(bf, 12, Font.NORMAL))); cell34.setColspan(1); cell34.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell34); PdfPCell cell35 = new PdfPCell(new Paragraph("數(shù)量小計(jì)", new Font(bf, 12, Font.NORMAL))); cell35.setColspan(1); cell35.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell35); PdfPCell cell36 = new PdfPCell(new Paragraph("存儲(chǔ)位置", new Font(bf, 12, Font.NORMAL))); cell36.setColspan(1); cell36.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell36); PdfPCell cell37 = new PdfPCell(new Paragraph("托盤數(shù)量", new Font(bf, 12, Font.NORMAL))); cell37.setColspan(1); cell37.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell37); PdfPCell cell38 = new PdfPCell(new Paragraph("外箱標(biāo)記或說(shuō)明", new Font(bf, 12, Font.NORMAL))); cell38.setColspan(1); cell38.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell38); //第七行 List<ExportSortingDetailVo> detailList = detailInfoMap.get(sorting.getKey()); //按照倉(cāng)庫(kù)代碼的A-Z順序來(lái)排序 detailList.sort(Comparator.comparing(ExportSortingDetailVo::getWarehouseCode, Comparator.nullsLast(Comparator.naturalOrder()))); Map<String, Long> warehouseCodeCountMap = detailList.stream().filter(Objects::nonNull).map(ExportSortingDetailVo::getWarehouseCode).filter(Objects::nonNull) .collect(Collectors.groupingBy(Function.identity(),Collectors.counting())); Map<String, Integer> firstOccurrenceMap = new HashMap<>(); for (int i = 0; i < detailList.size(); i++) { ExportSortingDetailVo detail = detailList.get(i); String warehouseCode = detail.getWarehouseCode(); if (warehouseCode != null && !firstOccurrenceMap.containsKey(warehouseCode)) { firstOccurrenceMap.put(warehouseCode, i); } } for (int i = 0; i < detailList.size(); i++) { ExportSortingDetailVo detail = detailList.get(i); PdfPCell cell39 = new PdfPCell(new Paragraph(detail.getOrderNo(), new Font(bf, 12, Font.NORMAL))); cell39.setColspan(1); cell39.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell39); PdfPCell cell40 = new PdfPCell(new Paragraph(ObjectUtils.isEmpty(detail.getBoxesNo()) ? StringUtils.EMPTY : detail.getBoxesNo().stripTrailingZeros().toPlainString(), new Font(bf, 12, Font.NORMAL))); cell40.setColspan(1); cell40.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell40); PdfPCell cell41 = new PdfPCell(new Paragraph(ObjectUtils.isEmpty(detail.getCbm()) ? StringUtils.EMPTY : detail.getCbm().stripTrailingZeros().toPlainString(), new Font(bf, 12, Font.NORMAL))); cell41.setColspan(1); cell41.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell41); Integer i1 = firstOccurrenceMap.get(detail.getWarehouseCode()); Long l = warehouseCodeCountMap.get(detail.getWarehouseCode()); if (i1 == i) { PdfPCell cell42 = new PdfPCell(new Paragraph(ObjectUtils.isEmpty(detail.getWarehouseCode()) ? StringUtils.EMPTY : detail.getWarehouseCode(), new Font(bf, 12, Font.NORMAL))); cell42.setColspan(1); cell42.setRowspan(Math.toIntExact(l)); cell42.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); cell42.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE); table.addCell(cell42); PdfPCell cell43 = new PdfPCell(new Paragraph(ObjectUtils.isEmpty(detail.getSubtotalQuantity()) ? StringUtils.EMPTY : detail.getSubtotalQuantity().stripTrailingZeros().toPlainString(), new Font(bf, 12, Font.NORMAL))); cell43.setColspan(1); cell43.setRowspan(Math.toIntExact(l)); cell43.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); cell43.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE); table.addCell(cell43); PdfPCell cell44 = new PdfPCell(new Paragraph(ObjectUtils.isEmpty(detail.getStorageLocation()) ? StringUtils.EMPTY : detail.getStorageLocation(), new Font(bf, 12, Font.NORMAL))); cell44.setColspan(1); cell44.setRowspan(Math.toIntExact(l)); cell44.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); cell44.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE); table.addCell(cell44); PdfPCell cell45 = new PdfPCell(new Paragraph(ObjectUtils.isEmpty(detail.getPalletsNo()) ? StringUtils.EMPTY : detail.getPalletsNo().stripTrailingZeros().toPlainString(), new Font(bf, 12, Font.NORMAL))); cell45.setColspan(1); cell45.setRowspan(Math.toIntExact(l)); cell45.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); cell45.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE); table.addCell(cell45); } PdfPCell cell46 = new PdfPCell(new Paragraph(ObjectUtils.isEmpty(detail.getInstructions()) ? StringUtils.EMPTY : detail.getInstructions(), new Font(bf, 12, Font.NORMAL))); cell46.setColspan(1); cell46.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); table.addCell(cell46); } document.add(table); } catch (DocumentException e) { log.error("error!", e); throw new ApiException(ResultCode.FAULT); } document.close(); return pdfOutputStream.toByteArray(); }
上面代碼就是一行行的把值塞進(jìn)去,
值得一提的是行合并,也就是幾行明細(xì)對(duì)應(yīng)一行的內(nèi)容
代碼
按照倉(cāng)庫(kù)代碼的A-Z順序來(lái)排序 處
detailList
中的ExportSortingDetailVo
對(duì)象將按照warehouseCode
的字母表順序進(jìn)行排序,null
值排在最后。
warehouseCodeCountMap
是一個(gè)Map<String, Long>
,其中鍵是倉(cāng)庫(kù)代碼,值是該倉(cāng)庫(kù)代碼在detailList
中出現(xiàn)的次數(shù)。firstOccurrenceMap
是一個(gè)Map<String, Integer>
,其中鍵是倉(cāng)庫(kù)代碼,值是該倉(cāng)庫(kù)代碼在detailList
中第一次出現(xiàn)的索引位置。
看這里可能有點(diǎn)不明白,看到效果圖相信你會(huì)恍然大悟的
四 條形碼工具類
private PdfPCell createBarcodeImage(PdfWriter writer, String code) { Barcode128 barcode = new Barcode128(); barcode.setCode(code); barcode.setCodeType(Barcode128.CODE128); barcode.setSize(12); // 設(shè)置條形碼的字體大小 barcode.setBaseline(10); // 設(shè)置基線位置 barcode.setX(1.5f); // 設(shè)置條形碼的寬度 barcode.setBarHeight(50f); // 設(shè)置條形碼的高度 // 將條形碼轉(zhuǎn)換為 Image 對(duì)象 Image barcodeImage = barcode.createImageWithBarcode(writer.getDirectContent(), null, null); PdfPCell cell = new PdfPCell(barcodeImage); cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); return cell; }
五 效果圖
大概是上面這個(gè)樣子
具體圖表根據(jù)實(shí)際業(yè)務(wù)進(jìn)行構(gòu)建代碼
以上就是Java使用itext生成復(fù)雜數(shù)據(jù)的pdf的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于Java itext生成pdf的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java攔截過(guò)濾器模式 (Intercepting Filter )實(shí)現(xiàn)方法
攔截過(guò)濾器模式(Intercepting Filter Pattern)用于對(duì)應(yīng)用程序的請(qǐng)求或響應(yīng)做一些預(yù)處理/后處理,本文通過(guò)實(shí)例代碼介紹Java攔截過(guò)濾器模式 (Intercepting Filter )的相關(guān)知識(shí),感興趣的朋友跟隨小編一起看看吧2024-03-03Assert.assertEquals的使用方法及注意事項(xiàng)說(shuō)明
這篇文章主要介紹了Assert.assertEquals的使用方法及注意事項(xiàng)說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05Java實(shí)戰(zhàn)個(gè)人博客系統(tǒng)的實(shí)現(xiàn)流程
讀萬(wàn)卷書不如行萬(wàn)里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+springboot+mybatis+redis+vue+elementui+Mysql實(shí)現(xiàn)一個(gè)個(gè)人博客系統(tǒng),大家可以在過(guò)程中查缺補(bǔ)漏,提升水平2022-01-01Java 實(shí)現(xiàn)限流器處理Rest接口請(qǐng)求詳解流程
在工作中是否會(huì)碰到這樣的場(chǎng)景,高并發(fā)的請(qǐng)求但是無(wú)法全部執(zhí)行,需要一定的限流。如果你是使用的微服務(wù)框架,比如SpringCloud,可以使用Gateway增加限流策略來(lái)解決。本篇文章是在沒(méi)有框架的情況實(shí)現(xiàn)限流器2021-11-11SpringBoot項(xiàng)目中使用Sharding-JDBC實(shí)現(xiàn)讀寫分離的詳細(xì)步驟
Sharding-JDBC是一個(gè)分布式數(shù)據(jù)庫(kù)中間件,它不僅支持?jǐn)?shù)據(jù)分片,還可以輕松實(shí)現(xiàn)數(shù)據(jù)庫(kù)的讀寫分離,本文介紹如何在Spring Boot項(xiàng)目中集成Sharding-JDBC并實(shí)現(xiàn)讀寫分離的詳細(xì)步驟,需要的朋友可以參考下2024-08-08如何使用?Spring?Boot?搭建?WebSocket?服務(wù)器實(shí)現(xiàn)多客戶端連接
本文介紹如何使用SpringBoot快速搭建WebSocket服務(wù)器,實(shí)現(xiàn)多客戶端連接和消息廣播,WebSocket協(xié)議提供全雙工通信,SpringBoot通過(guò)@ServerEndpoint簡(jiǎn)化配置,支持實(shí)時(shí)消息推送,適用于聊天室或通知系統(tǒng)等應(yīng)用場(chǎng)景2024-11-11Flutter驗(yàn)證碼輸入框的2種方法實(shí)現(xiàn)
本文主要介紹了Flutter驗(yàn)證碼輸入框的2種方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12webservice實(shí)現(xiàn)springboot項(xiàng)目間接口調(diào)用與對(duì)象傳遞示例
本文主要介紹了webservice實(shí)現(xiàn)springboot項(xiàng)目間接口調(diào)用與對(duì)象傳遞示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07