Java使用itext生成pdf標(biāo)簽的操作方法
一、利用Adobe Acrobat DC軟件創(chuàng)建pdf模板
備好Adobe Acrobat DC軟件
1.excel/jpg/png文件轉(zhuǎn)pdf文件
文件是正常的excel表格填上不會(huì)變動(dòng)的內(nèi)容
右擊打開我們要轉(zhuǎn)換的文件

2.然后點(diǎn)擊添加域

3.可以看到域的名字
域的名字是和代碼里參數(shù)名是一致的

4.調(diào)整字體大小/對齊方式等
調(diào)整字體格式和大小,對其方式可靠上/居中/靠下

5.保存
ctrl + S 保存后放入項(xiàng)目模板路徑下
比如 resources - template 目錄下
二,代碼部分
首先
1.上依賴
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>${com.itextpdf.version}</version>
</dependency>
<com.itextpdf.version>5.5.13.2</com.itextpdf.version>2.Controller層
HttpServletResponse:用于將生成的 PDF 文件直接寫入 HTTP 響應(yīng)流中,以便客戶端可以下載或查看 PDF 文件。
@PostMapping(value = "printlabel/pallet", produces = MediaType.APPLICATION_PDF_VALUE)
@ApiOperation(value = "打印托盤碼", produces = MediaType.APPLICATION_PDF_VALUE)
public void printlabelPallet(@Valid @RequestBody PalletPrintRequest request, HttpServletResponse response) throws Exception {
labelService.printlabelPallet(request, response);
}目前,方法聲明拋出了 Exception,這會(huì)導(dǎo)致所有未捕獲的異常都被拋出到客戶端。為了提高代碼的健壯性,建議捕獲特定的異常,并根據(jù)不同的異常類型返回適當(dāng)?shù)?HTTP 狀態(tài)碼和錯(cuò)誤信息。
例如,你可以使用 @ExceptionHandler 來捕獲常見的異常,如 IOException、DocumentException 等,并返回 500 Internal Server Error 或其他適當(dāng)?shù)捻憫?yīng)。
3.Service層
按照業(yè)務(wù)邏輯從數(shù)據(jù)庫獲取數(shù)據(jù)并處理數(shù)據(jù),放到合適的對象里
(這里主要是和業(yè)務(wù)相關(guān),不必深究里面內(nèi)容,最后能得出需要的數(shù)據(jù)傳出即可)
@Override
@Lock4j
@Transactional(rollbackFor = Exception.class)
public void printlabelPallet(PalletPrintRequest request, HttpServletResponse response) throws Exception {
Crossdock crossdock = new Crossdock();
CrossdockPlanConsignee consignee = new CrossdockPlanConsignee();
CrossdockPlan plan = new CrossdockPlan();
//暫存
if (request.getIsTemp()){
crossdock = crossdockService.getByFieldValue(request.getOrderNo(), Crossdock::getOrderNo);
}else{
plan = planService.getByFieldValue(request.getPlanNo(),CrossdockPlan::getPlanNo);
if (ObjectUtils.isEmpty(plan)){
throw new ApiException(ResultCode.PARAMES_INVALID,"plan not found");
}
crossdock = crossdockService.getValidById(plan.getOrderId());
consignee = planConsigneeService.getByFieldValue(plan.getId(), CrossdockPlanConsignee::getPlanId);
}
Customer customer = customerService.getValidById(crossdock.getCustomerId());
//托盤標(biāo)號(hào)
String consigneeName = consignee.getName() != null ? consignee.getName() : "";
if (request.getIsCustomize() && StringUtils.isNotBlank(request.getPalletNo())){
consigneeName = request.getPalletNo();
}else if (request.getIsTemp()) {
consigneeName += crossdock.getOrderNo();
consigneeName += LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMdd"));
String redisKey = redisService.genKey(new String[]{NoRules.class.getSimpleName()}, consigneeName);
redisService.setIfAbsent(redisKey, 0, NoRulesEnums.DateFormat.yyMMdd.getDays(), TimeUnit.DAYS);
Long no = redisService.increment(redisKey);
consigneeName = consigneeName + String.format("%0" + 5 + "d", no);
}else {
consigneeName += LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMdd"));
String redisKey = redisService.genKey(new String[]{NoRules.class.getSimpleName()}, consigneeName);
redisService.setIfAbsent(redisKey, 0, NoRulesEnums.DateFormat.yyMMdd.getDays(), TimeUnit.DAYS);
Long no = redisService.increment(redisKey);
consigneeName = consigneeName + String.format("%0" + 5 + "d", no);
}
//托盤信息
List<CrossdockPalletLabelNew> labelList = Lists.newArrayList();
CrossdockPalletLabelNew palletLabel = new CrossdockPalletLabelNew().setCustomer(customer.getCode())
.setPrintDate(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")))
.setContainerNo(StringUtils.right(crossdock.getContainerNo(), 5))//取后5位
.setTotalAmount(crossdock.getTotalAmount().stripTrailingZeros().toPlainString())// 轉(zhuǎn)運(yùn)單總箱數(shù)
.setWarehouse(consignee.getName())// 收件人名稱
.setPieces(request.getPieces().stripTrailingZeros().toPlainString())
.setBarcode(consigneeName)
.setPalletNO(consigneeName);
labelList.add(palletLabel);
//保存crossdock_plan_pallet
BigDecimal palletCount = planPalletService.countByFieldValue(consigneeName, CrossdockPlanPallet::getPalletNo);
if (palletCount.compareTo(BigDecimal.ZERO) <= 0) {
CrossdockPlanPallet pallet = new CrossdockPlanPallet();
pallet.setPalletNo(consigneeName).setOrderId(crossdock.getId()).setAmount(request.getPieces());
if (ObjectUtils.isNotEmpty(plan) && StringUtils.isNotBlank(plan.getId())){
pallet.setPlanId(plan.getId());
}
planPalletService.save(pallet);
}else {
throw new ApiException(ResultCode.FORBIDDEN,"msg:the_pallet_code_already_exists");
}
//保存crossdock_plan_pda
BigDecimal pdaCount = planPdaService.countByFieldValue(consigneeName, CrossdockPlanPda::getPalletNo);
if (pdaCount.compareTo(BigDecimal.ZERO) <= 0) {
CrossdockPlanPda pda = new CrossdockPlanPda();
pda.setPalletNo(consigneeName).setOrderNo(crossdock.getOrderNo()).setStatus(CrossdockEnums.PlanPdaStatus.INBOUND.name());
if (ObjectUtils.isNotEmpty(plan) && StringUtils.isNotBlank(plan.getPlanNo())){
pda.setPlanNo(plan.getPlanNo());
}
if(request.getIsTemp()){
pda.setSourcePalletNo(PrintEnums.sourcePalletNo.STORAGE.name());
}else {
pda.setSourcePalletNo(PrintEnums.sourcePalletNo.PLAN.name());
}
planPdaService.save(pda);
}else {
throw new ApiException(ResultCode.FORBIDDEN,"msg:the_pallet_code_already_exists");
}
//保存托盤打印日志
PalletPrintLogCreateRequest log = new PalletPrintLogCreateRequest().setOrderId(crossdock.getId())
.setPalletNo(consigneeName)
.setIsCustomize(request.getIsCustomize())
.setPieces(request.getPieces());
if (ObjectUtils.isNotEmpty(plan) && StringUtils.isNotBlank(plan.getId())){
log.setPlanId(plan.getId());
}
palletPrintLogService.createPalletPrintLog(log);
printPalletLabel(labelList, response.getOutputStream());
}這個(gè)是單個(gè)的,可以多個(gè),循環(huán)把數(shù)據(jù)放進(jìn)list即可
這里參數(shù)可以放進(jìn)list里,進(jìn)行批量生成并拼接到一個(gè)pdf里
private final String TEMPLATE_FONT = "template/font/Alibaba-PuHuiTi-Medium.ttf";
private final String PALLET_TEMPLATE = "template/pallet.pdf";
private final int NUM_TO_PRINT = 2;
public void printPalletLabel(List<CrossdockPalletLabelNew> labelList, OutputStream outputStream) throws Exception {
Document doc = new Document();
PdfCopy copy = new PdfCopy(doc, outputStream);
doc.open();
// 創(chuàng)建字體
BaseFont bf = BaseFont.createFont(TEMPLATE_FONT, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
// 遍歷標(biāo)簽列表
for (CrossdockPalletLabelNew label : labelList) {
// 每個(gè)標(biāo)簽打印 NUM_TO_PRINT 次
for (int i = 0; i < NUM_TO_PRINT; i++) {
// 創(chuàng)建字節(jié)數(shù)組輸出流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// 使用 PdfStamper 打開 PDF 模板
PdfStamper stamper = new PdfStamper(new PdfReader(PALLET_TEMPLATE), bos);
// 將標(biāo)簽對象轉(zhuǎn)換為 Map
Map<String, Object> fieldMap = BeanMap.create(label);
// 獲取 PDF 模板中的表單字段
AcroFields fields = stamper.getAcroFields();
// 添加自定義字體
fields.addSubstitutionFont(bf);
// 遍歷表單字段并填充內(nèi)容
for (String key : fieldMap.keySet()) {
if (key.equals(BARCODE)) {
// 如果是條形碼字段,調(diào)用 createBarcode 方法生成條形碼
createBarcode(stamper.getOverContent(1), label.getBarcode(), fields.getFieldPositions(BARCODE).get(0).position);
} else {
// 否則,設(shè)置表單字段的值
fields.setField(key, Objects.toString(fieldMap.get(key), StringPool.EMPTY));
}
}
// 平坦化表單,防止用戶編輯
stamper.setFormFlattening(true);
// 關(guān)閉 PdfStamper
stamper.close();
// 將生成的頁面添加到最終的 PDF 文檔中
copy.addPage(copy.getImportedPage(new PdfReader(bos.toByteArray()), 1));
}
}
// 關(guān)閉文檔
doc.close();
}循環(huán)兩次是業(yè)務(wù)需要,同一張打印兩次
字體可網(wǎng)上自行下載,或者更換其他字體
4.生成條形碼
這里可以設(shè)置具體的條形碼寬度/高度等,(條形碼下面默認(rèn)帶條形碼掃出來的內(nèi)容)
private void createBarcode(PdfContentByte cb, String barcode, Rectangle position) throws DocumentException {
Barcode128 barcode128 = new Barcode128();
barcode128.setCode(barcode);
barcode128.setX(1.7F);
barcode128.setBarHeight(position.getHeight());
Image image128 = barcode128.createImageWithBarcode(cb, null, null);
image128.scaleToFit(position.getWidth(), position.getHeight());
image128.setAbsolutePosition(position.getLeft() + (position.getWidth() - image128.getScaledWidth()) / 2,
position.getBottom() + (position.getHeight() - image128.getScaledHeight()) / 2);
cb.addImage(image128);
}三,標(biāo)簽效果圖

以上就是Java使用itext生成pdf標(biāo)簽的操作方法的詳細(xì)內(nèi)容,更多關(guān)于Java itext生成pdf標(biāo)簽的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java如何通過反射機(jī)制獲取數(shù)據(jù)類對象的屬性及方法
文章介紹了如何使用Java反射機(jī)制獲取類對象的所有屬性及其對應(yīng)的get、set方法,以及如何通過反射機(jī)制實(shí)現(xiàn)類對象的實(shí)例化,感興趣的朋友跟隨小編一起看看吧2025-01-01
Spring和MyBatis整合自動(dòng)生成代碼里面text類型遇到的坑
Spring和MyBatis整合以后,使用自動(dòng)生成代碼工具生成dao和mapper配置文件。下面通過本文給大家介紹Spring和MyBatis整合自動(dòng)生成代碼里面text類型遇到的坑,需要的朋友參考下吧2018-01-01
java運(yùn)行錯(cuò)誤A JNI error的解決方案
這篇文章主要介紹了java運(yùn)行錯(cuò)誤A JNI error的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
Java ArrayList與Vector和LinkedList的使用及源碼分析
ArrayList、Vector、LinkedList類均在java.util包中,均為可伸縮數(shù)組,即可以動(dòng)態(tài)改變長度的數(shù)組。ArrayList 和 Vector都是基于存儲(chǔ)元素的Object[] array來實(shí)現(xiàn)的,它們會(huì)在內(nèi)存中開辟一塊連續(xù)的內(nèi)存來存儲(chǔ)2022-11-11
SpringBoot整合Hashids實(shí)現(xiàn)數(shù)據(jù)ID加密隱藏的全過程
這篇文章主要為大家詳細(xì)介紹了SpringBoot整合Hashids實(shí)現(xiàn)數(shù)據(jù)ID加密隱藏的全過程,文中的示例代碼講解詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01
解析Orika的MapperFacade 屬性賦值的使用問題
在我們實(shí)際開發(fā)中,常常會(huì)有對象與對象之間的轉(zhuǎn)化,或者把一個(gè)對象的數(shù)據(jù)轉(zhuǎn)化到另一個(gè)數(shù)據(jù)之中,如果我們手動(dòng)的一個(gè)一個(gè)的set就會(huì)比較麻煩,代碼段看起來也會(huì)比較長。而Orika的MapperFacade就是解決這個(gè)問題的,實(shí)現(xiàn)對象屬性的復(fù)制2021-12-12
spring一個(gè)項(xiàng)目多個(gè)模塊聚合打包問題解決方案(最新推薦)
最近遇到個(gè)需求,針對后端解耦模塊較多的項(xiàng)目,想在云端啟動(dòng)時(shí)簡潔些只啟動(dòng)一個(gè)jar文件的情景,本文重點(diǎn)給大家介紹spring一個(gè)項(xiàng)目多個(gè)模塊聚合打包問題解決方案,感興趣的朋友一起看看吧2023-09-09
舉例講解Java的Spring框架中AOP程序設(shè)計(jì)方式的使用
這篇文章主要介紹了Java的Spring框架中AOP程序設(shè)計(jì)方式的使用講解,文中舉的AOP下拋出異常的例子非常實(shí)用,需要的朋友可以參考下2016-04-04

