【Mac版】Java生成二维码

软件版本

IntelliJ IDEA :2023.2
JDK :17
Tomcat :10.1.11
Maven:3.9.3

技术栈

  • servlet
  • 谷歌的:zxing
    • 生成普通的黑白二维码
    • 在二维码中间添加一个小图标
  • github开源项目:qrcode
    • qrcode开源项目的内部是基于zxing实现的,可以让二维码更加酷炫

项目结构

环境搭建

创建Empty Project


设置SDK

设置Maven

注意:自己安装的maven中settings配置文件中已经配置了本地仓库的位置:

添加web支持

右键项目:

添加框架支持:

注意:如果File菜单中没有上图的"Add Framework Support..."怎么办?

这样File菜单中就有了。

继续添加框架支持:web4.0,不创建web.xml文件

pom.xml文件配置

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.powernode</groupId>
    <artifactId>qrcode</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <version>6.0.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>
  • 打包方式:war
  • 引入servlet依赖

确认web的根是否正确(重点)

设置tomcat并部署应用


这个地方可能有些小伙伴还没有安装tomcat,mac推荐使用homebrew安装tomcat

然后这个Configure这里,需要我们自己去找:

在终端输入以获取tomcat路径:

sh 复制代码
brew ls tomcat


然后依次按照所给tomcat路径去找到自己的tomcat!

启动tomcat并访问

zxing相关依赖

xml 复制代码
<!--zxing依赖-->
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>core</artifactId>
    <version>3.1.0</version>
</dependency>
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>javase</artifactId>
    <version>3.1.0</version>
</dependency>

<!--commons-lang依赖-->
<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
</dependency>

zxing常用API

EncodeHintType(编码提示类型)

EncodeHintType是用来设置二维码编码时的一些额外参数的枚举类型,常用枚举值如下:

  • ERROR_CORRECTION
    • 误差校正级别。对于黑白二维码,可选值为L(7%)、M(15%)、Q(25%)、H(30%),表示二维码允许破损的最大容错率。在二维码出现破损时,根据设置的容错率级别,可以尝试修复二维码中的一些数据。
    • 二维码在生成过程中,可能会出现一些损坏或者缺失的情况,例如打印时墨水耗尽、图像压缩、摄像头拍摄角度不对等。这些问题可能导致二维码无法完全识别,或者识别出来的数据不准确,而误差校正码就是为了解决这些问题而产生的。
    • 例如,选择L级别的容错率,相当于允许在二维码的整体颜色区域中,最多可有约7%的坏像素点;而选择H级别的容错率时,最多可有约30%的坏像素点。
    • 注意:误差校正级别的具体值需要通过ErrorCorrectionLevel的枚举值来获取。
  • CHARACTER_SET
    • 编码字符集。可以设置使用的字符编码,例如utf-8、gb2312等等。
  • MARGIN
    • 二维码的空白区域大小。可以设置二维码周围的留白大小,以便于在不同的嵌入场景中使用二维码。

MultiFormatWriter(多格式写入程序)

MultiFormatWriter是一个便捷的二维码生成类,可以根据传入的BarcodeFormat参数,生成对应类型的二维码。
MultiFormatWriter封装了一系列的二维码生成方法,可以生成多种格式的二维码,包括QR Code、Aztec Code、PDF417、Data Matrix等。

BarcodeFormat(码格式)

BarcodeFormat是枚举类,通过它来制定二维码格式:

  • QR Code :QR Code是最常见的二维码格式之一,广泛应用于商品包装、票务、扫码支付等领域。QR Code矩阵有黑白两种颜色,其中黑色部分表示信息的编码,白色部分则用于衬托和辨识。
  • Aztec Code:Aztec Code是一种高密度、可靠性很高的二维码格式。相比于其他二维码格式,它具有更低的容错率、更小的尺寸和更高的解码效率。因此,它适合用于储存一些核心信息,例如个人信息、证件信息、账户密码等。
  • PDF417:是一种可以储存大量信息的二维码格式,它具有数据密度高、可靠性强等优点,可以应用于许多场景,例如航空机票,运输和配送标签,法律文件等。
  • Data Matrix:是一种小巧的二维码格式,它的编码方式类似于QR Code,但是其可靠性、识别率、扫描速度和牢固度都比QR Code更优秀。由于尺寸较小、可靠性较高,因此Data Matrix适合嵌入简单的产品标签、医疗图像、检测数据等领域。

BitMatrix(位矩阵)

BitMatrix是ZXing库中表示二维码矩阵的数据结构,它是由0和1构成的二维数组,用于存储二维码的编码信息。在二维码生成过程中,我们通过对BitMatrix对象的构建和操作,最终生成一个可被扫描解码的二维码图像。

BitMatrix实际上是一个紧凑型的布尔型二维数组 ,往往只需要占用一个字节即可表示8位二进制。在使用BitMatrix时,我们可以通过其不同的方法,例如get()set()等,来获取、设置矩阵中每个位置的值。

在ZXing中,BitMatrix常用于将编码后的信息转化为矩阵形式,并进行图像的生成和输出。在使用ZXing生成二维码时,我们首先需要使用MultiFormatWriter.encode()方法来生成一个BitMatrix;然后,在对BitMatrix进行各种处理和操作后,就可以在UI中显示和输出二维码。

总的来说,BitMatrix是ZXing库中非常重要的数据结构之一,它负责存储和处理生成二维码图像所需的二进制信息,是实现二维码生成功能的关键。

BitMatrix常用API:

  • getHeight():获取矩阵高度
  • getWidth():获取矩阵宽度
  • get(x, y):根据x,y的坐标获取矩阵中该坐标的值。结果是true(黑色)或者false(白色)。

生成普通黑白二维码

前端代码:

html 复制代码
<%--
  Created by IntelliJ IDEA.
  User: suyue
  Date: 2024/5/30
  Time: 16:21
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>使用JAVA语言生成二维码</title>
  </head>
  <body>
  <h1>使用Google的zxing二维码生成工具生成普通的黑白二维码</h1>
  <hr />
  请输入文本内容:<input type="text" id="url"/>
  <button onclick="generateQRcode()">生成二维码</button><br/>
  <hr />
  <img src="" id="qrcodeimg" />
  <script>
    function generateQRcode() {
      let url = document.getElementById("url").value
      let QRCode = document.getElementById("qrcodeimg");
      QRCode.src = "/QRcode/generate?url=" + url;
    }
  </script>
  </body>
</html>

后端代码:

java 复制代码
package com.powernode.qrcode.servlets;

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 jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


@WebServlet("/generate")
public class GenerateQRcode extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            // 准备一个Map集合,用来存储二维码图片的相关属性
            Map map = new HashMap();
            // 设置误差校验级别
            map.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            // 设置字符编码(因为文本内容要转换成二维码,需要指定转换时采用的字符集)
            map.put(EncodeHintType.CHARACTER_SET, "utf-8");
            // 设置二维码的外边距
            map.put(EncodeHintType.MARGIN, 1);

            // 获取要生成二维码的文本内容
            String url = request.getParameter("url");

            // 创建MultiFormatWriter对象
            MultiFormatWriter writer = new MultiFormatWriter();
            // 传入:内容、码的格式、宽度、高度、二维码参数。返回位矩阵对象。
            BitMatrix bitMatrix = writer.encode(url, BarcodeFormat.QR_CODE, 300, 300, map);
            // 获取位矩阵的宽度和高度
            int width = bitMatrix.getWidth();
            int height = bitMatrix.getHeight();

            // 创建BufferedImage对象
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            // 遍历位矩阵
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    // 0xFF000000 黑色
                    // 0xFFFFFFFF 白色
                    image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
                }
            }

            // 响应
            ServletOutputStream out = response.getOutputStream();
            ImageIO.write(image, "png", out);
            out.flush();
            out.close();

        } catch(Exception e){
            e.printStackTrace();
        }
    }
}

运行效果:

生成一个带logo的黑白二维码

html 复制代码
<%@page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
<!doctype html>
<html>
<head>
  <title>生成带有logo的黑白二维码</title>
  <meta charset="UTF-8">
</head>
<body>
<form action="/myqrcode/generateWithLogo" method="post" enctype="multipart/form-data">
  请输入文本内容:<input type="text" name="url"><br>
  请选择图片:<input type="file" name="logo"><br>
  <input type="submit" value="生成带有logo的二维码"/>
</form>
</body>
</html>
java 复制代码
package com.powernode.qrcode.servlets;

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 jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

@WebServlet("/generateWithLogo")
@MultipartConfig(fileSizeThreshold = 1024 * 1024 * 2, maxFileSize = 1024 * 1024 * 10, maxRequestSize = 1024 * 1024 * 100)
public class GenerateQrCodeWithLogo extends HttpServlet {

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            // 准备一个Map集合,用来存放二维码的属性
            Map map = new HashMap();
            map.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            map.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            map.put(EncodeHintType.MARGIN, 1);

            // 获取文本内容
            String url = request.getParameter("url");

            // 创建zxing核心对象
            MultiFormatWriter writer = new MultiFormatWriter();
            BitMatrix bitMatrix = writer.encode(url, BarcodeFormat.QR_CODE, 300, 300, map);
            int width = bitMatrix.getWidth();
            int height = bitMatrix.getHeight();

            // 生成二维码
            BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
                }
            }

            // 给二维码添加logo
            // 第一部分:将logo缩放。
            // 获取上传的logo Part对象
            Part logo = request.getPart("logo");
            // 通过Part对象获取输入流
            InputStream inputStream = logo.getInputStream();
            // 通过ImageIO的read方法,从输入流中读取,从而获得logo图片
            Image logoImage = ImageIO.read(inputStream);
            // 获取logo图片的宽度
            int logoWidth = logoImage.getWidth(null);
            // 获取logo图片的高度
            int logoHeight = logoImage.getHeight(null);
            // 如果logo的宽度或者高度大于100,则重新赋值100
            if (logoWidth > 60) {
                logoWidth = 60;
            }
            if (logoHeight > 60) {
                logoHeight = 60;
            }
            // 使用平滑缩放算法对原logo图像进行缩放得到一个全新的图像。
            Image scaledLogo = logoImage.getScaledInstance(logoWidth, logoHeight, Image.SCALE_SMOOTH);

            // 第二部分:将缩放后的logo画到黑白二维码上
            // 获取2D画笔
            Graphics2D graphics2D = bufferedImage.createGraphics();
            // 开始画的x和y坐标
            int x = (300 - logoWidth) / 2;
            int y = (300 - logoHeight) / 2;
            // 将缩放后的logo画上去
            graphics2D.drawImage(scaledLogo, x, y, null);
            // 创建一个具有指定位置、宽度、高度和圆角半径的圆角矩形。这个圆角矩形是用来绘制边框的。
            Shape shape = new RoundRectangle2D.Float(x, y, logoWidth, logoHeight, 10, 10);
            // 使用一个宽度为4像素的基本笔触
            graphics2D.setStroke(new BasicStroke(4f));
            // 给logo画圆角矩形
            graphics2D.draw(shape);
            // 释放画笔
            graphics2D.dispose();

            // 响应
            ImageIO.write(bufferedImage, "png", response.getOutputStream());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

运行效果:

使用github开源项目qrcode

xml 复制代码
<dependency>
    <groupId>com.github.liuyueyi.media</groupId>
    <artifactId>qrcode-plugin</artifactId>
    <version>2.5.2</version>
</dependency>

生成黑白二维码

java 复制代码
String url = request.getParameter("url");
BufferedImage image = QrCodeGenWrapper.of(url).asBufferedImage();
ImageIO.write(image, "png", response.getOutputStream());

生成带有logo的二维码

java 复制代码
String url = request.getParameter("url");

BufferedImage image = QrCodeGenWrapper.of(url)
        .setLogo(request.getPart("logo").getInputStream())
        .setLogoRate(7) // 设置 logo 图片与二维码之间的比例。在这个例子中,它设置为 7,表示 logo 的宽度等于二维码的 1/7。
        .setLogoStyle(QrCodeOptions.LogoStyle.ROUND) // 设置 logo 图片的样式。设置为 ROUND,表示将 logo 的边框形状设置为圆形。
        .asBufferedImage();

ImageIO.write(image, "png", response.getOutputStream());

生成彩色二维码

java 复制代码
String url = request.getParameter("url");

BufferedImage image = QrCodeGenWrapper.of(url)
        .setDrawPreColor(Color.BLUE)
        .asBufferedImage();

ImageIO.write(image, "png", response.getOutputStream());

生成背景图二维码

java 复制代码
String url = request.getParameter("url");

BufferedImage image = QrCodeGenWrapper.of(url)
        .setBgImg(request.getPart("logo").getInputStream())
        .setBgOpacity(0.7F)
        .asBufferedImage();

ImageIO.write(image, "png", response.getOutputStream());

特殊形状二维码

java 复制代码
String url = request.getParameter("url");

BufferedImage image = QrCodeGenWrapper.of(url)
        .setDrawEnableScale(true) // 启用二维码绘制时的缩放功能
        .setDrawStyle(QrCodeOptions.DrawStyle.DIAMOND) // 指定绘制样式
        .asBufferedImage();

ImageIO.write(image, "png", response.getOutputStream());

图片填充二维码

java 复制代码
String url = request.getParameter("url");

BufferedImage image = QrCodeGenWrapper.of(url)
        .setErrorCorrection(ErrorCorrectionLevel.H) // 设置二维码的错误纠正级别
        .setDrawStyle(QrCodeOptions.DrawStyle.IMAGE) // 绘制样式采用图片填充
        .addImg(1, 1, request.getPart("logo").getInputStream()) // 添加图片
        .asBufferedImage();

ImageIO.write(image, "png", response.getOutputStream());

生成gif动图二维码

java 复制代码
String url = request.getParameter("url");

BufferedImage image = QrCodeGenWrapper.of(url)
        .setW(500)
        .setH(500)
        .setBgImg(request.getPart("logo").getInputStream())
        .setBgOpacity(0.6f)
        .setPicType("gif")
        .asBufferedImage();

ImageIO.write(image, "gif", response.getOutputStream());
相关推荐
皮皮林5515 小时前
IDEA 源码阅读利器,你居然还不会?
java·intellij idea
卡尔特斯9 小时前
Android Kotlin 项目代理配置【详细步骤(可选)】
android·java·kotlin
白鲸开源9 小时前
Ubuntu 22 下 DolphinScheduler 3.x 伪集群部署实录
java·ubuntu·开源
ytadpole9 小时前
Java 25 新特性 更简洁、更高效、更现代
java·后端
纪莫10 小时前
A公司一面:类加载的过程是怎么样的? 双亲委派的优点和缺点? 产生fullGC的情况有哪些? spring的动态代理有哪些?区别是什么? 如何排查CPU使用率过高?
java·java面试⑧股
JavaGuide10 小时前
JDK 25(长期支持版) 发布,新特性解读!
java·后端
用户37215742613510 小时前
Java 轻松批量替换 Word 文档文字内容
java
白鲸开源10 小时前
教你数分钟内创建并运行一个 DolphinScheduler Workflow!
java
goodSleep11 小时前
更新Mac OS Tahoe26用命令恢复 Mac 启动台时不小心禁用了聚焦搜索
macos
Java中文社群11 小时前
有点意思!Java8后最有用新特性排行榜!
java·后端·面试