Java-生成二维码-两种方式:普通二维码和带有中间log(简单,高效,通俗,易懂)

时间:2025-04-05 22:43:35

最近公司里项目要求生成二维码来提供给用户扫码跳转页面,需求很简单,正好自己还是第一次做二维码这一块,所以写了此文章,供后来者借鉴!

这里我多啰嗦几句,其实二维码就是某个URL的另一种呈现形式,按照逻辑思考,第一,怎么样生成二维码?第二,二维码的时效性或者说有效性如何保持?那我们来带着问题往下看:

其实网上有很多二维码生成的示例或者工具类,但是我在使用的时候总觉得不是很好,有的生成的带有中间LOG的二维码颜色不是黑白的(我们的产品经理说,黑白色的二维码看起来正规!),有的生成的二维码会在本地服务器留下临时的文件,这种文件对于我们开发者来说是垃圾资源,我们还要写代码去处理掉这些资源,代码量就变大了,不划算,所以我从网上各个源码中借鉴了一下,写了一个工具类供大家参考:

1.由于我的是maven项目,所以先引入相关的jar包

<dependency>
   <groupId></groupId>
   <artifactId>javase</artifactId>
   <version>3.1.0</version>
</dependency>

2.直接上代码

代码里注释很全,注意我标记的红色注释

-----------------------------------------------------------------------------------------------------------------------------

package ;
import ;
import ;
import .Graphics2D;
import ;
import ;
import ;
import ;
import ;
import ;

import .Base64;
import .;
import ;
import ;
import ;

import ;
import ;
/**
 * Created by healer on 2019/7/29.
 */
public class QrCodeUtil {

    private static final int QRCOLOR = 0xFF000000; // 默认是黑色
    private static final int BGWHITE = 0xFFFFFFFF; // 背景颜色

    private static final int WIDTH = 400; // 二维码宽
    private static final int HEIGHT = 400; // 二维码高

    // 用于设置QR二维码参数
    private static Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>() {
        private static final long serialVersionUID = 1L;
        {
            put(EncodeHintType.ERROR_CORRECTION, );// 设置QR二维码的纠错级别(H为*别)具体级别信息
            put(EncodeHintType.CHARACTER_SET, "utf-8");// 设置编码方式
            put(, 0);
        }
    };


    /**
     * 生成带logo的二维码图片
     * note 二维码下方的标题,如果不需要为空即可
     * 返回字符串,将此字符串放入IMG标签的SRC即可
     */
    public static  String drawLogoQRCode(String qrUrl, String logUrl,String note) {
        File logoFile = new File(logUrl);//log存放的绝对路径,如果存放在本项目的resource底下,可以用 某个类.("/").getPath()来获取,这里如果有的图片是存放在远程服务器上,你们可以*发挥修改这行代码
        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        try {
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            // 参数顺序分别为:编码内容,编码类型,生成图片宽度,生成图片高度,设置参数
            BitMatrix bm = (qrUrl, BarcodeFormat.QR_CODE, WIDTH, HEIGHT, hints);

            // 开始利用二维码数据创建Bitmap图片,分别设为黑(0xFFFFFFFF)白(0xFF000000)两色
            for (int x = 0; x < WIDTH; x++) {
                for (int y = 0; y < HEIGHT; y++) {
                    (x, y, (x, y) ? QRCOLOR : BGWHITE);
                }
            }

            int width = ();
            int height = ();
            if ( ()) {
                // 构建绘图对象
                Graphics2D g = ();
                // 读取Logo图片
                BufferedImage logo = (logoFile);
                // 开始绘制logo图片
                (logo, width * 2 / 5, height * 2 / 5, width * 2 / 10, height * 2 / 10, null);
                ();
                ();
            }

            // 自定义文本描述
            if ((note)) {
                // 新的图片,把带logo的二维码下面加上文字
                BufferedImage outImage = new BufferedImage(400, 445, BufferedImage.TYPE_4BYTE_ABGR);
                Graphics2D outg = ();
                // 画二维码到新的面板
                (image, 0, 0, (), (), null);
                // 画文字到新的面板
                ();
                (new Font("楷体", , 30)); // 字体、字型、字号
                int strWidth = ().stringWidth(note);
                if (strWidth > 399) {
                    // //长度过长就截取前面部分
                    // 长度过长就换行
                    String note1 = (0, () / 2);
                    String note2 = (() / 2, ());
                    int strWidth1 = ().stringWidth(note1);
                    int strWidth2 = ().stringWidth(note2);
                    (note1, 200 - strWidth1 / 2, height + (() - height) / 2 + 12);
                    BufferedImage outImage2 = new BufferedImage(400, 485, BufferedImage.TYPE_4BYTE_ABGR);
                    Graphics2D outg2 = ();
                    (outImage, 0, 0, (), (), null);
                    ();
                    (new Font("宋体", , 30)); // 字体、字型、字号
                    (note2, 200 - strWidth2 / 2,() + (() - ()) / 2 + 5);
                    ();
                    ();
                    outImage = outImage2;
                } else {
                    (note, 200 - strWidth / 2, height + (() - height) / 2 + 12); // 画文字
                }
                ();
                ();
                image = outImage;
            }

            ();
            //写入输出流,用于转换
            ByteArrayOutputStream tmp = new ByteArrayOutputStream();
            (image, "png", tmp);
            ();
            return "data:image/png;base64,"+(new String(Base64.encodeBase64(())));
        } catch (Exception e) {
            ();
        }
        return null;
    }


    /**
     * 生成不带logo的二维码图片
     * note 二维码下方的标题,如果不需要为空即可
     * 返回字符串,将此字符串放入IMG标签的SRC即可
     */
    public static  String drawLogoQRCodeNotLog(String qrUrl, String note) {
        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        try {
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            // 参数顺序分别为:编码内容,编码类型,生成图片宽度,生成图片高度,设置参数
            BitMatrix bm = (qrUrl, BarcodeFormat.QR_CODE, WIDTH, HEIGHT, hints);

            // 开始利用二维码数据创建Bitmap图片,分别设为黑(0xFFFFFFFF)白(0xFF000000)两色
            for (int x = 0; x < WIDTH; x++) {
                for (int y = 0; y < HEIGHT; y++) {
                    (x, y, (x, y) ? QRCOLOR : BGWHITE);
                }
            }

            int height = ();

            // 自定义文本描述
            if ((note)) {
                // 新的图片,把带logo的二维码下面加上文字
                BufferedImage outImage = new BufferedImage(400, 445, BufferedImage.TYPE_4BYTE_ABGR);
                Graphics2D outg = ();
                // 画二维码到新的面板
                (image, 0, 0, (), (), null);
                // 画文字到新的面板
                ();
                (new Font("楷体", , 30)); // 字体、字型、字号
                int strWidth = ().stringWidth(note);
                if (strWidth > 399) {
                    // //长度过长就截取前面部分
                    // 长度过长就换行
                    String note1 = (0, () / 2);
                    String note2 = (() / 2, ());
                    int strWidth1 = ().stringWidth(note1);
                    int strWidth2 = ().stringWidth(note2);
                    (note1, 200 - strWidth1 / 2, height + (() - height) / 2 + 12);
                    BufferedImage outImage2 = new BufferedImage(400, 485, BufferedImage.TYPE_4BYTE_ABGR);
                    Graphics2D outg2 = ();
                    (outImage, 0, 0, (), (), null);
                    ();
                    (new Font("宋体", , 30)); // 字体、字型、字号
                    (note2, 200 - strWidth2 / 2,() + (() - ()) / 2 + 5);
                    ();
                    ();
                    outImage = outImage2;
                } else {
                    (note, 200 - strWidth / 2, height + (() - height) / 2 + 12); // 画文字
                }
                ();
                ();
                image = outImage;
            }

            ();
            //写入缓存区,用于转换
            ByteArrayOutputStream tmp = new ByteArrayOutputStream();
            (image, "png", tmp);
            ();
            return "data:image/png;base64,"+(new String(Base64.encodeBase64(())));
        } catch (Exception e) {
            ();
        }
        return null;
    }

}

 

 

上面的两个方法都是返回的字符串,将此字符串传入前端,放入IMG标签的SRC即可!

 

我们来说另外一个问题:

如何校验一个二维码的时效性,这里我不展示代码了,只给大家说个思路:

1.在生成二维码的那个URL中带上token,token的值你们*发挥,只要能保证这个token唯一就行

2.然后把这个token保存到redis中,设置有效期,比如60S

3.当用户扫描二维码的时候,就会带着token跳转URL到我们指定的页面,这时候我们获取到token,传到后端校验即可!

 

点关注不迷路,海哥教你学技术!