当前位置: 代码网 > it编程>编程语言>Java > SpringBoot集成ZXing实现二维码的生成与读取功能

SpringBoot集成ZXing实现二维码的生成与读取功能

2026年03月21日 Java 我要评论
一、概述本教程将详细讲解如何在 spring boot 项目中集成 zxing 库实现二维码的生成(返回 base64 编码)和读取(解析图片的二维码)功能,并覆盖常见异常处理、参数优化等实战要点,适

一、概述

本教程将详细讲解如何在 spring boot 项目中集成 zxing 库实现二维码的生成(返回 base64 编码)和读取(解析图片的二维码)功能,并覆盖常见异常处理、参数优化等实战要点,适合 java 开发新手快速上手。

二、环境准备

2.1 技术栈

  • 框架:spring boot 2.x/3.x(本人测试springboot版本影响较小)
  • 核心依赖:zxing(二维码处理)
  • 开发工具:idea/eclipse、maven

2.2 依赖引入

在 pom.xml 中添加 zxing 核心依赖:

<!-- springboot启动器 -->
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter</artifactid>
        </dependency>
        <!-- springboot的web启动器 -->
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-web</artifactid>
        </dependency>
        <!-- zxing 二维码核心依赖 -->
        <dependency>
            <groupid>com.google.zxing</groupid>
            <artifactid>core</artifactid>
            <version>3.5.2</version> <!-- 推荐使用最新稳定版 -->
        </dependency>
        <!-- zxing javase 扩展(处理图片) -->
        <dependency>
            <groupid>com.google.zxing</groupid>
            <artifactid>javase</artifactid>
            <version>3.5.2</version>
        </dependency>

三、工具类封装

import com.google.zxing.*;
import com.google.zxing.client.j2se.bufferedimageluminancesource;
import com.google.zxing.client.j2se.matrixtoimageconfig;
import com.google.zxing.client.j2se.matrixtoimagewriter;
import com.google.zxing.common.bitmatrix;
import com.google.zxing.common.hybridbinarizer;
import com.google.zxing.qrcode.qrcodereader;
import com.google.zxing.qrcode.qrcodewriter;
import com.google.zxing.qrcode.decoder.errorcorrectionlevel;
//注意jdk11以上javax包名需要修改为jakarta
import javax.imageio.imageio;
import java.awt.image.bufferedimage;
import java.io.bytearrayoutputstream;
import java.io.ioexception;
import java.io.inputstream;
import java.util.base64;
import java.util.hashmap;
import java.util.map;


/**
 * 二维码工具类(生成+读取)
 * 包含异常处理、参数优化、base64 转换等功能
 */
public class qrcodeutil {
    // 默认二维码宽度/高度
    private static final int default_size = 300;
    // 默认字符编码
    private static final string default_charset = "utf-8";
    // 二维码颜色(黑色)
    private static final int qr_code_color = 0xff000000;
    // 二维码背景色(白色)
    private static final int qr_code_background = 0xffffffff;

    /**
     * 生成二维码 bufferedimage 对象
     * @param content 二维码内容(必填)
     * @return bufferedimage 二维码图片
     * @throws writerexception 生成失败异常
     */
    public static bufferedimage createqrcode(string content) throws writerexception {
        return createqrcode(content, default_size, default_size);
    }

    /**
     * 自定义尺寸生成二维码
     * @param content 二维码内容
     * @param width 宽度
     * @param height 高度
     * @return bufferedimage
     * @throws writerexception 内容为空/尺寸非法时抛出
     */
    public static bufferedimage createqrcode(string content, int width, int height) throws writerexception {
        // 前置校验
        if (content == null || content.isempty()) {
            throw new writerexception("二维码内容不能为空");
        }
        if (width <= 0 || height <= 0) {
            throw new writerexception("二维码尺寸必须大于0");
        }

        // 配置二维码参数(关键:解决中文乱码、提升容错率)
        map<encodehinttype, object> hints = new hashmap<>();
        hints.put(encodehinttype.character_set, default_charset); // 字符编码
        hints.put(encodehinttype.error_correction, errorcorrectionlevel.h); // 最高容错率(30%)
        hints.put(encodehinttype.margin, 1); // 边距(0=无白边)

        // 生成二维码矩阵
        qrcodewriter qrcodewriter = new qrcodewriter();
        bitmatrix bitmatrix = qrcodewriter.encode(content, barcodeformat.qr_code, width, height, hints);

        // 转换为 bufferedimage(自定义颜色)
        matrixtoimageconfig config = new matrixtoimageconfig(qr_code_color, qr_code_background);
        return matrixtoimagewriter.tobufferedimage(bitmatrix, config);
    }

    /**
     * 将 bufferedimage 转换为字节数组
     * @param image 二维码图片
     * @return 字节数组
     * @throws ioexception 图片转换失败
     */
    public static byte[] imagetobytes(bufferedimage image) throws ioexception {
        if (image == null) {
            throw new ioexception("图片对象不能为空");
        }
        bytearrayoutputstream outputstream = new bytearrayoutputstream();
        imageio.write(image, "png", outputstream);
        return outputstream.tobytearray();
    }

    /**
     * 将字节数组转换为 base64 编码字符串(纯编码,无前缀)
     * @param bytes 图片字节数组
     * @return base64 字符串
     */
    public static string imagetobase64(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            throw new illegalargumentexception("字节数组不能为空");
        }
        return base64.getencoder().encodetostring(bytes);
    }

    /**
     * 读取图片流中的二维码内容
     * @param inputstream 图片输入流(如文件流、网络流)
     * @return 二维码内容
     * @throws notfoundexception 未识别到二维码
     * @throws ioexception 图片读取失败
     * @throws checksumexception 二维码数据校验失败
     * @throws formatexception 二维码格式错误
     */
    public static string readqrcode(inputstream inputstream) throws notfoundexception, ioexception, checksumexception, formatexception {
        if (inputstream == null) {
            throw new ioexception("图片输入流不能为空");
        }
        bufferedimage image = imageio.read(inputstream);
        if (image == null) {
            throw new ioexception("无法解析图片,请检查文件格式");
        }

        // 配置解析参数(提升识别率)
        map<decodehinttype, object> hints = new hashmap<>();
        hints.put(decodehinttype.try_harder, boolean.true); // 尝试更高精度解析
        hints.put(decodehinttype.possible_formats, barcodeformat.qr_code); // 仅解析二维码
        hints.put(decodehinttype.character_set, default_charset); // 字符编码

        // 解析二维码
        binarybitmap binarybitmap = new binarybitmap(new hybridbinarizer(new bufferedimageluminancesource(image)));
        qrcodereader qrcodereader = new qrcodereader();
        result result = qrcodereader.decode(binarybitmap, hints);
        return result.gettext();
    }

    /**
     * 读取 base64 编码中的二维码内容
     * @param base64str base64 字符串(支持带/不带 data:image/png;base64, 前缀)
     * @return 二维码内容
     * @throws exception 解析失败
     */
    public static string readqrcodefrombase64(string base64str) throws exception {
        if (base64str == null || base64str.isempty()) {
            throw new illegalargumentexception("base64 字符串不能为空");
        }
        // 移除 base64 前缀(如果有)
        string purebase64 = base64str.replace("data:image/png;base64,", "");
        // 解码为字节数组并转换为输入流
        byte[] bytes = base64.getdecoder().decode(purebase64);
        try (inputstream inputstream = new java.io.bytearrayinputstream(bytes)) {
            return readqrcode(inputstream);
        }
    }
}

四、接口实现(生成 + 读取)

4.1 二维码生成接口(支持显示图片/base64)

import com.google.zxing.notfoundexception;
import com.google.zxing.writerexception;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.multipartfile;
//注意jdk11以上javax包名需要修改为jakarta
import javax.imageio.imageio;
import javax.servlet.http.httpservletresponse;
import java.awt.image.bufferedimage;
import java.util.hashmap;
import java.util.map;

/**
 * 二维码生成接口
 */
@restcontroller
@requestmapping("/qrcode")
public class qrcodegeneratecontroller {


    /**
     * 生成二维码(直接在浏览器显示图片)
     * @param content 二维码内容(必填)
     * @param width 宽度(默认300)
     * @param height 高度(默认300)
     */
    @getmapping("/img")
    public void generate( @requestparam(required = true) string content,
                          @requestparam(defaultvalue = "300") int width,
                          @requestparam(defaultvalue = "300") int height, httpservletresponse response) throws exception {
        try {
            response.setcontenttype("image/png");
            bufferedimage image = qrcodeutil.createqrcode(content, width, height);
            com.example.demo.d1.qrcodeutil.imagetobytes(image);
            imageio.write(image, "png", response.getoutputstream());
        }catch (exception e){
            e.printstacktrace();
        }
    }

    /**
     * 生成二维码并返回 base64 编码(前端可直接用于 img 标签)
     * @param content 二维码内容(必填)
     * @param width 宽度(默认300)
     * @param height 高度(默认300)
     * @return 结构化响应
     */
    @getmapping("/generate")
    public map<string, object> generateqrcode(
            @requestparam(required = true) string content,
            @requestparam(defaultvalue = "300") int width,
            @requestparam(defaultvalue = "300") int height) {

        map<string, object> result = new hashmap<>();
        try {
            // 生成二维码图片
            bufferedimage qrimage = qrcodeutil.createqrcode(content, width, height);
            // 转换为字节数组
            byte[] qrbytes = qrcodeutil.imagetobytes(qrimage);
            // 转换为 base64(带前端可直接使用的前缀)
            string base64 = "data:image/png;base64," + qrcodeutil.imagetobase64(qrbytes);
            // 响应结果
            result.put("code", 200);
            result.put("msg", "二维码生成成功");
            result.put("data", base64);
        } catch (writerexception e) {
            // 处理生成失败异常(内容为空/尺寸非法等)
            result.put("code", 400);
            result.put("msg", "二维码生成失败:" + e.getmessage());
            result.put("data", null);
        } catch (exception e) {
            // 处理其他未知异常
            result.put("code", 500);
            result.put("msg", "服务器异常:" + e.getmessage());
            result.put("data", null);
        }
        return result;
    }
}

4.2 二维码读取接口(支持文件 / base64)

import com.google.zxing.notfoundexception;
import org.springframework.web.bind.annotation.postmapping;
import org.springframework.web.bind.annotation.requestparam;
import org.springframework.web.bind.annotation.restcontroller;
import org.springframework.web.multipart.multipartfile;

import java.util.hashmap;
import java.util.map;

/**
 * 二维码读取接口
 */
@restcontroller
@requestmapping("/qrcode")
public class qrcodereadcontroller {

    /**
     * 解析上传的图片文件中的二维码
     * @param file 图片文件(支持 png/jpg/jpeg)
     * @return 解析结果
     */
    @postmapping("/file")
    public map<string, object> readqrcodefromfile(@requestparam("file") multipartfile file) {
        map<string, object> result = new hashmap<>();
        try {
            // 前置校验
            if (file.isempty()) {
                result.put("code", 400);
                result.put("msg", "上传的文件不能为空");
                return result;
            }
            string contenttype = file.getcontenttype();
            if (contenttype == null || !contenttype.startswith("image/")) {
                result.put("code", 400);
                result.put("msg", "请上传图片文件(png/jpg/jpeg)");
                return result;
            }

            // 解析二维码
            string content = qrcodeutil.readqrcode(file.getinputstream());
            result.put("code", 200);
            result.put("msg", "二维码解析成功");
            result.put("data", content);
        } catch (notfoundexception e) {
            // 核心异常:未识别到二维码
            result.put("code", 400);
            result.put("msg", "未识别到二维码:图片中无有效二维码或二维码模糊/破损");
            result.put("data", null);
        } catch (exception e) {
            result.put("code", 500);
            result.put("msg", "解析失败:" + e.getmessage());
            result.put("data", null);
        }
        return result;
    }

    /**
     * 解析 base64 编码中的二维码
     * @param base64str base64 字符串(支持带/不带前缀)
     * @return 解析结果
     */
    @postmapping("/base64")
    public map<string, object> readqrcodefrombase64(@requestparam("base64") string base64str) {
        map<string, object> result = new hashmap<>();
        try {
            string content = qrcodeutil.readqrcodefrombase64(base64str);
            result.put("code", 200);
            result.put("msg", "解析成功");
            result.put("data", content);
        } catch (notfoundexception e) {
            result.put("code", 400);
            result.put("msg", "未识别到二维码");
        } catch (illegalargumentexception e) {
            result.put("code", 400);
            result.put("msg", "base64 格式错误:" + e.getmessage());
        } catch (exception e) {
            result.put("code", 500);
            result.put("msg", "解析失败:" + e.getmessage());
        }
        return result;
    }
}

五、常见异常与解决方案

5.1 核心异常列表

异常类型异常说明解决方案
com.google.zxing.notfoundexception未识别到二维码1. 检查图片是否包含有效二维码
2. 确保二维码清晰、无遮挡、分辨率≥200px
3. 解析时启用 try_harder 参数4. 避免二维码角度倾斜过大
com.google.zxing.writerexception二维码生成失败1. 检查内容是否为空
2. 确保尺寸参数大于 0
3. 内容过长时缩短(或提升容错级别)
java.io.ioexception图片读取 / 转换失败1. 检查文件格式是否为 png/jpg
2. 确保输入流未提前关闭
3. 验证 base64 编码是否完整
illegalargumentexception参数非法1. 校验 base64 字符串是否为空
2. 检查文件是否为空
3. 验证尺寸 / 编码参数合法性

5.2 通用优化建议

  1. 提升生成容错率:使用 errorcorrectionlevel.h(最高级别),即使二维码被遮挡 30% 仍可识别;
  2. 解决中文乱码:生成 / 解析时统一设置 character_set 为 utf-8;
  3. 优化解析成功率
    • 解析时启用 try_harder 参数;
    • 对图片进行预处理(灰度化、缩放至合适尺寸);
    • 使用 multiformatreader 替代 qrcodereader(支持多码制解析)
  4. base64 兼容性:返回时拼接 data:image/png;base64, 前缀,前端可直接用于 ;
  5. 参数校验:所有接口必须校验入参(内容、文件、尺寸),避免空指针 / 非法参数异常。

六、测试

可以直接使用如下测试页面进行测试,如修改请求url请根据修改内容同步修改页面测试地址

<!doctype html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <title>二维码识别&生成工具</title>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        body {
            padding: 30px;
            font-size: 16px;
        }
        .container {
            max-width: 500px;
            margin: 0 auto;
        }
        h2 {
            margin-bottom: 20px;
            text-align: center;
        }
        /* 新增:生成和识别模块的分隔 */
        .module {
            margin-bottom: 40px;
            padding-bottom: 20px;
            border-bottom: 1px solid #eee;
        }
        .module:last-child {
            border-bottom: none;
        }
        .upload-box {
            border: 2px dashed #ccc;
            padding: 40px;
            text-align: center;
            margin-bottom: 20px;
            cursor: pointer;
        }
        .upload-box:hover {
            border-color: #409eff;
        }
        #preview {
            max-width: 100%;
            max-height: 300px;
            margin: 20px 0;
            display: none;
        }
        /* 新增:生成二维码的预览样式 */
        #qrcode-preview {
            max-width: 200px;
            max-height: 200px;
            margin: 20px auto;
            display: none;
        }
        #result {
            margin-top: 20px;
            padding: 15px;
            background: #f5f5f5;
            border-radius: 6px;
            white-space: pre-wrap;
        }
        button {
            padding: 10px 20px;
            background: #409eff;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        button:disabled {
            background: #ccc;
        }
        /* 新增:生成二维码的输入框样式 */
        .generate-input {
            width: 100%;
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 4px;
            margin: 15px 0;
            resize: vertical;
            min-height: 80px;
        }
    </style>
</head>
<body>
<div class="container">
    <!-- 新增:二维码生成模块 -->
    <div class="module">
        <h2>二维码生成</h2>
        <textarea class="generate-input" id="qrcode-text" placeholder="请输入要生成二维码的文本内容(如网址、文字、手机号等)"></textarea>
        <div style="text-align: center; margin: 10px 0;">
            <button id="generatebtn">生成二维码</button>
        </div>
        <!-- 生成的二维码预览 -->
        <div style="text-align: center;">
            <img id="qrcode-preview" alt="生成的二维码">
        </div>
    </div>
    <!-- 原有:二维码识别模块 -->
    <div class="module">
        <h2>二维码图片识别</h2>
        <div class="upload-box" onclick="document.getelementbyid('file').click()">
            点击或拖拽上传二维码图片
        </div>
        <input type="file" id="file" accept="image/*" style="display: none;">
        <img id="preview" alt="预览图">
        <div style="text-align: center; margin: 10px 0;">
            <button id="recognizebtn" disabled>开始识别</button>
        </div>
        <div id="result"></div>
    </div>
</div>
<script>
    // ========== 原有:二维码识别功能 ==========
    const fileinput = document.getelementbyid('file');
    const preview = document.getelementbyid('preview');
    const recognizebtn = document.getelementbyid('recognizebtn');
    const result = document.getelementbyid('result');
    // 选择图片
    fileinput.onchange = function (e) {
        const file = e.target.files[0];
        if (!file) return;
        // 预览
        const url = url.createobjecturl(file);
        preview.src = url;
        preview.style.display = 'block';
        recognizebtn.disabled = false;
        // 识别
        recognizebtn.onclick = async function () {
            result.innertext = "识别中...";
            recognizebtn.disabled = true;
            const formdata = new formdata();
            formdata.append("file", file);
            try {
                const res = await fetch("http://localhost:8080/qrcode/read", {
                    method: "post",
                    body: formdata
                });
                const jsondata = await res.json();
                result.innertext = "识别结果:\n" + jsondata.data;
            } catch (err) {
                result.innertext = "识别失败:" + err.message;
            } finally {
                recognizebtn.disabled = false;
            }
        };
    }
    // ==========二维码生成功能 ==========
    const generatebtn = document.getelementbyid('generatebtn');
    const qrcodetext = document.getelementbyid('qrcode-text');
    const qrcodepreview = document.getelementbyid('qrcode-preview');
    // 生成二维码按钮点击事件
    generatebtn.onclick = async function () {
        const text = qrcodetext.value.trim();
        if (!text) {
            alert("请输入要生成二维码的内容!");
            return;
        }
        generatebtn.disabled = true;
        generatebtn.innertext = "生成中...";
        qrcodepreview.style.display = 'none';
        try {
            // 调用后端生成二维码接口(需后端配合实现/qrcode/generate接口)
            const res = await fetch("http://localhost:8080/qrcode/generate?content="+text, {
                method: "get",
                headers: {
                    "content-type": "application/json"
                }
            });
            if (!res.ok) throw new error("生成失败");
            const jsondata = await res.json();
            // 将后端返回的二维码图片转为url显示
            // const blob = await res.blob();
            // const qrurl = url.createobjecturl(blob);
             qrcodepreview.src = jsondata.data;
             qrcodepreview.style.display = 'block';
        } catch (err) {
            alert("二维码生成失败:" + err.message);
        } finally {
            generatebtn.disabled = false;
            generatebtn.innertext = "生成二维码";
        }
    }
</script>
</body>
</html>

以上就是springboot集成zxing实现二维码的生成与读取功能的详细内容,更多关于springboot zxing二维码生成与读取的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com