java使用itext生成复杂数据的pdf

上一篇文章是 java使用itext生成pdf标签 使用了 Adobe Acrobat 软件 设置域

本篇文章不使用其他工具,纯代码手写 pdf表格

首先,什么是Itext

Apache iText 是一个开源 Java 库,支持 PDF 文档的开发和转换。
在本教程中,我们将学习如何使用 iText 开发可以创建、转换和操作 PDF 文档的 Java 程序。
Itext目前遵从AGPL开源协议,AGPL 可以说是最严格的 GPL 了,强传染性,即使是 RPC 调用也会被感染,不发行软件而是作为 web 服务对外提供也必须开放源代码
目前Itext有很多product开始收费,但你所需的功能基本上open source都能满足

特点:

以下是 iText 库的显着特点 −

  • Interactive − iText 为你提供类(API)来生成交互式 PDF 文档。使用这些,你可以创建地图和书籍。
  • Adding bookmarks, page numbers, etc − 使用 iText,你可以添加书签、页码和水印。
  • Split & Merge − 使用 iText,你可以将现有的 PDF 拆分为多个 PDF,还可以向其中添加/连接其他页面。
  • Fill Forms − 使用 iText,你可以在 PDF 文档中填写交互式表单。
  • Save as Image − 使用 iText,你可以将 PDF 保存为图像文件,例如 PNG 或 JPEG。
  • Canvas − iText 库为您提供了一个 Canvas 类,你可以使用它在 PDF 文档上绘制各种几何形状,如圆形、线条等。
  • Create PDFs − 使用 iText,你可以从 Java 程序创建新的 PDF 文件。你也可以包含图像和字体。
  • 下载地址:Examples

    iText官网: 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 响应流中,以便客户端可以下载或查看 PDF 文件。

目前,方法声明抛出了 Exception,这会导致所有未捕获的异常都被抛出到客户端。为了提高代码的健壮性,建议捕获特定的异常,并根据不同的异常类型返回适当的 HTTP 状态码和错误信息。

例如,你可以使用 @ExceptionHandler 来捕获常见的异常,如 IOExceptionDocumentException 等,并返回 500 Internal Server Error 或其他适当的响应。

    @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层

按照业务逻辑从数据库获取数据并处理数据,放到合适的对象里

(这里主要是和业务相关,不必深究里面内容,最后能得出需要的数据传出即可)

@Overridepublic 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());// 集装箱编号/柜号、柜型List<Crossdock> crossdockList = crossdockService.listByFieldValueSet(idSet, Crossdock::getId);if (ObjectUtils.isEmpty(crossdockList)) {throw new ApiException(ResultCode.PARAMES_INVALID);}// 统计快递、卡派、自提、存仓数量List<CrossdockPlan> crossdockPlanByOrderList = crossdockPlanService.listByFieldValueSet(idSet, CrossdockPlan::getOrderId);Map<String, List<CrossdockPlan>> crossdockPlanOrderIdMap = crossdockPlanByOrderList.stream().collect(Collectors.groupingBy(CrossdockPlan::getOrderId));// 客户id、公司// 客户(发件人)信息 customerVoSet<String> customerIdSet = crossdockList.stream().map(Crossdock::getCustomerId).collect(Collectors.toSet());Map<String, Customer> customerMap = customerService.mapByFieldValueSet(customerIdSet, Customer::getId);// 箱数统计,分拣表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);// 拼接参数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());}// 设置统计数量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);}// 总数BigDecimal totalAmount = crossdockPlanList.stream().filter(crossdockPlan -> !ObjectUtils.isEmpty(crossdockPlan.getTotalAmount())).map(CrossdockPlan::getTotalAmount).reduce(BigDecimal.ZERO, BigDecimal::add);exportSortingVo.setTotal(crossdock.getTotalAmount());       //这里设置的总箱数应该是转运单里面的总箱数// 留仓/holdBigDecimal warehouseAmount = crossdock.getTotalAmount().subtract(totalAmount);exportSortingVo.setWarehouse(warehouseAmount);}exportSortingVoList.add(exportSortingVo);// 设置分拣详细信息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);}

上面数据处理好放进去然后继续调用

 public void complexFill(List<ExportSortingVo> baseInfoList, Map<String, List<ExportSortingDetailVo>> detailInfoMap, HttpServletResponse response) throws IOException {byte[] pdfBytes = convertExcelToPdf(baseInfoList,detailInfoMap);// 设置响应头response.setContentType("application/pdf");response.setHeader("Content-Disposition", "attachment; filename="+detailInfoMap.keySet().iterator().next()+".pdf");// 获取响应输出流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,但没有处理其他可能的异常(如 NullPointerExceptionIllegalArgumentException)。建议捕获特定的异常,并根据不同的异常类型返回适当的错误信息。

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);// 设置页边距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("客户编号:"+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("总数",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("柜号:"+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("留仓/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("拆柜开始时间", 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("拆柜结束时间", 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("订单号", new Font(bf, 12, Font.NORMAL)));cell31.setColspan(1);cell31.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);table.addCell(cell31);PdfPCell cell32 = new PdfPCell(new Paragraph("箱子数量", 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("仓库代码", new Font(bf, 12, Font.NORMAL)));cell34.setColspan(1);cell34.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);table.addCell(cell34);PdfPCell cell35 = new PdfPCell(new Paragraph("数量小计", new Font(bf, 12, Font.NORMAL)));cell35.setColspan(1);cell35.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);table.addCell(cell35);PdfPCell cell36 = new PdfPCell(new Paragraph("存储位置", new Font(bf, 12, Font.NORMAL)));cell36.setColspan(1);cell36.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);table.addCell(cell36);PdfPCell cell37 = new PdfPCell(new Paragraph("托盘数量", new Font(bf, 12, Font.NORMAL)));cell37.setColspan(1);cell37.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);table.addCell(cell37);PdfPCell cell38 = new PdfPCell(new Paragraph("外箱标记或说明", new Font(bf, 12, Font.NORMAL)));cell38.setColspan(1);cell38.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);table.addCell(cell38);//第七行List<ExportSortingDetailVo> detailList = detailInfoMap.get(sorting.getKey());//按照仓库代码的A-Z顺序来排序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();}

上面代码就是一行行的把值塞进去,

值得一提的是行合并,也就是几行明细对应一行的内容

代码 

按照仓库代码的A-Z顺序来排序 处
  • detailList 中的 ExportSortingDetailVo 对象将按照 warehouseCode 的字母表顺序进行排序,null 值排在最后。
  • warehouseCodeCountMap 是一个 Map<String, Long>,其中键是仓库代码,值是该仓库代码在 detailList 中出现的次数。
  • firstOccurrenceMap 是一个 Map<String, Integer>,其中键是仓库代码,值是该仓库代码在 detailList 中第一次出现的索引位置。

看这里可能有点不明白,看到效果图相信你会恍然大悟的

四 条形码工具类

    private PdfPCell createBarcodeImage(PdfWriter writer, String code) {Barcode128 barcode = new Barcode128();barcode.setCode(code);barcode.setCodeType(Barcode128.CODE128);barcode.setSize(12); // 设置条形码的字体大小barcode.setBaseline(10); // 设置基线位置barcode.setX(1.5f); // 设置条形码的宽度barcode.setBarHeight(50f); // 设置条形码的高度// 将条形码转换为 Image 对象Image barcodeImage = barcode.createImageWithBarcode(writer.getDirectContent(), null, null);PdfPCell cell = new PdfPCell(barcodeImage);cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);return cell;}

五 效果图

大概是上面这个样子

具体图表根据实际业务进行构建代码

这个也是支持批量的,需要代码可留言或私聊

有疑问可留言,看到后会及时的回复

欢迎交流,共同进步!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/489887.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

回归预测 | Matlab实现基于BiLSTM-Adaboost双向长短期记忆神经网络结合Adaboost集成学习回归预测

目录 效果一览基本介绍模型设计程序设计参考资料效果一览 基本介绍 回归预测 | Matlab实现基于BiLSTM-Adaboost双向长短期记忆神经网络结合Adaboost集成学习回归预测 模型设计 基于BiLSTM-Adaboost的回归预测模型结合了双向长短期记忆神经网络(BiLSTM)和Adaboost集成学习的…

MATLAB生成.exe独立程序过程(常见问题解决方法)(2024.12.14)

本文只记录我执行过程中遇到的关键问题、以及解决方法&#xff0c;不讲诉整个流程。 电脑环境 win11系统 matlab 2024b 版本 整体流程 1.下载matlab运行时库,简写为MCR 2.配置MCR环境 3.打包程序 4.目标机器安装程序 一、下载MCR 下载这个折腾了大半天&#xff0c;大概问题就是…

python 调Qt C++ 写法配置和坑点

python 示例写法 和调c动态库一样 通过回调函数方式 将python函数注册到c 动态库中 from ctypes import *def DllCall(nParam, nFlag):print(nParam, nFlag)z2 0.6z3 0.4z4 0.0z5 0.3z6 0.5z7 0.8z8 0.3z9 0.9strData str(z2) str(z3) str(z4) str(z5)…

从零开始学docker(五)-可用的docker镜像

最近docker镜像都不能访问&#xff0c;目前亲测可用的docker镜像可用&#xff0c;并拉取mysql测试完成。 [缺点] docker search 查不到镜像的索引列表&#xff0c;只能手动查询索引目录&#xff08;解决方案在最后&#xff09;。 linux服务器vim打开镜像文件daemon.json vim /e…

开源 AI 智能名片 S2B2C 商城小程序对私域流量运营的全方位助力

在当今竞争激烈的商业环境中&#xff0c;私域流量运营已成为企业实现可持续发展和提升竞争力的关键策略之一。开源 AI 智能名片 S2B2C 商城小程序凭借其独特的功能与特性&#xff0c;从多个维度为私域流量运营提供了强有力的支持与推动&#xff0c;以下将详细阐述其在各个方面的…

Hadoop学习笔记(包括hadoop3.4.0集群安装)(黑马)

Hadoop学习笔记 0-前置章节-环境准备 0.1 环境介绍 配置环境&#xff1a;hadoop-3.4.0&#xff0c;jdk-8u171-linux-x64 0.2 VMware准备Linux虚拟机 0.2.1主机名、IP、SSH免密登录 1.配置固定IP地址&#xff08;root权限&#xff09; 开启master&#xff0c;修改主机名为…

鸿蒙NEXT开发案例:九宫格随机

【引言】 在鸿蒙NEXT开发中&#xff0c;九宫格抽奖是一个常见且有趣的应用场景。通过九宫格抽奖&#xff0c;用户可以随机获得不同奖品&#xff0c;增加互动性和趣味性。本文将介绍如何使用鸿蒙开发框架实现九宫格抽奖功能&#xff0c;并通过代码解析展示实现细节。 【环境准…

redis集群安装部署 redis三主三从集群

redis集群安装部署 redis三主三从集群 1、下载redis2、安装redis集群 三主三从3、配置redis开机自启动3.1、建立启动脚本3.2、复制多份redis启动脚本给集群使用3.3、添加可执行权限3.4、配置开机自启动 1、下载redis 本次redis安装部署选择当前最新的稳定版本7.4.1 下载链接: …

链表的回文结构

链表的回文结构。OJ链接 import java.util.*;/* public class ListNode {int val;ListNode next null;ListNode(int val) {this.val val;} }*/ public class PalindromeList {public boolean chkPalindrome(ListNode head) {// write code hereListNode slowhead;ListNode …

electron 打包 webview 嵌入需要调用电脑摄像头拍摄失败问题

electron 打包 webview 嵌入需要调用电脑摄像头拍摄失败问题 这篇文章是接我cocos专栏的上一篇文章继续写的&#xff0c;我上一篇文章写的是 cocos 开发触摸屏项目&#xff0c;需要嵌入一个网页用来展示&#xff0c;最后通过 electron 打包成 exe 程序&#xff0c;而且网页里面…

计算机组成原理与系统结构——多核计算机

笔记内容及图片整理自XJTUSE “计算机组成原理与系统结构” 课程ppt&#xff0c;仅供学习交流使用&#xff0c;谢谢。 多核处理器也称为芯片多处理器&#xff0c;将两个及以上处理器单元组合在一个芯片上。通常&#xff0c;每个内核都由独立处理器的全部组件构成&#xff0c;例…

JAVA学习(三)

方法内部类 匿名内部类 如下使用匿名内部类去实现&#xff1a;&#xff08;对内存的损耗&#xff0c;对系统性能的影响相对较小&#xff09; 总结

IIS服务器部署C# WebApi程序,客户端PUT,DELETE请求无法执行

这两天在自己Windows10电脑上搭建IIS服务器&#xff0c;把自己写的WebApi代码部署上做个本地服务器&#xff0c;结果客户端的PUT和DELETE请求无法执行&#xff0c;GET、POST这些都正常&#xff0c;研究后发现要删除IIS中的“模块”中的"webdavmodule"才能解决。

微服务-01

1.认识微服务 1.1 单体架构 单体架构&#xff08;monolithic structure&#xff09;&#xff1a;顾名思义&#xff0c;整个项目中所有功能模块都在一个工程中开发&#xff1b;项目部署时需要对所有模块一起编译、打包&#xff1b;项目的架构设计、开发模式都非常简单。 当项目…

Vue2 基础

Vue 2 是 Vue.js 的第二个主要版本&#xff0c;于 2016 年发布。它是一个渐进式的 JavaScript 框架&#xff0c;以其简单、灵活、易用性高而广受欢迎。Vue 2 主要专注于构建用户界面&#xff08;UI&#xff09;&#xff0c;并且非常适合用于构建单页应用&#xff08;SPA&#x…

LSTM详解

1. LSTM设计 LSTM(长短期记忆网络)详解 长短期记忆网络(LSTM, Long Short-Term Memory) 是一种特殊的循环神经网络(RNN),特别适合处理和预测序列数据中的长时间依赖关系。LSTM 通过引入“门机制”(如输入门、遗忘门、输出门)来解决标准 RNN 在长时间序列任务中梯度消…

【从零开始入门unity游戏开发之——C#篇05】转义字符、@处理多行文本或者不使用转义字符、随机数

文章目录 一、转义字符1、什么是转义字符&#xff1f;2、常见的转义字符3、总结 二、使用处理多行文本或者不使用转义字符1、多行字符串2、不使用转义字符 三、随机数1、Random.Next()生成随机整数示例&#xff1a;生成一个随机整数生成指定范围内的随机整数 2、Random.NextSin…

3D 生成重建034-NerfDiff借助扩散模型直接生成nerf

3D 生成重建034-NerfDiff借助扩散模型直接生成nerf 文章目录 0 论文工作1 论文方法2 实验结果 0 论文工作 感觉这个论文可能能shapE差不多同时期工作&#xff0c;但是shapE是生成任意种类。 本文提出了一种新颖的单图像视图合成方法NerfDiff&#xff0c;该方法利用神经辐射场 …

3D一览通在线协同设计,助力汽车钣金件设计与制造数字化升级

汽车行业已迎来智能化的汹涌浪潮&#xff0c;在此背景下&#xff0c;零部件制造商唯有积极应对&#xff0c;以智能制造为核心驱动力&#xff0c;方能跟上行业发展步调&#xff0c;在激烈的市场竞争中抢占先机。作为整车制造不可或缺的核心组件之一&#xff0c;汽车钣金件亦需紧…

从资产流动分析WIF市场潜力X.game深究其他未知因素

近日&#xff0c;两则关于WIF最新消息引起了投资者们的注意。据报道&#xff0c;11月28日Vintermute在过去13小时内累计从Binance交易所提取了价值533万美元的WIF&#xff0c;此举不仅彰显了其强大的资金实力&#xff0c;更在某种程度上推动了WIF币价的反弹&#xff1b;另一方面…