前言
二维码应用到生活的各个方面,会用代码实现二维码,我想一定是一项加分的技能。好了,我们来一起实现一下吧。
我们实现的二维码是基于QR Code的标准的,QR Code是由日本Denso公司于1994年研制的一种矩阵二维码符号码,全称是Quick Response Code
QR Code:专利公开,支持中文;
QR Code与其他二维码相比,具有识读速度快、数据密度大、占用空间小的优势;
效果图
代码实现
maven 依赖
使用的是zxing所以需要2个依赖,下面是pom.xml的配置:
<!-- https://mvnrepository.com/artifact/com.google.zxing/core -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.2.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.zxing/javase --> <dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.2.1</version>
</dependency>
工具类编写(QRCodeUtil)
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
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.File;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Objects;
// 生成二维码工具类
public class QRCodeUtil {
//文字显示
private static final int QRCOLOR = 0x201f1f; // 二维码颜色:黑色
private static final int BGWHITE = 0xFFFFFF; //二维码背景颜色:白色
// 1、设置二维码的一些参数
private static HashMap hints = new HashMap();
static {
// 1.1设置字符集
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
// 1.2设置容错等级;因为有了容错,在一定范围内可以把二维码p成你喜欢的样式
/**
* 纠错能力:
* L级:约可纠错7%的数据码字
* M级:约可纠错15%的数据码字
* Q级:约可纠错25%的数据码字
* H级:约可纠错30%的数据码字
*/
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
// 1.3设置外边距;(即白色区域)
hints.put(EncodeHintType.MARGIN, 1);
}
/**
* 基础生成二维码的方法,不带 logo
*
* @param width 二维码的宽
* @param height 二维码的高
* @param content 二维码的内容
*/
public static BufferedImage createQrCode(int width, int height, String content) {
try {
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
return MatrixToImageWriter.toBufferedImage(bitMatrix);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 生成携带logo的二维码
*
* @param width
* @param height
* @param content
* @param logoFile logo 路径
*/
public static BufferedImage createLogoQrCode(int width, int height, String content, File logoFile) {
try {
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
// 参数顺序分别为: 编码内容,编码类型,生成图片宽度,生成图片高度,设置参数
BitMatrix bm = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 开始利用二维码数据创建Bitmap图片,分别设为黑(0xFFFFFFFF) 白(0xFF000000)两色
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
image.setRGB(x, y, bm.get(x, y) ? QRCOLOR : BGWHITE);
}
}
addLogo(image, logoFile);
return image;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* @param image 二维码图像。
* @param logoPic logo文件路径
*/
private static void addLogo(BufferedImage image, File logoPic) {
try {
// 1、读取二维码图片,并构建绘图对象
Graphics2D graph = image.createGraphics();
// 2、读取logo图片
BufferedImage logo = ImageIO.read(logoPic);
// 大小
int width = image.getWidth();
int height = image.getHeight();
int widthLogo = width / 5;
int heightLogo = height / 5;
// 3、计算图片放置的位置
int x = (width - widthLogo) / 2;
int y = (height - heightLogo) / 2;
if (false) { // 是否添加白底
int fillWidth = widthLogo + 15;
int fillHeight = heightLogo + 15;
int fillX = (width - fillWidth) / 2;
int fillY = (height - fillHeight) / 2;
graph.fillRect(fillX, fillY, fillWidth, fillHeight);
}
// 4、绘制图片
graph.drawImage(logo, x, y, widthLogo, heightLogo, null);
// 5、释放它正在使用的系统资源
graph.dispose();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 添加背景图、文字描述
* 如果X轴==null 则居中显示
* 如果Y轴==null 则居中显示
* 文字Y轴为null文字默认在二维码上方
*/
public static BufferedImage addBackground(BufferedImage qrImage, File bgFile, String text, Integer qrX, Integer qrY, Integer textX, Integer textY) {
try {
// 读取背景图片,并构建绘图对象
BufferedImage image = ImageIO.read(bgFile);
Graphics2D graph = image.createGraphics();
int bgWidth = image.getWidth();
int bgHeight = image.getHeight();
int width = qrImage.getWidth();
int height = qrImage.getHeight();
// 计算二维码图片放置的位置
if (Objects.isNull(qrX)) {
qrX = (bgWidth - width) / 2;
}
if (Objects.isNull(qrY)) {
qrY = (bgHeight - height) / 2;
}
// 绘制图片
graph.drawImage(qrImage, qrX, qrY, width, height, null);
//文字描述参数1
//设置字体类型和大小(BOLD加粗/ PLAIN平常)
graph.setFont(new Font("宋体", Font.PLAIN, 20));
//设置字体颜色
graph.setColor(Color.white);
int strWidth = graph.getFontMetrics().stringWidth(text);
//文字1显示位置
if (Objects.isNull(textX)) {
textX = (bgWidth - strWidth) / 2;
}
if (Objects.isNull(textY)) {
textY = qrY - 20;
}
// 绘制文字
graph.drawString(text, textX, textY);//上下
return image;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
后端下载代码(DownloadController)
@RequestMapping("/download")
public void download(String fileName, String content, HttpServletResponse response) throws Exception {
File logoFile = new File("C:\\Users\\Administrator\\Desktop/avatar.png");
BufferedImage qrImage = QRCodeUtil.createLogoQrCode(250, 250, "hello,world", logoFile);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(qrImage, "png", byteArrayOutputStream);
//设置response
response.setContentType("application/x-msdownload");
String downloadFilename = URLEncoder.encode("二维码文件名", "UTF-8");
response.setHeader("Content-Disposition", "attachment;filename=" + downloadFilename + ".png");
//输出流
response.getOutputStream().write(byteArrayOutputStream.toByteArray());
}
前端下载代码
<a href="/download/?fileName=联通">直接下载</a>
打包/批量下载
后端代码
/**
*
* 生成二维码下载压缩包
*/
@RequestMapping("/downloadZip")
public void downloadZip(@RequestBody List<Map<String,String>> list, HttpServletResponse response) throws Exception {
List<BufferedImage> images = new ArrayList<>();
for (Map<String,String> item : list) {
BufferedImage image = QRCodeUtil.createLogoQrCode(250, 250, "hello", new File("C:\\Users\\Administrator\\Desktop/test.png"));
images.add(image);
}
// 指明response的返回对象是文件流
response.setContentType("application/octet-stream; charset=UTF-8");
// 设置在下载框默认显示的文件名
String downloadFilename = URLEncoder.encode("二维码", "UTF-8");
response.setHeader("Content-Disposition", "attachment;filename=" + downloadFilename + ".zip");
ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
BufferedImage[] files = new BufferedImage[images.size()];
images.toArray(files);
for (int i = 0; i < files.length; i++) {
BufferedImage img = files[i];
zos.putNextEntry(new ZipEntry("temp_download" + File.separator + list.get(i).get("name") + ".jpg"));
ImageIO.write(img, "png", zos);
}
zos.flush();
zos.close();
}
前端代码
// 创建一个异步请求的对象
var xhr = new XMLHttpRequest();
// 设置使用 Post 方法进行提交,并且设置请求的 url
xhr.open("POST", "/downloadZip");
// 设置发送数据的格式为JSON
xhr.setRequestHeader("Content-Type", "application/json");
// 注册事件 (委托浏览器在请求结束的时候触发这个逻辑)
xhr.onload = function (e) {
var blob = xhr.response;
var a = document.createElement('a');
a.download = '打包好的.zip';
a.href=window.URL.createObjectURL(blob);
a.click();
};
// 开始发送请求!
var params = JSON.stringify([{name:'aaa'}])
xhr.send(params);