1. 引入包
com.google.zxingcore3.3.0
2. 工具类
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.BufferedImageLuminanceSource;
import com.google.zxing.*;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.pig4cloud.pigx.common.oss.service.OssTemplate;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import java.util.List;public class QRCodeUtil {private static final int BLACK &#61; 0xFF000000;// 二维码颜色&#61;&#61;白色private static final int WHITE &#61; 0xFFFFFFFF;// 二维码图片格式&#61;&#61;jpg和png两种private static final List IMAGE_TYPE &#61; new ArrayList<>();static {IMAGE_TYPE.add("jpg");IMAGE_TYPE.add("png");}/*** zxing方式生成二维码* 注意&#xff1a;* 1,文本生成二维码的方法独立出来,返回image流的形式,可以输出到页面* 2,设置容错率为最高,一般容错率越高,图片越不清晰, 但是只有将容错率设置高一点才能兼容logo图片* 3,logo图片默认占二维码图片的20%,设置太大会导致无法解析** &#64;param content 二维码包含的内容&#xff0c;文本或网址* &#64;param path 生成的二维码图片存放位置* &#64;param size 生成的二维码图片尺寸 可以自定义或者默认&#xff08;250&#xff09;* &#64;param logoPath logo的存放位置*/public static boolean zxingCodeCreate(String content, String path, Integer size, String logoPath) {try {//图片类型String imageType &#61; "jpg";//获取二维码流的形式&#xff0c;写入到目录文件中BufferedImage image &#61; getBufferedImage(content, size, logoPath);//获得随机数Random random &#61; new Random();//生成二维码存放文件File file &#61; new File(path&#43;".jpg");if (!file.exists()) {file.mkdirs();}ImageIO.write(image, imageType, file);return true;} catch (IOException e) {e.printStackTrace();return false;}}/*** zxing方式生成二维码&#xff08;上传到minio&#xff09;* 注意&#xff1a;* 1,文本生成二维码的方法独立出来,返回image流的形式,可以输出到页面* 2,设置容错率为最高,一般容错率越高,图片越不清晰, 但是只有将容错率设置高一点才能兼容logo图片* 3,logo图片默认占二维码图片的20%,设置太大会导致无法解析** &#64;param content 二维码包含的内容&#xff0c;文本或网址* &#64;param size 生成的二维码图片尺寸 可以自定义或者默认&#xff08;250&#xff09;* &#64;param logoPath logo的存放位置*/public static InputStream codeCreateMinio(String content, Integer size, String logoPath) {//图片类型String imageType &#61; "jpg";//获取二维码流的形式&#xff0c;写入到目录文件中BufferedImage image &#61; getBufferedImage(content, size, logoPath);ByteArrayOutputStream os &#61; new ByteArrayOutputStream();try {ImageIO.write(image, imageType, os);InputStream input &#61; new ByteArrayInputStream(os.toByteArray());return input;} catch (IOException e) {e.printStackTrace();}return null;}/*** 二维码流的形式&#xff0c;包含文本内容** &#64;param content 二维码文本内容* &#64;param size 二维码尺寸* &#64;param logoPath logo的存放位置* &#64;return*/public static BufferedImage getBufferedImage(String content, Integer size, String logoPath) {if (size &#61;&#61; null || size <&#61; 0) {size &#61; 250;}BufferedImage image &#61; null;try {// 设置编码字符集Map hints &#61; new HashMap<>();//设置编码hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");//设置容错率最高hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);hints.put(EncodeHintType.MARGIN, 1);// 1、生成二维码MultiFormatWriter multiFormatWriter &#61; new MultiFormatWriter();BitMatrix bitMatrix &#61; multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, size, size, hints);// 2、获取二维码宽高int codeWidth &#61; bitMatrix.getWidth();int codeHeight &#61; bitMatrix.getHeight();// 3、将二维码放入缓冲流image &#61; new BufferedImage(codeWidth, codeHeight, BufferedImage.TYPE_INT_RGB);for (int i &#61; 0; i image.getWidth() * 2 / 10 ? (image.getWidth() * 2 / 10) : logo.getWidth(null);int heightLogo &#61; logo.getHeight(null) > image.getHeight() * 2 / 10 ? (image.getHeight() * 2 / 10) : logo.getHeight(null);int x &#61; (image.getWidth() - widthLogo) / 2;int y &#61; (image.getHeight() - heightLogo) / 2;// 开始绘制图片g.drawImage(logo, x, y, widthLogo, heightLogo, null);g.drawRoundRect(x, y, widthLogo, heightLogo, 15, 15);//边框宽度g.setStroke(new BasicStroke(2));//边框颜色g.setColor(Color.WHITE);g.drawRect(x, y, widthLogo, heightLogo);g.dispose();logo.flush();image.flush();}}} catch (WriterException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return image;}/*** 给二维码图片添加Logo** &#64;param qrPic 二维码图片* &#64;param logoPic logo图片* &#64;param path 合成后的图片存储目录*/public static boolean zxingCodeCreate(File qrPic, File logoPic, String path) {try {String imageType &#61; path.substring(path.lastIndexOf(".") &#43; 1).toLowerCase();if (!IMAGE_TYPE.contains(imageType)) {return false;}if (!qrPic.isFile() && !logoPic.isFile()) {return false;}//读取二维码图片&#xff0c;并构建绘图对象BufferedImage image &#61; ImageIO.read(qrPic);Graphics2D g &#61; image.createGraphics();//读取Logo图片BufferedImage logo &#61; ImageIO.read(logoPic);//设置logo的大小,最多20%0int widthLogo &#61; logo.getWidth(null) > image.getWidth() * 2 / 10 ? (image.getWidth() * 2 / 10) : logo.getWidth(null);int heightLogo &#61; logo.getHeight(null) > image.getHeight() * 2 / 10 ? (image.getHeight() * 2 / 10) : logo.getHeight(null);// 计算图片放置位置&#xff0c;默认在中间int x &#61; (image.getWidth() - widthLogo) / 2;int y &#61; (image.getHeight() - heightLogo) / 2;// 开始绘制图片g.drawImage(logo, x, y, widthLogo, heightLogo, null);g.drawRoundRect(x, y, widthLogo, heightLogo, 15, 15);//边框宽度g.setStroke(new BasicStroke(2));//边框颜色g.setColor(Color.WHITE);g.drawRect(x, y, widthLogo, heightLogo);g.dispose();logo.flush();image.flush();File newFile &#61; new File(path);if (!newFile.exists()) {newFile.mkdirs();}ImageIO.write(image, imageType, newFile);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 二维码的解析方法** &#64;param path 二维码图片目录* &#64;return*/public static Result zxingCodeAnalyze(String path) {try {MultiFormatReader formatReader &#61; new MultiFormatReader();File file &#61; new File(path);if (file.exists()) {BufferedImage image &#61; ImageIO.read(file);LuminanceSource source &#61; new BufferedImageLuminanceSource(image);Binarizer binarizer &#61; new HybridBinarizer(source);BinaryBitmap binaryBitmap &#61; new BinaryBitmap(binarizer);Map hints &#61; new HashMap();hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");Result result &#61; formatReader.decode(binaryBitmap, hints);return result;}} catch (IOException e) {e.printStackTrace();} catch (NotFoundException e) {e.printStackTrace();}return null;}/*** 二维码流的形式&#xff0c;包含文本内容** &#64;param content 二维码文本内容* &#64;param size 二维码尺寸* &#64;param logoPath logo的存放位置* &#64;return*/public static BufferedImage getBufferedImage8(String content, Integer size, String logoPath,List ptexts) {if (size &#61;&#61; null || size <&#61; 0) {size &#61; 250;}BufferedImage image &#61; null;try {// 设置编码字符集Map hints &#61; new HashMap<>();//设置编码hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");//设置容错率最高hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);hints.put(EncodeHintType.MARGIN, 1);// 1、生成二维码MultiFormatWriter multiFormatWriter &#61; new MultiFormatWriter();BitMatrix bitMatrix &#61; multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, size, size, hints);// 2、获取二维码宽高int codeWidth &#61; bitMatrix.getWidth();int codeHeight &#61; bitMatrix.getHeight();if(CollUtil.isNotEmpty(ptexts)){codeHeight&#61;codeHeight&#43;20*ptexts.size()&#43;10;}// 3、将二维码放入缓冲流image &#61; new BufferedImage(codeWidth, codeHeight, BufferedImage.TYPE_INT_RGB);for (int i &#61; 0; i image.getWidth() * 2 / 10 ? (image.getWidth() * 2 / 10) : logo.getWidth(null);int heightLogo &#61; logo.getHeight(null) > image.getHeight() * 2 / 10 ? (image.getHeight() * 2 / 10) : logo.getHeight(null);int x &#61; (image.getWidth() - widthLogo) / 2;int y &#61; (image.getHeight() - heightLogo) / 2;// 开始绘制图片g.drawImage(logo, x, y, widthLogo, heightLogo, null);g.drawRoundRect(x, y, widthLogo, heightLogo, 15, 15);//边框宽度g.setStroke(new BasicStroke(2));//边框颜色g.setColor(Color.WHITE);g.drawRect(x, y, widthLogo, heightLogo);g.dispose();logo.flush();image.flush();}}} catch (WriterException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return image;}/*** 返回base64* */public static String crateQRCode(String content, Integer size, String logoPath,List ptexts) throws IOException {//输出流ByteArrayOutputStream stream &#61; new ByteArrayOutputStream();try {//图片类型String imageType &#61; "png";//获取二维码流的形式&#xff0c;写入到目录文件中BufferedImage image &#61; getBufferedImage8(content, size, logoPath,ptexts);ImageIO.write(image, imageType, stream);return Base64.encode(stream.toByteArray());} catch (IOException e) {e.printStackTrace();}return null;}/*** zxing方式生成二维码* 注意&#xff1a;* 1,文本生成二维码的方法独立出来,返回image流的形式,可以输出到页面* 2,设置容错率为最高,一般容错率越高,图片越不清晰, 但是只有将容错率设置高一点才能兼容logo图片* 3,logo图片默认占二维码图片的20%,设置太大会导致无法解析** &#64;param content 二维码包含的内容&#xff0c;文本或网址* &#64;param path 生成的二维码图片存放位置* &#64;param size 生成的二维码图片尺寸 可以自定义或者默认&#xff08;250&#xff09;* &#64;param logoPath logo的存放位置*/public static boolean zxingCodeCreate8(String content, String path, Integer size, String logoPath) {try {//图片类型String imageType &#61; "png";//获取二维码流的形式&#xff0c;写入到目录文件中List ptexts &#61; new ArrayList<>();ptexts.add("设备id: NO20220309-00909");ptexts.add("设备名称: 松下打印机哈哈哈哈哈哈哈哈就好哈哈哈哈哈哈哈哈哈哈哈哈gh哈哈哈哈哈哈哈哈哈哈103室");ptexts.add("设备名称: 松下打印机哈哈哈哈哈哈哈哈就好哈哈哈哈哈哈哈哈哈哈哈哈gh哈哈哈哈哈哈哈哈哈哈103室");ptexts.add("设备名称: 松下打印机哈哈哈哈哈哈哈哈就好哈哈哈哈哈哈哈哈哈哈哈哈gh哈哈哈哈哈哈哈哈哈哈103室");ptexts.add("设备名称: 松下打印机哈哈哈哈哈哈哈哈就好哈哈哈哈哈哈哈哈哈哈哈哈gh哈哈哈哈哈哈哈哈哈哈103室");BufferedImage image &#61; getBufferedImage8(content, size, logoPath,ptexts);//获得随机数Random random &#61; new Random();//生成二维码存放文件File file &#61; new File(path&#43;".png");if (!file.exists()) {file.mkdirs();}ImageIO.write(image, imageType, file);return true;} catch (IOException e) {e.printStackTrace();return false;}}
// public static void main(String[] args) {
// String path&#61;"/Users/liangyating/IdeaProjects/cltech-dmin/cltech/cltech-biz/src/main/resources/file/";
// String url &#61; "https://test.chaolingroup.com/#/device/upkeep/type";
// //生成二维码
// boolean qc&#61; QRCodeUtil.zxingCodeCreate8(url,path&#43;"1",300,null);
//
//
// }}
3. 效果如下