软件版本
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 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路径:
brew ls tomcat
然后依次按照所给tomcat路径去找到自己的tomcat!
启动tomcat并访问
zxing相关依赖
<!--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(白色)。
生成普通黑白二维码
前端代码:
<%--Created by IntelliJ IDEA.User: suyueDate: 2024/5/30Time: 16:21To 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").valuelet QRCode = document.getElementById("qrcodeimg");QRCode.src = "/QRcode/generate?url=" + url;}</script></body>
</html>
后端代码:
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 {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req, resp);}@Overrideprotected 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的黑白二维码
<%@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>
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,则重新赋值100if (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
<dependency><groupId>com.github.liuyueyi.media</groupId><artifactId>qrcode-plugin</artifactId><version>2.5.2</version>
</dependency>
生成黑白二维码
String url = request.getParameter("url");
BufferedImage image = QrCodeGenWrapper.of(url).asBufferedImage();
ImageIO.write(image, "png", response.getOutputStream());
生成带有logo的二维码
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());
生成彩色二维码
String url = request.getParameter("url");BufferedImage image = QrCodeGenWrapper.of(url).setDrawPreColor(Color.BLUE).asBufferedImage();ImageIO.write(image, "png", response.getOutputStream());
生成背景图二维码
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());
特殊形状二维码
String url = request.getParameter("url");BufferedImage image = QrCodeGenWrapper.of(url).setDrawEnableScale(true) // 启用二维码绘制时的缩放功能.setDrawStyle(QrCodeOptions.DrawStyle.DIAMOND) // 指定绘制样式.asBufferedImage();ImageIO.write(image, "png", response.getOutputStream());
图片填充二维码
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动图二维码
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());