无论是扫码登录、商品追溯还是支付跳转,二维码和条形码在Java后端服务中的出场率都很高。Spring Boot项目里整合ZXing库可以非常简洁地实现这些能力,而且ZXing原生支持多种编码格式,不需要额外的图像处理框架。接下来我们会从依赖配置开始,逐步给出可复用的工具类代码,并深入解析生成与解析过程中容易踩到的坑。

引入ZXing依赖与基础配置
ZXing由Google维护,核心模块负责编码和解码逻辑,但不包含图像输出能力。要在Java中把BitMatrix转换成BufferedImage,通常会额外引入javase模块。Maven项目可以在pom.xml中添加以下两个依赖:
<dependencies>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.5.3</version>
</dependency>
</dependencies>
core提供了编解码的核心类,比如MultiFormatWriter、MultiFormatReader、BarcodeFormat、EncodeHintType等;javase则包含用于图像处理的BufferedImageLuminanceSource和MatrixToImageWriter。如果你使用Gradle,依赖写法类似,版本号保持一致即可。需要注意的是,ZXing的3.5.3是当前稳定版本,但不同版本之间API变化不大,基本可以直接使用。
引入依赖后,无需额外配置Spring容器,因为ZXing本身是无状态的工具类集合。我们可以创建一个单例工具类,把常用的生成和解析方法封装进去,方便在Service层或Controller中直接调用。下面先来看二维码生成部分的实现。
二维码生成实现与参数调优
生成二维码的核心是使用MultiFormatWriter的encode方法,它接收内容、格式、宽高和提示参数,返回一个BitMatrix二维矩阵。BitMatrix中的每个布尔值代表一个像素点,true表示黑色,false表示白色。要把矩阵渲染成图片,需要遍历所有像素并设置颜色。下面是一个完整的生成方法:
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class QRCodeUtil {
public static void generateQRCode(String content, int width, int height, String filePath) throws Exception {
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
hints.put(EncodeHintType.MARGIN, 1);
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
image.setRGB(x, y, bitMatrix.get(x, y) ? Color.BLACK.getRGB() : Color.WHITE.getRGB());
}
}
ImageIO.write(image, "png", new File(filePath));
}
}
上面的代码中,CHARACTER_SET设置为UTF-8可以避免中文内容乱码;ERROR_CORRECTION控制纠错级别,L、M、Q、H分别对应7%、15%、25%、30%的容错率,级别越高二维码越密集,但抗污损能力越强。MARGIN是二维码四周的空白边距,默认值为4,设置为1能有效减小图片尺寸。如果希望对生成的图片进一步处理,比如添加logo或调整颜色,可以基于BufferedImage继续操作。
实际业务中往往需要返回字节数组而不是直接写入文件,方便通过HTTP响应输出。此时可以使用ByteArrayOutputStream结合ImageIO.write将图片转为byte[]。另外,如果二维码内容包含URL或者长文本,建议先进行base64编码或使用短链服务,避免二维码过于复杂导致扫描困难。生成速度方面,MultiFormatWriter的encode操作是CPU密集型,对于高并发场景可以考虑缓存生成的二维码图片或使用异步生成。
条形码解析与二维码解析实战
解析图片中的条形码或者二维码,需要使用MultiFormatReader配合BinaryBitmap。读取图片文件后,先转换为BufferedImage,再通过BufferedImageLuminanceSource获取亮度数据,经过HybridBinarizer二值化处理,最后调用decode方法。解析时通常需要指定可能的条码格式集合,这样可以缩小识别范围,提高准确率。下面展示一个通用的解析方法,同时支持二维码和常见一维条形码:
import com.google.zxing.*;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Map;
public class BarcodeParser {
public static String parseImage(String filePath) throws Exception {
BufferedImage image = ImageIO.read(new File(filePath));
if (image == null) {
throw new IllegalArgumentException("无法读取图片文件");
}
BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
hints.put(DecodeHintType.POSSIBLE_FORMATS,
EnumSet.of(BarcodeFormat.QR_CODE, BarcodeFormat.EAN_13, BarcodeFormat.CODE_128));
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
Result result = new MultiFormatReader().decode(bitmap, hints);
return result.getText();
}
}
需要注意的是,一维条形码(如EAN-13、Code 128)对图片的清晰度要求较高,如果图片模糊或者有旋转,解析成功率会显著下降。TRY_HARDER设置为true会尝试更多优化算法,但会消耗更多CPU时间。POSSIBLE_FORMATS中如果只放QR_CODE,解析一维码时会直接抛出NotFoundException。因此,在不确定图片内容类型时,建议保留多个常用格式,也可以完全省略POSSIBLE_FORMATS让ZXing自动探测所有格式,但性能会略差。
解析成功返回的Result对象除了文本内容外,还包含条码格式、原始字节和结果点等信息,可以根据业务需要进一步处理。对于多二维码的情况,可以使用GenericMultipleBarcodeReader进行批量解析,但普通场景下单个解析已经足够。另外,如果解析过程中遇到NotFoundException,说明图片中没有可识别的条码,可以提示用户重新上传或检查图片质量。
常见问题与性能优化建议
在实际项目中,中文乱码是最常见的问题之一。生成二维码时务必设置EncodeHintType.CHARACTER_SET为UTF-8,解析时也要设置对应的字符集,否则默认使用平台编码可能导致中文显示异常。另一个常见问题是生成出来的二维码无法被某些扫描工具识别,这通常是因为边距过小或者纠错级别设置过高。建议MARGIN保持1到2之间,纠错级别使用M或Q即可,H级别虽然抗损能力强,但会显著增加二维码密度,对打印精度要求更高。
性能方面,如果需要批量生成二维码,可以考虑复用BitMatrix对象或者使用缓存。ZXing本身不是线程不安全的,但MultiFormatWriter和MultiFormatReader都是无状态类,可以安全地作为单例使用。解析大量图片时,图片尺寸过大会导致HybridBinarizer处理变慢,可以在解析前将图片缩小到适当尺寸(例如宽度不超过1000像素),同时保持条码区域清晰。此外,把图片转为灰度图再进行二值化也能提高识别速度。
如果业务需要生成带有logo的二维码,不要直接在BitMatrix上叠加图标,因为这样会破坏纠错区域。正确做法是生成基础二维码后,在BufferedImage上使用Graphics2D绘制logo,logo大小控制在二维码面积的10%以内,并利用纠错级别来保证即使logo遮挡部分区域仍能正常扫描。最后提醒一点,ZXing的javase模块依赖Java 2D,如果你的运行环境是精简版JDK或者使用GraalVM原生镜像,需要额外验证图像处理能力是否完整。
Spring BootQRCode条形码解析修改时间:2026-10-01 22:33:09