<!-- PDFBox -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.22</version>
</dependency>
<dependency>
<groupId>com.github.vandeseer</groupId>
<artifactId>easytable</artifactId>
<version>0.8.1</version>
</dependency>
<dependency>
<groupId>com.ione</groupId>
<artifactId>ione-font-simfang</artifactId>
<version>1.0.0</version>
</dependency>
Controller
@ApiOperation(value = "要货单打印")
@GetMapping(value = "/purchase-orders/export-pdf", produces = MediaType.APPLICATION_PDF_VALUE)
public @ResponseBody
byte[] exportPdf(@RequestParam String... uuids) throws Exception {
LambdaQueryWrapper<PurchaseOrderMst> wrapper = Wrappers.lambdaQuery();
wrapper.in(uuids.length > 0, PurchaseOrderMst::getUuid, uuids);
List<PurchaseOrderMst> orders = orderMstService.list(wrapper);
if (orders.isEmpty()) {
throw new ResourceNotFoundException(PurchaseOrderMst.class, Arrays.stream(uuids).collect(Collectors.joining()));
}
Path pdf = pdfService.exportPdf(orders);
return IOUtils.toByteArray(Files.newInputStream(pdf));
}
Servicec
@Service
public class PurchaseOrderPdfServiceImpl {
private final Logger logger = LoggerFactory.getLogger(PurchaseOrderPdfServiceImpl.class);
private PurchaseOrderDtlService dtlService;
private PurchaseOrderMapper orderMapper;
private Path pdfHome;
@Value("${ione.pdf.home}")
public void setPdfHome(Path pdfHome) throws IOException {
this.pdfHome = pdfHome;
if (!Files.exists(pdfHome)) {
Files.createDirectories(pdfHome);
}
}
@Autowired
public void setDtlService(PurchaseOrderDtlService dtlService) {
this.dtlService = dtlService;
}
@Autowired
public void setOrderMapper(PurchaseOrderMapper orderMapper) {
this.orderMapper = orderMapper;
}
public Path exportPdf(List<PurchaseOrderMst> orders) throws Exception {
if (orders.isEmpty()) {
return null;
}
String timeStamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
Path result = pdfHome.resolve(timeStamp + ".pdf");
try {
final PDDocument document = new PDDocument();
for (PurchaseOrderMst order : orders) {
exportPage(document, order);
}
document.save(result.toFile());
document.close();
logger.info("export pdf to : {}", result);
} catch (Exception e) {
logger.error("export pdf fail", e);
}
return result;
}
private void exportPage(PDDocument document, PurchaseOrderMst orderMst) throws IOException {
InputStream inFont = this.getClass().getClassLoader().getResourceAsStream("simfang.ttf");
PDType0Font font = PDType0Font.load(document, inFont);
//获取要货人和要货单位、销售经理
Map map = orderMapper.findEmplNameAndCompanyByUuid(orderMst.getUuid());
//通过单头uuid获取全部的要货单身
//标题行空间
final Table.TableBuilder tableHeaderBuilder1 = Table.builder()
.addColumnsOfWidth(120, 280, 140)
.font(font);
//日期行空间
final Table.TableBuilder tableHeaderBuilder2 = Table.builder()
.addColumnsOfWidth(300, 240)
.font(font);
//内容行空间
final Table.TableBuilder tableHeaderBuilder3 = Table.builder()
.addColumnsOfWidth(140, 120, 60, 65, 65, 90)
.padding(6)
.font(font)
.borderWidth(0.1f)
.borderColor(Color.BLACK);
//结尾行空间
final Table.TableBuilder tableHeaderBuilder4 = Table.builder()
.addColumnsOfWidth(300, 240)
.font(font);
//创建标题表
Table tableHeader1 = tableHeaderBuilder1
.font(font)
.addRow(Row.builder()
.add(TextCell.builder().text("").build())
.add(TextCell.builder().text(" 浙江云峰莫干山装饰建材有限公司要货计划单 ").build())
.horizontalAlignment(HorizontalAlignment.CENTER)
.add(TextCell.builder().text("No:" + orderMst.getNo()).build())
.horizontalAlignment(HorizontalAlignment.LEFT)
.build())
.build();
//创建日期表
Table tableHeader2 = tableHeaderBuilder2
.font(font)
.addRow(Row.builder()
.horizontalAlignment(HorizontalAlignment.LEFT)
.add(TextCell.builder().text("日期:" + new SimpleDateFormat("yyyy年MM月dd日").format(orderMst.getDeliveryDate())).textColor(Color.BLACK).build())
.add(TextCell.builder().text("要货单位:" + map.get("chanName")).textColor(Color.BLACK).build())
.build())
.build();
//填充内容目录文本
List<PurchaseOrderDtl> details = dtlService.list(Wrappers.<PurchaseOrderDtl>lambdaQuery().eq(PurchaseOrderDtl::getPurchaseOrderMstUuid, orderMst.getUuid()));
Table tableHeader3 = buildContent(font, tableHeaderBuilder3, details);
//创建结尾表
Table tableHeader4 = tableHeaderBuilder4
.font(font)
.addRow(Row.builder()
.horizontalAlignment(HorizontalAlignment.LEFT)
.add(TextCell.builder().text("销售经理:" + map.get("marketingManagerName")).textColor(Color.BLACK).build())
.add(TextCell.builder().text("要货人:" + map.get("name")).textColor(Color.BLACK).build())
.build())
.build();
//表格转译
TableDrawer headerDrawer1 = TableDrawer.builder()
.table(tableHeader1)
.startX(25)
.build();
TableDrawer headerDrawer2 = TableDrawer.builder()
.table(tableHeader2)
.startX(25)
.build();
TableDrawer headerDrawer3 = TableDrawer.builder()
.table(tableHeader3)
.startX(25)
.build();
TableDrawer headerDrawer4 = TableDrawer.builder()
.table(tableHeader4)
.startX(25)
.build();
//定义内容在PDF页面位置 以左下角为原点
float startY = 820F;
//创建页
PDPage page = new PDPage(PDRectangle.A4);
//将页添加到PDF文件
document.addPage(page);
//生成页内容流
PDPageContentStream contentStream = new PDPageContentStream(document, page);
//将四张表按顺序拼接
headerDrawer1.startY(startY);
headerDrawer1.contentStream(contentStream).draw();
headerDrawer2.startY(startY - tableHeader1.getHeight());
headerDrawer2.contentStream(contentStream).draw();
headerDrawer3.startY(startY - tableHeader2.getHeight() - tableHeader1.getHeight());
headerDrawer3.contentStream(contentStream).draw();
headerDrawer4.startY(startY - tableHeader3.getHeight() - tableHeader2.getHeight() - tableHeader1.getHeight());
headerDrawer4.contentStream(contentStream).draw();
//关闭流
contentStream.close();
}
private Table buildContent(PDType0Font font, Table.TableBuilder tableHeaderBuilder3, List<PurchaseOrderDtl> details) {
tableHeaderBuilder3
.addRow(Row.builder()
.horizontalAlignment(HorizontalAlignment.CENTER)
.add(TextCell.builder().text("品名").textColor(Color.BLACK).build())
.add(TextCell.builder().text("规格").textColor(Color.BLACK).build())
.add(TextCell.builder().text("单位").textColor(Color.BLACK).build())
.add(TextCell.builder().text("数量").textColor(Color.BLACK).build())
.add(TextCell.builder().text("单价").textColor(Color.BLACK).build())
.add(TextCell.builder().text("备注").textColor(Color.BLACK).build())
.build());
//默认打应5条记录
int count = 5;
if (details.size() > count) {
count = details.size();
}
//内容赋值
Map<String, Object> purchaseDtlMap = new HashMap<>();
for (int i = 0; i < count; i++) {
//初始化空字符串
purchaseDtlMap.put("itemName", " ");
purchaseDtlMap.put("standard", " ");
purchaseDtlMap.put("unitDesc", " ");
purchaseDtlMap.put("qty", " ");
purchaseDtlMap.put("price", " ");
purchaseDtlMap.put("remark", " ");
//存在单身信息时填充
if (details.size() > i) {
purchaseDtlMap.put("itemName", details.get(i).getItemName());
purchaseDtlMap.put("standard", details.get(i).getStandard());
purchaseDtlMap.put("unitDesc", details.get(i).getUnitDesc());
purchaseDtlMap.put("qty", details.get(i).getPurchaseQty());
purchaseDtlMap.put("price", details.get(i).getPurPrice());
purchaseDtlMap.put("remark", details.get(i).getRemark());
}
//内容文本填充
tableHeaderBuilder3
.font(font)
.addRow(Row.builder()
.horizontalAlignment(HorizontalAlignment.LEFT)
.add(TextCell.builder().text(String.valueOf(purchaseDtlMap.get("itemName"))).build())
.add(TextCell.builder().text(String.valueOf(purchaseDtlMap.get("standard"))).build())
.add(TextCell.builder().text(String.valueOf(purchaseDtlMap.get("unitDesc"))).build())
.add(TextCell.builder().text(String.valueOf(purchaseDtlMap.get("qty"))).build())
.add(TextCell.builder().text(String.valueOf(purchaseDtlMap.get("price"))).build())
.add(TextCell.builder().text(String.valueOf(purchaseDtlMap.get("remark"))).build())
.build())
.build();
}
//创建内容表
return tableHeaderBuilder3.build();
}
}