Java如何實(shí)現(xiàn)批量打印條形碼
一、項(xiàng)目背景詳細(xì)介紹
在倉儲管理、商品追溯、物流配送等場景中,條形碼(Barcode)作為物品唯一標(biāo)識被廣泛使用。為提高效率,經(jīng)常需要將一批數(shù)據(jù)轉(zhuǎn)為條形碼并打印在標(biāo)簽紙或 A4 頁面上,滿足打包掃描、入庫出庫等作業(yè)流程。
傳統(tǒng)做法可能依賴專有打標(biāo)簽軟件,靈活性差且難以集成到定制化系統(tǒng)。使用 Java 開發(fā)一套 批量生成并打印條形碼 的工具,可以:
靈活集成:嵌入現(xiàn)有倉儲或 ERP 系統(tǒng),直接從數(shù)據(jù)庫或 CSV 導(dǎo)入數(shù)據(jù);
定制標(biāo)簽:支持調(diào)整條形碼大小、分辨率、文字位置;
自動化批量:一鍵批量生成、分頁排版、提交給打印機(jī);
零第三方依賴:僅需開源庫 ZXing 和 Java 自帶打印 API。
本項(xiàng)目將演示如何基于 ZXing 庫生成條形碼位圖,利用 Java 打印服務(wù)(PrinterJob)將它們以網(wǎng)格方式批量打印到 A4 標(biāo)簽紙或標(biāo)簽紙格式(如 3×10 布局)。
二、項(xiàng)目需求詳細(xì)介紹
2.1 功能需求
1.批量數(shù)據(jù)導(dǎo)入
支持從文本文件(CSV)、數(shù)據(jù)庫或內(nèi)存列表讀取多條待編碼內(nèi)容;
2.條形碼生成
- 使用 ZXing 生成 Code128 或 EAN-13 條形碼;
- 支持指定寬度、高度、邊距及是否顯示文本;
3.分頁排版
- 在 A4 紙或標(biāo)簽紙上按指定行列(如 2 列×5 行)自動排版;
- 支持頁眉頁腳或批次號打??;
4.打印預(yù)覽(可選)
彈出打印對話框預(yù)覽分頁及打印機(jī)設(shè)置;
5.提交打印
通過 PrinterJob 接口,支持選擇打印機(jī)及打印范圍;
6.錯誤處理與日志
捕獲生成失敗、打印失敗,記錄日志并跳過繼續(xù);
2.2 非功能需求
易用性:一行命令或簡單 GUI 即可完成;
配置化:頁面尺寸、行列數(shù)、條碼樣式通過配置文件管理;
跨平臺:僅依賴 Java SE 與 ZXing,可在 Windows、Linux、macOS 上運(yùn)行;
可擴(kuò)展:后續(xù)可支持二維碼(QR Code)等多種格式;
三、相關(guān)技術(shù)詳細(xì)介紹
1.ZXing (com.google.zxing)
- 主流開源條碼/二維碼生成與解析庫;
- 支持多種碼制:Code128, EAN13, QR_CODE 等;
2.Java2D (java.awt.Graphics2D)
在 BufferedImage 上繪制條碼位圖;
3.PrinterJob (java.awt.print)
- 標(biāo)準(zhǔn)打印 API:PrinterJob、PageFormat、Printable;
- 支持頁面設(shè)置與打印對話框;
4.配置管理
使用 java.util.Properties 或 Spring @ConfigurationProperties 加載標(biāo)簽布局;
5.日志框架
SLF4J + Logback 記錄運(yùn)行狀態(tài);
四、實(shí)現(xiàn)思路詳細(xì)介紹
1.加載配置與數(shù)據(jù)
- 從 config.properties 讀?。喉撁鎸挾?、高度、行數(shù)、列數(shù)、條形碼尺寸、邊距等;
- 從 CSV 或數(shù)據(jù)庫加載待打印的編碼字符串列表;
2.生成條形碼圖像
- 對每條內(nèi)容調(diào)用 ZXing 的 MultiFormatWriter.encode(),生成 BitMatrix;
- 將 BitMatrix 轉(zhuǎn)換為 BufferedImage,并在底部添加文本標(biāo)簽(可選);
3.分頁排版
實(shí)現(xiàn) Printable 接口:
- 在 print(Graphics g, PageFormat pf, int pageIndex) 中,根據(jù) pageIndex 計(jì)算當(dāng)前頁的數(shù)據(jù)子列表;
- 對每行每列繪制對應(yīng)條碼圖像,使用 g.drawImage();
- 如有文字批次號或條碼文本,使用 Graphics2D.drawString();
- 返回 PAGE_EXISTS 或 NO_SUCH_PAGE;
4.打印提交
PrinterJob job = PrinterJob.getPrinterJob(); job.setPrintable(printable, pageFormat); if(job.printDialog()) job.print();
5.日志與異常
條碼生成或打印異常時,捕獲并記錄,跳過當(dāng)前碼或重試;
五、完整實(shí)現(xiàn)代碼
import com.google.zxing.*;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.oned.Code128Writer;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.print.*;
import java.io.*;
import java.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BatchBarcodePrinter implements Printable {
private static final Logger logger = LoggerFactory.getLogger(BatchBarcodePrinter.class);
private List<String> codes; // 待打印內(nèi)容
private Properties config; // 布局及條碼配置
private List<BufferedImage> images; // 生成的條碼圖像列表
private int cols, rows; // 每頁列數(shù)和行數(shù)
private int imgWidth, imgHeight; // 條碼圖像尺寸
private int marginX, marginY; // 頁面邊距
private int gapX, gapY; // 圖像間隔
public BatchBarcodePrinter(List<String> codes, Properties cfg) throws Exception {
this.codes = codes;
this.config = cfg;
loadConfig();
generateImages();
}
// 讀取配置
private void loadConfig() {
cols = Integer.parseInt(config.getProperty("page.cols", "2"));
rows = Integer.parseInt(config.getProperty("page.rows", "5"));
imgWidth = Integer.parseInt(config.getProperty("barcode.width", "200"));
imgHeight = Integer.parseInt(config.getProperty("barcode.height", "80"));
marginX = Integer.parseInt(config.getProperty("page.marginX", "50"));
marginY = Integer.parseInt(config.getProperty("page.marginY", "50"));
gapX = Integer.parseInt(config.getProperty("page.gapX", "20"));
gapY = Integer.parseInt(config.getProperty("page.gapY", "30"));
}
// 生成所有條碼圖像
private void generateImages() {
images = new ArrayList<>();
Code128Writer writer = new Code128Writer();
for (String code : codes) {
try {
BitMatrix bm = writer.encode(code, BarcodeFormat.CODE_128, imgWidth, imgHeight);
BufferedImage img = new BufferedImage(imgWidth, imgHeight + 20, BufferedImage.TYPE_INT_RGB);
Graphics2D g = img.createGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, img.getWidth(), img.getHeight());
// 繪制條碼
for (int x = 0; x < imgWidth; x++) {
for (int y = 0; y < imgHeight; y++) {
g.setColor(bm.get(x, y) ? Color.BLACK : Color.WHITE);
g.fillRect(x, y, 1, 1);
}
}
// 繪制文本
g.setColor(Color.BLACK);
g.setFont(new Font("Monospaced", Font.PLAIN, 14));
FontMetrics fm = g.getFontMetrics();
int tx = (imgWidth - fm.stringWidth(code)) / 2;
g.drawString(code, tx, imgHeight + fm.getAscent());
g.dispose();
images.add(img);
} catch (Exception e) {
logger.error("生成條碼失敗: {}", code, e);
}
}
}
@Override
public int print(Graphics graphics, PageFormat pf, int pageIndex) {
int perPage = cols * rows;
int start = pageIndex * perPage;
if (start >= images.size()) return NO_SUCH_PAGE;
Graphics2D g = (Graphics2D) graphics;
g.translate(pf.getImageableX(), pf.getImageableY());
int x0 = marginX, y0 = marginY;
// 繪制本頁條碼
for (int i = 0; i < perPage; i++) {
int idx = start + i;
if (idx >= images.size()) break;
int row = i / cols, col = i % cols;
int x = x0 + col * (imgWidth + gapX);
int y = y0 + row * (imgHeight + gapY + 20);
g.drawImage(images.get(idx), x, y, null);
}
return PAGE_EXISTS;
}
// 啟動打印
public void printAll() throws PrinterException {
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(this);
if (job.printDialog()) {
job.print();
}
}
public static void main(String[] args) throws Exception {
// 1. 加載待打印數(shù)據(jù)
List<String> codes = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new FileReader("codes.csv"))) {
String line;
while ((line = br.readLine()) != null) {
if (!line.trim().isEmpty()) codes.add(line.trim());
}
}
// 2. 加載配置
Properties cfg = new Properties();
try (InputStream in = new FileInputStream("config.properties")) {
cfg.load(in);
}
// 3. 批量打印
BatchBarcodePrinter printer = new BatchBarcodePrinter(codes, cfg);
printer.printAll();
}
}六、代碼詳細(xì)解讀
1.配置加載
從 config.properties 中讀?。簆age.cols, page.rows(每頁行列數(shù))、barcode.width, barcode.height(條碼圖像尺寸)、頁邊距與間隔等,便于靈活調(diào)整布局。
2.條碼生成
使用 ZXing 的 Code128Writer 生成 BitMatrix,逐像素渲染到 BufferedImage,并在下方繪制文本。
3.實(shí)現(xiàn) Printable
print(...) 根據(jù) pageIndex 計(jì)算本頁起始索引,并按行列遍歷繪制對應(yīng)條碼圖像,返回 PAGE_EXISTS 或 NO_SUCH_PAGE 控制分頁。
4.打印提交
PrinterJob 彈出打印對話框,用戶可選擇打印機(jī)與份數(shù),調(diào)用 print() 發(fā)起。
5.主方法流程
- 從 codes.csv 讀取待打印條碼列表;
- 從 config.properties 加載布局與尺寸;
- 構(gòu)造 BatchBarcodePrinter 并調(diào)用 printAll()。
七、項(xiàng)目詳細(xì)總結(jié)
本項(xiàng)目展示了如何用 Java + ZXing + PrinterJob 實(shí)現(xiàn) 批量打印條形碼:
數(shù)據(jù)靈活:支持從文件或數(shù)據(jù)庫導(dǎo)入任意數(shù)量的編碼字符串;
配置驅(qū)動:行列數(shù)、圖像大小、頁邊距等通過外部配置調(diào)整;
圖形生成:ZXing 可靠生成高質(zhì)量 Code128 條碼,并可擴(kuò)展到 QR Code;
分頁打?。簶?biāo)準(zhǔn) Java 打印 API 自動分頁,兼容任意打印機(jī);
零商業(yè)依賴:僅用開源組件即可完成企業(yè)級標(biāo)簽打印需求。
適合物流、倉儲、制造業(yè)等需要批量生產(chǎn)標(biāo)簽的場景,也可作為 Java 圖形與打印 API 教學(xué)案例。
八、項(xiàng)目常見問題及解答
Q1:條碼圖像模糊或尺寸不符?
A:確認(rèn) imgWidth/imgHeight 與實(shí)際打印機(jī) DPI 配合,必要時增加分辨率或調(diào)整頁面縮放。
Q2:打印出現(xiàn)空白頁?
A:檢查 print() 返回值邏輯,確保當(dāng) start >= images.size() 時返回 NO_SUCH_PAGE,否則會多打印空頁。
Q3:條碼下方文字不居中?
A:文本繪制使用 FontMetrics 計(jì)算字符串寬度,確保 x = (imgWidth - textWidth)/2。
Q4:需要打印二維碼?
A:將 Code128Writer 換為 QRCodeWriter,并設(shè)置 BitMatrix 尺寸,文本可放到旁邊或不顯示。
九、擴(kuò)展方向與性能優(yōu)化
大批量流式生成:對超萬條數(shù)據(jù),分批生成圖像并實(shí)時打印,避免一次性占用大量內(nèi)存;
自定義標(biāo)簽紙尺寸:支持常見標(biāo)簽紙(如 4×8 標(biāo)簽)模板配置,精確匹配打印機(jī)紙張;
并發(fā)打?。憾嗑€程調(diào)用不同 PrinterJob 實(shí)例同時發(fā)送到多臺打印機(jī);
網(wǎng)絡(luò)打印集成:支持通過 IPP 協(xié)議或打印服務(wù)器推送打印作業(yè);
RTF/Word 導(dǎo)出:在 Word 文檔或 RTF 中嵌入條碼圖像,擴(kuò)展報(bào)表輸出;
GUI 預(yù)覽與編輯:用 Swing 或 JavaFX 提供可視化布局工具,讓用戶拖拽調(diào)整標(biāo)簽位置。
到此這篇關(guān)于Java如何實(shí)現(xiàn)批量打印條形碼的文章就介紹到這了,更多相關(guān)Java打印條形碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在Eclipse中運(yùn)行Solr 基礎(chǔ)知識
Solr我還是個菜鳥,寫這一些文章只是記錄一下最近一段時間學(xué)習(xí)Solr的心得,望各位同仁不要見笑,還希望多多指點(diǎn)2012-11-11
Java中注解@JsonFormat與@DateTimeFormat的使用
從數(shù)據(jù)庫獲取時間傳到前端進(jìn)行展示的時候,我們有時候可能無法得到一個滿意的時間格式的時間日期,本文主要介紹了Java中注解@JsonFormat與@DateTimeFormat的使用,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08
Spring Boot WebSocket 兩種集成方式詳解
WebSocket 是實(shí)現(xiàn)服務(wù)器主動推送、實(shí)時通信的利器,常見于聊天室、消息通知、實(shí)時監(jiān)控大屏等場景,本文詳細(xì)介紹了SpringBoot集成WebSocket的兩種方式,感興趣的朋友跟隨小編一起看看吧2026-05-05
Java中常用的設(shè)計(jì)模式之責(zé)任鏈模式詳解
這篇文章主要為大家詳細(xì)介紹了Java中常用的設(shè)計(jì)模式之責(zé)任鏈模式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-02-02
Java中id,pid格式數(shù)據(jù)轉(zhuǎn)樹和森林結(jié)構(gòu)工具類實(shí)現(xiàn)
本文主要介紹了Java中id,pid格式數(shù)據(jù)轉(zhuǎn)樹和森林結(jié)構(gòu)工具類實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05

