logo头像

From zero to HERO

java 快速开发二维码生成服务

1. 前言

不知道从什么时候开始,我们的生活突然之间就充满了二维码,连街边大妈的鸡蛋饼早餐摊也贴上了二维码。而且这次疫情的管控也用上了二维码,避免手工填写造成交叉感染。那么 Java 如何开发二维码功能呢?今天来简单探讨一下。

2. 关于二维码

作为开发者我们肯定会想到二维码是将内容编码成了二维码的图案。对于其原理我们并不需要知道,就是一个编码和解码的过程。但是我们开发中还是需要知道了解一些关于二维码的东西:

  • 完全相同的二维码在算法一致的前提下内容完全相同,反之不成立。
  • 内容越多二维码越复杂,这可以从二维码的图像上肉眼可见。意味着解码就越耗时。
  • 二维码有容错率,容错率越高意味着二维码包含的信息量越大。

根据以上的几点,我们在开发中根据实际情况来作出一些调整,后面会来讲一下我自己的经验。

3. Java 实现二维码的生成

通常我们使用 Google 开源的 1D/2D 条码图像处理库 ZXing 来实现。我们可以通过引入其依赖来集成二维码生成功能:

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

然后我们可以通过下面短短几行代码就生成了一个二维码并将其保存到本地:

QRCodeWriter qrCodeWriter = new QRCodeWriter();
# 第一个参数为二维码的内容 第二个参数不变  第三 四 个参数依次为 宽高
BitMatrix bitMatrix = qrCodeWriter.encode("https://www.felord.cn", BarcodeFormat.QR_CODE, 30, 30);
# 将二维码保存为 png 本地图片。
MatrixToImageWriter.writeToPath(encode, "png", Paths.get("E:\\workbase\\qr.png"));

如果你要控制编码的字符集和纠错率,上面的代码可更改为:

QRCodeWriter qrCodeWriter = new QRCodeWriter();
Map<EncodeHintType, Object> hints = new HashMap<>();
   hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
   hints.put(EncodeHintType.CHARACTER_SET,"UTF-8");
BitMatrix bitMatrix = qrCodeWriter.encode("https://www.felord.cn", BarcodeFormat.QR_CODE, 80, 80,hints);
# 将二维码保存为 png 本地图片。
MatrixToImageWriter.writeToPath(encode, "png", Paths.get("E:\\workbase\\qr.png")); 

其实 MatrixToImageWriter 不但提供将二维码保存为文件,还可以转化为流:

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
MatrixToImageWriter.writeToStream(bitMatrix,"png",byteArrayOutputStream);

byte[] bytes = byteArrayOutputStream.toByteArray();
String base64Image = new BASE64Encoder().encode(bytes);

生成的 base64Image 我们可以在前端通过以下方式进行展示:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQAQAAAACmas8AAAAAvklEQVR42tXSsRGDMAwFUKWxV0jl
rGY39gpOg6BxVoDGWQ0aewVorOQOzgeCARJVr9G/rzsB1YEfZgHh5QjIiPn1zoVTu6SsOLPIdMEh
2BMxJ1lzK0FYq4GRqJgWt76V5e665Na1HQ1F09/oSIpu6qaIRxaztG5pOZXrmy1sRzPjqJ7EKIQ2
Ye27o8clD4ETJxrB0JHfg7xqOAvIrtgGGTFH3XhObS3ABTHn+UQXXAROTI88a04QGB6R8Q9e+QOH
lnNzjaH0oAAAAABJRU5ErkJggg=="  alt="">

Base64 展示体积小的二维码是没有问题的,如果生成的 Base64 字符串比较长将会有较大的渲染消耗。实际生产中要权衡利弊。

4. 动态二维码

如果我们需要动态的来生成二维码,或者换句话来说将二维码作为服务。我们可以借助于 Servlet 来实现一个动态的二维码服务。我们使用 Spring MVC 来实现:

package cn.felord.qr.format;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author dax
 * @since 2020/2/29 21:09
 */
@Controller
@RequestMapping("/qr")
public class QRController {

    @GetMapping("/felord")
   public void gen(HttpServletResponse response) throws IOException, WriterException {

       response.setContentType("image/png");
       ServletOutputStream outputStream = response.getOutputStream();
       outputStream.write(imageBytes());
       outputStream.flush();
       outputStream.close();
   }


   private byte [] imageBytes() throws IOException, WriterException {
       QRCodeWriter qrCodeWriter = new QRCodeWriter();

       Map<EncodeHintType, Object> hints = new HashMap<>();
       hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
       hints.put(EncodeHintType.CHARACTER_SET,"UTF-8");

       BitMatrix bitMatrix = qrCodeWriter.encode("https://www.felord.cn", BarcodeFormat.QR_CODE, 80, 80,hints);

       ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
       MatrixToImageWriter.writeToStream(bitMatrix,"png",byteArrayOutputStream);
      return byteArrayOutputStream.toByteArray();
   }

}

5. 一些实践中的经验

在实际生产中我们要注意以下几点:

  • 尽量避免在二维码中传递敏感的明文信息,应对其进行摘要处理或者脱敏。
  • 对于比较长的网址应该使用短网址服务以减少二维码的信息载荷。
  • 尽量保证二维码一定时间内的唯一性,比如加一些无意义随机值等。
  • 其实也有其它一些功能强大开箱即用的的zxing二次封装库可用,比如 qrext4j

6. 总结

今天就 Java 开发二维码功能进行了一些探讨,从二维码的一些特点到 ZXing 生成二维码并开发为服务,最后还对实际使用中的一些要点进行了罗列,希望对你有用。欢迎通过留言发表你的看法和疑问。

评论系统未开启,无法评论!