1. 概述

条形码(Barcode)是一种通过视觉方式传递信息的技术,广泛应用于网页、邮件或可打印文档中。作为后端开发者,你可能在生成电子发票、物流单、会员卡或支付凭证时,都需要动态生成条码。

本文将带你掌握在 Java 中生成主流条形码和二维码的实战技巧。我们会:

✅ 解析常见条码类型的技术特点
✅ 对比主流 Java 条码库的优劣
✅ 实现基于 Spring Boot 的 RESTful 条码服务接口
✅ 踩坑提醒:校验位、文本显示、Maven 依赖等细节

目标是让你快速选出最适合项目的方案,避免掉进“生成出来扫不了”这种低级但致命的坑。


2. 条码类型详解

条码本质是将数字、文本等信息编码成机器可读的图形。按结构可分为两大类:

  • 线性条码(Linear Barcode):一维码,横向排列
  • 二维条码(2D Barcode):信息密度高,可存储更多内容

2.1 UPC 码(Universal Product Code)

主要用于北美地区,最常见的是一维码 UPC-A:

  • ✅ 固定 12 位纯数字
  • ✅ 前 6 位:厂商代码,中间 5 位:商品编号,最后 1 位:校验位
  • ⚠️ 小包装可用 UPC-E(8 位)

2.2 EAN 码(European / International Article Number)

全球通用的商品条码标准,最常见的是 EAN-13:

  • ✅ 13 位数字,结构与 UPC-A 类似
  • ✅ 本质是 “0” + UPC-A(即 EAN-13 是 UPC-A 的超集)
  • ✅ 广泛用于零售、图书(ISBN-13 实际就是 EAN-13 的一种)

2.3 Code 128

物流、仓储行业常用的一维高密度条码:

  • ✅ 支持完整的 ASCII 128 个字符
  • ✅ 变长编码,压缩率高
  • ✅ 常用于快递单、资产标签

2.4 PDF417

一种“堆叠式”二维条码,由多个一维条码垂直堆叠而成:

  • ✅ 兼容传统线性扫描仪
  • ✅ 常见于登机牌、身份证、驾照、物流单据
  • ✅ 使用 Reed-Solomon 纠错算法,轻微破损仍可读
  • ❌ 体积较大,通常是 QR 码的 4 倍左右

2.5 QR 码(Quick Response Code)

目前最流行的二维条码,优势明显:

  • ✅ 存储容量大(最多可存 7089 个数字或 4296 个字母)
  • ✅ 支持四种编码模式:数字、字母、字节(二进制)、汉字(Kanji)
  • ✅ 手机扫码识别快,容错能力强(L/M/Q/H 四级纠错)
  • ✅ 可嵌入 Logo、变色、加文字说明,适合营销场景

3. Java 条码库选型对比

Java 生态中有多个成熟的条码生成库,以下是主流选项的横向对比:

库名 支持类型 特点 推荐场景
Barbecue 1D 为主 API 极简,EAN/UPC 自动生成校验位 快速生成商品条码
Barcode4j 1D + 2D(PDF417) 功能全,支持 SVG 输出 生成 PDF417 登机牌
ZXing(核心库) 全格式(含 QR) Google 出品,社区活跃,扫码+生成一体 需要扫码或生成 QR 码
QRGen 仅 QR 基于 ZXing 封装,API 更友好 简单生成二维码
QR Code Generator(Nayuki) 仅 QR 代码清晰,纠错精准 对 QR 码正确性要求极高
Okapi Barcode 超 50 种 纯 Java,持续维护 需要支持冷门条码

结论

  • 生成 QR 码 → 优先选 ZXingQRGen
  • 生成 EAN/UPC → Barbecue 最省心
  • 需要 PDF417 → Barcode4jZXing

4. 生成线性条码(1D)

4.1 使用 Barbecue 库

特点:API 简单粗暴,自动处理校验位,适合快速上手。

添加依赖:

<dependency>
    <groupId>net.sourceforge.barbecue</groupId>
    <artifactId>barbecue</artifactId>
    <version>1.5-beta1</version>
</dependency>

生成 EAN-13 示例:

public static BufferedImage generateEAN13BarcodeImage(String barcodeText) throws Exception {
    Barcode barcode = BarcodeFactory.createEAN13(barcodeText);
    barcode.setFont(new Font("Arial", Font.PLAIN, 12)); // 可选:设置下方文字字体

    return BarcodeImageHandler.getImage(barcode);
}

⚠️ 注意:

  • barcodeText 传 12 位即可,第 13 位(校验位)会自动计算
  • 默认显示下方文本,无需额外配置

4.2 使用 Barcode4j 库

特点:支持更多格式,但 API 稍复杂。

添加依赖:

<dependency>
    <groupId>net.sf.barcode4j</groupId>
    <artifactId>barcode4j</artifactId>
    <version>2.1</version>
</dependency>

生成 EAN-13 示例:

public static BufferedImage generateEAN13BarcodeImage(String barcodeText) {
    EAN13Bean barcodeGenerator = new EAN13Bean();
    BitmapCanvasProvider canvas = 
        new BitmapCanvasProvider(160, BufferedImage.TYPE_BYTE_BINARY, false, 0);

    barcodeGenerator.generateBarcode(canvas, barcodeText);
    return canvas.getBufferedImage();
}

参数说明:

  • 160:DPI(分辨率)
  • TYPE_BYTE_BINARY:黑白图像
  • false:关闭抗锯齿
  • 0:旋转角度

✅ 文本默认显示在条码下方,无需额外设置。


4.3 使用 ZXing 库

特点:功能强大,但需手动处理细节。

添加依赖:

<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>core</artifactId>
    <version>3.3.0</version>
</dependency>
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>javase</artifactId>
    <version>3.3.0</version>
</dependency>

生成 EAN-13 示例:

public static BufferedImage generateEAN13BarcodeImage(String barcodeText) throws Exception {
    EAN13Writer barcodeWriter = new EAN13Writer();
    BitMatrix bitMatrix = barcodeWriter.encode(barcodeText, BarcodeFormat.EAN_13, 300, 150);

    return MatrixToImageWriter.toBufferedImage(bitMatrix);
}

⚠️ 踩坑提醒:

  • 必须传 13 位完整编码,包括校验位(ZXing 不自动计算)
  • 生成的图像不带下方文本,需自行叠加
  • 尺寸需明确指定(宽度、高度)

5. 生成二维条码(2D)

5.1 使用 ZXing 生成 QR 码

ZXing 是 Java 中生成 QR 码的事实标准。

public static BufferedImage generateQRCodeImage(String barcodeText) throws Exception {
    QRCodeWriter barcodeWriter = new QRCodeWriter();
    BitMatrix bitMatrix = 
        barcodeWriter.encode(barcodeText, BarcodeFormat.QR_CODE, 200, 200);

    return MatrixToImageWriter.toBufferedImage(bitMatrix);
}

✅ 支持中文、URL、JSON 等任意文本
✅ 纠错级别可通过 EncodeHintType.ERROR_CORRECTION 设置(L/M/Q/H)


5.2 使用 QRGen 库

QRGen 是 ZXing 的封装,API 更简洁,但已不在 Maven Central,需从 JitPack 引入。

添加仓库和依赖:

<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>

<dependency>
    <groupId>com.github.kenglxn.qrgen</groupId>
    <artifactId>javase</artifactId>
    <version>2.6.0</version>
</dependency>

生成 QR 码:

public static BufferedImage generateQRCodeImage(String barcodeText) throws Exception {
    ByteArrayOutputStream stream = QRCode
        .from(barcodeText)
        .withSize(250, 250)
        .stream();
    
    ByteArrayInputStream bis = new ByteArrayInputStream(stream.toByteArray());
    return ImageIO.read(bis);
}

✅ Builder 风格 API,链式调用,清爽
✅ 支持直接输出到文件或流


5.3 使用 QR Code Generator(Nayuki)

追求极致正确性和清晰代码结构时可选。

添加依赖:

<dependency>
    <groupId>io.nayuki</groupId>
    <artifactId>qrcodegen</artifactId>
    <version>1.8.0</version>
</dependency>

生成 QR 码:

public static BufferedImage generateQrcode(String barcodeText) throws Exception {
    QrCode qrCode = QrCode.encodeText(barcodeText, QrCode.Ecc.MEDIUM);
    return toImage(qrCode, 4, 10); // scale=4, border=10
}

自定义图像渲染方法:

public static BufferedImage toImage(QrCode qr, int scale, int border, int lightColor, int darkColor) {
    Objects.requireNonNull(qr);
    if (scale <= 0 || border < 0) {
        throw new IllegalArgumentException("Value out of range");
    }
    int size = (qr.size + border * 2) * scale;
    BufferedImage result = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
    
    for (int y = 0; y < result.getHeight(); y++) {
        for (int x = 0; x < result.getWidth(); x++) {
            boolean color = qr.getModule(x / scale - border, y / scale - border);
            result.setRGB(x, y, color ? darkColor : lightColor);
        }
    }
    return result;
}

✅ 可精确控制颜色、边框、缩放
✅ 适合定制化需求(如彩色 QR 码)


5.4 使用 Okapi Barcode 生成 Code 128

Okapi 支持超过 50 种条码格式,适合复杂场景。

添加依赖:

<dependency>
    <groupId>uk.org.okapibarcode</groupId>
    <artifactId>okapibarcode</artifactId>
    <version>0.4.6</version>
</dependency>

生成 Code 128 示例:

public static BufferedImage generateOkapiBarcode(String barcodeText) throws Exception {
    Code128 barcode = new Code128();
    barcode.setFontName("Monospaced");
    barcode.setFontSize(16);
    barcode.setModuleWidth(2);
    barcode.setBarHeight(50);
    barcode.setHumanReadableLocation(HumanReadableLocation.BOTTOM);
    barcode.setContent(barcodeText);

    int width = barcode.getWidth();
    int height = barcode.getHeight();
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
    Graphics2D g2d = image.createGraphics();
    Java2DRenderer renderer = new Java2DRenderer(g2d, 1, Color.WHITE, Color.BLACK);
    renderer.render(barcode);
    g2d.dispose(); 

    return image;
}

✅ 配置项丰富,控制精细
✅ 适合生成工业级条码标签


6. 生成带文字的 QR 码

有时需要在 QR 码上下添加说明文字,提升用户体验(比如“扫码访问官网”)。

ZXing 原生不支持,需手动合成图像。

public static BufferedImage createQRwithText(String data, String topText, String bottomText) 
        throws WriterException, IOException {
    
    QRCodeWriter barcodeWriter = new QRCodeWriter();
    BitMatrix matrix = barcodeWriter.encode(data, BarcodeFormat.QR_CODE, 200, 200);
    
    return modifiedQRCode(matrix, topText, bottomText);
}

图像合成核心逻辑:

private static BufferedImage modifiedQRCode(BitMatrix matrix, String topText, String bottomText) {
    int matrixWidth = matrix.getWidth();
    int matrixHeight = matrix.getHeight();

    // 1. 先绘制原始 QR 码
    BufferedImage image = new BufferedImage(matrixWidth, matrixHeight, BufferedImage.TYPE_INT_RGB);
    Graphics2D graphics = image.createGraphics();
    graphics.setColor(Color.WHITE);
    graphics.fillRect(0, 0, matrixWidth, matrixHeight);
    graphics.setColor(Color.BLACK);
    for (int i = 0; i < matrixWidth; i++) {
        for (int j = 0; j < matrixHeight; j++) {
            if (matrix.get(i, j)) {
                graphics.fillRect(i, j, 1, 1);
            }
        }
    }
    graphics.dispose();

    // 2. 计算最终图像尺寸(含文字区域)
    Font font = new Font("SansSerif", Font.PLAIN, 14);
    graphics = image.createGraphics();
    graphics.setFont(font);
    FontMetrics fontMetrics = graphics.getFontMetrics();
    int topTextWidth = fontMetrics.stringWidth(topText);
    int bottomTextWidth = fontMetrics.stringWidth(bottomText);
    int textHeight = fontMetrics.getHeight();
    int ascent = fontMetrics.getAscent();
    int finalWidth = Math.max(matrixWidth, Math.max(topTextWidth, bottomTextWidth)) + 10;
    int finalHeight = matrixHeight + textHeight * 2 + 10;

    // 3. 创建最终图像并绘制
    BufferedImage finalImage = new BufferedImage(finalWidth, finalHeight, BufferedImage.TYPE_INT_RGB);
    Graphics2D finalGraphics = finalImage.createGraphics();
    finalGraphics.setColor(Color.WHITE);
    finalGraphics.fillRect(0, 0, finalWidth, finalHeight);
    finalGraphics.setColor(Color.BLACK);
    finalGraphics.setFont(font);

    // 居中绘制 QR 码
    int qrX = (finalWidth - matrixWidth) / 2;
    int qrY = textHeight + 5;
    finalGraphics.drawImage(image, qrX, qrY, null);

    // 绘制上下文字
    finalGraphics.drawString(topText, (finalWidth - topTextWidth) / 2, ascent + 5);
    finalGraphics.drawString(bottomText, (finalWidth - bottomTextWidth) / 2, finalHeight - 5);

    finalGraphics.dispose();
    return finalImage;
}

✅ 效果:文字居中,QR 码自动对齐
✅ 可扩展支持 Logo 叠加、背景色设置等


7. 构建 REST 接口服务

将条码生成功能暴露为 HTTP 接口,便于前端或移动端调用。

基础配置

Spring Boot 需注册 BufferedImage 的消息转换器:

@Bean
public HttpMessageConverter<BufferedImage> createImageHttpMessageConverter() {
    return new BufferedImageHttpMessageConverter();
}

控制器示例

@RestController
@RequestMapping("/barcodes")
public class BarcodesController {

    @GetMapping(value = "/barbecue/ean13/{barcode}", produces = MediaType.IMAGE_PNG_VALUE)
    public ResponseEntity<BufferedImage> barbecueEAN13Barcode(@PathVariable String barcode) throws Exception {
        BufferedImage image = BarbecueBarcodeGenerator.generateEAN13BarcodeImage(barcode);
        return ResponseEntity.ok(image);
    }
}

接口测试示例

7.1 生成 UPC-A 条码

GET http://localhost:8080/barcodes/barbecue/upca/12345678901

upca-1

7.2 生成 EAN-13 条码

GET http://localhost:8080/barcodes/barbecue/ean13/012345678901

ean13-1

7.3 生成 Code128 条码(POST)

POST http://localhost:8080/barcodes/barbecue/code128
Content-Type: text/plain

长文本内容,如:Lorem ipsum dolor sit amet...

code128 barbecue2

7.4 生成 PDF417 条码

POST http://localhost:8080/barcodes/barbecue/pdf417
Content-Type: text/plain

长文本内容...

pdf417 barbecue 3

7.5 生成 QR 码

POST http://localhost:8080/barcodes/zxing/qrcode
Content-Type: text/plain

任意长文本、URL、JSON...

qrcode zxing3

7.6 生成带文字的 QR 码

GET http://localhost:8080/barcodes/zxing/qrcode/text?barcode=https://example.com&toptext=访问官网&bottomtext=扫码立即体验

qr code generated with zxing library with text.


8. 总结

本文系统梳理了 Java 条码生成的核心技术方案:

  • 选型建议

    • 商品条码(EAN/UPC)→ Barbecue(省心)
    • 二维码(QR Code)→ ZXing 或 QRGen(主流)
    • PDF417 → Barcode4j
    • 高定制需求 → Okapi 或 Nayuki
  • 关键踩坑点

    • 校验位是否自动生成(Barbecue ✅,ZXing ❌)
    • 文本是否默认显示
    • Maven 依赖是否可用(QRGen 需 JitPack)
  • 生产建议

    • 封装统一的 BarcodeService
    • 接口支持多种格式、尺寸、纠错级别
    • 增加缓存避免重复生成

所有示例代码已托管至 GitHub:https://github.com/your-repo/barcode-demo
实际项目中可根据业务需求灵活组合使用。


原始标题:Generating Barcodes and QR Codes in Java | Baeldung