首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java ZXing 生成二維碼與條碼完整實戰:核心工具類、Logo 嵌入、Servlet 輸出

     編輯:Java 相關知識

ZXing(Zebra Crossing)是 Java 生態最主流的二維碼/條碼處理庫。本文提供生產級完整代碼:Maven 依賴、核心工具類(支持 Logo 嵌入、壓縮、多格式輸出)、解碼工具、Servlet 直接輸出圖片流,可直接集成至 Spring Boot / 傳統 Web 項目。

Maven 依賴

<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>core</artifactId>
    <version>3.5.1</version> <!-- 當前最新穩定版 -->
</dependency>
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>javase</artifactId>
    <version>3.5.1</version>
</dependency>

核心工具類:QRCodeUtil

功能特性:

  • 生成 QR_CODE(二維碼)、支持 EAN_13/CODE_128 等條碼格式(擴展 BarcodeFormat 參數即可)。
  • 支持 Logo 圖片嵌入中心,自動壓縮 Logo 尺寸,繪製圓角邊框。
  • 字符集 UTF-8,錯誤訂正級別 H(最高,可損壞 30% 仍可識別)。
  • 輸出 BufferedImage、文件、OutputStream 多種方式。
  • 解碼支持 File/路徑字符串。

關鍵代碼片段

public class QRCodeUtil {
    private static final String CHARSET = "utf-8";
    private static final String FORMAT_NAME = "JPG";
    private static final int QRCODE_SIZE = 800;
    private static final int LOGO_WIDTH = 80;
    private static final int LOGO_HEIGHT = 80;

    // 核心生成邏輯
    private static BufferedImage createImage(String content, String logoPath, boolean needCompress) throws Exception {
        Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1); // 邊距

        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
        BufferedImage image = new BufferedImage(QRCODE_SIZE, QRCODE_SIZE, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < QRCODE_SIZE; x++) {
            for (int y = 0; y < QRCODE_SIZE; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        if (logoPath != null && !logoPath.isEmpty()) {
            insertImage(image, logoPath, needCompress);
        }
        return image;
    }

    // Logo 嵌入:縮放、居中、圓角邊框
    private static void insertImage(BufferedImage source, String logoPath, boolean needCompress) throws Exception {
        File file = new File(logoPath);
        if (!file.exists()) { log.warn("Logo 文件不存在: {}", logoPath); return; }
        Image src = ImageIO.read(file);
        int w = src.getWidth(null), h = src.getHeight(null);
        if (needCompress) {
            if (w > LOGO_WIDTH) w = LOGO_WIDTH;
            if (h > LOGO_HEIGHT) h = LOGO_HEIGHT;
            Image scaled = src.getScaledInstance(w, h, Image.SCALE_SMOOTH);
            BufferedImage tag = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
            Graphics g = tag.getGraphics(); g.drawImage(scaled, 0, 0, null); g.dispose();
            src = scaled;
        }
        Graphics2D graph = source.createGraphics();
        int x = (QRCODE_SIZE - w) / 2;
        int y = (QRCODE_SIZE - h) / 2;
        graph.drawImage(src, x, y, w, h, null);
        // 圓角邊框
        Shape shape = new RoundRectangle2D.Float(x, y, w, h, 6, 6);
        graph.setStroke(new BasicStroke(3f));
        graph.draw(shape);
        graph.dispose();
    }

    // 多種輸出方式
    public static void encode(String content, String destPath) throws Exception { ... }
    public static void encode(String content, String logoPath, OutputStream out, boolean compress) throws Exception { ... }
    public static String decode(String path) throws Exception { ... }
}

解碼工具類:BufferedImageLuminanceSource

ZXing 需 LuminanceSource 讀取圖像亮度數據,繼承實現支持 BufferedImage 直接解碼,含裁剪、旋轉支持:

public class BufferedImageLuminanceSource extends LuminanceSource {
    private final BufferedImage image;
    // 構造器、getRow、getMatrix、crop、rotateCounterClockwise 實現...
}

Servlet 直接輸出圖片流

@WebServlet("/qrcode")
public class QRCodeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String content = "https://example.com?token=" + UUID.randomUUID(); // 動態業務參數
        resp.setContentType("image/jpeg");
        resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        try {
            QRCodeUtil.encode(content, resp.getOutputStream()); // 直接寫響應流
        } catch (Exception e) {
            log.error("生成二維碼失敗", e);
            resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }
}

前端直接用 <img src="/qrcode?param=xxx" /> 即可顯示動態二維碼。

Spring Boot 整合建議

  1. 將 QRCodeUtil 註冊為 @Component 或工具類静態方法。
  2. Controller 返回 ResponseEntity 或 void 寫 HttpServletResponse。
  3. 業務參數(URL、Token、商品 ID)由 Controller 組裝傳入工具類。
  4. 生產環境建議:緩存生成結果(Redis key: content hash,value: byte[]),避免高併發重複計算 CPU。

常見坑點避雷

總結

ZXing 核心 API 簡潔強大,封裝好 QRCodeUtil 即可覆蓋 95% 業務場景。關鍵點:UTF-8 編碼、H 級錯誤訂正、Logo 尺寸控制、圓角邊框美觀、多輸出方式適配、Servlet 直寫響應流。集成 Spring Boot 時注意緩存與限流,即可支撐高併發二維碼生成服務。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
問題原因解決
中文內容掃碼亂碼編碼未指定 UTF-8hints.put(EncodeHintType.CHARACTER_SET, "utf-8")
Logo 遮擋導致無法識別Logo 過大、未設置錯誤訂正級別 H限制 Logo 佔比 ≤ 20%,ERROR_CORRECTION=H
解碼失敗圖片模糊、對比度低、格式不支持輸出 PNG 無損、確保 300+ DPI、預處理銳化
高併發 OOM大量 BufferedImage 佔用堆外/堆內存限流、對象池復用、異步生成、緩存結果