SpringBoot genera y analiza el código QR para compartir clases de herramientas completas (se proporciona el código fuente de Gitee)

Prólogo: En el trabajo de desarrollo diario, puede ser necesario implementar una pequeña función de código QR. Consulte muchos tutoriales en línea sobre cómo SpringBoot genera códigos QR y finalmente encapsula un conjunto completo de herramientas para generar códigos QR que pueden admitir Basic Black. Y código QR blanco, código QR de color, código QR de logotipo, código QR de color y logotipo y análisis de código QR. También puede generar archivos de códigos QR específicos o regresar a Base64. Todos están escritos a mano y empaquetados por el propio blogger, aquí está ¡Gratis y de código abierto para que todos puedan usarlo con un solo clic! ¡Solo pídales a todos soporte gratuito de tres enlaces!

Tabla de contenido

1. Registro de problemas

2. Importar dependencias de pom

3. Código completo de la clase de herramienta QRCodeUtil

4. Ejemplo de uso

5. Código fuente de Gitee

6. Resumen


1. Registro de problemas

Aquí estoy usando el código QR generado por el paquete jar proporcionado por zxing, pero hay un problema que el blog aún no ha resuelto. Si hay una solución, espero que puedas compartirla en el área de comentarios. El problema es como sigue:

Si el contenido del código QR está configurado en chino, se informará un error de com.google.zxing.NotFoundException. Los blogueros han buscado mucha información en Internet pero no han encontrado una solución específica a este problema.

2. Importar dependencias de pom

    <dependencies>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 二维码生成器依赖 -->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.3.0</version>
        </dependency>

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

        <!-- 常用工具类 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        
    </dependencies>

3. Código completo de la clase de herramienta QRCodeUtil

package com.example.ewm.utils;

import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Random;
import javax.imageio.ImageIO;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
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.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

/**
 * @author HTT
 */
@Component
public class QRCodeUtil {
    /**
     * 编码格式
     */
    private static final String CHARSET = "utf-8";

    /**
     * 二维码后缀名
     */
    private static final String FORMAT_NAME = "JPG";

    /**
     * 二维码尺寸
     */
    private static final int QRCODE_SIZE = 300;

    /**
     * 插入图宽度
     */
    private static final int WIDTH = 60;

    /**
     * 插入图高度
     */
    private static final int HEIGHT = 60;

    /**
     * 插入图片
     * @param source 文件流
     * @param imgPath 图片路径
     * @param needCompress 是否压缩图片
     * @throws Exception
     */
    private void insertImage(BufferedImage source, String imgPath, boolean needCompress) throws Exception {
        File file = new File(imgPath);
        if (!file.exists()) {
            throw new Exception(imgPath+"图片文件不存在");
        }
        Image src = ImageIO.read(new File(imgPath));
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        // 压缩LOGO
        if (needCompress) {
            if (width > WIDTH) {
                width = WIDTH;
            }
            if (height > HEIGHT) {
                height = HEIGHT;
            }
            Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
            BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics g = tag.getGraphics();
            // 绘制缩小后的图
            g.drawImage(image, 0, 0, null);
            g.dispose();
            src = image;
        }
        // 插入LOGO
        Graphics2D graph = source.createGraphics();
        int x = (QRCODE_SIZE - width) / 2;
        int y = (QRCODE_SIZE - height) / 2;
        graph.drawImage(src, x, y, width, height, null);
        Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
        graph.setStroke(new BasicStroke(3f));
        graph.draw(shape);
        graph.dispose();
    }

    /**
     * 创建带图片的二维码核心方法(如果图片路径为空,不会生成图片)
     * @param content 二维码内容
     * @param imgPath 图片路径
     * @param needCompress 是否压缩图片
     * @return
     * @throws Exception
     */
    private BufferedImage createEwm(String content, String imgPath, boolean needCompress) throws Exception {
        Hashtable hints = new Hashtable(16);
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE,
                hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        if (StringUtils.isEmpty(imgPath)) {
            return image;
        }
        // 插入图片
        insertImage(image, imgPath, needCompress);
        return image;
    }

    /**
     * 创建自定义颜色和图片的二维码核心方法(如果图片路径为空,不会生成图片)
     * @param content 二维码内容
     * @param imgPath 图片路径
     * @param needCompress 是否压缩图片
     * @param frontColor 前景色
     * @param backgroundColor 背景色
     * @return
     * @throws Exception
     */
    private BufferedImage createEwm(String content, String imgPath, boolean needCompress,int frontColor,int backgroundColor) throws Exception {
        Hashtable hints = new Hashtable(16);
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE,
                hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? frontColor : backgroundColor);
            }
        }
        if (StringUtils.isEmpty(imgPath)) {
            return image;
        }
        // 插入图片
        insertImage(image, imgPath, needCompress);
        return image;
    }

    /**
     * 生成带图片的二维码保存为文件(如果图片路径为空,不会生成图片)
     * @param content 二维码内容
     * @param imgPath 图片路径
     * @param destPath 存放路径
     * @param needCompress 是否压缩图片
     * @throws Exception
     */
    private void generate(String content, String imgPath, String destPath, boolean needCompress) throws Exception {
        BufferedImage image = createEwm(content, imgPath, needCompress);
        mkdirs(destPath);
        ImageIO.write(image, FORMAT_NAME, new File(destPath));
    }

    /**
     * 创建自定义颜色和图片的二维码保存为文件(如果图片路径为空,不会生成图片)
     * @param content 二维码内容
     * @param imgPath 图片路径(路径为空,则只生成基础的二维码)
     * @param destPath 存放路径
     * @param needCompress 是否压缩图片
     * @param frontColor 前景色
     * @param backgroundColor 背景色
     * 例举一些16进制的颜色代码
     * 0x000000 黑
     * 0xff0000 亮红
     * 0x00ff00 亮绿
     * 0xffff00 亮黄
     * 0x0000ff 亮蓝
     * 0xff00ff 亮紫
     * 0x00ffff 亮浅蓝
     * 0xffffff 白
     * 0xc6c6c6 亮灰
     * 0x848484 暗灰
     * @throws Exception
     */
    private void generate(String content, String imgPath, String destPath, boolean needCompress,int frontColor,int backgroundColor) throws Exception {
        BufferedImage image = createEwm(content, imgPath, needCompress,frontColor,backgroundColor);
        mkdirs(destPath);
        ImageIO.write(image, FORMAT_NAME, new File(destPath));
    }

    /**
     * 生成带有图片的二维码并返回Base64(如果图片路径为空,不会生成图片)
     * @param content 二维码内容
     * @param imgPath 图片路径
     * @param needCompress 是否压缩图片
     * @return
     * @throws Exception
     */
    private String generateBase64(String content, String imgPath, boolean needCompress) throws Exception {
        if (!StringUtils.isEmpty(content)) {
            HashMap<EncodeHintType, Comparable> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            hints.put(EncodeHintType.MARGIN, 0);
            BufferedImage bufferedImage = createEwm(content, imgPath, needCompress);
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            ImageIO.write(bufferedImage, FORMAT_NAME, os);
            String base64 = Base64.encode(os.toByteArray());
            os.flush();
            os.close();
            return "data:image/png;base64," + base64;
        }
        return "";
    }

    /**
     * 生成带有自定义颜色和图片的二维码并返回Base64(如果图片路径为空,不会生成图片)
     * @param content 二维码内容
     * @param imgPath 图片路径
     * @param needCompress 是否压缩图片
     * @param frontColor 前景色
     * @param backgroundColor 背景色
     * @return
     * @throws Exception
     */
    private String generateBase64(String content, String imgPath, boolean needCompress,int frontColor,int backgroundColor) throws Exception {
        if (!StringUtils.isEmpty(content)) {
            HashMap<EncodeHintType, Comparable> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            hints.put(EncodeHintType.MARGIN, 0);
            BufferedImage bufferedImage = createEwm(content, imgPath, needCompress,frontColor,backgroundColor);
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            ImageIO.write(bufferedImage, FORMAT_NAME, os);
            String base64 = Base64.encode(os.toByteArray());
            os.flush();
            os.close();
            return "data:image/png;base64," + base64;
        }
        return "";
    }

    /**
     * 创建多级目录
     * @param destPath
     */
    private void mkdirs(String destPath) {
        File file = new File(destPath);
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

    /**
     * 根据文件解析二维码
     * @param file
     * @return
     * @throws Exception
     */
    private String analysis(File file) throws Exception {
        BufferedImage image;
        image = ImageIO.read(file);
        if (image == null) {
            return null;
        }
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        HashMap hints = new HashMap<DecodeHintType, Object>();
        hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
        Result result = new MultiFormatReader().decode(bitmap, hints);
        String resultStr = result.getText();
        return resultStr;
    }

    /*******************************************************以下是创建二维码提供的方法封装*******************************************************/

    /******************************另存为文件版本******************************/

    /**
     * 创建基础的二维码
     * @param content 二维码内容
     * @param destPath 存放路径
     * @throws Exception
     */
    public void create(String content, String destPath) throws Exception {
        generate(content, null, destPath, false);
    }

    /**
     * 创建带颜色基础的二维码
     * @param content 二维码内容
     * @param destPath 存放路径
     * @throws Exception
     */
    public void create(String content, String destPath,int frontColor,int backgroundColor) throws Exception {
        generate(content, null, destPath, false,frontColor,backgroundColor);
    }

    /**
     * 创建带图片的二维码
     * @param content 二维码内容
     * @param imgPath 图片路径
     * @param destPath 存放路径
     * @param needCompress 是否压缩图片
     * @throws Exception
     */
    public void create(String content, String imgPath, String destPath,boolean needCompress) throws Exception {
        generate(content, imgPath, destPath, needCompress);
    }

    /**
     * 创建带有自定义颜色和图片的二维码
     * @param content 二维码内容
     * @param imgPath 图片路径
     * @param destPath 存放路径
     * @param needCompress 是否压缩图片
     * @param frontColor 前景色
     * @param backgroundColor 背景色
     * @throws Exception
     */
    public void create(String content, String imgPath, String destPath,boolean needCompress,int frontColor,int backgroundColor) throws Exception {
        generate(content, imgPath, destPath, needCompress,frontColor,backgroundColor);
    }

    /******************************另存为文件版本******************************/

    /******************************Base64版本******************************/

    /**
     * 创建基础的二维码并返回Base64
     * @param content
     * @throws Exception
     */
    public String create(String content) throws Exception {
        return generateBase64(content,null,false);
    }

    /**
     * 创建带颜色基础的二维码并返回Base64
     * @param content
     * @throws Exception
     */
    public String create(String content,int frontColor,int backgroundColor) throws Exception {
        return generateBase64(content,null,false,frontColor,backgroundColor);
    }

    /**
     * 创建带图片的二维码并返回Base64
     * @param content 二维码内容
     * @param imgPath 图片路径
     * @param needCompress 是否压缩图片
     * @throws Exception
     */
    public String create(String content, String imgPath,boolean needCompress) throws Exception {
        return generateBase64(content, imgPath, needCompress);
    }

    /**
     * 创建带有自定义颜色和图片的二维码并返回Base64
     * @param content 二维码内容
     * @param imgPath 图片路径
     * @param needCompress 是否压缩图片
     * @param frontColor 前景色
     * @param backgroundColor 背景色
     * @throws Exception
     */
    public String create(String content, String imgPath,boolean needCompress,int frontColor,int backgroundColor) throws Exception {
        return generateBase64(content, imgPath, needCompress,frontColor,backgroundColor);
    }

    /******************************Base64版本******************************/

    /**
     * 根据文件路径解析二维码
     * @param path 文件路径
     * @return
     * @throws Exception
     */
    public String decode(String path) throws Exception {
        File file = new File(path);
        if(!file.exists()){
            throw new Exception("文件不存在!");
        }
        return analysis(file);
    }

}

4. Ejemplo de uso

Recordatorio amistoso: el valor booleano en el código representa si la imagen del logotipo debe comprimirse. Si es verdadero, significa que la imagen del logotipo incrustada debe comprimirse. Mi sugerencia es establecerlo en verdadero de forma predeterminada, porque si no está comprimido, utilizará decodificación para analizar la imagen con Logo. Se informará el error com.google.zxing.NotFoundException al usar el código QR y el blogger lo ha probado personalmente.

prueba de unidad:

@SpringBootTest
class EwmApplicationTests {

    @Resource
    private QRCodeUtil qrCodeUtil;

    @Test
    void contextLoads() throws Exception {

        qrCodeUtil.create("httstudy","F:\\基础二维码.jpg");
        qrCodeUtil.create("httstudy","F:\\带颜色的二维码.jpg",0xff0000,0xffff00);
        qrCodeUtil.create("httstudy","F:\\Logo.png","F:\\带logo的二维码.jpg",true);
        qrCodeUtil.create("httstudy","F:\\Logo.png","F:\\带颜色和logo的二维码.jpg",true,0xff0000,0xffff00);

        String str = qrCodeUtil.create("httstudy");
        String str2 = qrCodeUtil.create("httstudy",0xff0000,0xffff00);
        String str3 = qrCodeUtil.create("httstudy","F:\\Logo.png",true);
        String str4 = qrCodeUtil.create("httstudy","F:\\Logo.png",true,0xff0000,0xffff00);
        System.out.println(str);
        System.out.println(str2);
        System.out.println(str3);
        System.out.println(str4);

        String result = qrCodeUtil.decode("F:\\基础二维码.jpg");
        String result2 = qrCodeUtil.decode("F:\\带颜色的二维码.jpg");
        String result3 = qrCodeUtil.decode("F:\\带logo的二维码.jpg");
        String result4 = qrCodeUtil.decode("F:\\带颜色和logo的二维码.jpg");
        System.out.println(result);
        System.out.println(result2);
        System.out.println(result3);
        System.out.println(result4);
    }

}

 resultado de la operación:

5. Código fuente de Gitee

Dirección de nube de código: SpringBoot genera código QR para compartir clases de herramientas completas

6. Resumen

No es fácil para los bloggers concienzudos crear empaques originales. Hemos empaquetado todos los tipos de códigos QR que se necesitan en escenarios comunes. Solo necesita generarlos con un clic como una prueba unitaria. Si tiene alguna pregunta, por favor deje ¡Un mensaje en el área de comentarios!

Supongo que te gusta

Origin blog.csdn.net/HJW_233/article/details/132437302
Recomendado
Clasificación